This commit is contained in:
Lana Steuck 2014-10-16 14:16:03 -07:00
commit 6a5adc81a0
70 changed files with 2176 additions and 562 deletions

View File

@ -26,3 +26,5 @@ jcov2/*
test/lib/testng.jar
test/script/external/*
.project
.externalToolBuilders/*
.settings/*

137
nashorn/bin/runopt.sh Normal file
View File

@ -0,0 +1,137 @@
#!/bin/sh
#
# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
###########################################################################################
# This is a helper script to evaluate nashorn with optimistic types
# it produces a flight recording for every run, and uses the best
# known flags for performance for the current configration
###########################################################################################
# Flags to enable assertions, we need the system assertions too, since
# this script runs Nashorn in the BCP to override any nashorn.jar that might
# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
#
ENABLE_ASSERTIONS_FLAGS="-ea -esa"
# Flags to instrument lambdaform computation, caching, interpretation and compilation
# Default compile threshold for lambdaforms is 30
#
#LAMBDAFORM_FLAGS="\
# -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
# -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
# -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
# -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
# Flags to run trusted tests from the Nashorn test suite
#
#TRUSTED_TEST_FLAGS="\
#-Djava.security.manager \
#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
# Testing out new code optimizations using the generic hotspot "new code" parameter
#
#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
#
#-Dnashorn.typeInfo.disabled=false \
# and for Nashorn options:
# --class-cache-size=0 --persistent-code-cache=false
# Unique timestamped file name for JFR recordings. For JFR, we also have to
# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
# stack traces.
#
# It is also recommended that you go into $JAVA_HOME/jre/lib/jfr/default.jfc and
# set the "method-sampling-interval" Normal and Maximum sample time as low as you
# can go (10 ms on most platforms). The default is normally higher. The increased
# sampling overhead is usually negligible for Nashorn runs, but the data is better
if [ -z $JFR_FILENAME ]; then
JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
echo "Using default JFR filename: ${JFR_FILENAME}..."
fi
# Flight recorder
#
# see above - already in place, copy the flags down here to disable
ENABLE_FLIGHT_RECORDER_FLAGS="\
-XX:+UnlockCommercialFeatures \
-XX:+FlightRecorder \
-XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
# keeping this flag around for experimental reasons. Replace + with - to switch it off
#
#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
# this disables them if needed
#
#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
# Add timing to time the compilation phases.
#ENABLE_TIME_FLAGS=--log=time
# Add ShowHiddenFrames to get lambda form internals on the stack traces
#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
# That tired compilation is switched off, for C2 only output and that the number of
# compiler threads is set to 1 for determinsm.
#
#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
# that we run the script from the make dir
DIR=..
NASHORN_JAR=$DIR/dist/nashorn.jar
# The built Nashorn jar is placed first in the bootclasspath to override the JDK
# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
# nashorn count as system assertions in this configuration
# Type profiling default level is 111, 222 adds some compile time, but is faster
$JAVA_HOME/bin/java \
$ENABLE_ASSERTIONS_FLAGS \
$LAMBDAFORM_FLAGS \
$TRUSTED_FLAGS \
$USE_NEW_CODE_FLAGS \
$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
$ENABLE_FLIGHT_RECORDER_FLAGS \
$ENABLE_TYPE_SPECIALIZATION_FLAGS \
$TIERED_COMPILATION_THRESOLD_FLAGS \
$DISABLE_MATH_INTRINSICS_FLAGS \
$PRINT_ASM_FLAGS \
-Xbootclasspath/p:$NASHORN_JAR \
-Xms2G -Xmx2G \
-XX:TypeProfileLevel=222 \
-cp $CLASSPATH:../build/test/classes/ \
jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}

View File

@ -408,7 +408,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}">
<include name="**/framework/ScriptTest.class"/>
</fileset>
<testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes"
<testng outputdir="${build.nosecurity.test.results.dir}/${testResultsSubDir}" classfilesetref="test.nosecurity.classes"
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
<jvmarg line="${ext.class.path}"/>
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} -Dbuild.dir=${build.dir}"/>
@ -431,7 +431,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="-test-security">
<delete dir="${build.dir}/nashorn_code_cache"/>
<property name="debug.test.jvmargs" value=""/>
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
<testng outputdir="${build.test.results.dir}/${testResultsSubDir}" classfilesetref="test.classes"
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
<jvmarg line="${ext.class.path}"/>
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
@ -457,9 +457,11 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<echo message="Running test suite in OPTIMISTIC mode..."/>
<antcall target="-test-nosecurity" inheritRefs="true">
<param name="optimistic" value="true"/>
<param name="testResultsSubDir" value="optimistic"/>
</antcall>
<antcall target="-test-security" inheritRefs="true">
<param name="optimistic" value="true"/>
<param name="testResultsSubDir" value="optimistic"/>
</antcall>
</target>
@ -467,9 +469,11 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<echo message="Running test suite in PESSIMISTIC mode..."/>
<antcall target="-test-nosecurity" inheritRefs="true">
<param name="optimistic" value="false"/>
<param name="testResultsSubDir" value="pessimistic"/>
</antcall>
<antcall target="-test-security" inheritRefs="true">
<param name="optimistic" value="false"/>
<param name="testResultsSubDir" value="pessimistic"/>
</antcall>
</target>

View File

