--- a/nashorn/.hgignore Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/.hgignore Thu Oct 16 14:16:03 2014 -0700
@@ -26,3 +26,5 @@
test/lib/testng.jar
test/script/external/*
.project
+.externalToolBuilders/*
+.settings/*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/bin/runopt.sh Thu Oct 16 14:16:03 2014 -0700
@@ -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 ${@}
+
+
--- a/nashorn/make/build.xml Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/make/build.xml Thu Oct 16 14:16:03 2014 -0700
@@ -408,7 +408,7 @@
<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 @@
<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 @@
<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 @@
<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>
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java Thu Oct 16 14:16:03 2014 -0700
@@ -229,6 +229,8 @@
}
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"));
}
@@ -254,17 +256,6 @@
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"));
- }
}
if (realSelf == null) {
@@ -368,6 +359,7 @@
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 @@
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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java Thu Oct 16 14:16:03 2014 -0700
@@ -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 @@
* @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 @@
* @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 @@
}
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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Thu Oct 16 14:16:03 2014 -0700
@@ -511,16 +511,6 @@
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,14 +522,34 @@
@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) {
+ if (!varNode.isFunctionDeclaration()) {
+ defineVarIdent(varNode);
+ }
+ return super.leaveVarNode(varNode);
+ }
+
+ private void defineVarIdent(final VarNode varNode) {
final IdentNode ident = varNode.getName();
- defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
- return super.leaveVarNode(varNode);
+ 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() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Thu Oct 16 14:16:03 2014 -0700
@@ -410,10 +410,29 @@
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('/').
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Oct 16 14:16:03 2014 -0700
@@ -98,6 +98,7 @@
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 @@
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++) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Thu Oct 16 14:16:03 2014 -0700
@@ -29,16 +29,22 @@
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 @@
* 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 @@
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();
}
- // 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();
+ } 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;
+ }
+ }
+ }
}
return null;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Thu Oct 16 14:16:03 2014 -0700
@@ -80,11 +80,12 @@
/**
* 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 @@
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;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -55,19 +55,36 @@
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 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
@@ -186,15 +193,6 @@
}
/**
- * 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 @@
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));
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -31,7 +31,6 @@
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.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 @@
* @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 @@
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 @@
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 @@
* @return the id
*/
public int getId() {
- return position();
+ return isProgram() ? -1: Token.descPosition(firstToken);
}
/**
@@ -903,34 +911,6 @@
}
/**
- * 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.
*/
@@ -939,33 +919,6 @@
}
/**
- * 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
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LoopNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -53,14 +53,15 @@
* @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;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Node.java Thu Oct 16 14:16:03 2014 -0700
@@ -39,7 +39,7 @@
protected final int start;
/** End of source range. */
- protected int finish;
+ protected final int finish;
/** Token descriptor. */
private final long token;
@@ -81,6 +81,18 @@
}
/**
+ * 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?
*
* @return true if atom
@@ -152,14 +164,6 @@
}
/**
- * 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
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/VarNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -272,4 +272,12 @@
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();
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WhileNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -45,9 +45,11 @@
* @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 @@
* 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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/WithNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -42,14 +42,16 @@
/**
* 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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java Thu Oct 16 14:16:03 2014 -0700
@@ -31,7 +31,6 @@
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.TypedArrayData;
@ScriptClass("ArrayBufferView")
-abstract class ArrayBufferView extends ScriptObject {
+public abstract class ArrayBufferView extends ScriptObject {
private final NativeArrayBuffer buffer;
private final int byteOffset;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Thu Oct 16 14:16:03 2014 -0700
@@ -561,7 +561,6 @@
*
* @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 @@
return func;
}
- @SuppressWarnings("hiding")
private void init(final ScriptEngine engine) {
assert Context.getGlobal() == this : "this global is not set as current";
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeError.java Thu Oct 16 14:16:03 2014 -0700
@@ -27,7 +27,6 @@
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 @@
// 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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
@@ -141,6 +142,11 @@
}
@Override
+ public double getDoubleOptimistic(final int index, final int programPoint) {
+ return getElem(index);
+ }
+
+ @Override
public Object getObject(final int index) {
return getDouble(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
@@ -141,6 +142,11 @@
}
@Override
+ public double getDoubleOptimistic(final int index, final int programPoint) {
+ return getElem(index);
+ }
+
+ @Override
public Object getObject(final int index) {
return getDouble(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
@@ -124,16 +125,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
@@ -122,16 +123,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
@@ -122,16 +123,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java Thu Oct 16 14:16:03 2014 -0700
@@ -27,7 +27,6 @@
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 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 @@
*/
@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));
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJavaImporter.java Thu Oct 16 14:16:03 2014 -0700
@@ -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.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 @@
}
/**
- * "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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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,16 +129,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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 @@
@Override
public Class<?> getElementType() {
- return int.class;
+ return long.class;
}
@Override
@@ -142,11 +143,21 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Thu Oct 16 14:16:03 2014 -0700
@@ -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,16 +129,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Thu Oct 16 14:16:03 2014 -0700
@@ -28,6 +28,7 @@
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;
@@ -158,16 +159,31 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Thu Oct 16 14:16:03 2014 -0700
@@ -53,7 +53,6 @@
import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
import static jdk.nashorn.internal.parser.TokenType.TERNARY;
import static jdk.nashorn.internal.parser.TokenType.WHILE;
-
import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -71,10 +70,8 @@
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.BlockLexicalContext;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
@@ -90,9 +87,7 @@
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyKey;
@@ -138,8 +133,8 @@
private List<Statement> functionDeclarations;
- private final BlockLexicalContext lc = new BlockLexicalContext();
- private final Deque<Object> defaultNames = new ArrayDeque<>();
+ private final ParserContext lc;
+ private final Deque<Object> defaultNames;
/** Namespace for function names where not explicitly given */
private final Namespace namespace;
@@ -187,6 +182,8 @@
*/
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
super(source, errors, strict, lineOffset);
+ this.lc = new ParserContext();
+ this.defaultNames = new ArrayDeque<>();
this.env = env;
this.namespace = new Namespace(env.getNamespace());
this.scripting = env._scripting;
@@ -344,26 +341,35 @@
final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
// Set up the function to append elements.
- FunctionNode function = newFunctionNode(
- functionToken,
- new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()),
- new ArrayList<IdentNode>(),
- FunctionNode.Kind.NORMAL,
- functionLine);
+ final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName());
+ final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList());
+ lc.push(function);
+
+ final ParserContextBlockNode body = newBlock();
functionDeclarations = new ArrayList<>();
sourceElements(false);
addFunctionDeclarations(function);
functionDeclarations = null;
+ restoreBlock(body);
+ body.setFlag(Block.NEEDS_SCOPE);
+
+ final Block functionBody = new Block(functionToken, source.getLength() - 1, body.getFlags(), body.getStatements());
+ lc.pop(function);
+
expect(EOF);
- function.setFinish(source.getLength() - 1);
- function = restoreFunctionNode(function, token); //commit code
- function = function.setBody(lc, function.getBody().setNeedsScope(lc));
-
- printAST(function);
- return function;
+ final FunctionNode functionNode = createFunctionNode(
+ function,
+ functionToken,
+ ident,
+ Collections.<IdentNode>emptyList(),
+ FunctionNode.Kind.NORMAL,
+ functionLine,
+ functionBody);
+ printAST(functionNode);
+ return functionNode;
} catch (final Exception e) {
handleParseException(e);
return null;
@@ -444,21 +450,15 @@
*
* @return New block.
*/
- private Block newBlock() {
- return lc.push(new Block(token, Token.descPosition(token)));
+ private ParserContextBlockNode newBlock() {
+ return lc.push(new ParserContextBlockNode(token));
}
- /**
- * Set up a new function block.
- *
- * @param ident Name of function.
- * @return New block.
- */
- private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
+ private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) {
// Build function name.
final StringBuilder sb = new StringBuilder();
- final FunctionNode parentFunction = lc.getCurrentFunction();
+ final ParserContextFunctionNode parentFunction = lc.getCurrentFunction();
if (parentFunction != null && !parentFunction.isProgram()) {
sb.append(parentFunction.getName()).append('$');
}
@@ -477,25 +477,33 @@
flags |= FunctionNode.IS_PROGRAM;
}
+ final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters);
+ functionNode.setFlag(flags);
+ return functionNode;
+ }
+
+ private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
+ final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED;
// Start new block.
final FunctionNode functionNode =
new FunctionNode(
source,
functionLine,
- token,
- Token.descPosition(token),
+ body.getToken(),
+ Token.descPosition(body.getToken()),
startToken,
+ function.getLastToken(),
namespace,
ident,
- name,
+ function.getName(),
parameters,
kind,
- flags);
-
- lc.push(functionNode);
- // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
- // FunctionNode.
- newBlock();
+ function.getFlags(),
+ body,
+ state,
+ function.getEndParserState());
+
+ printAST(functionNode);
return functionNode;
}
@@ -503,27 +511,17 @@
/**
* Restore the current block.
*/
- private Block restoreBlock(final Block block) {
+ private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) {
return lc.pop(block);
}
-
- private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
- final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
-
- return lc.pop(functionNode).
- setBody(lc, newBody).
- setLastToken(lc, lastToken).
- setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
- }
-
/**
* Get the statements in a block.
* @return Block statements.
*/
private Block getBlock(final boolean needsBraces) {
- // Set up new block. Captures LBRACE.
- Block newBlock = newBlock();
+ final long blockToken = token;
+ final ParserContextBlockNode newBlock = newBlock();
try {
// Block opening brace.
if (needsBraces) {
@@ -533,21 +531,18 @@
statementList();
} finally {
- newBlock = restoreBlock(newBlock);
+ restoreBlock(newBlock);
}
- final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
-
// Block closing brace.
if (needsBraces) {
expect(RBRACE);
}
- newBlock.setFinish(possibleEnd);
-
- return newBlock;
+ return new Block(blockToken, finish, newBlock.getFlags(), newBlock.getStatements());
}
+
/**
* Get all the statements generated by a single statement.
* @return Statements.
@@ -557,13 +552,13 @@
return getBlock(true);
}
// Set up new block. Captures first token.
- Block newBlock = newBlock();
+ final ParserContextBlockNode newBlock = newBlock();
try {
statement();
} finally {
- newBlock = restoreBlock(newBlock);
+ restoreBlock(newBlock);
}
- return newBlock;
+ return new Block(newBlock.getToken(), finish, newBlock.getFlags(), newBlock.getStatements());
}
/**
@@ -584,7 +579,7 @@
*/
private void detectSpecialProperty(final IdentNode ident) {
if (isArguments(ident)) {
- lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
+ lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS);
}
}
@@ -698,18 +693,19 @@
// Make a pseudo-token for the script holding its start and length.
final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
final int functionLine = line;
- // Set up the script to append elements.
-
- FunctionNode script = newFunctionNode(
- functionToken,
- new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
- new ArrayList<IdentNode>(),
- FunctionNode.Kind.SCRIPT,
- functionLine);
-
+
+ final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName);
+ final ParserContextFunctionNode script = createParserContextFunctionNode(
+ ident,
+ functionToken,
+ FunctionNode.Kind.SCRIPT,
+ functionLine,
+ Collections.<IdentNode>emptyList());
+ lc.push(script);
+ final ParserContextBlockNode body = newBlock();
// If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
final int startLine = start;
- Block outer = useBlockScope() ? newBlock() : null;
+ final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
functionDeclarations = new ArrayList<>();
try {
@@ -717,20 +713,25 @@
addFunctionDeclarations(script);
} finally {
if (outer != null) {
- outer = restoreBlock(outer);
- appendStatement(new BlockStatement(startLine, outer));
+ restoreBlock(outer);
+ appendStatement(new BlockStatement(
+ startLine,
+ new Block(
+ functionToken,
+ startLine, outer.getFlags(),
+ outer.getStatements())));
}
}
functionDeclarations = null;
+ restoreBlock(body);
+ body.setFlag(Block.NEEDS_SCOPE);
+ final Block programBody = new Block(functionToken, functionLine, body.getFlags(), body.getStatements());
+ lc.pop(script);
+ script.setLastToken(token);
expect(EOF);
- script.setFinish(source.getLength() - 1);
-
- script = restoreFunctionNode(script, token); //commit code
- script = script.setBody(lc, script.getBody().setNeedsScope(lc));
-
- return script;
+ return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody);
}
/**
@@ -789,7 +790,7 @@
// check for directive prologues
if (checkDirective) {
// skip any debug statement like line number to get actual first line
- final Node lastStatement = lc.getLastStatement();
+ final Statement lastStatement = lc.getLastStatement();
// get directive prologue, if any
final String directive = getDirective(lastStatement);
@@ -809,8 +810,8 @@
// handle use strict directive
if ("use strict".equals(directive)) {
isStrictMode = true;
- final FunctionNode function = lc.getCurrentFunction();
- lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
+ final ParserContextFunctionNode function = lc.getCurrentFunction();
+ function.setFlag(FunctionNode.IS_STRICT);
// We don't need to check these, if lexical environment is already strict
if (!oldStrictMode && directiveStmts != null) {
@@ -831,8 +832,8 @@
} else if (Context.DEBUG) {
final int flag = FunctionNode.getDirectiveFlag(directive);
if (flag != 0) {
- final FunctionNode function = lc.getCurrentFunction();
- lc.setFlag(function, flag);
+ final ParserContextFunctionNode function = lc.getCurrentFunction();
+ function.setFlag(flag);
}
}
}
@@ -1114,11 +1115,7 @@
// If is a statement then handle end of line.
if (isStatement) {
- final boolean semicolon = type == SEMICOLON;
endOfLine();
- if (semicolon) {
- lc.getCurrentBlock().setFinish(finish);
- }
}
return vars;
@@ -1166,11 +1163,6 @@
}
endOfLine();
-
- if (expressionStatement != null) {
- expressionStatement.setFinish(finish);
- lc.getCurrentBlock().setFinish(finish);
- }
}
/**
@@ -1216,13 +1208,23 @@
* Parse a FOR statement.
*/
private void forStatement() {
+ final long forToken = token;
+ final int forLine = line;
// When ES6 for-let is enabled we create a container block to capture the LET.
final int startLine = start;
- Block outer = useBlockScope() ? newBlock() : null;
+ final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
+
// Create FOR node, capturing FOR token.
- ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
+ final ParserContextLoopNode forNode = new ParserContextLoopNode();
lc.push(forNode);
+ Block body = null;
+ List<VarNode> vars = null;
+ Expression init = null;
+ JoinPredecessorExpression test = null;
+ JoinPredecessorExpression modify = null;
+
+ int flags = 0;
try {
// FOR tested in caller.
@@ -1231,13 +1233,12 @@
// Nashorn extension: for each expression.
// iterate property values rather than property names.
if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
- forNode = forNode.setIsForEach(lc);
+ flags |= ForNode.IS_FOR_EACH;
next();
}
expect(LPAREN);
- List<VarNode> vars = null;
switch (type) {
case VAR:
@@ -1258,8 +1259,7 @@
break;
}
- final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
- forNode = forNode.setInit(lc, expression);
+ init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
break;
}
@@ -1268,26 +1268,27 @@
// for (init; test; modify)
// for each (init; test; modify) is invalid
- if (forNode.isForEach()) {
+ if ((flags & ForNode.IS_FOR_EACH) != 0) {
throw error(AbstractParser.message("for.each.without.in"), token);
}
expect(SEMICOLON);
if (type != SEMICOLON) {
- forNode = forNode.setTest(lc, joinPredecessorExpression());
+ test = joinPredecessorExpression();
}
expect(SEMICOLON);
if (type != RPAREN) {
- forNode = forNode.setModify(lc, joinPredecessorExpression());
+ modify = joinPredecessorExpression();
}
break;
case IN:
- forNode = forNode.setIsForIn(lc).setTest(lc, new JoinPredecessorExpression());
+ flags |= ForNode.IS_FOR_IN;
+ test = new JoinPredecessorExpression();
if (vars != null) {
// for (var i in obj)
if (vars.size() == 1) {
- forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
+ init = new IdentNode(vars.get(0).getName());
} else {
// for (var i, j in obj) is invalid
throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
@@ -1295,7 +1296,6 @@
} else {
// for (expr in obj)
- final Node init = forNode.getInit();
assert init != null : "for..in init expression can not be null here";
// check if initial expression is a valid L-value
@@ -1316,7 +1316,7 @@
next();
// Get the collection expression.
- forNode = forNode.setModify(lc, joinPredecessorExpression());
+ modify = joinPredecessorExpression();
break;
default:
@@ -1327,38 +1327,28 @@
expect(RPAREN);
// Set the for body.
- final Block body = getStatement();
- forNode = forNode.setBody(lc, body);
- forNode.setFinish(body.getFinish());
-
- appendStatement(forNode);
+ body = getStatement();
} finally {
lc.pop(forNode);
+ if (vars != null) {
+ for (final VarNode var : vars) {
+ appendStatement(var);
+ }
+ }
+ if (body != null) {
+ appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
+ }
if (outer != null) {
- outer.setFinish(forNode.getFinish());
- outer = restoreBlock(outer);
- appendStatement(new BlockStatement(startLine, outer));
+ restoreBlock(outer);
+ appendStatement(new BlockStatement(startLine, new Block(
+ outer.getToken(),
+ body.getFinish(),
+ outer.getStatements())));
}
}
}
/**
- * ... IterationStatement :
- * ...
- * Expression[NoIn]?; Expression? ; Expression?
- * var VariableDeclarationList[NoIn]; Expression? ; Expression?
- * LeftHandSideExpression in Expression
- * var VariableDeclaration[NoIn] in Expression
- *
- * See 12.6
- *
- * Parse the control section of a FOR statement. Also used for
- * comprehensions.
- * @param forNode Owning FOR.
- */
-
-
- /**
* ...IterationStatement :
* ...
* while ( Expression ) Statement
@@ -1371,25 +1361,26 @@
private void whileStatement() {
// Capture WHILE token.
final long whileToken = token;
+ final int whileLine = line;
// WHILE tested in caller.
next();
- // Construct WHILE node.
- WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
+ final ParserContextLoopNode whileNode = new ParserContextLoopNode();
lc.push(whileNode);
+ JoinPredecessorExpression test = null;
+ Block body = null;
+
try {
expect(LPAREN);
- final int whileLine = line;
- final JoinPredecessorExpression test = joinPredecessorExpression();
+ test = joinPredecessorExpression();
expect(RPAREN);
- final Block body = getStatement();
- appendStatement(whileNode =
- new WhileNode(whileLine, whileToken, finish, false).
- setTest(lc, test).
- setBody(lc, body));
+ body = getStatement();
} finally {
lc.pop(whileNode);
+ if (body != null){
+ appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
+ }
}
}
@@ -1406,34 +1397,32 @@
private void doStatement() {
// Capture DO token.
final long doToken = token;
+ int doLine = 0;
// DO tested in the caller.
next();
- WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true);
+ final ParserContextLoopNode doWhileNode = new ParserContextLoopNode();
lc.push(doWhileNode);
+ Block body = null;
+ JoinPredecessorExpression test = null;
+
try {
// Get DO body.
- final Block body = getStatement();
+ body = getStatement();
expect(WHILE);
expect(LPAREN);
- final int doLine = line;
- final JoinPredecessorExpression test = joinPredecessorExpression();
+ doLine = line;
+ test = joinPredecessorExpression();
expect(RPAREN);
if (type == SEMICOLON) {
endOfLine();
}
- doWhileNode.setFinish(finish);
-
- //line number is last
- appendStatement(doWhileNode =
- new WhileNode(doLine, doToken, finish, true).
- setBody(lc, body).
- setTest(lc, test));
} finally {
lc.pop(doWhileNode);
+ appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
}
}
@@ -1452,7 +1441,7 @@
// CONTINUE tested in caller.
nextOrEOL();
- LabelNode labelNode = null;
+ ParserContextLabelNode labelNode = null;
// SEMICOLON or label.
switch (type) {
@@ -1474,7 +1463,7 @@
}
final String labelName = labelNode == null ? null : labelNode.getLabelName();
- final LoopNode targetNode = lc.getContinueTo(labelName);
+ final ParserContextLoopNode targetNode = lc.getContinueTo(labelName);
if (targetNode == null) {
throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
@@ -1500,7 +1489,7 @@
// BREAK tested in caller.
nextOrEOL();
- LabelNode labelNode = null;
+ ParserContextLabelNode labelNode = null;
// SEMICOLON or label.
switch (type) {
@@ -1524,7 +1513,7 @@
//either an explicit label - then get its node or just a "break" - get first breakable
//targetNode is what we are breaking out from.
final String labelName = labelNode == null ? null : labelNode.getLabelName();
- final BreakableNode targetNode = lc.getBreakable(labelName);
+ final ParserContextBreakableNode targetNode = lc.getBreakable(labelName);
if (targetNode == null) {
throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
}
@@ -1632,20 +1621,17 @@
throw error(AbstractParser.message("strict.no.with"), withToken);
}
- // Get WITH expression.
- WithNode withNode = new WithNode(withLine, withToken, finish);
-
+ Expression expression = null;
+ Block body = null;
try {
- lc.push(withNode);
expect(LPAREN);
- withNode = withNode.setExpression(lc, expression());
+ expression = expression();
expect(RPAREN);
- withNode = withNode.setBody(lc, getStatement());
+ body = getStatement();
} finally {
- lc.pop(withNode);
+ appendStatement(new WithNode(withLine, withToken, finish, expression, body));
}
- appendStatement(withNode);
}
/**
@@ -1677,19 +1663,22 @@
next();
// Create and add switch statement.
- SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+ final ParserContextSwitchNode switchNode= new ParserContextSwitchNode();
lc.push(switchNode);
+ CaseNode defaultCase = null;
+ // Prepare to accumulate cases.
+ final List<CaseNode> cases = new ArrayList<>();
+
+ Expression expression = null;
+
try {
expect(LPAREN);
- switchNode = switchNode.setExpression(lc, expression());
+ expression = expression();
expect(RPAREN);
expect(LBRACE);
- // Prepare to accumulate cases.
- final List<CaseNode> cases = new ArrayList<>();
- CaseNode defaultCase = null;
while (type != RBRACE) {
// Prepare for next case.
@@ -1720,7 +1709,6 @@
// Get CASE body.
final Block statements = getBlock(false);
final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
- statements.setFinish(finish);
if (caseExpression == null) {
defaultCase = caseNode;
@@ -1729,13 +1717,10 @@
cases.add(caseNode);
}
- switchNode = switchNode.setCases(lc, cases, defaultCase);
next();
- switchNode.setFinish(finish);
-
- appendStatement(switchNode);
} finally {
lc.pop(switchNode);
+ appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
}
}
@@ -1759,15 +1744,17 @@
throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
}
- LabelNode labelNode = new LabelNode(line, labelToken, finish, ident.getName(), null);
+ final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName());
+ Block body = null;
try {
lc.push(labelNode);
- labelNode = labelNode.setBody(lc, getStatement());
- labelNode.setFinish(finish);
- appendStatement(labelNode);
+ body = getStatement();
} finally {
- assert lc.peek() instanceof LabelNode;
+ assert lc.peek() instanceof ParserContextLabelNode;
lc.pop(labelNode);
+ if (ident != null){
+ appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
+ }
}
}
@@ -1835,8 +1822,7 @@
// Container block needed to act as target for labeled break statements
final int startLine = line;
- Block outer = newBlock();
-
+ final ParserContextBlockNode outer = newBlock();
// Create try.
try {
@@ -1867,15 +1853,15 @@
expect(RPAREN);
- Block catchBlock = newBlock();
+ final ParserContextBlockNode catchBlock = newBlock();
try {
// Get CATCH body.
final Block catchBody = getBlock(true);
final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
appendStatement(catchNode);
} finally {
- catchBlock = restoreBlock(catchBlock);
- catchBlocks.add(catchBlock);
+ restoreBlock(catchBlock);
+ catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags(), catchBlock.getStatements()));
}
// If unconditional catch then should to be the end.
@@ -1897,19 +1883,15 @@
throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
}
- final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+ final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements);
// Add try.
assert lc.peek() == outer;
appendStatement(tryNode);
-
- tryNode.setFinish(finish);
- outer.setFinish(finish);
-
} finally {
- outer = restoreBlock(outer);
+ restoreBlock(outer);
}
- appendStatement(new BlockStatement(startLine, outer));
+ appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags(), outer.getStatements())));
}
/**
@@ -1927,7 +1909,7 @@
// DEBUGGER tested in caller.
next();
endOfLine();
- appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
+ appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, Collections.<Expression>emptyList())));
}
/**
@@ -1954,7 +1936,7 @@
case THIS:
final String name = type.getName();
next();
- lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
+ lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS);
return new IdentNode(primaryToken, finish, name);
case IDENT:
final IdentNode ident = getIdent();
@@ -2314,9 +2296,24 @@
final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
expect(LPAREN);
expect(RPAREN);
- final FunctionNode functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER, functionLine);
-
- return new PropertyFunction(getIdent, functionNode);
+
+ final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
+ lc.push(functionNode);
+
+ final Block functionBody = functionBody(functionNode);
+
+ lc.pop(functionNode);
+
+ final FunctionNode function = createFunctionNode(
+ functionNode,
+ getSetToken,
+ getNameNode,
+ Collections.<IdentNode>emptyList(),
+ FunctionNode.Kind.GETTER,
+ functionLine,
+ functionBody);
+
+ return new PropertyFunction(getIdent, function);
}
private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
@@ -2338,9 +2335,25 @@
if (argIdent != null) {
parameters.add(argIdent);
}
- final FunctionNode functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER, functionLine);
-
- return new PropertyFunction(setIdent, functionNode);
+
+
+ final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
+ lc.push(functionNode);
+
+ final Block functionBody = functionBody(functionNode);
+
+ lc.pop(functionNode);
+
+ final FunctionNode function = createFunctionNode(
+ functionNode,
+ getSetToken,
+ setNameNode,
+ parameters,
+ FunctionNode.Kind.SETTER,
+ functionLine,
+ functionBody);
+
+ return new PropertyFunction(setIdent, function);
}
private static class PropertyFunction {
@@ -2655,11 +2668,18 @@
final List<IdentNode> parameters = formalParameterList();
expect(RPAREN);
- FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
+ final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters);
+ lc.push(functionNode);
+ Block functionBody = null;
+ try{
+ functionBody = functionBody(functionNode);
+ } finally {
+ lc.pop(functionNode);
+ }
if (isStatement) {
if (topLevel || useBlockScope()) {
- functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
+ functionNode.setFlag(FunctionNode.IS_DECLARED);
} else if (isStrictMode) {
throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
} else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
@@ -2668,12 +2688,12 @@
warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
}
if (isArguments(name)) {
- lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
+ lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS);
}
}
if (isAnonymous) {
- functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
+ functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
}
final int arity = parameters.size();
@@ -2687,7 +2707,7 @@
String parameterName = parameter.getName();
if (isArguments(parameterName)) {
- functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+ functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
}
if (parametersSet.contains(parameterName)) {
@@ -2705,17 +2725,26 @@
}
} else if (arity == 1) {
if (isArguments(parameters.get(0))) {
- functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+ functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
}
}
+ final FunctionNode function = createFunctionNode(
+ functionNode,
+ functionToken,
+ name,
+ parameters,
+ FunctionNode.Kind.NORMAL,
+ functionLine,
+ functionBody);
+
if (isStatement) {
int varFlags = VarNode.IS_STATEMENT;
if (!topLevel && useBlockScope()) {
// mark ES6 block functions as lexically scoped
varFlags |= VarNode.IS_LET;
}
- final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
+ final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
if (topLevel) {
functionDeclarations.add(varNode);
} else if (useBlockScope()) {
@@ -2725,7 +2754,7 @@
}
}
- return functionNode;
+ return function;
}
private String getDefaultValidFunctionName(final int functionLine) {
@@ -2832,15 +2861,19 @@
* Parse function body.
* @return function node (body.)
*/
- private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
- FunctionNode functionNode = null;
+ private Block functionBody(final ParserContextFunctionNode functionNode) {
long lastToken = 0L;
+ ParserContextBlockNode body = null;
+ final long bodyToken = token;
+ Block functionBody;
+ int bodyFinish = 0;
+
final boolean parseBody;
Object endParserState = null;
try {
// Create a new function block.
- functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
+ body = newBlock();
assert functionNode != null;
final int functionId = functionNode.getId();
parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
@@ -2856,6 +2889,7 @@
// just expression as function body
final Expression expr = assignmentExpression(true);
lastToken = previousToken;
+ functionNode.setLastToken(previousToken);
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
// EOL uses length field to store the line number
final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
@@ -2868,7 +2902,6 @@
final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
appendStatement(returnNode);
}
- functionNode.setFinish(lastFinish);
} else {
expectDontAdvance(LBRACE);
if (parseBody || !skipFunctionBody(functionNode)) {
@@ -2902,25 +2935,25 @@
// we'll rather just restart parsing from this well-known, friendly token instead.
}
}
+ bodyFinish = finish;
+ functionNode.setLastToken(token);
expect(RBRACE);
- functionNode.setFinish(finish);
}
} finally {
- functionNode = restoreFunctionNode(functionNode, lastToken);
+ restoreBlock(body);
}
// NOTE: we can only do alterations to the function node after restoreFunctionNode.
if (parseBody) {
- functionNode = functionNode.setEndParserState(lc, endParserState);
- } else if (functionNode.getBody().getStatementCount() > 0){
+ functionNode.setEndParserState(endParserState);
+ } else if (!body.getStatements().isEmpty()){
// This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
// skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
// enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
// an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
// nested bodies early if we were supposed to skip 'em.
- functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null,
- Collections.<Statement>emptyList()));
+ body.setStatements(Collections.<Statement>emptyList());
}
if (reparsedFunction != null) {
@@ -2932,20 +2965,20 @@
if (data != null) {
// Data can be null if when we originally parsed the file, we removed the function declaration
// as it was dead code.
- functionNode = functionNode.setFlags(lc, data.getFunctionFlags());
+ functionNode.setFlag(data.getFunctionFlags());
// This compensates for missing markEval() in case the function contains an inner function
// that contains eval(), that now we didn't discover since we skipped the inner function.
if (functionNode.hasNestedEval()) {
assert functionNode.hasScopeBlock();
- functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null));
+ body.setFlag(Block.NEEDS_SCOPE);
}
}
}
- printAST(functionNode);
- return functionNode;
+ functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements());
+ return functionBody;
}
- private boolean skipFunctionBody(final FunctionNode functionNode) {
+ private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) {
if (reparsedFunction == null) {
// Not reparsing, so don't skip any function body.
return false;
@@ -3008,13 +3041,13 @@
}
}
- private void addFunctionDeclarations(final FunctionNode functionNode) {
+ private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) {
VarNode lastDecl = null;
for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
Statement decl = functionDeclarations.get(i);
if (lastDecl == null && decl instanceof VarNode) {
decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
- lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
+ functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS);
}
prependStatement(decl);
}
@@ -3359,29 +3392,31 @@
return "'JavaScript Parsing'";
}
- private static void markEval(final LexicalContext lc) {
- final Iterator<FunctionNode> iter = lc.getFunctions();
+ private static void markEval(final ParserContext lc) {
+ final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
boolean flaggedCurrentFn = false;
while (iter.hasNext()) {
- final FunctionNode fn = iter.next();
+ final ParserContextFunctionNode fn = iter.next();
if (!flaggedCurrentFn) {
- lc.setFlag(fn, FunctionNode.HAS_EVAL);
+ fn.setFlag(FunctionNode.HAS_EVAL);
flaggedCurrentFn = true;
} else {
- lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
+ fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
}
+ final ParserContextBlockNode body = lc.getFunctionBody(fn);
// NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
// parsing a nested function. functionBody() contains code to compensate for the lack of invoking
// this method when the parser skips a nested function.
- lc.setBlockNeedsScope(lc.getFunctionBody(fn));
+ body.setFlag(Block.NEEDS_SCOPE);
+ fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK);
}
}
private void prependStatement(final Statement statement) {
- lc.prependStatement(statement);
+ lc.prependStatementToCurrentNode(statement);
}
private void appendStatement(final Statement statement) {
- lc.appendStatement(statement);
+ lc.appendStatementToCurrentNode(statement);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java Thu Oct 16 14:16:03 2014 -0700
@@ -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();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBaseNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBlockNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextBreakableNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLabelNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextLoopNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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);
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextSwitchNode.java Thu Oct 16 14:16:03 2014 -0700
@@ -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;
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Oct 16 14:16:03 2014 -0700
@@ -483,7 +483,7 @@
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 @@
* 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 @@
@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);
+ }
+
+ final ClassReference ref = super.get(key);
+ if (ref != null && log.isEnabled()) {
+ log.info("Retrieved class reference for ", ref.source, " from class cache");
}
- return super.get(key);
+ return ref;
+ }
+
+ @Override
+ public DebugLogger initLogger(final Context context) {
+ return context.getLogger(getClass());
+ }
+
+ @Override
+ public DebugLogger getLogger() {
+ return log;
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Thu Oct 16 14:16:03 2014 -0700
@@ -31,7 +31,6 @@
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 @@
}
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 @@
}
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;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Oct 16 14:16:03 2014 -0700
@@ -676,6 +676,22 @@
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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Thu Oct 16 14:16:03 2014 -0700
@@ -210,6 +210,19 @@
}
@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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -30,6 +30,7 @@
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 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<?> 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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java Thu Oct 16 14:16:03 2014 -0700
@@ -66,9 +66,9 @@
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 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);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -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 @@
@Override
public Object[] asObjectArray() {
- return toObjectArray();
+ return toObjectArray(true);
}
@SuppressWarnings("unused")
@@ -116,9 +116,9 @@
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 @@
}
private ObjectArrayData convertToObject() {
- return new ObjectArrayData(toObjectArray(), (int)length);
+ return new ObjectArrayData(toObjectArray(false), (int)length);
}
@Override
@@ -257,11 +257,6 @@
}
@Override
- public Type getOptimisticType() {
- return Type.INT;
- }
-
- @Override
public int getInt(final int index) {
return array[index];
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -27,10 +27,10 @@
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 @@
@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 @@
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 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 @@
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();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -28,10 +28,10 @@
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 @@
@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 @@
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 @@
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();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -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 @@
@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();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Thu Oct 16 14:16:03 2014 -0700
@@ -78,7 +78,7 @@
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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Thu Oct 16 14:16:03 2014 -0700
@@ -152,6 +152,7 @@
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 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 @@
// 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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Thu Oct 16 14:16:03 2014 -0700
@@ -39,6 +39,7 @@
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 @@
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;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java Thu Oct 16 14:16:03 2014 -0700
@@ -47,7 +47,6 @@
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 @@
* @return the filtered return value.
*/
public static Object exportReturnValue(final Object obj) {
- return ScriptUtils.wrap(NashornBeansLinker.exportArgument(obj));
+ return NashornBeansLinker.exportArgument(obj, true);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Thu Oct 16 14:16:03 2014 -0700
@@ -35,17 +35,28 @@
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 @@
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 @@
@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 @@
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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java Thu Oct 16 14:16:03 2014 -0700
@@ -292,7 +292,7 @@
@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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties Thu Oct 16 14:16:03 2014 -0700
@@ -73,6 +73,7 @@
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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/mozilla_compat.js Thu Oct 16 14:16:03 2014 -0700
@@ -105,7 +105,7 @@
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 @@
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 "{}";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8060011.js Thu Oct 16 14:16:03 2014 -0700
@@ -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"]));
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8060101.js Thu Oct 16 14:16:03 2014 -0700
@@ -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;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8061113.js Thu Oct 16 14:16:03 2014 -0700
@@ -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());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8061113.js.EXPECTED Thu Oct 16 14:16:03 2014 -0700
@@ -0,0 +1,1 @@
+true
--- a/nashorn/test/script/basic/convert.js Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/script/basic/convert.js Thu Oct 16 14:16:03 2014 -0700
@@ -42,7 +42,7 @@
// 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]);
--- a/nashorn/test/script/nosecurity/JDK-8044798.js Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/script/nosecurity/JDK-8044798.js Thu Oct 16 14:16:03 2014 -0700
@@ -25,6 +25,8 @@
* JDK-8044798: API for debugging Nashorn
*
* @test
+ * @option -Dnashorn.mirror.always=false
+ * @fork
* @run
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/JDK-8060688.js Thu Oct 16 14:16:03 2014 -0700
@@ -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'");
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineSecurityTest.java Thu Oct 16 14:16:03 2014 -0700
@@ -168,42 +168,6 @@
}
}
- @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) {
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Thu Oct 16 14:16:03 2014 -0700
@@ -38,6 +38,7 @@
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 @@
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);
--- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Thu Oct 16 14:16:03 2014 -0700
@@ -72,6 +72,7 @@
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
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Thu Oct 16 12:02:10 2014 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java Thu Oct 16 14:16:03 2014 -0700
@@ -325,4 +325,29 @@
);
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';");
+ }
}