@ -229,6 +229,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
private <T> T getInterfaceInner(final Object thiz, final Class<T> clazz) {
assert !(thiz instanceof ScriptObject) : "raw ScriptObject not expected here";
if (clazz == null || !clazz.isInterface()) {
throw new IllegalArgumentException(getMessage("interface.class.expected"));
}
@ -251,17 +253,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
final ScriptObjectMirror mirror = (ScriptObjectMirror)thiz;
realSelf = mirror.getScriptObject();
realGlobal = mirror.getHomeGlobal();
if (! isOfContext(realGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
} else if (thiz instanceof ScriptObject) {
// called from script code.
realSelf = (ScriptObject)thiz;
realGlobal = Context.getGlobal();
if (realGlobal == null) {
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
}
if (! isOfContext(realGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
@ -368,6 +359,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
name.getClass(); // null check
assert !(selfObject instanceof ScriptObject) : "raw ScriptObject not expected here";
Global invokeGlobal = null;
ScriptObjectMirror selfMirror = null;
@ -377,20 +369,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
invokeGlobal = selfMirror.getHomeGlobal();
} else if (selfObject instanceof ScriptObject) {
// invokeMethod called from script code - in which case we may get 'naked' ScriptObject
// Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
final Global oldGlobal = Context.getGlobal();
invokeGlobal = oldGlobal;
if (oldGlobal == null) {
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
}
if (! isOfContext(oldGlobal, nashornContext)) {
throw new IllegalArgumentException(getMessage("script.object.from.another.engine"));
}
selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
} else if (selfObject == null) {
// selfObject is null => global function call
final Global ctxtGlobal = getNashornGlobalFrom(context);

View File

@ -25,8 +25,6 @@
package jdk.nashorn.api.scripting;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.LinkerServices;
@ -75,11 +73,8 @@ public final class ScriptUtils {
* @param sync the object to synchronize on
* @return a synchronizing wrapper function
*/
public static Object makeSynchronizedFunction(final Object func, final Object sync) {
if (func instanceof ScriptFunction) {
return ((ScriptFunction)func).makeSynchronizedFunction(sync);
}
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
return func.makeSynchronizedFunction(unwrap(sync));
}
/**
@ -88,12 +83,8 @@ public final class ScriptUtils {
* @param obj object to be wrapped
* @return wrapped object
*/
public static Object wrap(final Object obj) {
if (obj instanceof ScriptObject) {
return ScriptObjectMirror.wrap(obj, Context.getGlobal());
}
return obj;
public static ScriptObjectMirror wrap(final ScriptObject obj) {
return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
}
/**
@ -160,14 +151,15 @@ public final class ScriptUtils {
}
final LinkerServices linker = Bootstrap.getLinkerServices();
final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz);
final Object objToConvert = unwrap(obj);
final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(), clazz);
if (converter == null) {
// no supported conversion!
throw new UnsupportedOperationException("conversion not supported");
}
try {
return converter.invoke(obj);
return converter.invoke(objToConvert);
} catch (final RuntimeException | Error e) {
throw e;
} catch (final Throwable t) {

View File

@ -511,16 +511,6 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
thisProperties.push(new HashSet<String>());
if (functionNode.isDeclared()) {
// Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
// is not a program - it is a function being compiled on-demand.
final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
final IdentNode ident = functionNode.getIdent();
defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
}
}
// Every function has a body, even the ones skipped on reparse (they have an empty one). We're
// asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
// are used in them.
@ -532,16 +522,36 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
@Override
public boolean enterVarNode(final VarNode varNode) {
start(varNode);
// Normally, a symbol assigned in a var statement is not live for its RHS. Since we also represent function
// declarations as VarNodes, they are exception to the rule, as they need to have the symbol visible to the
// body of the declared function for self-reference.
if (varNode.isFunctionDeclaration()) {
defineVarIdent(varNode);
}
return true;
}
@Override
public Node leaveVarNode(final VarNode varNode) {
final IdentNode ident = varNode.getName();
defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
if (!varNode.isFunctionDeclaration()) {
defineVarIdent(varNode);
}
return super.leaveVarNode(varNode);
}
private void defineVarIdent(final VarNode varNode) {
final IdentNode ident = varNode.getName();
final int flags;
if (varNode.isAnonymousFunctionDeclaration()) {
flags = IS_INTERNAL;
} else if (lc.getCurrentFunction().isProgram()) {
flags = IS_SCOPE;
} else {
flags = 0;
}
defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | flags);
}
private Symbol exceptionSymbol() {
return newObjectInternal(EXCEPTION_PREFIX);
}

View File

@ -410,10 +410,29 @@ public final class Compiler implements Loggable {
baseName = baseName + installer.getUniqueScriptId();
}
final String mangled = NameCodec.encode(baseName);
// ASM's bytecode verifier does not allow JVM allowed safe escapes using '\' as escape char.
// While ASM accepts such escapes for method names, field names, it enforces Java identifier
// for class names. Workaround that ASM bug here by replacing JVM 'dangerous' chars with '_'
// rather than safe encoding using '\'.
final String mangled = env._verify_code? replaceDangerChars(baseName) : NameCodec.encode(baseName);
return mangled != null ? mangled : baseName;
}
private static final String DANGEROUS_CHARS = "\\/.;:$[]<>";
private static String replaceDangerChars(final String name) {
final int len = name.length();
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < len; i++) {
final char ch = name.charAt(i);
if (DANGEROUS_CHARS.indexOf(ch) != -1) {
buf.append('_');
} else {
buf.append(ch);
}
}
return buf.toString();
}
private String firstCompileUnitName() {
final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE).
append('/').

View File

@ -98,6 +98,7 @@ import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.runtime.ArgumentSetter;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
@ -2125,7 +2126,14 @@ public class MethodEmitter implements Emitter {
int pos = 0;
for (int i = argCount - 1; i >= 0; i--) {
paramTypes[i] = stack.peek(pos++);
Type pt = stack.peek(pos++);
// "erase" specific ScriptObject subtype info - except for NativeArray.
// NativeArray is used for array/List/Deque conversion for Java calls.
if (ScriptObject.class.isAssignableFrom(pt.getTypeClass()) &&
!NativeArray.class.isAssignableFrom(pt.getTypeClass())) {
pt = Type.SCRIPT_OBJECT;
}
paramTypes[i] = pt;
}
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
for (int i = 0; i < argCount; i++) {

View File

@ -29,16 +29,22 @@ import static jdk.nashorn.internal.runtime.Property.NOT_CONFIGURABLE;
import static jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
import static jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
import java.lang.invoke.MethodType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.Optimistic;
import jdk.nashorn.internal.objects.ArrayBufferView;
import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@ -47,6 +53,13 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Used during recompilation.
*/
final class TypeEvaluator {
/**
* Type signature for invocation of functions without parameters: we must pass (callee, this) of type
* (ScriptFunction, Object) respectively. We also use Object as the return type (we must pass something,
* but it'll be ignored; it can't be void, though).
*/
private static final MethodType EMPTY_INVOCATION_TYPE = MethodType.methodType(Object.class, ScriptFunction.class, Object.class);
private final Compiler compiler;
private final ScriptObject runtimeScope;
@ -190,30 +203,46 @@ final class TypeEvaluator {
return null;
}
return getPropertyType(runtimeScope, ((IdentNode)expr).getName());
}
if (expr instanceof AccessNode) {
} else if (expr instanceof AccessNode) {
final AccessNode accessNode = (AccessNode)expr;
final Object base = evaluateSafely(accessNode.getBase());
if (!(base instanceof ScriptObject)) {
return null;
}
return getPropertyType((ScriptObject)base, accessNode.getProperty());
}
if (expr instanceof IndexNode) {
} else if (expr instanceof IndexNode) {
final IndexNode indexNode = (IndexNode)expr;
final Object base = evaluateSafely(indexNode.getBase());
if(!(base instanceof NativeArray)) {
// We only know how to deal with NativeArray. TODO: maybe manage buffers too
return null;
if(base instanceof NativeArray || base instanceof ArrayBufferView) {
// NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their
// underlying array storage, not based on values of individual elements. Thus, a LongArrayData will
// throw UOE for every optimistic int linkage attempt, even if the long value being returned in the
// first invocation would be representable as int. That way, we can presume that the array's optimistic
// type is the most optimistic type for which an element getter has a chance of executing successfully.
return ((ScriptObject)base).getArray().getOptimisticType();
}
} else if (expr instanceof CallNode) {
// Currently, we'll only try to guess the return type of immediately invoked function expressions with no
// parameters, that is (function() { ... })(). We could do better, but these are all heuristics and we can
// gradually introduce them as needed. An easy one would be to do the same for .call(this) idiom.
final CallNode callExpr = (CallNode)expr;
final Expression fnExpr = callExpr.getFunction();
if (fnExpr instanceof FunctionNode) {
final FunctionNode fn = (FunctionNode)fnExpr;
if (callExpr.getArgs().isEmpty()) {
final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
if (data != null) {
final Type returnType = Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
if (returnType == Type.BOOLEAN) {
// We don't have optimistic booleans. In fact, optimistic call sites getting back boolean
// currently deoptimize all the way to Object.
return Type.OBJECT;
}
assert returnType == Type.INT || returnType == Type.LONG || returnType == Type.NUMBER || returnType == Type.OBJECT;
return returnType;
}
}
}
// NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their underlying
// array storage, not based on values of individual elements. Thus, a LongArrayData will throw UOE for every
// optimistic int linkage attempt, even if the long value being returned in the first invocation would be
// representable as int. That way, we can presume that the array's optimistic type is the most optimistic
// type for which an element getter has a chance of executing successfully.
return ((NativeArray)base).getArray().getOptimisticType();
}
return null;

View File

@ -80,11 +80,12 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
/**
* Constructor
*
* @param token token
* @param finish finish
* @param statements statements
* @param token The first token of the block
* @param finish The index of the last character
* @param flags The flags of the block
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final Statement... statements) {
public Block(final long token, final int finish, final int flags, final Statement... statements) {
super(token, finish);
this.statements = Arrays.asList(statements);
@ -92,29 +93,52 @@ public class Block extends Node implements BreakableNode, Terminal, Flags<Block>
this.entryLabel = new Label("block_entry");
this.breakLabel = new Label("block_break");
final int len = statements.length;
this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
final int terminalFlags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
this.flags = terminalFlags | flags;
this.conversion = null;
}
/**
* Constructs a new block
*
* @param token The first token of the block
* @param finish The index of the last character
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final Statement...statements){
this(token, finish, 0, statements);
}
/**
* Constructs a new block
*
* @param token The first token of the block
* @param finish The index of the last character
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final List<Statement> statements){
this(token, finish, 0, statements);
}
/**
* Constructor
*
* @param token token
* @param finish finish
* @param statements statements
* @param token The first token of the block
* @param finish The index of the last character
* @param flags The flags of the block
* @param statements All statements in the block
*/
public Block(final long token, final int finish, final List<Statement> statements) {
this(token, finish, statements.toArray(new Statement[statements.size()]));
public Block(final long token, final int finish, final int flags, final List<Statement> statements) {
this(token, finish, flags, statements.toArray(new Statement[statements.size()]));
}
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols, final LocalVariableConversion conversion) {
super(block);
super(block, finish);
this.statements = statements;
this.flags = flags;
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
this.entryLabel = new Label(block.entryLabel);
this.breakLabel = new Label(block.breakLabel);
this.finish = finish;
this.conversion = conversion;
}

View File

@ -54,20 +54,37 @@ public final class ForNode extends LoopNode {
private final int flags;
/**
* Constructs a ForNode
*
* @param lineNumber The line number of header
* @param token The for token
* @param finish The last character of the for node
* @param body The body of the for node
* @param flags The flags
*/
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags){
this(lineNumber, token, finish, body, flags, null, null, null);
}
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param body body
* @param flags flags
* @param lineNumber The line number of header
* @param token The for token
* @param finish The last character of the for node
* @param body The body of the for node
* @param flags The flags
* @param init The initial expression
* @param test The test expression
* @param modify The modify expression
*/
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags) {
super(lineNumber, token, finish, body, false);
public ForNode(final int lineNumber, final long token, final int finish, final Block body, final int flags, final Expression init, final JoinPredecessorExpression test, final JoinPredecessorExpression modify) {
super(lineNumber, token, finish, body, test, false);
this.flags = flags;
this.init = null;
this.modify = null;
this.init = init;
this.modify = modify;
}
private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
@ -166,16 +183,6 @@ public final class ForNode extends LoopNode {
public boolean isForIn() {
return (flags & IS_FOR_IN) != 0;
}
/**
* Flag this to be a for in construct
* @param lc lexical context
* @return new for node if changed or existing if not
*/
public ForNode setIsForIn(final LexicalContext lc) {
return setFlags(lc, flags | IS_FOR_IN);
}
/**
* Is this a for each construct, known from e.g. Rhino. This will be a for of construct
* in ECMAScript 6
@ -185,15 +192,6 @@ public final class ForNode extends LoopNode {
return (flags & IS_FOR_EACH) != 0;
}
/**
* Flag this to be a for each construct
* @param lc lexical context
* @return new for node if changed or existing if not
*/
public ForNode setIsForEach(final LexicalContext lc) {
return setFlags(lc, flags | IS_FOR_EACH);
}
/**
* If this is a for in or for each construct, there is an iterator symbol
* @return the symbol for the iterator to be used, or null if none exists
@ -260,13 +258,6 @@ public final class ForNode extends LoopNode {
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
}
private ForNode setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));

View File

@ -31,7 +31,6 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
@ -46,6 +45,7 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
@ -299,12 +299,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @param token token
* @param finish finish
* @param firstToken first token of the function node (including the function declaration)
* @param lastToken lastToken
* @param namespace the namespace
* @param ident the identifier
* @param name the name of the function
* @param parameters parameter list
* @param kind kind of function as in {@link FunctionNode.Kind}
* @param flags initial flags
* @param body body of the function
* @param state The initial state from the parser. Must be one of {@link CompilationState#PARSED} and {@link CompilationState#PARSE_ERROR}
* @param endParserState The parser state at the end of the parsing.
*/
public FunctionNode(
final Source source,
@ -312,12 +316,16 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final long token,
final int finish,
final long firstToken,
final long lastToken,
final Namespace namespace,
final IdentNode ident,
final String name,
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
final int flags) {
final int flags,
final Block body,
final CompilationState state,
final Object endParserState) {
super(token, finish);
this.source = source;
@ -327,15 +335,15 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
this.kind = kind;
this.parameters = parameters;
this.firstToken = firstToken;
this.lastToken = token;
this.lastToken = lastToken;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.compilationState = EnumSet.of(CompilationState.INITIALIZED, state);
this.flags = flags;
this.compileUnit = null;
this.body = null;
this.body = body;
this.thisProperties = 0;
this.rootClass = null;
this.endParserState = null;
this.endParserState = endParserState;
}
private FunctionNode(
@ -439,7 +447,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @return the id
*/
public int getId() {
return position();
return isProgram() ? -1: Token.descPosition(firstToken);
}
/**
@ -902,34 +910,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return lastToken;
}
/**
* Set the last token for this function's code
* @param lc lexical context
* @param lastToken the last token
* @return function node or a new one if state was changed
*/
public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
if (this.lastToken == lastToken) {
return this;
}
return Node.replaceInLexicalContext(
lc,
this,
new FunctionNode(
this,
lastToken,
endParserState,
flags,
name,
returnType,
compileUnit,
compilationState,
body,
parameters,
thisProperties,
rootClass));
}
/**
* Returns the end parser state for this function.
* @return the end parser state for this function.
@ -938,33 +918,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return endParserState;
}
/**
* Set the end parser state for this function.
* @param lc lexical context
* @param endParserState the parser state to set
* @return function node or a new one if state was changed
*/
public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
if (this.endParserState == endParserState) {
return this;
}
return Node.replaceInLexicalContext(
lc,
this,
new FunctionNode(
this,
lastToken,
endParserState,
flags,
name,
returnType,
compileUnit,
compilationState,
body,
parameters,
thisProperties, rootClass));
}
/**
* Get the name of this function
* @return the name

View File

@ -53,14 +53,15 @@ public abstract class LoopNode extends BreakableStatement {
* @param token token
* @param finish finish
* @param body loop body
* @param test test
* @param controlFlowEscapes controlFlowEscapes
*/
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final boolean controlFlowEscapes) {
protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = null;
this.body = body;
this.controlFlowEscapes = controlFlowEscapes;
this.test = test;
}
/**

View File

@ -39,7 +39,7 @@ public abstract class Node implements Cloneable {
protected final int start;
/** End of source range. */
protected int finish;
protected final int finish;
/** Token descriptor. */
private final long token;
@ -80,6 +80,18 @@ public abstract class Node implements Cloneable {
this.finish = node.finish;
}
/**
* Copy constructor that overrides finish
*
* @param node source node
* @param finish Last character
*/
protected Node(final Node node, final int finish) {
this.token = node.token;
this.start = node.start;
this.finish = finish;
}
/**
* Is this a loop node?
*
@ -151,14 +163,6 @@ public abstract class Node implements Cloneable {
return finish;
}
/**
* Set finish position for this node in the source string
* @param finish finish
*/
public void setFinish(final int finish) {
this.finish = finish;
}
/**
* Get start position for node
* @return start position

View File

@ -272,4 +272,12 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
public boolean isFunctionDeclaration() {
return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
}
/**
* Returns true if this is an anonymous function declaration.
* @return true if this is an anonymous function declaration.
*/
public boolean isAnonymousFunctionDeclaration() {
return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
}
}

View File

@ -45,9 +45,11 @@ public final class WhileNode extends LoopNode {
* @param token token
* @param finish finish
* @param isDoWhile is this a do while loop?
* @param test test expression
* @param body body of the while loop
*/
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
super(lineNumber, token, finish, null, false);
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile, final JoinPredecessorExpression test, final Block body) {
super(lineNumber, token, finish, body, test, false);
this.isDoWhile = isDoWhile;
}
@ -55,10 +57,10 @@ public final class WhileNode extends LoopNode {
* Internal copy constructor
*
* @param whileNode while node
* @param test test
* @param body body
* @param test Test expression
* @param body body of the while loop
* @param controlFlowEscapes control flow escapes?
* @param conversion TODO
* @param conversion local variable conversion info
*/
private WhileNode(final WhileNode whileNode, final JoinPredecessorExpression test, final Block body, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
super(whileNode, test, body, controlFlowEscapes, conversion);

View File

@ -42,14 +42,16 @@ public final class WithNode extends LexicalContextStatement {
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param lineNumber Line number of the header
* @param token First token
* @param finish Character index of the last token
* @param expression With expression
* @param body Body of with node
*/
public WithNode(final int lineNumber, final long token, final int finish) {
public WithNode(final int lineNumber, final long token, final int finish, final Expression expression, final Block body) {
super(lineNumber, token, finish);
this.expression = null;
this.body = null;
this.expression = expression;
this.body = body;
}
private WithNode(final WithNode node, final Expression expression, final Block body) {

View File

@ -31,7 +31,6 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@ -46,7 +45,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
@ScriptClass("ArrayBufferView")
abstract class ArrayBufferView extends ScriptObject {
public abstract class ArrayBufferView extends ScriptObject {
private final NativeArrayBuffer buffer;
private final int byteOffset;

View File

@ -561,7 +561,6 @@ public final class Global extends ScriptObject implements Scope {
*
* @param engine ScriptEngine to initialize
*/
@SuppressWarnings("hiding")
public void initBuiltinObjects(final ScriptEngine engine) {
if (this.builtinObject != null) {
// already initialized, just return
@ -1718,7 +1717,6 @@ public final class Global extends ScriptObject implements Scope {
return func;
}
@SuppressWarnings("hiding")
private void init(final ScriptEngine engine) {
assert Context.getGlobal() == this : "this global is not set as current";

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.nashorn.api.scripting.NashornException;
@ -131,7 +130,6 @@ public final class NativeError extends ScriptObject {
// This is called NativeError, NativeTypeError etc. to
// associate a ECMAException with the ECMA Error object.
@SuppressWarnings("unused")
static void initException(final ScriptObject self) {
// ECMAException constructor has side effects
new ECMAException(self, null);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -140,6 +141,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
return getElem(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getDouble(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -140,6 +141,11 @@ public final class NativeFloat64Array extends ArrayBufferView {
return getElem(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getDouble(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -123,16 +124,31 @@ public final class NativeInt16Array extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -121,16 +122,31 @@ public final class NativeInt32Array extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -121,16 +122,31 @@ public final class NativeInt8Array extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.util.Collection;
@ -36,7 +35,6 @@ import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@ -90,7 +88,11 @@ public final class NativeJava {
*/
@Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
return ScriptUtils.makeSynchronizedFunction(func, obj);
if (func instanceof ScriptFunction) {
return ((ScriptFunction)func).makeSynchronizedFunction(obj);
}
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
}
/**

View File

@ -25,6 +25,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import jdk.internal.dynalink.CallSiteDescriptor;
@ -36,9 +37,11 @@ import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
/**
@ -94,33 +97,30 @@ public final class NativeJavaImporter extends ScriptObject {
}
/**
* "No such property" call placeholder.
*
* This can never be called as we override {@link ScriptObject#noSuchProperty}. We do declare it here as it's a signal
* to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a {@code noSuchProperty} on this object.
* "No such property" handler.
*
* @param self self reference
* @param name property name
* @return never returns
* @return value of the missing property
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object __noSuchProperty__(final Object self, final Object name) {
throw new AssertionError("__noSuchProperty__ placeholder called");
if (! (self instanceof NativeJavaImporter)) {
throw typeError("not.a.java.importer", ScriptRuntime.safeToString(self));
}
return ((NativeJavaImporter)self).createProperty(JSType.toString(name));
}
/**
* "No such method call" placeholder
*
* This can never be called as we override {@link ScriptObject#noSuchMethod}. We do declare it here as it's a signal
* to {@link jdk.nashorn.internal.runtime.WithObject} that it's worth trying doing a noSuchProperty on this object.
* "No such method call" handler
*
* @param self self reference
* @param args arguments to method
* @return never returns
* @return never returns always throw TypeError
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object __noSuchMethod__(final Object self, final Object... args) {
throw new AssertionError("__noSuchMethod__ placeholder called");
throw typeError("not.a.function", ScriptRuntime.safeToString(args[0]));
}
@Override

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -127,16 +128,31 @@ public final class NativeUint16Array extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -128,7 +129,7 @@ public final class NativeUint32Array extends ArrayBufferView {
@Override
public Class<?> getElementType() {
return int.class;
return long.class;
}
@Override
@ -141,11 +142,21 @@ public final class NativeUint32Array extends ArrayBufferView {
return getElem(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getLong(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getLong(index);
}
@Override
public Object getObject(final int index) {
return getLong(index);

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -127,16 +128,31 @@ public final class NativeUint8Array extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -157,16 +158,31 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
return getElem(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public long getLong(final int index) {
return getInt(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public double getDouble(final int index) {
return getInt(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
return getElem(index);
}
@Override
public Object getObject(final int index) {
return getInt(index);

View File

@ -0,0 +1,334 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.Iterator;
import java.util.NoSuchElementException;
import jdk.nashorn.internal.ir.Statement;
/**
* A class that tracks the current lexical context of node visitation as a stack of {@code ParserContextNode} nodes. Has special
* methods to retrieve useful subsets of the context.
*
* This is implemented with a primitive array and a stack pointer, because it really makes a difference
* performance wise. None of the collection classes were optimal
*/
class ParserContext {
private ParserContextNode[] stack;
private int sp;
private static final int INITIAL_DEPTH = 16;
/**
* Constructs a ParserContext,
* initializes the stack
*/
public ParserContext(){
this.sp = 0;
this.stack = new ParserContextNode[INITIAL_DEPTH];
}
/**
* Pushes a new block on top of the context, making it the innermost open block.
* @param node the new node
* @return The node that was pushed
*/
public <T extends ParserContextNode> T push(final T node) {
assert !contains(node);
if (sp == stack.length) {
final ParserContextNode[] newStack = new ParserContextNode[sp * 2];
System.arraycopy(stack, 0, newStack, 0, sp);
stack = newStack;
}
stack[sp] = node;
sp++;
return node;
}
/**
* The topmost node on the stack
* @return The topmost node on the stack
*/
public ParserContextNode peek() {
return stack[sp - 1];
}
/**
* Removes and returns the topmost Node from the stack.
* @param node The node expected to be popped, used for sanity check
* @return The removed node
*/
public <T extends ParserContextNode> T pop(final T node) {
--sp;
@SuppressWarnings("unchecked")
final T popped = (T)stack[sp];
stack[sp] = null;
assert node == popped;
return popped;
}
/**
* Tests if a node is on the stack.
* @param node The node to test
* @return true if stack contains node, false otherwise
*/
public boolean contains(final ParserContextNode node) {
for (int i = 0; i < sp; i++) {
if (stack[i] == node) {
return true;
}
}
return false;
}
/**
* Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
* @return Returns the topmost {@link ParserContextBreakableNode} on the stack, null if none on stack
*/
private ParserContextBreakableNode getBreakable() {
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
final ParserContextBreakableNode next = iter.next();
if (next.isBreakableWithoutLabel()) {
return next;
}
}
return null;
}
/**
* Find the breakable node corresponding to this label.
* @param labelName name of the label to search for. If null, the closest breakable node will be returned
* unconditionally, e.g. a while loop with no label
* @return closest breakable node
*/
public ParserContextBreakableNode getBreakable(final String labelName) {
if (labelName != null) {
final ParserContextLabelNode foundLabel = findLabel(labelName);
if (foundLabel != null) {
// iterate to the nearest breakable to the foundLabel
ParserContextBreakableNode breakable = null;
for (final NodeIterator<ParserContextBreakableNode> iter = new NodeIterator<>(ParserContextBreakableNode.class, foundLabel); iter.hasNext(); ) {
breakable = iter.next();
}
return breakable;
}
return null;
} else {
return getBreakable();
}
}
/**
* Returns the loop node of the current loop, or null if not inside a loop
* @return loop noder
*/
public ParserContextLoopNode getCurrentLoop() {
final Iterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, getCurrentFunction());
return iter.hasNext() ? iter.next() : null;
}
private ParserContextLoopNode getContinueTo() {
return getCurrentLoop();
}
/**
* Find the continue target node corresponding to this label.
* @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a
* while loop with no label
* @return closest continue target node
*/
public ParserContextLoopNode getContinueTo(final String labelName) {
if (labelName != null) {
final ParserContextLabelNode foundLabel = findLabel(labelName);
if (foundLabel != null) {
// iterate to the nearest loop to the foundLabel
ParserContextLoopNode loop = null;
for (final NodeIterator<ParserContextLoopNode> iter = new NodeIterator<>(ParserContextLoopNode.class, foundLabel); iter.hasNext(); ) {
loop = iter.next();
}
return loop;
}
return null;
}
return getContinueTo();
}
/**
* Get the function body of a function node on the stack.
* This will trigger an assertion if node isn't present
* @param functionNode function node
* @return body of function node
*/
public ParserContextBlockNode getFunctionBody(final ParserContextFunctionNode functionNode) {
for (int i = sp - 1; i >= 0 ; i--) {
if (stack[i] == functionNode) {
return (ParserContextBlockNode)stack[i + 1];
}
}
throw new AssertionError(functionNode.getName() + " not on context stack");
}
/**
* Check the stack for a given label node by name
* @param name name of the label
* @return LabelNode if found, null otherwise
*/
public ParserContextLabelNode findLabel(final String name) {
for (final Iterator<ParserContextLabelNode> iter = new NodeIterator<>(ParserContextLabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
final ParserContextLabelNode next = iter.next();
if (next.getLabelName().equals(name)) {
return next;
}
}
return null;
}
/**
* Prepends a statement to the current node.
* @param statement The statement to prepend
*/
public void prependStatementToCurrentNode(final Statement statement) {
assert statement != null;
stack[sp - 1].prependStatement(statement);
}
/**
* Appends a statement to the current Node.
* @param statement The statement to append
*/
public void appendStatementToCurrentNode(final Statement statement) {
assert statement != null;
stack[sp - 1].appendStatement(statement);
}
/**
* Returns the innermost function in the context.
* @return the innermost function in the context.
*/
public ParserContextFunctionNode getCurrentFunction() {
for (int i = sp - 1; i >= 0; i--) {
if (stack[i] instanceof ParserContextFunctionNode) {
return (ParserContextFunctionNode) stack[i];
}
}
return null;
}
/**
* Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
* @return an iterator over all blocks in the context.
*/
public Iterator<ParserContextBlockNode> getBlocks() {
return new NodeIterator<>(ParserContextBlockNode.class);
}
/**
* Returns the innermost block in the context.
* @return the innermost block in the context.
*/
public ParserContextBlockNode getCurrentBlock() {
return getBlocks().next();
}
/**
* The last statement added to the context
* @return The last statement added to the context
*/
public Statement getLastStatement() {
if (sp == 0) {
return null;
}
final ParserContextNode top = stack[sp - 1];
final int s = top.getStatements().size();
return s == 0 ? null : top.getStatements().get(s - 1);
}
/**
* Returns an iterator over all functions in the context, with the top (innermost open) function first.
* @return an iterator over all functions in the context.
*/
public Iterator<ParserContextFunctionNode> getFunctions() {
return new NodeIterator<>(ParserContextFunctionNode.class);
}
private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
private int index;
private T next;
private final Class<T> clazz;
private ParserContextNode until;
NodeIterator(final Class<T> clazz) {
this(clazz, null);
}
NodeIterator(final Class<T> clazz, final ParserContextNode until) {
this.index = sp - 1;
this.clazz = clazz;
this.until = until;
this.next = findNext();
}
@Override
public boolean hasNext() {
return next != null;
}
@Override
public T next() {
if (next == null) {
throw new NoSuchElementException();
}
final T lnext = next;
next = findNext();
return lnext;
}
@SuppressWarnings("unchecked")
private T findNext() {
for (int i = index; i >= 0; i--) {
final Object node = stack[i];
if (node == until) {
return null;
}
if (clazz.isAssignableFrom(node.getClass())) {
index = i - 1;
return (T)node;
}
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.ir.Statement;
/**
* Base class for parser context nodes
*/
abstract class ParserContextBaseNode implements ParserContextNode {
/**
* Flags for this node
*/
protected int flags;
private List<Statement> statements;
/**
* Constructor
*/
public ParserContextBaseNode() {
this.statements = new ArrayList<>();
}
/**
* @return The flags for this node
*/
@Override
public int getFlags() {
return flags;
}
/**
* Returns a single flag
* @param flag
* @return A single flag
*/
protected int getFlag(final int flag) {
return (flags & flag);
}
/**
* @param flag
* @return the new flags
*/
@Override
public int setFlag(final int flag) {
flags |= flag;
return flags;
}
/**
* @return The list of statements that belongs to this node
*/
@Override
public List<Statement> getStatements() {
return statements;
}
/**
* @param statements
*/
@Override
public void setStatements(final List<Statement> statements) {
this.statements = statements;
}
/**
* Adds a Statement at the end of the Statementlist
* @param statement The statement to add
*/
@Override
public void appendStatement(final Statement statement) {
this.statements.add(statement);
}
/**
* Adds a statement at the begining of the statementlist
* @param statement The statement to add
*/
@Override
public void prependStatement(final Statement statement) {
this.statements.add(0, statement);
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a block that is currently being parsed
*/
class ParserContextBlockNode extends ParserContextBaseNode implements ParserContextBreakableNode {
private final long token;
/**
* Constructs a ParserContextBlockNode
*
* @param token The first token of the block
*/
public ParserContextBlockNode(final long token) {
this.token = token;
}
@Override
public boolean isBreakableWithoutLabel() {
return false;
}
/**
* Get token
* @return The first token of the block
*/
public long getToken() {
return token;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import jdk.nashorn.internal.ir.BreakNode;
/**
* An interface that is implemented by ParserContextNodes that can
* contain a {@link BreakNode}
*/
interface ParserContextBreakableNode extends ParserContextNode {
/**
* Returns true if not i breakable without label, false otherwise
* @return Returns true if not i breakable without label, false otherwise
*/
boolean isBreakableWithoutLabel();
}

View File

@ -0,0 +1,197 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.List;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
/**
* ParserContextNode that represents a function that is currently being parsed
*/
class ParserContextFunctionNode extends ParserContextBaseNode {
/** Function name */
private final String name;
/** Function identifier node */
private final IdentNode ident;
/** Name space for function */
private final Namespace namespace;
/** Line number for function declaration */
private final int line;
/** Function node kind, see {@link FunctionNode#Kind} */
private final FunctionNode.Kind kind;
/** List of parameter identifiers for function */
private final List<IdentNode> parameters;
/** Token for function start */
private final long token;
/** Last function token */
private long lastToken;
/** Opaque node for parser end state, see {@link Parser} */
private Object endParserState;
/**
* @param token The token for the function
* @param ident External function name
* @param name Internal name of the function
* @param namespace Function's namespace
* @param line The source line of the function
* @param kind Function kind
* @param parameters The parameters of the function
*/
public ParserContextFunctionNode(final long token, final IdentNode ident, final String name, final Namespace namespace, final int line, final FunctionNode.Kind kind, final List<IdentNode> parameters) {
this.ident = ident;
this.namespace = namespace;
this.line = line;
this.kind = kind;
this.name = name;
this.parameters = parameters;
this.token = token;
}
/**
* @return Internal name of the function
*/
public String getName() {
return name;
}
/**
* @return The external identifier for the function
*/
public IdentNode getIdent() {
return ident;
}
/**
*
* @return true if function is the program function
*/
public boolean isProgram() {
return getFlag(FunctionNode.IS_PROGRAM) != 0;
}
/**
* @return if function in strict mode
*/
public boolean isStrict() {
return getFlag(FunctionNode.IS_STRICT) != 0;
}
/**
* @return true if the function has nested evals
*/
public boolean hasNestedEval() {
return getFlag(FunctionNode.HAS_NESTED_EVAL) != 0;
}
/**
* Returns true if any of the blocks in this function create their own scope.
* @return true if any of the blocks in this function create their own scope.
*/
public boolean hasScopeBlock() {
return getFlag(FunctionNode.HAS_SCOPE_BLOCK) != 0;
}
/**
* Create a unique name in the namespace of this FunctionNode
* @param base prefix for name
* @return base if no collision exists, otherwise a name prefix with base
*/
public String uniqueName(final String base) {
return namespace.uniqueName(base);
}
/**
* @return line number of the function
*/
public int getLineNumber() {
return line;
}
/**
* @return The kind if function
*/
public FunctionNode.Kind getKind() {
return kind;
}
/**
* Get parameters
* @return The parameters of the function
*/
public List<IdentNode> getParameters() {
return parameters;
}
/**
* Set last token
* @param token New last token
*/
public void setLastToken(final long token) {
this.lastToken = token;
}
/**
* @return lastToken Function's last token
*/
public long getLastToken() {
return lastToken;
}
/**
* Returns the ParserState of when the parsing of this function was ended
* @return endParserState The end parser state
*/
public Object getEndParserState() {
return endParserState;
}
/**
* Sets the ParserState of when the parsing of this function was ended
* @param endParserState The end parser state
*/
public void setEndParserState(final Object endParserState) {
this.endParserState = endParserState;
}
/**
* Returns the if of this function
* @return The function id
*/
public int getId() {
return isProgram() ? -1 : Token.descPosition(token);
}
}

View File

@ -0,0 +1,52 @@
/**
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* ParserContextNode that represents a LabelNode
*/
class ParserContextLabelNode extends ParserContextBaseNode {
/** Name for label */
private final String name;
/**
* Constructor
*
* @param name The name of the label
*/
public ParserContextLabelNode(final String name) {
this.name = name;
}
/**
* Returns the name of the label
* @return name of label
*/
public String getLabelName() {
return name;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a loop that is being parsed
*/
class ParserContextLoopNode extends ParserContextBaseNode implements ParserContextBreakableNode {
@Override
public boolean isBreakableWithoutLabel() {
return true;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
import java.util.List;
import jdk.nashorn.internal.ir.Statement;
/**
* Used for keeping state when needed in the parser.
*/
interface ParserContextNode {
/**
* @return The flags for this node
*/
public int getFlags();
/**
* @param flag The flag to set
* @return All current flags after update
*/
public int setFlag(final int flag);
/**
* @return The list of statements that belongs to this node
*/
public List<Statement> getStatements();
/**
* @param statements The statement list
*/
public void setStatements(final List<Statement> statements);
/**
* Adds a Statement at the end of the Statementlist
* @param statement The statement to add
*/
public void appendStatement(final Statement statement);
/**
* Adds a statement at the begining of the statementlist
* @param statement The statement to add
*/
public void prependStatement(final Statement statement);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a SwithcNode that is currently being parsed
*/
class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {
@Override
public boolean isBreakableWithoutLabel() {
return true;
}
}

View File

@ -483,7 +483,7 @@ public final class Context {
final int cacheSize = env._class_cache_size;
if (cacheSize > 0) {
classCache = new ClassCache(cacheSize);
classCache = new ClassCache(this, cacheSize);
}
if (env._persistent_cache) {
@ -1261,17 +1261,23 @@ public final class Context {
* Cache for compiled script classes.
*/
@SuppressWarnings("serial")
private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
@Logger(name="classcache")
private static class ClassCache extends LinkedHashMap<Source, ClassReference> implements Loggable {
private final int size;
private final ReferenceQueue<Class<?>> queue;
private final DebugLogger log;
ClassCache(final int size) {
ClassCache(final Context context, final int size) {
super(size, 0.75f, true);
this.size = size;
this.queue = new ReferenceQueue<>();
this.log = initLogger(context);
}
void cache(final Source source, final Class<?> clazz) {
if (log.isEnabled()) {
log.info("Caching ", source, " in class cache");
}
put(source, new ClassReference(clazz, queue, source));
}
@ -1283,9 +1289,28 @@ public final class Context {
@Override
public ClassReference get(final Object key) {
for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
remove(ref.source);
final Source source = ref.source;
if (log.isEnabled()) {
log.info("Evicting ", source, " from class cache.");
}
remove(source);
}
return super.get(key);
final ClassReference ref = super.get(key);
if (ref != null && log.isEnabled()) {
log.info("Retrieved class reference for ", ref.source, " from class cache");
}
return ref;
}
@Override
public DebugLogger initLogger(final Context context) {
return context.getLogger(getClass());
}
@Override
public DebugLogger getLogger() {
return log;
}
}

View File

@ -31,7 +31,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.getProgramPoint;
import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.SwitchPoint;
@ -328,7 +327,9 @@ public final class GlobalConstants implements Loggable {
}
if (!acc.mayRetry()) {
log.info("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
if (log.isEnabled()) {
log.fine("*** SET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
}
return null;
}
@ -404,7 +405,9 @@ public final class GlobalConstants implements Loggable {
}
if (acc.hasBeenInvalidated() || acc.guardFailed()) {
log.fine("*** GET: Giving up on " + quote(name) + " - retry count has exceeded");
if (log.isEnabled()) {
log.info("*** GET: Giving up on " + quote(name) + " - retry count has exceeded " + DynamicLinker.getLinkedCallSiteLocation());
}
return null;
}

View File

@ -676,6 +676,22 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
}
/**
* Returns the return type of a function specialization for particular parameter types.<br>
* <b>Be aware that the way this is implemented, it forces full materialization (compilation and installation) of
* code for that specialization.</b>
* @param callSiteType the parameter types at the call site. It must include the mandatory {@code callee} and
* {@code this} parameters, so it needs to start with at least {@code ScriptFunction.class} and
* {@code Object.class} class. Since the return type of the function is calculated from the code itself, it is
* irrelevant and should be set to {@code Object.class}.
* @param runtimeScope a current runtime scope. Can be null but when it's present it will be used as a source of
* current runtime values that can improve the compiler's type speculations (and thus reduce the need for later
* recompilations) if the specialization is not already present and thus needs to be freshly compiled.
* @return the return type of the function specialization.
*/
public Class<?> getReturnType(final MethodType callSiteType, final ScriptObject runtimeScope) {
return getBest(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS).type().returnType();
}
@Override
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {

View File

@ -209,6 +209,19 @@ public final class WithObject extends ScriptObject implements Scope {
return super.findProperty(key, deep, start);
}
@Override
protected Object invokeNoSuchProperty(final String name, final int programPoint) {
FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
if (find != null) {
final Object func = find.getObjectValue();
if (func instanceof ScriptFunction) {
return ScriptRuntime.apply((ScriptFunction)func, expression, name);
}
}
return getProto().invokeNoSuchProperty(name, programPoint);
}
@Override
public void setSplitState(final int state) {
getNonWithParent().setSplitState(state);

View File

@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -37,6 +38,7 @@ import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@ -120,6 +122,11 @@ public abstract class ContinuousArrayData extends ArrayData {
*/
public abstract Class<?> getElementType();
@Override
public Type getOptimisticType() {
return Type.typeFor(getElementType());
}
/**
* Look up a continuous array element getter
* @param get getter, sometimes combined with a has check that throws CCE on failure for relink

View File

@ -66,9 +66,9 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
public Object[] asObjectArray() {
final Object[] value = super.asObjectArray();
if (lo <= Integer.MAX_VALUE) {
final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
for (int i = (int)lo; i <= intHi; i++) {
if (lo < Integer.MAX_VALUE) {
final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
for (int i = (int)lo; i < end; i++) {
value[i] = ScriptRuntime.UNDEFINED;
}
}
@ -81,9 +81,9 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
final Object value = super.asArrayOfType(componentType);
final Object undefValue = convertUndefinedValue(componentType);
if (lo <= Integer.MAX_VALUE) {
final int intHi = (int)Math.min(hi, Integer.MAX_VALUE);
for (int i = (int)lo; i <= intHi; i++) {
if (lo < Integer.MAX_VALUE) {
final int end = (int)Math.min(hi + 1, Integer.MAX_VALUE);
for (int i = (int)lo; i < end; i++) {
Array.set(value, i, undefValue);
}
}

View File

@ -26,10 +26,10 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@ -73,7 +73,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public Object[] asObjectArray() {
return toObjectArray();
return toObjectArray(true);
}
@SuppressWarnings("unused")
@ -116,9 +116,9 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
return super.asArrayOfType(componentType);
}
private Object[] toObjectArray() {
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[array.length];
final Object[] oarray = new Object[trim ? (int)length : array.length];
for (int index = 0; index < length; index++) {
oarray[index] = Integer.valueOf(array[index]);
@ -158,7 +158,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
}
private ObjectArrayData convertToObject() {
return new ObjectArrayData(toObjectArray(), (int)length);
return new ObjectArrayData(toObjectArray(false), (int)length);
}
@Override
@ -256,11 +256,6 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
return convert(Double.class).set(index, value, strict);
}
@Override
public Type getOptimisticType() {
return Type.INT;
}
@Override
public int getInt(final int index) {
return array[index];

View File

@ -27,10 +27,10 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@ -67,12 +67,12 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public Object[] asObjectArray() {
return toObjectArray(array, (int)length);
return toObjectArray(true);
}
private static Object[] toObjectArray(final long[] array, final int length) {
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[array.length];
final Object[] oarray = new Object[trim ? (int)length : array.length];
for (int index = 0; index < length; index++) {
oarray[index] = Long.valueOf(array[index]);
@ -89,7 +89,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
return super.asArrayOfType(componentType);
}
private static double[] toDoubleArray(final long[] array, final int length) {
private double[] toDoubleArray() {
assert length <= array.length : "length exceeds internal array size";
final double[] darray = new double[array.length];
@ -107,9 +107,9 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
}
final int len = (int)length;
if (type == Double.class) {
return new NumberArrayData(LongArrayData.toDoubleArray(array, len), len);
return new NumberArrayData(toDoubleArray(), len);
}
return new ObjectArrayData(LongArrayData.toObjectArray(array, len), len);
return new ObjectArrayData(toObjectArray(false), len);
}
@Override
@ -186,11 +186,6 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
return convert(Double.class).set(index, value, strict);
}
@Override
public Type getOptimisticType() {
return Type.LONG;
}
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle();

View File

@ -28,10 +28,10 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import jdk.nashorn.internal.codegen.types.Type;
/**
* Implementation of {@link ArrayData} as soon as a double has been
@ -66,12 +66,12 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public Object[] asObjectArray() {
return toObjectArray(array, (int)length);
return toObjectArray(true);
}
private static Object[] toObjectArray(final double[] array, final int length) {
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[array.length];
final Object[] oarray = new Object[trim ? (int)length : array.length];
for (int index = 0; index < length; index++) {
oarray[index] = Double.valueOf(array[index]);
@ -91,7 +91,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
public ArrayData convert(final Class<?> type) {
if (type != Double.class && type != Integer.class && type != Long.class) {
final int len = (int)length;
return new ObjectArrayData(NumberArrayData.toObjectArray(array, len), len);
return new ObjectArrayData(toObjectArray(false), len);
}
return this;
}
@ -166,11 +166,6 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
return this;
}
@Override
public Type getOptimisticType() {
return Type.NUMBER;
}
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "getElem", double.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();

View File

@ -26,10 +26,10 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@ -155,15 +155,11 @@ final class ObjectArrayData extends ContinuousArrayData {
@Override
public ArrayData setEmpty(final long lo, final long hi) {
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
// hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive
Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
return this;
}
@Override
public Type getOptimisticType() {
return Type.OBJECT;
}
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle();

View File

@ -78,7 +78,7 @@ class SparseArrayData extends ArrayData {
for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
final long key = entry.getKey();
if (key <= Integer.MAX_VALUE) {
if (key < Integer.MAX_VALUE) {
objArray[(int)key] = entry.getValue();
} else {
break; // ascending key order

View File

@ -152,6 +152,7 @@ final class JavaAdapterBytecodeGenerator {
static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
private static final Type STRING_TYPE = Type.getType(String.class);
private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
@ -536,8 +537,8 @@ final class JavaAdapterBytecodeGenerator {
final int argLen = originalArgTypes.length;
final Type[] newArgTypes = new Type[argLen + 1];
// Insert ScriptFunction|Object as the last argument to the constructor
final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE;
// Insert ScriptFunction|ScriptObject as the last argument to the constructor
final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
newArgTypes[argLen] = extraArgumentType;
System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
@ -588,6 +589,34 @@ final class JavaAdapterBytecodeGenerator {
// Initialize converters
generateConverterInit(mv, fromFunction);
endInitMethod(mv);
if (! fromFunction) {
newArgTypes[argLen] = OBJECT_TYPE;
final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
}
}
// Object additional param accepting constructor - generated to handle null and undefined value
// for script adapters. This is effectively to throw TypeError on such script adapters. See
// JavaAdapterServices.getHandle as well.
private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) {
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
final Class<?>[] argTypes = ctor.getParameterTypes();
int offset = 1; // First arg is at position 1, after this.
for (int i = 0; i < argTypes.length; ++i) {
final Type argType = Type.getType(argTypes[i]);
mv.load(offset, argType);
offset += argType.getSize();
}
mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
mv.visitVarInsn(ALOAD, offset);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ACONST_NULL);
mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
endInitMethod(mv);
}
private static void endInitMethod(final InstructionAdapter mv) {

View File

@ -39,6 +39,7 @@ import jdk.nashorn.internal.codegen.DumpBytecode;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
* This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
@ -51,7 +52,7 @@ final class JavaAdapterClassLoader {
private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
private static final AccessControlContext GET_CONTEXT_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_GET_CONTEXT);
private static final Collection<String> VISIBLE_INTERNAL_CLASS_NAMES = Collections.unmodifiableCollection(new HashSet<>(
Arrays.asList(JavaAdapterServices.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
Arrays.asList(JavaAdapterServices.class.getName(), ScriptObject.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
private final String className;
private final byte[] classBytes;

View File

@ -47,7 +47,6 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@ -220,7 +219,7 @@ public final class JavaAdapterServices {
* @return the filtered return value.
*/
public static Object exportReturnValue(final Object obj) {
return ScriptUtils.wrap(NashornBeansLinker.exportArgument(obj));
return NashornBeansLinker.exportArgument(obj, true);
}
/**

View File

@ -35,17 +35,28 @@ import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Lookup;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.options.Options;
/**
* This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
* {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
* observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
* observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
* this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
* the target method handle parameter signature is {@code Object}.
*/
public class NashornBeansLinker implements GuardingDynamicLinker {
// System property to control whether to wrap ScriptObject->ScriptObjectMirror for
// Object type arguments of Java method calls, field set and array set.
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
private static final MethodHandle EXPORT_NATIVE_ARRAY = new Lookup(MethodHandles.lookup()).findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
private static final MethodHandle EXPORT_SCRIPT_OBJECT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
private static final MethodHandle IMPORT_RESULT = new Lookup(MethodHandles.lookup()).findOwnStatic("importResult", Object.class, Object.class);
private final BeansLinker beansLinker = new BeansLinker();
@ -67,8 +78,39 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
}
static Object exportArgument(final Object arg) {
return arg instanceof ConsString ? arg.toString() : arg;
@SuppressWarnings("unused")
private static Object exportArgument(final Object arg) {
return exportArgument(arg, MIRROR_ALWAYS);
}
@SuppressWarnings("unused")
private static Object exportNativeArray(final NativeArray arg) {
return exportArgument(arg, MIRROR_ALWAYS);
}
@SuppressWarnings("unused")
private static Object exportScriptObject(final ScriptObject arg) {
return exportArgument(arg, MIRROR_ALWAYS);
}
@SuppressWarnings("unused")
private static Object exportScriptArray(final NativeArray arg) {
return exportArgument(arg, MIRROR_ALWAYS);
}
static Object exportArgument(final Object arg, final boolean mirrorAlways) {
if (arg instanceof ConsString) {
return arg.toString();
} else if (mirrorAlways && arg instanceof ScriptObject) {
return ScriptUtils.wrap((ScriptObject)arg);
} else {
return arg;
}
}
@SuppressWarnings("unused")
private static Object importResult(final Object arg) {
return ScriptUtils.unwrap(arg);
}
private static class NashornBeansLinkerServices implements LinkerServices {
@ -80,23 +122,50 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
@Override
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
final MethodHandle typed = linkerServices.asType(handle, fromType);
final MethodType handleType = handle.type();
final int paramCount = handleType.parameterCount();
assert fromType.parameterCount() == handleType.parameterCount();
MethodType newFromType = fromType;
MethodHandle[] filters = null;
for(int i = 0; i < paramCount; ++i) {
if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
if(filters == null) {
final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
if (filter != null) {
if (filters == null) {
filters = new MethodHandle[paramCount];
}
filters[i] = EXPORT_ARGUMENT;
// "erase" specific type with Object type or else we'll get filter mismatch
newFromType = newFromType.changeParameterType(i, Object.class);
filters[i] = filter;
}
}
return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
final MethodHandle typed = linkerServices.asType(handle, newFromType);
MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
// Filter Object typed return value for possible ScriptObjectMirror. We convert
// ScriptObjectMirror as ScriptObject (if it is mirror from current global).
if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
}
return result;
}
private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
if (handleType == Object.class) {
if (fromType == Object.class) {
return EXPORT_ARGUMENT;
} else if (fromType == NativeArray.class) {
return EXPORT_NATIVE_ARRAY;
} else if (fromType == ScriptObject.class) {
return EXPORT_SCRIPT_OBJECT;
}
}
return null;
}
private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
return handleType == Object.class && fromType == Object.class;
}
@Override
@ -104,10 +173,6 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
return Implementation.asTypeLosslessReturn(this, handle, fromType);
}
private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
return handleType == Object.class && fromType == Object.class;
}
@Override
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
return linkerServices.getTypeConverter(sourceType, targetType);

View File

@ -292,7 +292,7 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
@SuppressWarnings("unused")
private static Object createMirror(final Object obj) {
return ScriptUtils.wrap(obj);
return obj instanceof ScriptObject? ScriptUtils.wrap((ScriptObject)obj) : obj;
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {

View File

@ -73,6 +73,7 @@ type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "
type.error.not.an.object={0} is not an Object
type.error.not.a.boolean={0} is not a Boolean
type.error.not.a.date={0} is not a Date
type.error.not.a.java.importer={0} is not a JavaImporter object
type.error.not.a.number={0} is not a Number
type.error.not.a.regexp={0} is not a RegExp
type.error.not.a.string={0} is not a String

View File

@ -105,7 +105,7 @@ Object.defineProperty(this, "sync", {
if (arguments.length < 1 || arguments.length > 2 ) {
throw "sync(function [,object]) parameter count mismatch";
}
return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
return Java.synchronized(func, syncobj);
}
});
@ -160,7 +160,7 @@ Object.defineProperty(Object.prototype, "toSource", {
configurable: true, enumerable: false, writable: true,
value: function(state) {
if (! state) {
state = java.util.Collections.newSetFromMap(new java.util.IdentityHashMap());
state = java.util.Collections.newSetFromMap(new java.util.HashMap());
}
if (state.contains(this)) {
return "{}";

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8060011: Concatenating an array and converting it to Java gives wrong result
*
* @test
* @run
*/
function compareAsJavaArrays(a1, a2) {
var ja1 = Java.to(a1);
var ja2 = Java.to(a2);
if (ja1.length !== ja2.length) {
throw "different length";
}
for (var i = 0; i < ja1.length; i++) {
if (ja1[i] !== ja2[i]) {
throw "different element at " + i;
}
}
if (java.util.Arrays.toString(ja1) !== java.util.Arrays.toString(ja2)) {
throw "different string representation";
}
}
compareAsJavaArrays([0, 1, 2, 3],
[0].concat([1, 2, 3]));
compareAsJavaArrays([1000000000, 2000000000, 3000000000, 4000000000],
[1000000000].concat([2000000000, 3000000000, 4000000000]));
compareAsJavaArrays([0.5, 1.5, 2.5, 3.5],
[0.5].concat([1.5, 2.5, 3.5]));
compareAsJavaArrays(["0", "1", "2", "3"],
["0"].concat(["1", "2", "3"]));

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8060101: AssertionError: __noSuchProperty__ placeholder called from NativeJavaImporter
*
* @test
* @run
*/
var constant = 0.50;
var ind = 0.0;
// make sure callsites are exercised quite a few times
// to induce megamorphic callsite for with/JavaImporter
// combo - which triggered that AssertionError.
for (var i = 0; i < 50; i++) {
var math = new JavaImporter(java.lang.StrictMath);
ind += 10.0;
with (math) {
StrictMath.exp(-constant*ind);
}
}
for (var i = 0; i < 50; i++) {
var math = new JavaImporter(java.lang.StrictMath);
try {
math.Foo();
} catch (e) {
if (! (e instanceof TypeError)) {
throw e;
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8061113: Boolean used as optimistic call return type
*
* @test
* @run
*/
function testcase() {
var a = {x:0};
return (function () {return a.x === 0})();
}
print(testcase());

View File

@ -0,0 +1 @@
true

View File

@ -42,7 +42,7 @@ print(list);
// object to Map
obj = { foo: 333, bar: 'hello'};
var map = ScriptUtils.convert(obj, java.util.Map.class);
var map = ScriptUtils.wrap(obj);
print(map instanceof java.util.Map);
for (m in map) {
print(m + " " + map[m]);

View File

@ -25,6 +25,8 @@
* JDK-8044798: API for debugging Nashorn
*
* @test
* @option -Dnashorn.mirror.always=false
* @fork
* @run
*/

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8060688: Nashorn: Generated script class name fails --verify-code for names with special chars
*
* @test
* @run
*/
var NashornEngineFactory = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
var ScriptEngine = Java.type("javax.script.ScriptEngine");
var ScriptContext = Java.type("javax.script.ScriptContext");
var factory = new NashornEngineFactory();
var e = factory.getScriptEngine("--verify-code");
function evalAndCheck(code) {
try {
e.eval(code);
} catch (exp) {
exp.printStackTrace();
}
}
// check default name
evalAndCheck("var a = 3");
// check few names with special chars
var scontext = e.context;
scontext.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
evalAndCheck("var h = 'hello'");
scontext.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
evalAndCheck("var foo = 'world'");
scontext.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
evalAndCheck("var foo = 'helloworld'");

View File

@ -168,42 +168,6 @@ public class ScriptEngineSecurityTest {
}
}
@Test
/**
* Check that script can't implement sensitive package interfaces.
*/
public void checkSensitiveInterfaceImplTest() throws ScriptException {
if (System.getSecurityManager() == null) {
// pass vacuously
return;
}
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
final Object[] holder = new Object[1];
e.put("holder", holder);
// put an empty script object into array
e.eval("holder[0] = {}");
// holder[0] is an object of some subclass of ScriptObject
final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass();
final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0];
// implementation methods for PropertyAccess class
e.eval("function set() {}; function get() {}; function getInt(){} " +
"function getDouble(){}; function getLong() {}; " +
"this.delete = function () {}; function has() {}; " +
"function hasOwnProperty() {}");
// get implementation of a restricted package interface
try {
log(Objects.toString(((Invocable)e).getInterface((Class<?>)PropertyAccessClass)));
fail("should have thrown SecurityException");
} catch (final Exception exp) {
if (! (exp instanceof SecurityException)) {
fail("SecurityException expected, got " + exp);
}
}
}
// @bug 8032948: Nashorn linkages awry
public static class FakeProxy extends Proxy {
public FakeProxy(final InvocationHandler ih) {

View File

@ -38,6 +38,7 @@ import java.lang.reflect.Proxy;
import java.util.concurrent.Callable;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
@ -629,6 +630,40 @@ public class ScriptEngineTest {
assertEquals(enumerable, Boolean.FALSE);
}
public static class Context {
private Object myobj;
public void set(Object o) {
myobj = o;
}
public Object get() {
return myobj;
}
}
// @bug 8050977: Java8 Javascript Nashorn exception:
// no current Global instance for nashorn
@Test
public void currentGlobalMissingTest() throws Exception {
final ScriptEngineManager manager = new ScriptEngineManager();
final ScriptEngine e = manager.getEngineByName("nashorn");
final Context ctx = new Context();
e.put("ctx", ctx);
e.eval("var obj = { foo: function(str) { return str.toUpperCase() } }");
e.eval("ctx.set(obj)");
final Invocable inv = (Invocable)e;
assertEquals("HELLO", inv.invokeMethod(ctx.get(), "foo", "hello"));
// try object literal
e.eval("ctx.set({ bar: function(str) { return str.toLowerCase() } })");
assertEquals("hello", inv.invokeMethod(ctx.get(), "bar", "HELLO"));
// try array literal
e.eval("var arr = [ 'hello', 'world' ]");
e.eval("ctx.set(arr)");
assertEquals("helloworld", inv.invokeMethod(ctx.get(), "join", ""));
}
private static void checkProperty(final ScriptEngine e, final String name)
throws ScriptException {
final String value = System.getProperty(name);

View File

@ -72,6 +72,7 @@ public class CompilerTest {
options.set("print.parse", true);
options.set("scripting", true);
options.set("const.as.var", true);
options.set("verify.code", true);
final ErrorManager errors = new ErrorManager() {
@Override

View File

@ -325,4 +325,29 @@ public class TrustedScriptEngineTest {
);
assertEquals(ret, 10, "Parsed and executed OK");
}
@Test
public void evalDefaultFileNameTest() throws ScriptException {
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
// default FILENAME being "<eval>" make sure generated code bytecode verifies.
engine.eval("var a = 3;");
}
@Test
public void evalFileNameWithSpecialCharsTest() throws ScriptException {
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" });
final ScriptContext ctxt = new SimpleScriptContext();
// use file name with "dangerous" chars.
ctxt.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE);
engine.eval("var a = 3;");
ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE);
engine.eval("var h = 'hello';");
ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE);
engine.eval("var foo = 'world';");
// name used by jjs shell tool for the interactive mode
ctxt.setAttribute(ScriptEngine.FILENAME, "<shell>", ScriptContext.ENGINE_SCOPE);
engine.eval("var foo = 'world';");
}
}