aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlana <none@none>2013-04-01 21:42:31 -0700
committerlana <none@none>2013-04-01 21:42:31 -0700
commita63fd3534f02f2c7bdaae3437af94571f3e1cfc2 (patch)
treea9ce95e609d767b46d2a76cb569ce3af8ac94003
parente554fb1a4d5b7d2ee707a78b5fd943f652b61fe1 (diff)
parent30fc6a3b149c2c607de22baad8971c8dc4072193 (diff)
-rw-r--r--bin/jjs2
-rw-r--r--bin/jjssecure2
-rw-r--r--bin/nashorn2
-rw-r--r--bin/nashornsecure2
-rw-r--r--docs/DEVELOPER_README11
-rw-r--r--docs/JavaScriptingProgrammersGuide.html8
-rw-r--r--docs/source/javaarray.js3
-rw-r--r--make/build.xml6
-rw-r--r--make/code_coverage.xml60
-rw-r--r--make/java.security.override4
-rw-r--r--make/project.properties6
-rw-r--r--src/jdk/nashorn/api/scripting/Formatter.java10
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngine.java34
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java10
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptUtils.java60
-rw-r--r--src/jdk/nashorn/api/scripting/resources/engine.js46
-rw-r--r--src/jdk/nashorn/api/scripting/resources/init.js939
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java587
-rw-r--r--src/jdk/nashorn/internal/codegen/BranchOptimizer.java1
-rw-r--r--src/jdk/nashorn/internal/codegen/ClassEmitter.java12
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java276
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilationPhase.java100
-rw-r--r--src/jdk/nashorn/internal/codegen/CompileUnit.java20
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java204
-rw-r--r--src/jdk/nashorn/internal/codegen/FinalizeTypes.java176
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java24
-rw-r--r--src/jdk/nashorn/internal/codegen/FunctionSignature.java12
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java251
-rw-r--r--src/jdk/nashorn/internal/codegen/MethodEmitter.java5
-rw-r--r--src/jdk/nashorn/internal/codegen/Splitter.java91
-rw-r--r--src/jdk/nashorn/internal/codegen/WeighNodes.java81
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java15
-rw-r--r--src/jdk/nashorn/internal/ir/AccessNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/Assignment.java7
-rw-r--r--src/jdk/nashorn/internal/ir/BaseNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java22
-rw-r--r--src/jdk/nashorn/internal/ir/Block.java363
-rw-r--r--src/jdk/nashorn/internal/ir/BreakNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/CallNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/CaseNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/CatchNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/ContinueNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/DoWhileNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/EmptyNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/ExecuteNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/ForNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/FunctionNode.java364
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java63
-rw-r--r--src/jdk/nashorn/internal/ir/IfNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/IndexNode.java9
-rw-r--r--src/jdk/nashorn/internal/ir/LabelNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java198
-rw-r--r--src/jdk/nashorn/internal/ir/LineNumberNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java34
-rw-r--r--src/jdk/nashorn/internal/ir/Location.java6
-rw-r--r--src/jdk/nashorn/internal/ir/Node.java18
-rw-r--r--src/jdk/nashorn/internal/ir/ObjectNode.java25
-rw-r--r--src/jdk/nashorn/internal/ir/PropertyNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/ReferenceNode.java91
-rw-r--r--src/jdk/nashorn/internal/ir/ReturnNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/RuntimeNode.java9
-rw-r--r--src/jdk/nashorn/internal/ir/SplitNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/SwitchNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/Symbol.java60
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java18
-rw-r--r--src/jdk/nashorn/internal/ir/ThrowNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/TryNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/TypeOverride.java6
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java28
-rw-r--r--src/jdk/nashorn/internal/ir/VarNode.java88
-rw-r--r--src/jdk/nashorn/internal/ir/WhileNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/WithNode.java4
-rw-r--r--src/jdk/nashorn/internal/ir/annotations/ChildNode.java42
-rw-r--r--src/jdk/nashorn/internal/ir/annotations/ParentNode.java44
-rw-r--r--src/jdk/nashorn/internal/ir/annotations/Reference.java1
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ASTWriter.java38
-rw-r--r--src/jdk/nashorn/internal/ir/debug/JSONWriter.java79
-rw-r--r--src/jdk/nashorn/internal/ir/debug/PrintVisitor.java78
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java16
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java151
-rw-r--r--src/jdk/nashorn/internal/objects/Global.java55
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java4
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDebug.java17
-rw-r--r--src/jdk/nashorn/internal/objects/NativeError.java2
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJava.java17
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java13
-rw-r--r--src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java11
-rw-r--r--src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java122
-rw-r--r--src/jdk/nashorn/internal/parser/JSONParser.java2
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java381
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeInstaller.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunction.java162
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunctions.java73
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java30
-rw-r--r--src/jdk/nashorn/internal/runtime/ECMAException.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java100
-rw-r--r--src/jdk/nashorn/internal/runtime/NashornLoader.java47
-rw-r--r--src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java185
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptEnvironment.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunction.java115
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java847
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptLoader.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java99
-rw-r--r--src/jdk/nashorn/internal/runtime/StructureLoader.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java29
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornGuards.java39
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java60
-rw-r--r--src/jdk/nashorn/internal/runtime/options/OptionTemplate.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/options/Options.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExp.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Messages.properties4
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Options.properties6
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js18
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/parser.js10
-rw-r--r--test/script/basic/JDK-8006755.js2
-rw-r--r--test/script/basic/JDK-8008448.js4
-rw-r--r--test/script/basic/JDK-8009868.js35
-rw-r--r--test/script/basic/JDK-8010199.js51
-rw-r--r--test/script/basic/JDK-8010709.js46
-rw-r--r--test/script/basic/JDK-8010720.js49
-rw-r--r--test/script/basic/JDK-8017010.js68
-rw-r--r--test/script/basic/JDK-8017010.js.EXPECTED3
-rw-r--r--test/script/basic/NASHORN-258.js12
-rw-r--r--test/script/basic/NASHORN-258.js.EXPECTED1
-rw-r--r--test/script/basic/NASHORN-401.js2
-rw-r--r--test/script/basic/NASHORN-837.js24
-rw-r--r--test/script/basic/compile-octane.js.EXPECTED3
-rw-r--r--test/script/basic/consstring.js2
-rw-r--r--test/script/basic/fileline.js4
-rw-r--r--test/script/basic/javainnerclasses.js18
-rw-r--r--test/script/basic/list.js2
-rw-r--r--test/script/basic/map.js2
-rw-r--r--test/script/basic/run-octane.js23
-rw-r--r--test/script/basic/runsunspider-eager.js33
-rw-r--r--test/script/basic/runsunspider-eager.js.EXPECTED (renamed from test/script/basic/runsunspider.js.EXPECTED)0
-rw-r--r--test/script/basic/runsunspider-lazy.js34
-rw-r--r--test/script/basic/runsunspider-lazy.js.EXPECTED1
-rw-r--r--test/script/basic/runsunspider.js30
-rw-r--r--test/script/basic/stdin.js6
-rw-r--r--test/script/currently-failing/JDK-8006529.js13
-rw-r--r--test/script/currently-failing/clone_ir.js100
-rw-r--r--test/script/sandbox/javaextend.js2
-rw-r--r--test/script/sandbox/javaextend.js.EXPECTED6
-rw-r--r--test/script/sandbox/reflection.js4
-rw-r--r--test/script/sandbox/reflection.js.EXPECTED1
-rw-r--r--test/script/sandbox/unsafe.js4
-rw-r--r--test/script/sandbox/unsafe.js.EXPECTED4
-rw-r--r--test/script/trusted/urlreader.js6
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java112
-rw-r--r--test/src/jdk/nashorn/internal/codegen/CompilerTest.java12
-rw-r--r--test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java31
-rw-r--r--test/src/jdk/nashorn/test/models/ConstructorWithArgument.java (renamed from test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/DessertTopping.java (renamed from test/src/jdk/nashorn/internal/test/models/DessertTopping.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java (renamed from test/src/jdk/nashorn/internal/test/models/DessertToppingFloorWaxDriver.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/FinalClass.java (renamed from test/src/jdk/nashorn/internal/test/models/FinalClass.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/FloorWax.java (renamed from test/src/jdk/nashorn/internal/test/models/FloorWax.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java (renamed from test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java (renamed from test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/NonPublicClass.java (renamed from test/src/jdk/nashorn/internal/test/models/NonPublicClass.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/OuterClass.java (renamed from test/src/jdk/nashorn/internal/test/models/OuterClass.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/OverloadedSam.java (renamed from test/src/jdk/nashorn/internal/test/models/OverloadedSam.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/OverrideObject.java (renamed from test/src/jdk/nashorn/internal/test/models/OverrideObject.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/SourceHelper.java55
-rw-r--r--test/src/jdk/nashorn/test/models/StringArgs.java (renamed from test/src/jdk/nashorn/internal/test/models/StringArgs.java)2
-rw-r--r--test/src/jdk/nashorn/test/models/Toothpaste.java (renamed from test/src/jdk/nashorn/internal/test/models/Toothpaste.java)2
176 files changed, 4284 insertions, 4122 deletions
diff --git a/bin/jjs b/bin/jjs
index ca531f4d..fe6665c3 100644
--- a/bin/jjs
+++ b/bin/jjs
@@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
-$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
+$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
diff --git a/bin/jjssecure b/bin/jjssecure
index 614ffd36..db6bdfc4 100644
--- a/bin/jjssecure
+++ b/bin/jjssecure
@@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
-$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=`dirname $0`/../make/java.security.override -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $*
+$JAVA_HOME/bin/java -Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -Djava.security.properties=`dirname $0`/../make/java.security.override -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Dnashorn.debug=true -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=true -Dnashorn.home=`dirname $0`/.. -Djava.security.manager jdk.nashorn.tools.Shell $*
diff --git a/bin/nashorn b/bin/nashorn
index 3fccdd04..da22be1f 100644
--- a/bin/nashorn
+++ b/bin/nashorn
@@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
-$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $*
+$JAVA_HOME/bin/jrunscript -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $*
diff --git a/bin/nashornsecure b/bin/nashornsecure
index 3d02c529..77c7c529 100644
--- a/bin/nashornsecure
+++ b/bin/nashornsecure
@@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
-$JAVA_HOME/bin/jrunscript -J-Djava.security.properties=`dirname $0`/../make/java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:`dirname $0`/../dist -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $*
+$JAVA_HOME/bin/jrunscript -J-Djava.security.properties=`dirname $0`/../make/java.security.override -J-Djava.security.manager -J-Xms2G -J-Xmx2G -J-XX:-TieredCompilation -J-server -J-esa -J-ea -J-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -J-XX:+HeapDumpOnOutOfMemoryError -J-Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -J-Dnashorn.debug=true -l nashorn $*
diff --git a/docs/DEVELOPER_README b/docs/DEVELOPER_README
index 3bd220b2..d0587ce6 100644
--- a/docs/DEVELOPER_README
+++ b/docs/DEVELOPER_README
@@ -13,6 +13,17 @@ properties described herein are subject to change without notice.
This documentation of the system property flags assume that the
default value of the flag is false, unless otherwise specified.
+SYSTEM PROPERTY: -Dnashorn.args=<string>
+
+This property takes as its value a space separated list of Nashorn
+command line options that should be passed to Nashorn. This might be useful
+in environments where it is hard to tell how a nashorn.jar is launched.
+
+Example:
+
+> java -Dnashorn.args="--lazy-complation --log=compiler" large-java-app-with-nashorn.jar
+> ant -Dnashorn.args="--log=codegen" antjob
+
SYSTEM PROPERTY: -Dnashorn.unstable.relink.threshold=x
This property controls how many call site misses are allowed before a
diff --git a/docs/JavaScriptingProgrammersGuide.html b/docs/JavaScriptingProgrammersGuide.html
index cf248140..dd243d3a 100644
--- a/docs/JavaScriptingProgrammersGuide.html
+++ b/docs/JavaScriptingProgrammersGuide.html
@@ -533,9 +533,8 @@ with (SwingGui) {
<hr>
<a name="jsarrays" id="jsarrays"></a>
<h3>Creating, Converting and Using Java Arrays</h3>
-<p>While creating a Java object is the same as in Java, to create
-Java arrays in JavaScript we can use Java reflection
-explicitly. But once created the element access or length access is
+<p>
+Array element access or length access is
the same as in Java. Also, a script array can be used when a Java
method expects a Java array (auto conversion). So in most cases we
don't have to create Java arrays explicitly.</p>
@@ -543,7 +542,8 @@ don't have to create Java arrays explicitly.</p>
// <a href="source/javaarray.js">javaarray.js</a>
// create Java String array of 5 elements
-var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
+var StringArray = Java.type("java.lang.String[]");
+var a = new StringArray(5);
// Accessing elements and length access is by usual Java syntax
a[0] = "scripting is great!";
diff --git a/docs/source/javaarray.js b/docs/source/javaarray.js
index b9d93f0d..a02aa3ca 100644
--- a/docs/source/javaarray.js
+++ b/docs/source/javaarray.js
@@ -30,7 +30,8 @@
*/
// create Java String array of 5 elements
-var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
+var StringArray = Java.type("java.lang.String[]");
+var a = new StringArray(5);
// Accessing elements and length access is by usual Java syntax
a[0] = "scripting is great!";
diff --git a/make/build.xml b/make/build.xml
index 34f56e46..945ccaa2 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -124,7 +124,7 @@
<echo message="release=${nashorn.version}" file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true"/>
</target>
- <target name="jar" depends="compile, run-nasgen" description="Creates nashorn.jar">
+ <target name="jar" depends="compile, run-nasgen, generate-cc-template" description="Creates nashorn.jar">
<jar jarfile="${dist.jar}" manifest="${meta.inf.dir}/MANIFEST.MF" index="true" filesetmanifest="merge">
<fileset dir="${build.classes.dir}"/>
<manifest>
@@ -191,12 +191,12 @@
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
- <fileset dir="${build.test.classes.dir}" excludes="**/api/*"/>
+ <fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
</jar>
<!-- tests that check nashorn script engine (jsr-223) API -->
<jar jarfile="${nashorn.api.tests.jar}">
- <fileset dir="${build.test.classes.dir}" includes="**/api/*"/>
+ <fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
</jar>
</target>
diff --git a/make/code_coverage.xml b/make/code_coverage.xml
index 41d85ff3..33980bdf 100644
--- a/make/code_coverage.xml
+++ b/make/code_coverage.xml
@@ -36,7 +36,12 @@
<equals arg1="${jcov}" arg2="dynamic" trim="true"/>
</condition>
+ <condition property="cc.generate.template" value="true">
+ <equals arg1="${cc.dynamic.genereate.template}" arg2="true" trim="true"/>
+ </condition>
+
<mkdir dir="${cc.dir}"/>
+ <mkdir dir="${build.dir}/to_be_instrumented"/>
<!-- info -->
<echo message="jcov=${jcov}"/>
@@ -51,25 +56,66 @@
<property name="run.test.cc.jvmargs" value=""/>
</target>
+ <target name="prepare-to-be-instrumented" depends="compile" description="Prepares to_be_instrumented dir">
+ <copy todir="${build.dir}/to_be_instrumented">
+ <fileset dir="${build.classes.dir}">
+ <include name="**/*.class"/>
+ <include name="**/*.clazz"/>
+ </fileset>
+ </copy>
+
+ <move todir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
+ <fileset dir="${build.dir}/to_be_instrumented/jdk/nashorn/internal/objects">
+ <include name="**/*.clazz"/>
+ </fileset>
+ <mapper type="glob" from="*.clazz" to="*.class"/>
+ </move>
+ </target>
+
+ <target name="generate-cc-template" depends="prepare-to-be-instrumented" description="Generates code coverage template for dynamic CC" if="cc.generate.template">
+ <property name="cc.instrumented.path" location="${build.dir}/to_be_instrumented"/>
+ <java classname="com.sun.tdk.jcov.TmplGen">
+ <arg value="-verbose"/>
+ <arg line="-include ${cc.include}"/>
+ <arg line="-type all"/>
+ <arg line="-template ${cc.template}"/>
+ <arg value="${cc.instrumented.path}"/>
+ <classpath>
+ <pathelement location="${jcov.jar}"/>
+ </classpath>
+ </java>
+
+ <java classname="com.sun.tdk.jcov.RepGen">
+ <arg value="-verbose"/>
+ <arg line="-output ${cc.dir}/CC_template_report"/>
+ <arg value="${cc.template}"/>
+ <classpath>
+ <pathelement location="${jcov.jar}"/>
+ </classpath>
+ </java>
+ </target>
+
<target name="init-cc" depends="init-cc-disabled, init-cc-enabled">
<property name="run.test.cc.jvmargs" value=""/>
</target>
<target name="init-cc-cleanup" if="${cc.enabled}">
<delete dir="${cc.dir}" failonerror="false" />
+ <delete dir="${build.dir}/to_be_instrumented" failonerror="false" />
</target>
<target name="check-merging-files" depends="init">
- <resourcecount property="cc.xmls">
- <filelist dir="${cc.dir}" files="*.xml" />
- </resourcecount>
+ <echo message="checking avalibility of ${cc.template}"/>
<condition property="nothing-to-merge" value="true">
- <equals arg1="${cc.xmls}" arg2="1" trim="true"/>
+ <not>
+ <available file="${cc.template}"/>
+ </not>
</condition>
+ <echo message="nothing-to-merge = ${nothing-to-merge}"/>
</target>
<target name="fix-merging-files" depends="check-merging-files" if="${nothing-to-merge}">
- <echo message="making pre-merge workaround"/>
+ <echo message="making pre-merge workaround due to missed template"/>
<move todir="${cc.dir}" includeemptydirs="false">
<fileset dir="${cc.dir}">
<include name="*.xml"/>
@@ -81,12 +127,12 @@
<target name="merge-code-coverage" depends="fix-merging-files" unless="${nothing-to-merge}">
<echo message="merging files"/>
<fileset dir="${cc.dir}" id="cc.xmls">
- <include name="**/*${jcov}*.xml"/>
+ <include name="**/*_${jcov}_*.xml"/>
<include name="**/CC_template.xml"/>
</fileset>
<pathconvert pathsep=" " property="cc.all.xmls" refid="cc.xmls"/>
-
+ <echo message="merging files - ${cc.all.xmls}" />
<java classname="com.sun.tdk.jcov.Merger">
<arg value="-verbose"/>
<arg value="-output"/>
diff --git a/make/java.security.override b/make/java.security.override
index 00219852..a7edf33b 100644
--- a/make/java.security.override
+++ b/make/java.security.override
@@ -3,7 +3,7 @@
# We ensure that by overriding "package.access" security property.
# The following "package.access" value was copied from default java.security
-# of jre/lib/security and appended with nashorn IR, Codegen and Parser packages.
+# of jre/lib/security and appended with nashorn sensitive packages.
#
# List of comma-separated packages that start with or equal this string
@@ -11,4 +11,4 @@
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
-package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.ir., jdk.nashorn.internal.codegen., jdk.nashorn.internal.lookup., jdk.nashorn.internal.parser.
+package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.org.apache.xerces.internal.utils.,com.sun.org.apache.xalan.internal.utils.,com.sun.org.glassfish.external.,com.sun.org.glassfish.gmbal.,jdk.internal.,jdk.nashorn.internal.,jdk.nashorn.tools.
diff --git a/make/project.properties b/make/project.properties
index c4d0b943..58da977d 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -210,7 +210,7 @@ run.test.xms=2G
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
-run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs}
+run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
@@ -235,10 +235,12 @@ jcov=dynamic
#naming of CC results
#NB directory specified in the cc.dir will be cleaned up!!!
cc.dir=${basedir}/../Codecoverage_Nashorn
-cc.result.file.name=cc_nashorn.xml
+cc.result.file.name=CC_${jcov}_nashorn.xml
#dynamic CC parameters; please redefine in the ${user.home}/.nashorn.project.local.properties
jcov2.lib.dir=${basedir}/../jcov2/lib
jcov.jar=${jcov2.lib.dir}/jcov.jar
cc.include=jdk\.nashorn\.*
cc.exclude=jdk\.nashorn\.internal\.scripts\.*
+cc.dynamic.genereate.template=true
+cc.template=${cc.dir}/CC_template.xml
cc.dynamic.args=-javaagent:${jcov.jar}=include=${cc.include},exclude=${cc.exclude},type=all,verbose=0,file=${cc.dir}/${cc.result.file.name}
diff --git a/src/jdk/nashorn/api/scripting/Formatter.java b/src/jdk/nashorn/api/scripting/Formatter.java
index 3b47d347..5cb19ed4 100644
--- a/src/jdk/nashorn/api/scripting/Formatter.java
+++ b/src/jdk/nashorn/api/scripting/Formatter.java
@@ -46,7 +46,7 @@ import java.util.regex.Pattern;
* <p>Pattern and the logic for parameter position: java.util.Formatter
*
*/
-public final class Formatter {
+final class Formatter {
private Formatter() {
}
@@ -59,8 +59,8 @@ public final class Formatter {
* @param args arguments referenced by the format specifiers in format
* @return a formatted string
*/
- public static String format(final String format, final Object[] args) {
- Matcher m = FS_PATTERN.matcher(format);
+ static String format(final String format, final Object[] args) {
+ final Matcher m = FS_PATTERN.matcher(format);
int positionalParameter = 1;
while (m.find()) {
@@ -143,7 +143,7 @@ public final class Formatter {
/**
* Method to parse the integer of the argument index.
*
- * @param s
+ * @param s string to parse
* @return -1 if parsing failed, 0 if string is null, > 0 integer
*/
private static int index(final String s) {
@@ -166,7 +166,7 @@ public final class Formatter {
* Method to check if a string contains '&lt;'. This is used to find out if
* previous parameter is used.
*
- * @param s
+ * @param s string to check
* @return true if '&lt;' is in the string, else false
*/
private static boolean isPreviousArgument(final String s) {
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index ce16a7e8..55967bb0 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -179,14 +180,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
private <T> T getInterfaceInner(final Object self, final Class<T> clazz) {
- final Object realSelf;
+ final ScriptObject realSelf;
final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
if(self == null) {
realSelf = ctxtGlobal;
} else if (!(self instanceof ScriptObject)) {
- realSelf = ScriptObjectMirror.unwrap(self, ctxtGlobal);
+ realSelf = (ScriptObject)ScriptObjectMirror.unwrap(self, ctxtGlobal);
} else {
- realSelf = self;
+ realSelf = (ScriptObject)self;
}
try {
final ScriptObject oldGlobal = getNashornGlobal();
@@ -194,6 +195,10 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
if(oldGlobal != ctxtGlobal) {
setNashornGlobal(ctxtGlobal);
}
+
+ if (! isInterfaceImplemented(clazz, realSelf)) {
+ return null;
+ }
return clazz.cast(JavaAdapterFactory.getConstructor(realSelf.getClass(), clazz).invoke(realSelf));
} finally {
if(oldGlobal != ctxtGlobal) {
@@ -394,14 +399,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
setContextVariables(ctxt);
final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
final String fileName = (val != null) ? val.toString() : "<eval>";
-
- // NOTE: FIXME: If this is jrunscript's init.js, we want to run the replacement.
- // This should go away once we fix jrunscript's copy of init.js.
- if ("<system-init>".equals(fileName)) {
- evalSupportScript("resources/init.js", "nashorn:engine/resources/init.js");
- return null;
- }
-
Object res = ScriptRuntime.apply(script, ctxtGlobal);
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal));
} catch (final Exception e) {
@@ -471,6 +468,21 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}
+ private static boolean isInterfaceImplemented(final Class<?> iface, final ScriptObject sobj) {
+ for (final Method method : iface.getMethods()) {
+ // ignore methods of java.lang.Object class
+ if (method.getDeclaringClass() == Object.class) {
+ continue;
+ }
+
+ Object obj = sobj.get(method.getName());
+ if (! (obj instanceof ScriptFunction)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
// don't make this public!!
static ScriptObject getNashornGlobal() {
return Context.getGlobal();
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
index 47a0c595..e38284da 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
@@ -147,6 +147,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final ClassLoader appLoader) {
+ checkConfigPermission();
return new NashornScriptEngine(this, appLoader);
}
@@ -157,6 +158,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final String[] args) {
+ checkConfigPermission();
return new NashornScriptEngine(this, args, getAppClassLoader());
}
@@ -168,11 +170,19 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* @return newly created script engine.
*/
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) {
+ checkConfigPermission();
return new NashornScriptEngine(this, args, appLoader);
}
// -- Internals only below this point
+ private static void checkConfigPermission() {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("nashorn.setConfig"));
+ }
+ }
+
private static final List<String> names;
private static final List<String> mimeTypes;
private static final List<String> extensions;
diff --git a/src/jdk/nashorn/api/scripting/ScriptUtils.java b/src/jdk/nashorn/api/scripting/ScriptUtils.java
new file mode 100644
index 00000000..ccd5879b
--- /dev/null
+++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, 2013, 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.api.scripting;
+
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Utilities that are to be called from script code
+ */
+public final class ScriptUtils {
+ private ScriptUtils() {}
+
+ /**
+ * Returns AST as JSON compatible string. This is used to
+ * implement "parse" function in resources/parse.js script.
+ *
+ * @param code code to be parsed
+ * @param name name of the code source (used for location)
+ * @param includeLoc tells whether to include location information for nodes or not
+ * @return JSON string representation of AST of the supplied code
+ */
+ public static String parse(final String code, final String name, final boolean includeLoc) {
+ return ScriptRuntime.parse(code, name, includeLoc);
+ }
+
+ /**
+ * Method which converts javascript types to java types for the
+ * String.format method (jrunscript function sprintf).
+ *
+ * @param format a format string
+ * @param args arguments referenced by the format specifiers in format
+ * @return a formatted string
+ */
+ public static String format(final String format, final Object[] args) {
+ return Formatter.format(format, args);
+ }
+}
diff --git a/src/jdk/nashorn/api/scripting/resources/engine.js b/src/jdk/nashorn/api/scripting/resources/engine.js
index 65b82dfe..e9560728 100644
--- a/src/jdk/nashorn/api/scripting/resources/engine.js
+++ b/src/jdk/nashorn/api/scripting/resources/engine.js
@@ -46,3 +46,49 @@ function print(str) {
}
writer.println(String(str));
}
+
+/**
+ * This is C-like printf
+ *
+ * @param format string to format the rest of the print items
+ * @param args variadic argument list
+ */
+Object.defineProperty(this, "printf", {
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ value: function (format, args/*, more args*/) {
+ print(sprintf.apply(this, arguments));
+ }
+});
+
+/**
+ * This is C-like sprintf
+ *
+ * @param format string to format the rest of the print items
+ * @param args variadic argument list
+ */
+Object.defineProperty(this, "sprintf", {
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ value: function (format, args/*, more args*/) {
+ var len = arguments.length - 1;
+ var array = [];
+
+ if (len < 0) {
+ return "";
+ }
+
+ for (var i = 0; i < len; i++) {
+ if (arguments[i+1] instanceof Date) {
+ array[i] = arguments[i+1].getTime();
+ } else {
+ array[i] = arguments[i+1];
+ }
+ }
+
+ array = Java.toJavaArray(array);
+ return Packages.jdk.nashorn.api.scripting.ScriptUtils.format(format, array);
+ }
+});
diff --git a/src/jdk/nashorn/api/scripting/resources/init.js b/src/jdk/nashorn/api/scripting/resources/init.js
deleted file mode 100644
index 18cde929..00000000
--- a/src/jdk/nashorn/api/scripting/resources/init.js
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
- * Copyright (c) 2005, 2013, 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.
- */
-
-/**
- * jrunscript JavaScript built-in functions and objects.
- */
-
-/**
- * Creates an object that delegates all method calls on
- * it to the 'invoke' method on the given delegate object.<br>
- *
- * Example:
- * <pre>
- * <code>
- * var x = { invoke: function(name, args) { //code...}
- * var y = new JSInvoker(x);
- * y.func(3, 3); // calls x.invoke('func', args); where args is array of arguments
- * </code>
- * </pre>
- * @param obj object to be wrapped by JSInvoker
- * @constructor
- */
-function JSInvoker(obj) {
- return new JSAdapter({
- __get__ : function(name) {
- return function() {
- return obj.invoke(name, arguments);
- }
- }
- });
-}
-
-/**
- * This variable represents OS environment. Environment
- * variables can be accessed as fields of this object. For
- * example, env.PATH will return PATH value configured.
- */
-var env = new JSAdapter({
- __get__ : function (name) {
- return java.lang.System.getenv(name);
- },
- __has__ : function (name) {
- return java.lang.System.getenv().containsKey(name);
- },
- __getIds__ : function() {
- return java.lang.System.getenv().keySet().toArray();
- },
- __delete__ : function(name) {
- println("can't delete env item");
- },
- __put__ : function (name, value) {
- println("can't change env item");
- },
- toString: function() {
- return java.lang.System.getenv().toString();
- }
-});
-
-/**
- * Creates a convenient script object to deal with java.util.Map instances.
- * The result script object's field names are keys of the Map. For example,
- * scriptObj.keyName can be used to access value associated with given key.<br>
- * Example:
- * <pre>
- * <code>
- * var x = java.lang.SystemProperties();
- * var y = jmap(x);
- * println(y['java.class.path']); // prints java.class.path System property
- * delete y['java.class.path']; // remove java.class.path System property
- * </code>
- * </pre>
- *
- * @param map java.util.Map instance that will be wrapped
- * @constructor
- */
-function jmap(map) {
- return new JSAdapter({
- __get__ : function(name) {
- if (map.containsKey(name)) {
- return map.get(name);
- } else {
- return undefined;
- }
- },
- __has__ : function(name) {
- return map.containsKey(name);
- },
-
- __delete__ : function (name) {
- return map.remove(name);
- },
- __put__ : function(name, value) {
- map.put(name, value);
- },
- __getIds__ : function() {
- return map.keySet().toArray();
- },
- toString: function() {
- return map.toString();
- }
- });
-}
-
-/**
- * Creates a convenient script object to deal with java.util.List instances.
- * The result script object behaves like an array. For example,
- * scriptObj[index] syntax can be used to access values in the List instance.
- * 'length' field gives size of the List. <br>
- *
- * Example:
- * <pre>
- * <code>
- * var x = new java.util.ArrayList(4);
- * x.add('Java');
- * x.add('JavaScript');
- * x.add('SQL');
- * x.add('XML');
- *
- * var y = jlist(x);
- * println(y[2]); // prints third element of list
- * println(y.length); // prints size of the list
- *
- * @param map java.util.List instance that will be wrapped
- * @constructor
- */
-function jlist(list) {
- function isValid(index) {
- return typeof(index) == 'number' &&
- index > -1 && index < list.size();
- }
- return new JSAdapter({
- __get__ : function(name) {
- if (isValid(name)) {
- return list.get(name);
- } else if (name == 'length') {
- return list.size();
- } else {
- return undefined;
- }
- },
- __has__ : function (name) {
- return isValid(name) || name == 'length';
- },
- __delete__ : function(name) {
- if (isValid(name)) {
- list.remove(name);
- }
- },
- __put__ : function(name, value) {
- if (isValid(name)) {
- list.set(name, value);
- }
- },
- __getIds__: function() {
- var res = new Array(list.size());
- for (var i = 0; i < res.length; i++) {
- res[i] = i;
- }
- return res;
- },
- toString: function() {
- return list.toString();
- }
- });
-}
-
-/**
- * This is java.lang.System properties wrapped by JSAdapter.
- * For eg. to access java.class.path property, you can use
- * the syntax sysProps["java.class.path"]
- */
-var sysProps = new JSAdapter({
- __get__ : function (name) {
- return java.lang.System.getProperty(name);
- },
- __has__ : function (name) {
- return java.lang.System.getProperty(name) != null;
- },
- __getIds__ : function() {
- return java.lang.System.getProperties().keySet().toArray();
- },
- __delete__ : function(name) {
- java.lang.System.clearProperty(name);
- return true;
- },
- __put__ : function (name, value) {
- java.lang.System.setProperty(name, value);
- },
- toString: function() {
- return "<system properties>";
- }
-});
-
-// stdout, stderr & stdin
-var out = java.lang.System.out;
-var err = java.lang.System.err;
-// can't use 'in' because it is a JavaScript keyword :-(
-var inp = java.lang.System["in"];
-
-var BufferedInputStream = java.io.BufferedInputStream;
-var BufferedOutputStream = java.io.BufferedOutputStream;
-var BufferedReader = java.io.BufferedReader;
-var DataInputStream = java.io.DataInputStream;
-var File = java.io.File;
-var FileInputStream = java.io.FileInputStream;
-var FileOutputStream = java.io.FileOutputStream;
-var InputStream = java.io.InputStream;
-var InputStreamReader = java.io.InputStreamReader;
-var OutputStream = java.io.OutputStream;
-var Reader = java.io.Reader;
-var URL = java.net.URL;
-
-/**
- * Generic any object to input stream mapper
- * @param str input file name, URL or InputStream
- * @return InputStream object
- * @private
- */
-function inStream(str) {
- if (typeof(str) == "string") {
- // '-' means standard input
- if (str == '-') {
- return java.lang.System["in"];
- }
- // try file first
- var file = null;
- try {
- file = pathToFile(str);
- } catch (e) {
- }
- if (file && file.exists()) {
- return new FileInputStream(file);
- } else {
- try {
- // treat the string as URL
- return new URL(str).openStream();
- } catch (e) {
- throw 'file or URL ' + str + ' not found';
- }
- }
- } else {
- if (str instanceof InputStream) {
- return str;
- } else if (str instanceof URL) {
- return str.openStream();
- } else if (str instanceof File) {
- return new FileInputStream(str);
- }
- }
- // everything failed, just give input stream
- return java.lang.System["in"];
-}
-
-/**
- * Generic any object to output stream mapper
- *
- * @param out output file name or stream
- * @return OutputStream object
- * @private
- */
-function outStream(out) {
- if (typeof(out) == "string") {
- if (out == '>') {
- return java.lang.System.out;
- } else {
- // treat it as file
- return new FileOutputStream(pathToFile(out));
- }
- } else {
- if (out instanceof OutputStream) {
- return out;
- } else if (out instanceof File) {
- return new FileOutputStream(out);
- }
- }
-
- // everything failed, just return System.out
- return java.lang.System.out;
-}
-
-/**
- * stream close takes care not to close stdin, out & err.
- * @private
- */
-function streamClose(stream) {
- if (stream) {
- if (stream != java.lang.System["in"] &&
- stream != java.lang.System.out &&
- stream != java.lang.System.err) {
- try {
- stream.close();
- } catch (e) {
- println(e);
- }
- }
- }
-}
-
-/**
- * Loads and evaluates JavaScript code from a stream or file or URL<br>
- *
- * Examples:
- * <pre>
- * <code>
- * load('test.js'); // load script file 'test.js'
- * load('http://java.sun.com/foo.js'); // load from a URL
- * </code>
- * </pre>
- *
- * @param str input from which script is loaded and evaluated
- */
-if (typeof(load) == 'undefined') {
- var load = function(str) {
- var stream = inStream(str);
- var bstream = new BufferedInputStream(stream);
- var reader = new BufferedReader(new InputStreamReader(bstream));
- var oldFilename = engine.get(engine.FILENAME);
- engine.put(engine.FILENAME, str);
- try {
- engine.eval(reader);
- } finally {
- engine.put(engine.FILENAME, oldFilename);
- streamClose(stream);
- }
- }
-}
-
-// file system utilities
-
-/**
- * Creates a Java byte[] of given length
- * @param len size of the array to create
- * @private
- */
-function javaByteArray(len) {
- return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len);
-}
-
-var curDir = new File('.');
-
-/**
- * Print present working directory
- */
-function pwd() {
- println(curDir.getAbsolutePath());
-}
-
-/**
- * Changes present working directory to given directory
- * @param target directory to change to. optional, defaults to user's HOME
- */
-function cd(target) {
- if (target == undefined) {
- target = sysProps["user.home"];
- }
- if (!(target instanceof File)) {
- target = pathToFile(target);
- }
- if (target.exists() && target.isDirectory()) {
- curDir = target;
- } else {
- println(target + " is not a directory");
- }
-}
-
-/**
- * Converts path to java.io.File taking care of shell present working dir
- *
- * @param pathname file path to be converted
- * @private
- */
-function pathToFile(pathname) {
- var tmp = pathname;
- if (!(tmp instanceof File)) {
- tmp = new File(tmp);
- }
- if (!tmp.isAbsolute()) {
- return new File(curDir, pathname);
- } else {
- return tmp;
- }
-}
-
-/**
- * Copies a file or URL or stream to another file or stream
- *
- * @param from input file or URL or stream
- * @param to output stream or file
- */
-function cp(from, to) {
- if (from == to) {
- println("file " + from + " cannot be copied onto itself!");
- return;
- }
- var inp = inStream(from);
- var out = outStream(to);
- var binp = new BufferedInputStream(inp);
- var bout = new BufferedOutputStream(out);
- var buff = javaByteArray(1024);
- var len;
- while ((len = binp.read(buff)) > 0 )
- bout.write(buff, 0, len);
-
- bout.flush();
- streamClose(inp);
- streamClose(out);
-}
-
-/**
- * Shows the content of a file or URL or any InputStream<br>
- * Examples:
- * <pre>
- * <code>
- * cat('test.txt'); // show test.txt file contents
- * cat('http://java.net'); // show the contents from the URL http://java.net
- * </code>
- * </pre>
- * @param obj input to show
- * @param pattern optional. show only the lines matching the pattern
- */
-function cat(obj, pattern) {
- if (obj instanceof File && obj.isDirectory()) {
- ls(obj);
- return;
- }
-
- var inp = null;
- if (!(obj instanceof Reader)) {
- inp = inStream(obj);
- obj = new BufferedReader(new InputStreamReader(inp));
- }
- var line;
- if (pattern) {
- var count = 1;
- while ((line=obj.readLine()) != null) {
- if (line.match(pattern)) {
- println(count + "\t: " + line);
- }
- count++;
- }
- } else {
- while ((line=obj.readLine()) != null) {
- println(line);
- }
- }
-}
-
-/**
- * Returns directory part of a filename
- *
- * @param pathname input path name
- * @return directory part of the given file name
- */
-function dirname(pathname) {
- var dirName = ".";
- // Normalize '/' to local file separator before work.
- var i = pathname.replace('/', File.separatorChar ).lastIndexOf(
- File.separator );
- if ( i != -1 )
- dirName = pathname.substring(0, i);
- return dirName;
-}
-
-/**
- * Creates a new dir of given name
- *
- * @param dir name of the new directory
- */
-function mkdir(dir) {
- dir = pathToFile(dir);
- println(dir.mkdir()? "created" : "can not create dir");
-}
-
-/**
- * Creates the directory named by given pathname, including
- * any necessary but nonexistent parent directories.
- *
- * @param dir input path name
- */
-function mkdirs(dir) {
- dir = pathToFile(dir);
- println(dir.mkdirs()? "created" : "can not create dirs");
-}
-
-/**
- * Removes a given file
- *
- * @param pathname name of the file
- */
-function rm(pathname) {
- var file = pathToFile(pathname);
- if (!file.exists()) {
- println("file not found: " + pathname);
- return false;
- }
- // note that delete is a keyword in JavaScript!
- println(file["delete"]()? "deleted" : "can not delete");
-}
-
-/**
- * Removes a given directory
- *
- * @param pathname name of the directory
- */
-function rmdir(pathname) {
- rm(pathname);
-}
-
-/**
- * Synonym for 'rm'
- */
-function del(pathname) {
- rm(pathname);
-}
-
-/**
- * Moves a file to another
- *
- * @param from original name of the file
- * @param to new name for the file
- */
-function mv(from, to) {
- println(pathToFile(from).renameTo(pathToFile(to))?
- "moved" : "can not move");
-}
-
-/**
- * Synonym for 'mv'.
- */
-function ren(from, to) {
- mv(from, to);
-}
-
-var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
-
-/**
- * Helper function called by ls
- * @private
- */
-function printFile(f) {
- var sb = new java.lang.StringBuffer();
- sb.append(f.isDirectory()? "d" : "-");
- sb.append(f.canRead() ? "r": "-" );
- sb.append(f.canWrite() ? "w": "-" );
- sb.append(" ");
-
- var d = new java.util.Date(f.lastModified());
- var c = new java.util.GregorianCalendar();
- c.setTime(d);
- var day = c.get(java.util.Calendar.DAY_OF_MONTH);
- sb.append(months[c.get(java.util.Calendar.MONTH)]
- + " " + day );
- if (day < 10) {
- sb.append(" ");
- }
-
- // to get fixed length 'length' field
- var fieldlen = 8;
- var len = new java.lang.StringBuffer();
- for(var j=0; j<fieldlen; j++)
- len.append(" ");
- len.insert(0, java.lang.Long.toString(f.length()));
- len.setLength(fieldlen);
- // move the spaces to the front
- var si = len.toString().indexOf(" ");
- if ( si != -1 ) {
- var pad = len.toString().substring(si);
- len.setLength(si);
- len.insert(0, pad);
- }
- sb.append(len.toString());
- sb.append(" ");
- sb.append(f.getName());
- if (f.isDirectory()) {
- sb.append('/');
- }
- println(sb.toString());
-}
-
-/**
- * Lists the files in a directory
- *
- * @param dir directory from which to list the files. optional, default to pwd
- * @param filter pattern to filter the files listed. optional, default is '.'.
- */
-function ls(dir, filter) {
- if (dir) {
- dir = pathToFile(dir);
- } else {
- dir = curDir;
- }
- if (dir.isDirectory()) {
- var files = dir.listFiles();
- for (var i in files) {
- var f = files[i];
- if (filter) {
- if(!f.getName().match(filter)) {
- continue;
- }
- }
- printFile(f);
- }
- } else {
- printFile(dir);
- }
-}
-
-/**
- * Synonym for 'ls'.
- */
-function dir(d, filter) {
- ls(d, filter);
-}
-
-/**
- * Unix-like grep, but accepts JavaScript regex patterns
- *
- * @param pattern to search in files
- * @param files one or more files
- */
-function grep(pattern, files /*, one or more files */) {
- if (arguments.length < 2) return;
- for (var i = 1; i < arguments.length; i++) {
- println(arguments[i] + ":");
- cat(arguments[i], pattern);
- }
-}
-
-/**
- * Find in files. Calls arbitrary callback function
- * for each matching file.<br>
- *
- * Examples:
- * <pre>
- * <code>
- * find('.')
- * find('.', '.*\.class', rm); // remove all .class files
- * find('.', '.*\.java'); // print fullpath of each .java file
- * find('.', '.*\.java', cat); // print all .java files
- * </code>
- * </pre>
- *
- * @param dir directory to search files
- * @param pattern to search in the files
- * @param callback function to call for matching files
- */
-function find(dir, pattern, callback) {
- dir = pathToFile(dir);
- if (!callback) callback = print;
- var files = dir.listFiles();
- for (var f in files) {
- var file = files[f];
- if (file.isDirectory()) {
- find(file, pattern, callback);
- } else {
- if (pattern) {
- if (file.getName().match(pattern)) {
- callback(file);
- }
- } else {
- callback(file);
- }
- }
- }
-}
-
-// process utilities
-
-/**
- * Exec's a child process, waits for completion &amp; returns exit code
- *
- * @param cmd command to execute in child process
- */
-function exec(cmd) {
- var process = java.lang.Runtime.getRuntime().exec(cmd);
- var inp = new DataInputStream(process.getInputStream());
- var line = null;
- while ((line = inp.readLine()) != null) {
- println(line);
- }
- process.waitFor();
- $exit = process.exitValue();
-}
-
-// XML utilities
-
-/**
- * Converts input to DOM Document object
- *
- * @param inp file or reader. optional, without this param,
- * this function returns a new DOM Document.
- * @return returns a DOM Document object
- */
-function XMLDocument(inp) {
- var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance();
- var builder = factory.newDocumentBuilder();
- if (inp) {
- if (typeof(inp) == "string") {
- return builder.parse(pathToFile(inp));
- } else {
- return builder.parse(inp);
- }
- } else {
- return builder.newDocument();
- }
-}
-
-/**
- * Converts arbitrary stream, file, URL to XMLSource
- *
- * @param inp input stream or file or URL
- * @return XMLSource object
- */
-function XMLSource(inp) {
- if (inp instanceof javax.xml.transform.Source) {
- return inp;
- } else if (inp instanceof Packages.org.w3c.dom.Document) {
- return new javax.xml.transform.dom.DOMSource(inp);
- } else {
- inp = new BufferedInputStream(inStream(inp));
- return new javax.xml.transform.stream.StreamSource(inp);
- }
-}
-
-/**
- * Converts arbitrary stream, file to XMLResult
- *
- * @param inp output stream or file
- * @return XMLResult object
- */
-function XMLResult(out) {
- if (out instanceof javax.xml.transform.Result) {
- return out;
- } else if (out instanceof Packages.org.w3c.dom.Document) {
- return new javax.xml.transform.dom.DOMResult(out);
- } else {
- out = new BufferedOutputStream(outStream(out));
- return new javax.xml.transform.stream.StreamResult(out);
- }
-}
-
-/**
- * Perform XSLT transform
- *
- * @param inp Input XML to transform (URL, File or InputStream)
- * @param style XSL Stylesheet to be used (URL, File or InputStream). optional.
- * @param out Output XML (File or OutputStream
- */
-function XSLTransform(inp, style, out) {
- switch (arguments.length) {
- case 2:
- inp = arguments[0];
- out = arguments[1];
- break;
- case 3:
- inp = arguments[0];
- style = arguments[1];
- out = arguments[2];
- break;
- default:
- println("XSL tranform requires 2 or 3 arguments");
- return;
- }
-
- var factory = javax.xml.transform.TransformerFactory.newInstance();
- var transformer;
- if (style) {
- transformer = factory.newTransformer(XMLSource(style));
- } else {
- transformer = factory.newTransformer();
- }
- var source = XMLSource(inp);
- var result = XMLResult(out);
- transformer.transform(source, result);
- if (source.getInputStream) {
- streamClose(source.getInputStream());
- }
- if (result.getOutputStream) {
- streamClose(result.getOutputStream());
- }
-}
-
-// miscellaneous utilities
-
-/**
- * Prints which command is selected from PATH
- *
- * @param cmd name of the command searched from PATH
- */
-function which(cmd) {
- var st = new java.util.StringTokenizer(env.PATH, File.pathSeparator);
- while (st.hasMoreTokens()) {
- var file = new File(st.nextToken(), cmd);
- if (file.exists()) {
- println(file.getAbsolutePath());
- return;
- }
- }
-}
-
-/**
- * Prints IP addresses of given domain name
- *
- * @param name domain name
- */
-function ip(name) {
- var addrs = InetAddress.getAllByName(name);
- for (var i in addrs) {
- println(addrs[i]);
- }
-}
-
-/**
- * Prints current date in current locale
- */
-function date() {
- println(new Date().toLocaleString());
-}
-
-/**
- * Echoes the given string arguments
- */
-function echo(x) {
- for (var i = 0; i < arguments.length; i++) {
- println(arguments[i]);
- }
-}
-
-/**
- * Reads one or more lines from stdin after printing prompt
- *
- * @param prompt optional, default is '>'
- * @param multiline to tell whether to read single line or multiple lines
- */
-function read(prompt, multiline) {
- if (!prompt) {
- prompt = '>';
- }
- var inp = java.lang.System["in"];
- var reader = new BufferedReader(new InputStreamReader(inp));
- if (multiline) {
- var line = '';
- while (true) {
- java.lang.System.err.print(prompt);
- java.lang.System.err.flush();
- var tmp = reader.readLine();
- if (tmp == '' || tmp == null) break;
- line += tmp + '\n';
- }
- return line;
- } else {
- java.lang.System.err.print(prompt);
- java.lang.System.err.flush();
- return reader.readLine();
- }
-}
-
-if (typeof(println) == 'undefined') {
- var print = function(str, newline) {
- if (typeof(str) == 'undefined') {
- str = 'undefined';
- } else if (str == null) {
- str = 'null';
- }
-
- if (!(out instanceof java.io.PrintWriter)) {
- out = new java.io.PrintWriter(out);
- }
-
- out.print(String(str));
- if (newline) {
- out.print('\n');
- }
- out.flush();
- }
-
- var println = function(str) {
- print(str, true);
- };
-}
-
-/**
- * This is C-like printf
- *
- * @param format string to format the rest of the print items
- * @param args variadic argument list
- */
-function printf(format, args/*, more args*/) {
- print(sprintf.apply(this, arguments));
-}
-
-/**
- * This is C-like sprintf
- *
- * @param format string to format the rest of the print items
- * @param args variadic argument list
- */
-function sprintf(format, args/*, more args*/) {
- var len = arguments.length - 1;
- var array = [];
-
- if (len < 0) {
- return "";
- }
-
- for (var i = 0; i < len; i++) {
- if (arguments[i+1] instanceof Date) {
- array[i] = arguments[i+1].getTime();
- } else {
- array[i] = arguments[i+1];
- }
- }
-
- array = Java.toJavaArray(array);
- return Packages.jdk.nashorn.api.scripting.Formatter.format(format, array);
-}
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 211140e4..9ecf7c89 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -37,13 +37,16 @@ import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
import static jdk.nashorn.internal.ir.Symbol.IS_LET;
import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
+import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
+import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.LinkedList;
+import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
@@ -55,14 +58,15 @@ import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -115,6 +119,8 @@ final class Attr extends NodeOperatorVisitor {
*/
private Set<String> localUses;
+ private final LexicalContext lexicalContext = new LexicalContext();
+
private static final DebugLogger LOG = new DebugLogger("attr");
private static final boolean DEBUG = LOG.isEnabled();
@@ -135,14 +141,15 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
end(accessNode);
return accessNode;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
+ lexicalContext.push(block);
start(block);
final Set<String> savedLocalDefs = localDefs;
@@ -158,9 +165,7 @@ final class Attr extends NodeOperatorVisitor {
localDefs = new HashSet<>(savedLocalDefs);
localUses = new HashSet<>(savedLocalUses);
- for (final Node statement : block.getStatements()) {
- statement.accept(this);
- }
+ block.visitStatements(this);
} finally {
localDefs = savedLocalDefs;
localUses = savedLocalUses;
@@ -170,11 +175,12 @@ final class Attr extends NodeOperatorVisitor {
end(block);
+ lexicalContext.pop(block);
return null;
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
start(callNode);
callNode.getFunction().accept(this);
@@ -195,8 +201,7 @@ final class Attr extends NodeOperatorVisitor {
evalArgs.setThis(thisNode);
}
- newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later
- newType(callNode.getFunction().getSymbol(), Type.OBJECT);
+ newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later
end(callNode);
@@ -204,29 +209,106 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
final Block block = getCurrentBlock();
start(catchNode);
// define block-local exception variable
- final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception);
+ final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
newType(def, Type.OBJECT);
addLocalDef(exception.getName());
return catchNode;
}
+ /**
+ * Declare the definition of a new symbol.
+ *
+ * @param name Name of symbol.
+ * @param symbolFlags Symbol flags.
+ * @param node Defining Node.
+ *
+ * @return Symbol for given name or null for redefinition.
+ */
+ private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
+ int flags = symbolFlags;
+ Symbol symbol = findSymbol(block, name); // Locate symbol.
+
+ if ((flags & KINDMASK) == IS_GLOBAL) {
+ flags |= IS_SCOPE;
+ }
+
+ final FunctionNode function = lexicalContext.getFunction(block);
+ if (symbol != null) {
+ // Symbol was already defined. Check if it needs to be redefined.
+ if ((flags & KINDMASK) == IS_PARAM) {
+ if (!isLocal(function, symbol)) {
+ // Not defined in this function. Create a new definition.
+ symbol = null;
+ } else if (symbol.isParam()) {
+ // Duplicate parameter. Null return will force an error.
+ assert false : "duplicate parameter";
+ return null;
+ }
+ } else if ((flags & KINDMASK) == IS_VAR) {
+ if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
+ assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block";
+ // Always create a new definition.
+ symbol = null;
+ } else {
+ // Not defined in this function. Create a new definition.
+ if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
+ symbol = null;
+ }
+ }
+ }
+ }
+
+ if (symbol == null) {
+ // If not found, then create a new one.
+ Block symbolBlock;
+
+ // Determine where to create it.
+ if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
+ symbolBlock = block;
+ } else {
+ symbolBlock = function;
+ }
+
+ // Create and add to appropriate block.
+ symbol = new Symbol(name, flags, node, symbolBlock);
+ symbolBlock.putSymbol(name, symbol);
+
+ if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
+ symbolBlock.getFrame().addSymbol(symbol);
+ symbol.setNeedsSlot(true);
+ }
+ } else if (symbol.less(flags)) {
+ symbol.setFlags(flags);
+ }
+
+ if (node != null) {
+ node.setSymbol(symbol);
+ }
+
+ return symbol;
+ }
+
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
start(functionNode, false);
if (functionNode.isLazy()) {
- LOG.info("LAZY: " + functionNode.getName());
+ LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT");
+ newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode);
+ functionNode.setReturnType(Type.OBJECT);
end(functionNode);
return null;
}
+ lexicalContext.push(functionNode);
+
clearLocalDefs();
clearLocalUses();
@@ -242,24 +324,36 @@ final class Attr extends NodeOperatorVisitor {
initScope(functionNode);
initReturn(functionNode);
- // Add all nested functions as symbols in this function
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
+ // Add all nested declared functions as symbols in this function
+ for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) {
final IdentNode ident = nestedFunction.getIdent();
- if (ident != null && nestedFunction.isStatement()) {
- final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction);
+ if (ident != null) {
+ assert nestedFunction.isDeclared();
+ final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction);
newType(functionSymbol, Type.typeFor(ScriptFunction.class));
}
}
- if (functionNode.isScript()) {
+ if (functionNode.isProgram()) {
initFromPropertyMap(functionNode);
}
// Add function name as local symbol
- if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) {
- final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode);
- newType(selfSymbol, Type.OBJECT);
- selfSymbol.setNode(functionNode);
+ if (!functionNode.isDeclared() && !functionNode.isProgram()) {
+ if(functionNode.getSymbol() != null) {
+ // a temporary left over from an earlier pass when the function was lazy
+ assert functionNode.getSymbol().isTemp();
+ // remove it
+ functionNode.setSymbol(null);
+ }
+ final Symbol selfSymbol;
+ if(functionNode.isAnonymous()) {
+ selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode);
+ } else {
+ selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode);
+ newType(selfSymbol, Type.OBJECT);
+ selfSymbol.setNode(functionNode);
+ }
}
/*
@@ -280,32 +374,26 @@ final class Attr extends NodeOperatorVisitor {
*/
final List<Symbol> declaredSymbols = new ArrayList<>();
- for (final VarNode decl : functionNode.getDeclarations()) {
- final IdentNode ident = decl.getName();
- // any declared symbols that aren't visited need to be typed as well, hence the list
- declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident)));
- }
-
- // Every nested function needs a definition in the outer function with its name. Add these.
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final VarNode varNode = nestedFunction.getFunctionVarNode();
- if (varNode != null) {
- varNode.accept(this);
- assert varNode.isFunctionVarNode() : varNode + " should be function var node";
+ // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
+ // in a separate step above) and "var" declarations in for loop initializers.
+ functionNode.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode nestedFn) {
+ // Don't descend into nested functions
+ return nestedFn == functionNode ? nestedFn : null;
}
- }
-
- for (final Node statement : functionNode.getStatements()) {
- if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) {
- continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined"
+ @Override
+ public Node enterVarNode(VarNode varNode) {
+ if(varNode.isStatement() && !varNode.isFunctionDeclaration()) {
+ final IdentNode ident = varNode.getName();
+ // any declared symbols that aren't visited need to be typed as well, hence the list
+ declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident)));
+ }
+ return null;
}
- statement.accept(this);
- }
+ });
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName());
- nestedFunction.accept(this);
- }
+ visitFunctionStatements(functionNode);
//unknown parameters are promoted to object type.
finalizeParameters(functionNode);
@@ -332,13 +420,28 @@ final class Attr extends NodeOperatorVisitor {
functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this));
}
+ if (functionNode.hasLazyChildren()) {
+ objectifySymbols(functionNode);
+ }
+
functionNode.popFrame();
+ functionNode.setState(CompilationState.ATTR);
+
end(functionNode, false);
+ lexicalContext.pop(functionNode);
return null;
}
+ private void visitFunctionStatements(final FunctionNode functionNode) {
+ final List<Node> newStatements = new ArrayList<>(functionNode.getStatements());
+ for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) {
+ stmts.set(stmts.next().accept(this));
+ }
+ functionNode.setStatements(newStatements);
+ }
+
@Override
public Node leaveCONVERT(final UnaryNode unaryNode) {
assert false : "There should be no convert operators in IR during Attribution";
@@ -347,7 +450,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
final String name = identNode.getName();
start(identNode);
@@ -364,7 +467,7 @@ final class Attr extends NodeOperatorVisitor {
final Block block = getCurrentBlock();
final Symbol oldSymbol = identNode.getSymbol();
- Symbol symbol = block.findSymbol(name);
+ Symbol symbol = findSymbol(block, name);
//If an existing symbol with the name is found, use that otherwise, declare a new one
if (symbol != null) {
@@ -388,22 +491,13 @@ final class Attr extends NodeOperatorVisitor {
}
identNode.setSymbol(symbol);
- if (!getCurrentFunctionNode().isLocal(symbol)) {
- // non-local: we need to put symbol in scope (if it isn't already)
- if (!symbol.isScope()) {
- final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction());
- for (final Block lookupBlock : lookupBlocks) {
- final Symbol refSymbol = lookupBlock.findSymbol(name);
- if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f()
- LOG.finest("Found a ref symbol that must be scope " + refSymbol);
- refSymbol.setIsScope();
- }
- }
- }
+ // non-local: we need to put symbol in scope (if it isn't already)
+ if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) {
+ symbol.setIsScope();
}
} else {
LOG.info("No symbol exists. Declare undefined: " + symbol);
- symbol = block.useSymbol(name, identNode);
+ symbol = useSymbol(block, name, identNode);
// we have never seen this before, it can be undefined
newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
symbol.setCanBeUndefined();
@@ -412,9 +506,10 @@ final class Attr extends NodeOperatorVisitor {
assert symbol != null;
if(symbol.isGlobal()) {
- getCurrentFunctionNode().setUsesGlobalSymbol();
+ setUsesGlobalSymbol();
} else if(symbol.isScope()) {
- getCurrentFunctionNode().setUsesScopeSymbol(symbol);
+ final Iterator<Block> blocks = lexicalContext.getBlocks();
+ blocks.next().setUsesScopeSymbol(symbol, blocks);
}
if (symbol != oldSymbol && !identNode.isInitializedHere()) {
@@ -427,15 +522,68 @@ final class Attr extends NodeOperatorVisitor {
return null;
}
+ /**
+ * Marks the current function as one using any global symbol. The function and all its parent functions will all be
+ * marked as needing parent scope.
+ * @see #needsParentScope()
+ */
+ private void setUsesGlobalSymbol() {
+ for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) {
+ fns.next().setUsesAncestorScope();
+ }
+ }
+
+ /**
+ * Declare the use of a symbol in a block.
+ *
+ * @param block block in which the symbol is used
+ * @param name Name of symbol.
+ * @param node Using node
+ *
+ * @return Symbol for given name.
+ */
+ private Symbol useSymbol(final Block block, final String name, final Node node) {
+ Symbol symbol = findSymbol(block, name);
+
+ if (symbol == null) {
+ // If not found, declare as a free var.
+ symbol = defineSymbol(block, name, IS_GLOBAL, node);
+ } else {
+ node.setSymbol(symbol);
+ }
+
+ return symbol;
+ }
+
+
+ /**
+ * Search for symbol in the lexical context starting from the given block.
+ * @param name Symbol name.
+ * @return Found symbol or null if not found.
+ */
+ private Symbol findSymbol(final Block block, final String name) {
+ // Search up block chain to locate symbol.
+
+ for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) {
+ // Find name.
+ final Symbol symbol = blocks.next().getExistingSymbol(name);
+ // If found then we are good.
+ if(symbol != null) {
+ return symbol;
+ }
+ }
+ return null;
+ }
+
@Override
- public Node leave(final IndexNode indexNode) {
- newTemporary(Type.OBJECT, indexNode); //TORO
+ public Node leaveIndexNode(final IndexNode indexNode) {
+ newTemporary(Type.OBJECT, indexNode); //TODO
return indexNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
try {
start(literalNode);
assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
@@ -464,14 +612,14 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final ObjectNode objectNode) {
+ public Node leaveObjectNode(final ObjectNode objectNode) {
newTemporary(Type.OBJECT, objectNode);
end(objectNode);
return objectNode;
}
@Override
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
// assign a pseudo symbol to property name, see NASHORN-710
propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
end(propertyNode);
@@ -479,31 +627,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ReferenceNode referenceNode) {
- final FunctionNode functionNode = referenceNode.getReference();
- if (functionNode != null) {
- functionNode.addReferencingParentBlock(getCurrentBlock());
- }
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReferenceNode referenceNode) {
- newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though
-
- final FunctionNode functionNode = referenceNode.getReference();
- //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType();
- if (functionNode.isLazy()) {
- LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT");
- functionNode.setReturnType(Type.OBJECT);
- }
- end(referenceNode);
-
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
if (expr != null) {
@@ -522,7 +646,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
Type type = Type.UNKNOWN;
for (final CaseNode caseNode : switchNode.getCases()) {
@@ -559,7 +683,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
tryNode.setException(exceptionSymbol());
if (tryNode.getFinallyBody() != null) {
@@ -572,13 +696,13 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
start(varNode);
final IdentNode ident = varNode.getName();
final String name = ident.getName();
- final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident);
+ final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident);
assert symbol != null;
LOG.info("VarNode " + varNode + " set symbol " + symbol);
@@ -590,23 +714,15 @@ final class Attr extends NodeOperatorVisitor {
symbol.setCanBeUndefined();
}
- if (varNode.getInit() != null) {
- varNode.getInit().accept(this);
- }
-
return varNode;
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
final IdentNode ident = varNode.getName();
final String name = ident.getName();
- if (init != null) {
- addLocalDef(name);
- }
-
if (init == null) {
// var x; with no init will be treated like a use of x by
// visit(IdentNode) unless we remove the name
@@ -615,8 +731,10 @@ final class Attr extends NodeOperatorVisitor {
return varNode;
}
+ addLocalDef(name);
+
final Symbol symbol = varNode.getSymbol();
- final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56
+ final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56
if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
// Forbid integers as local vars for now as we have no way to treat them as undefined
newType(symbol, init.getType());
@@ -710,11 +828,9 @@ final class Attr extends NodeOperatorVisitor {
runtimeNode = new RuntimeNode(unaryNode, request, args);
assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this
- runtimeNode.accept(this);
- return runtimeNode;
+ return leaveRuntimeNode(runtimeNode);
}
-
@Override
public Node leaveNEW(final UnaryNode unaryNode) {
newTemporary(Type.OBJECT, unaryNode);
@@ -747,7 +863,7 @@ final class Attr extends NodeOperatorVisitor {
runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
assert runtimeNode.getSymbol() == unaryNode.getSymbol();
- runtimeNode.accept(this);
+ runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode);
end(unaryNode);
@@ -755,7 +871,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
return runtimeNode;
}
@@ -815,12 +931,12 @@ final class Attr extends NodeOperatorVisitor {
final IdentNode ident = (IdentNode)lhs;
final String name = ident.getName();
- Symbol symbol = getCurrentBlock().findSymbol(name);
+ Symbol symbol = findSymbol(getCurrentBlock(), name);
if (symbol == null) {
- symbol = block.defineSymbol(name, IS_GLOBAL, ident);
+ symbol = defineSymbol(block, name, IS_GLOBAL, ident);
binaryNode.setSymbol(symbol);
- } else if (!getCurrentFunctionNode().isLocal(symbol)) {
+ } else if (!isLocal(getCurrentFunctionNode(), symbol)) {
symbol.setIsScope();
}
@@ -830,6 +946,12 @@ final class Attr extends NodeOperatorVisitor {
return binaryNode;
}
+ private boolean isLocal(FunctionNode function, Symbol symbol) {
+ final Block block = symbol.getBlock();
+ // some temp symbols have no block, so can be assumed local
+ return block == null || lexicalContext.getFunction(block) == function;
+ }
+
@Override
public Node enterASSIGN(final BinaryNode binaryNode) {
return enterAssignmentNode(binaryNode);
@@ -957,20 +1079,17 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveBIT_AND(final BinaryNode binaryNode) {
- newTemporary(Type.INT, binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.INT));
}
@Override
public Node leaveBIT_OR(final BinaryNode binaryNode) {
- newTemporary(Type.INT, binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.INT));
}
@Override
public Node leaveBIT_XOR(final BinaryNode binaryNode) {
- newTemporary(Type.INT, binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.INT));
}
@Override
@@ -990,7 +1109,7 @@ final class Attr extends NodeOperatorVisitor {
return leaveBinaryArithmetic(binaryNode);
}
- private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
+ private Node leaveCmp(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
@@ -1002,49 +1121,64 @@ final class Attr extends NodeOperatorVisitor {
return binaryNode;
}
+ private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) {
+ // TODO we currently don't support changing inferred type based on uses, only on
+ // definitions. we would need some additional logic. We probably want to do that
+ // in the future, if e.g. a specialized method gets parameter that is only used
+ // as, say, an int : function(x) { return x & 4711 }, and x is not defined in
+ // the function. to make this work, uncomment the following two type inferences
+ // and debug.
+
+ //newType(binaryNode.lhs().getSymbol(), operandType);
+ //newType(binaryNode.rhs().getSymbol(), operandType);
+ newTemporary(destType, binaryNode);
+ return binaryNode;
+ }
+
+ private Node coerce(final BinaryNode binaryNode, final Type type) {
+ return coerce(binaryNode, type, type);
+ }
+
//leave a binary node and inherit the widest type of lhs , rhs
private Node leaveBinaryArithmetic(final BinaryNode binaryNode) {
- if (!Compiler.shouldUseIntegerArithmetic()) {
- newTemporary(Type.NUMBER, binaryNode);
- return binaryNode;
- }
- newTemporary(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType(), Type.NUMBER), binaryNode);
- return binaryNode;
+ assert !Compiler.shouldUseIntegerArithmetic();
+ return end(coerce(binaryNode, Type.NUMBER));
}
@Override
public Node leaveEQ(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ_STRICT);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveGE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveGT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GT);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveIN(final BinaryNode binaryNode) {
- try {
- return new RuntimeNode(binaryNode, Request.IN).accept(this);
- } finally {
- end(binaryNode);
- }
+ return leaveBinaryRuntimeOperator(binaryNode, Request.IN);
}
@Override
public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
+ return leaveBinaryRuntimeOperator(binaryNode, Request.INSTANCEOF);
+ }
+
+ private Node leaveBinaryRuntimeOperator(final BinaryNode binaryNode, final Request request) {
try {
- return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this);
+ // Don't do a full RuntimeNode.accept, as we don't want to double-visit the binary node operands
+ return leaveRuntimeNode(new RuntimeNode(binaryNode, request));
} finally {
end(binaryNode);
}
@@ -1052,12 +1186,12 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveLE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveLT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LT);
+ return leaveCmp(binaryNode);
}
@Override
@@ -1072,12 +1206,12 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveNE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveNE_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE_STRICT);
+ return leaveCmp(binaryNode);
}
@Override
@@ -1089,23 +1223,17 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveSAR(final BinaryNode binaryNode) {
- newTemporary(Type.INT, binaryNode);
- end(binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.INT));
}
@Override
public Node leaveSHL(final BinaryNode binaryNode) {
- newTemporary(Type.INT, binaryNode);
- end(binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.INT));
}
@Override
public Node leaveSHR(final BinaryNode binaryNode) {
- newTemporary(Type.LONG, binaryNode);
- end(binaryNode);
- return binaryNode;
+ return end(coerce(binaryNode, Type.LONG));
}
@Override
@@ -1114,9 +1242,9 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
- forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
+ forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
/*
* Iterators return objects, so we need to widen the scope of the
* init variable if it, for example, has been assigned double type
@@ -1131,7 +1259,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node lhs = ternaryNode.rhs();
final Node rhs = ternaryNode.third();
@@ -1146,24 +1274,24 @@ final class Attr extends NodeOperatorVisitor {
return ternaryNode;
}
- private static void initThis(final FunctionNode functionNode) {
- final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null);
+ private void initThis(final FunctionNode functionNode) {
+ final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null);
newType(thisSymbol, Type.OBJECT);
thisSymbol.setNeedsSlot(true);
functionNode.getThisNode().setSymbol(thisSymbol);
LOG.info("Initialized scope symbol: " + thisSymbol);
}
- private static void initScope(final FunctionNode functionNode) {
- final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
+ private void initScope(final FunctionNode functionNode) {
+ final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
newType(scopeSymbol, Type.typeFor(ScriptObject.class));
scopeSymbol.setNeedsSlot(true);
functionNode.getScopeNode().setSymbol(scopeSymbol);
LOG.info("Initialized scope symbol: " + scopeSymbol);
}
- private static void initReturn(final FunctionNode functionNode) {
- final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
+ private void initReturn(final FunctionNode functionNode) {
+ final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
newType(returnSymbol, Type.OBJECT);
returnSymbol.setNeedsSlot(true);
functionNode.getResultNode().setSymbol(returnSymbol);
@@ -1173,7 +1301,7 @@ final class Attr extends NodeOperatorVisitor {
private void initVarArg(final FunctionNode functionNode) {
if (functionNode.isVarArg()) {
- final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
+ final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
varArgsSymbol.setNeedsSlot(true);
functionNode.getVarArgsNode().setSymbol(varArgsSymbol);
@@ -1181,7 +1309,7 @@ final class Attr extends NodeOperatorVisitor {
if (functionNode.needsArguments()) {
final String argumentsName = functionNode.getArgumentsNode().getName();
- final Symbol argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null);
+ final Symbol argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null);
newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
argumentsSymbol.setNeedsSlot(true);
functionNode.getArgumentsNode().setSymbol(argumentsSymbol);
@@ -1191,9 +1319,9 @@ final class Attr extends NodeOperatorVisitor {
}
}
- private static void initCallee(final FunctionNode functionNode) {
+ private void initCallee(final FunctionNode functionNode) {
assert functionNode.getCalleeNode() != null : functionNode + " has no callee";
- final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
+ final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
newType(calleeSymbol, Type.typeFor(ScriptFunction.class));
calleeSymbol.setNeedsSlot(true);
functionNode.getCalleeNode().setSymbol(calleeSymbol);
@@ -1211,11 +1339,17 @@ final class Attr extends NodeOperatorVisitor {
// type or its parameters with the widest (OBJECT) type for safety.
functionNode.setReturnType(Type.UNKNOWN);
- for (final IdentNode ident : functionNode.getParameters()) {
- addLocalDef(ident.getName());
- final Symbol paramSymbol = functionNode.defineSymbol(ident.getName(), IS_PARAM, ident);
+ for (final IdentNode param : functionNode.getParameters()) {
+ addLocalDef(param.getName());
+ final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param);
if (paramSymbol != null) {
- newType(paramSymbol, Type.UNKNOWN);
+ final Type callSiteParamType = functionNode.getSpecializedType(param);
+ if (callSiteParamType != null) {
+ LOG.info("Param " + paramSymbol + " has a callsite type " + callSiteParamType + ". Using that.");
+
+ System.err.println("Param " + param + " has a callsite type " + callSiteParamType + ". Using that.");
+ }
+ newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
}
LOG.info("Initialized param " + paramSymbol);
@@ -1229,36 +1363,29 @@ final class Attr extends NodeOperatorVisitor {
* @param functionNode functionNode
*/
private static void finalizeParameters(final FunctionNode functionNode) {
- boolean nonObjectParams = false;
- List<Type> paramSpecializations = new ArrayList<>();
+ final boolean isVarArg = functionNode.isVarArg();
for (final IdentNode ident : functionNode.getParameters()) {
final Symbol paramSymbol = ident.getSymbol();
- if (paramSymbol != null) {
- Type type = paramSymbol.getSymbolType();
- if (type.isUnknown()) {
- type = Type.OBJECT;
- }
- paramSpecializations.add(type);
- if (!type.isObject()) {
- nonObjectParams = true;
- }
- newType(paramSymbol, Type.OBJECT);
+
+ assert paramSymbol != null;
+ Type type = functionNode.getSpecializedType(ident);
+ if (type == null) {
+ type = Type.OBJECT;
}
- }
- if (!nonObjectParams) {
- paramSpecializations = null;
- // Later, when resolving a call to this method, the linker can say "I have a double, an int and an object" as parameters
- // here. If the callee has parameter specializations, we can regenerate it with those particular types for speed.
- } else {
- LOG.info("parameter specialization possible: " + functionNode.getName() + " " + paramSpecializations);
- }
+ // if we know that a parameter is only used as a certain type throughout
+ // this function, we can tell the runtime system that no matter what the
+ // call site is, use this information. TODO
+ if (!paramSymbol.getSymbolType().isObject()) {
+ LOG.finest("Parameter " + ident + " could profit from specialization to " + paramSymbol.getSymbolType());
+ }
- // parameters should not be slots for a function that uses variable arity signature
- if (functionNode.isVarArg()) {
- for (final IdentNode param : functionNode.getParameters()) {
- param.getSymbol().setNeedsSlot(false);
+ newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType()));
+
+ // parameters should not be slots for a function that uses variable arity signature
+ if (isVarArg) {
+ paramSymbol.setNeedsSlot(false);
}
}
}
@@ -1267,15 +1394,15 @@ final class Attr extends NodeOperatorVisitor {
* Move any properties from a global map into the scope of this method
* @param functionNode the function node for which to init scope vars
*/
- private static void initFromPropertyMap(final FunctionNode functionNode) {
+ private void initFromPropertyMap(final FunctionNode functionNode) {
// For a script, add scope symbols as defined in the property map
- assert functionNode.isScript();
+ assert functionNode.isProgram();
final PropertyMap map = Context.getGlobalMap();
for (final Property property : map.getProperties()) {
final String key = property.getKey();
- final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null);
+ final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null);
newType(symbol, Type.OBJECT);
LOG.info("Added global symbol from property map " + symbol);
}
@@ -1342,9 +1469,14 @@ final class Attr extends NodeOperatorVisitor {
private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
assignmentDest.accept(new NodeVisitor() {
@Override
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
+ assert indexNode.getSymbol().isTemp();
final Node index = indexNode.getIndex();
- index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant());
+ //only temps can be set as needing slots. the others will self resolve
+ //it is illegal to take a scope var and force it to be a slot, that breaks
+ if (index.getSymbol().isTemp() && !index.getSymbol().isConstant()) {
+ index.getSymbol().setNeedsSlot(true);
+ }
return indexNode;
}
});
@@ -1387,7 +1519,7 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
return node.isLazy() ? null : node;
}
@@ -1407,7 +1539,7 @@ final class Attr extends NodeOperatorVisitor {
*/
@SuppressWarnings("fallthrough")
@Override
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
switch (binaryNode.tokenType()) {
default:
@@ -1465,22 +1597,6 @@ final class Attr extends NodeOperatorVisitor {
return binaryNode;
}
- private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) {
- if (currentFunction.findParentFunction() == topFunction) {
- final List<Block> blocks = new LinkedList<>();
-
- blocks.add(currentFunction.getParent());
- blocks.addAll(currentFunction.getReferencingParentBlocks());
- return blocks;
- }
- /*
- * assumption: all parent blocks of an inner function will always be in the same outer function;
- * therefore we can simply skip through intermediate functions.
- * @see FunctionNode#addReferencingParentBlock(Block)
- */
- return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction);
- }
-
private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName());
@@ -1497,16 +1613,12 @@ final class Attr extends NodeOperatorVisitor {
return newTemporary(getCurrentFunctionNode(), type, node);
}
- private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) {
- final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
+ private Symbol newInternal(final String name, final Type type) {
+ final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null);
iter.setType(type); // NASHORN-73
return iter;
}
- private Symbol newInternal(final String name, final Type type) {
- return newInternal(getCurrentFunctionNode(), name, type);
- }
-
private static void newType(final Symbol symbol, final Type type) {
final Type oldType = symbol.getSymbolType();
symbol.setType(type);
@@ -1548,6 +1660,39 @@ final class Attr extends NodeOperatorVisitor {
localUses.add(name);
}
+ /**
+ * Pessimistically promote all symbols in current function node to Object types
+ * This is done when the function contains unevaluated black boxes such as
+ * lazy sub-function nodes that have not been compiled.
+ *
+ * @param functionNode function node in whose scope symbols should conservatively be made objects
+ */
+ private static void objectifySymbols(final FunctionNode functionNode) {
+ functionNode.accept(new NodeVisitor() {
+ private void toObject(final Block block) {
+ for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) {
+ final Symbol symbol = iter.next();
+ newType(symbol, Type.OBJECT);
+ }
+ }
+
+ @Override
+ public Node enterBlock(final Block block) {
+ toObject(block);
+ return block;
+ }
+
+ @Override
+ public Node enterFunctionNode(final FunctionNode node) {
+ toObject(node);
+ if (node.isLazy()) {
+ return null;
+ }
+ return node;
+ }
+ });
+ }
+
private static String name(final Node node) {
final String cn = node.getClass().getName();
int lastDot = cn.lastIndexOf('.');
diff --git a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
index 84cef437..ee922115 100644
--- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
+++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
@@ -32,7 +32,6 @@ import static jdk.nashorn.internal.codegen.Condition.LE;
import static jdk.nashorn.internal.codegen.Condition.LT;
import static jdk.nashorn.internal.codegen.Condition.NE;
-import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Node;
diff --git a/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/src/jdk/nashorn/internal/codegen/ClassEmitter.java
index 35e74824..7ca7f994 100644
--- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java
+++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java
@@ -195,6 +195,14 @@ public class ClassEmitter implements Emitter {
}
/**
+ * Returns the name of the compile unit class name.
+ * @return the name of the compile unit class name.
+ */
+ String getUnitClassName() {
+ return unitClassName;
+ }
+
+ /**
* Convert a binary name to a package/class name.
*
* @param name Binary name.
@@ -244,7 +252,7 @@ public class ClassEmitter implements Emitter {
// $getMap - get the ith entry from the constants table and cast to PropertyMap.
final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class);
getMapMethod.begin();
- getMapMethod.loadConstants(unitClassName)
+ getMapMethod.loadConstants()
.load(Type.INT, 0)
.arrayload()
.checkcast(PropertyMap.class)
@@ -254,7 +262,7 @@ public class ClassEmitter implements Emitter {
// $setMap - overwrite an existing map.
final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class);
setMapMethod.begin();
- setMapMethod.loadConstants(unitClassName)
+ setMapMethod.loadConstants()
.load(Type.INT, 0)
.load(Type.OBJECT, 1)
.arraystore();
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 2ffb5bd8..1d09e9c9 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -25,10 +25,8 @@
package jdk.nashorn.internal.codegen;
-import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.HANDLE_STATIC;
import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE;
import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC;
-import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP;
import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF;
@@ -50,7 +48,6 @@ import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALL
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
import java.io.PrintWriter;
-import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
@@ -79,9 +76,11 @@ import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
@@ -89,7 +88,6 @@ import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -108,14 +106,14 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Lexer.RegexToken;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.Scope;
import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
@@ -149,8 +147,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */
private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl";
- private static final String SCRIPTFUNCTION_TRAMPOLINE_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionTrampolineImpl";
-
/** Constant data & installation. The only reason the compiler keeps this is because it is assigned
* by reflection in class installation */
private final Compiler compiler;
@@ -161,12 +157,20 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** How many regexp fields have been emitted */
private int regexFieldCount;
+ /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling
+ * a just-defined anonymous function expression. */
+ private boolean functionNodeIsCallee;
+
/** Map of shared scope call sites */
private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
+ private final LexicalContext lexicalContext = new LexicalContext();
+
/** When should we stop caching regexp expressions in fields to limit bytecode size? */
private static final int MAX_REGEX_FIELDS = 2 * 1024;
+ private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug");
+
/**
* Constructor.
*
@@ -215,7 +219,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final int flags = CALLSITE_SCOPE | getCallSiteFlags();
method.loadScope();
- if (symbol.isFastScope(getCurrentFunctionNode())) {
+ if (isFastScope(symbol)) {
// Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) {
return loadSharedScopeVar(identNode.getType(), symbol, flags);
@@ -226,8 +230,28 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
}
+ /**
+ * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
+ *
+ * @param function function to check for fast scope
+ * @return true if fast scope
+ */
+ private boolean isFastScope(final Symbol symbol) {
+ if (!symbol.isScope() || !symbol.getBlock().needsScope()) {
+ return false;
+ }
+ // Allow fast scope access if no function contains with or eval
+ for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) {
+ final FunctionNode func = it.next();
+ if (func.hasWith() || func.hasEval()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
- method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
+ method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE);
scopeCall.generateInvoke(method);
return method;
@@ -245,30 +269,18 @@ final class CodeGenerator extends NodeOperatorVisitor {
return method;
}
- private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) {
- if (currentBlock == symbol.getBlock()) {
- return 0;
- }
-
- final int delta = currentBlock.needsScope() ? 1 : 0;
- final Block parentBlock = currentBlock.getParent();
-
- if (parentBlock != null) {
- final int result = getScopeProtoDepth(parentBlock, symbol);
- if (result != -1) {
- return delta + result;
+ private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
+ int depth = 0;
+ final Block definingBlock = symbol.getBlock();
+ for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) {
+ final Block currentBlock = blocks.next();
+ if (currentBlock == definingBlock) {
+ return depth;
}
- }
-
- if (currentBlock instanceof FunctionNode) {
- for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) {
- final int result = getScopeProtoDepth(lookupBlock, symbol);
- if (result != -1) {
- return delta + result;
- }
+ if (currentBlock.needsScope()) {
+ ++depth;
}
}
-
return -1;
}
@@ -318,13 +330,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
node.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
loadIdent(identNode);
return null;
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
if (!baseAlreadyOnStack) {
load(accessNode.getBase()).convert(Type.OBJECT);
}
@@ -334,7 +346,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
if (!baseAlreadyOnStack) {
load(indexNode.getBase()).convert(Type.OBJECT);
load(indexNode.getIndex());
@@ -344,6 +356,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ // function nodes will always leave a constructed function object on stack, no need to load the symbol
+ // separately as in enterDefault()
+ functionNode.accept(codegen);
+ return null;
+ }
+
+ @Override
public Node enterDefault(final Node otherNode) {
otherNode.accept(codegen); // generate code for whatever we are looking at.
method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
@@ -355,7 +375,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
if (accessNode.testResolved()) {
return null;
}
@@ -427,10 +447,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (block.testResolved()) {
return null;
}
+ lexicalContext.push(block);
method.label(block.getEntryLabel());
initLocals(block);
@@ -439,14 +460,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
method.label(block.getBreakLabel());
symbolInfo(block);
if (block.needsScope()) {
popBlockScope(block);
}
-
+ lexicalContext.pop(block);
return block;
}
@@ -472,7 +493,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
if (breakNode.testResolved()) {
return null;
}
@@ -520,14 +541,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
if (callNode.testResolved()) {
return null;
}
final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction();
- final FunctionNode currentFunction = getCurrentFunctionNode();
final Block currentBlock = getCurrentBlock();
function.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@@ -536,7 +556,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final Symbol symbol = identNode.getSymbol();
int scopeCallFlags = flags;
method.loadScope();
- if (symbol.isFastScope(currentFunction)) {
+ if (isFastScope(symbol)) {
method.load(getScopeProtoDepth(currentBlock, symbol));
scopeCallFlags |= CALLSITE_FAST_SCOPE;
} else {
@@ -598,7 +618,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
if (symbol.isScope()) {
@@ -611,7 +631,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
if (callNode.isEval()) {
evalCall(node, flags);
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
- || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
+ || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
|| callNode.inWithBlock()) {
scopeCall(node, flags);
} else {
@@ -626,7 +646,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
load(node.getBase());
method.convert(Type.OBJECT);
method.dup();
@@ -639,8 +659,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ReferenceNode node) {
- final FunctionNode callee = node.getReference();
+ public Node enterFunctionNode(final FunctionNode callee) {
final boolean isVarArg = callee.isVarArg();
final int argCount = isVarArg ? -1 : callee.getParameters().size();
@@ -658,12 +677,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
loadArgs(args, signature, isVarArg, argCount);
method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
-
+ functionNodeIsCallee = true;
+ callee.accept(CodeGenerator.this);
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
load(node.getBase());
method.convert(Type.OBJECT);
method.dup();
@@ -699,7 +719,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
if (continueNode.testResolved()) {
return null;
}
@@ -714,17 +734,17 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return null;
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
if (executeNode.testResolved()) {
return null;
}
@@ -736,7 +756,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
if (forNode.testResolved()) {
return null;
}
@@ -818,7 +838,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @param block block with local vars.
*/
private void initLocals(final Block block) {
- final FunctionNode function = block.getFunction();
+ final FunctionNode function = lexicalContext.getFunction(block);
final boolean isFunctionNode = block == function;
/*
@@ -920,7 +940,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
foc.makeObject(method);
// runScript(): merge scope into global
- if (isFunctionNode && function.isScript()) {
+ if (isFunctionNode && function.isProgram()) {
method.invoke(ScriptRuntime.MERGE_SCOPE);
}
@@ -963,31 +983,42 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final FunctionNode functionNode) {
- if (functionNode.isLazy()) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
+ final boolean isCallee = functionNodeIsCallee;
+ functionNodeIsCallee = false;
+
+ if (functionNode.testResolved()) {
return null;
}
- if (functionNode.testResolved()) {
+ if(!(isCallee || functionNode == compiler.getFunctionNode())) {
+ newFunctionObject(functionNode);
+ }
+
+ if (functionNode.isLazy()) {
return null;
}
+ LOG.info("=== BEGIN " + functionNode.getName());
+ lexicalContext.push(functionNode);
+
setCurrentCompileUnit(functionNode.getCompileUnit());
assert getCurrentCompileUnit() != null;
- method = getCurrentCompileUnit().getClassEmitter().method(functionNode);
+ setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode));
functionNode.setMethodEmitter(method);
// Mark end for variable tables.
method.begin();
method.label(functionNode.getEntryLabel());
initLocals(functionNode);
+ functionNode.setState(CompilationState.EMITTED);
return functionNode;
}
@Override
- public Node leave(final FunctionNode functionNode) {
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
// Mark end for variable tables.
method.label(functionNode.getBreakLabel());
@@ -1005,16 +1036,18 @@ final class CodeGenerator extends NodeOperatorVisitor {
throw e;
}
+ lexicalContext.pop(functionNode);
+ LOG.info("=== END " + functionNode.getName());
return functionNode;
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
return null;
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
if (ifNode.testResolved()) {
return null;
}
@@ -1053,7 +1086,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
if (indexNode.testResolved()) {
return null;
}
@@ -1064,7 +1097,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (lineNumberNode.testResolved()) {
return null;
}
@@ -1072,7 +1105,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")");
method.label(label);
method.lineNumber(lineNumberNode.getLineNumber(), label);
-
return null;
}
@@ -1110,7 +1142,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag());
final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
- method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature);
+ setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
method.setFunctionNode(getCurrentFunctionNode());
method.begin();
@@ -1216,7 +1248,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class));
classEmitter.needGetConstantMethod(cls);
} else {
- method.loadConstants(unitClassName).load(index).arrayload();
+ method.loadConstants().load(index).arrayload();
if (cls != Object.class) {
method.checkcast(cls);
}
@@ -1296,14 +1328,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
load(literalNode).store(literalNode.getSymbol());
return null;
}
@Override
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
if (objectNode.testResolved()) {
return null;
}
@@ -1376,10 +1408,10 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
for (final Node element : elements) {
- final PropertyNode propertyNode = (PropertyNode)element;
- final Object key = propertyNode.getKey();
- final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter();
- final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter();
+ final PropertyNode propertyNode = (PropertyNode)element;
+ final Object key = propertyNode.getKey();
+ final FunctionNode getter = (FunctionNode)propertyNode.getGetter();
+ final FunctionNode setter = (FunctionNode)propertyNode.getSetter();
if (getter == null && setter == null) {
continue;
@@ -1408,18 +1440,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ReferenceNode referenceNode) {
- if (referenceNode.testResolved()) {
- return null;
- }
-
- newFunctionObject(referenceNode.getReference());
-
- return null;
- }
-
- @Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
if (returnNode.testResolved()) {
return null;
}
@@ -1560,7 +1581,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
if (runtimeNode.testResolved()) {
return null;
}
@@ -1641,7 +1662,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
if (splitNode.testResolved()) {
return null;
}
@@ -1710,7 +1731,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
try {
// Wrap up this method.
method.loadResult();
@@ -1767,7 +1788,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
if (switchNode.testResolved()) {
return null;
}
@@ -1899,7 +1920,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
if (throwNode.testResolved()) {
return null;
}
@@ -1926,7 +1947,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
if (tryNode.testResolved()) {
return null;
}
@@ -1959,7 +1980,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
setCurrentBlock(catchBlock);
try {
- enter(catchBlock);
+ enterBlock(catchBlock);
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
final IdentNode exception = catchNode.getException();
@@ -1970,6 +1991,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Generate catch body (inlined finally) and rethrow exception
catchBody.accept(this);
method.load(symbol).athrow();
+ lexicalContext.pop(catchBlock);
continue;
}
@@ -2016,7 +2038,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
}
- leave(catchBlock);
+ leaveBlock(catchBlock);
} finally {
setCurrentBlock(saveBlock);
}
@@ -2031,7 +2053,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
if (varNode.testResolved() || init == null) {
@@ -2053,7 +2075,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
int flags = CALLSITE_SCOPE | getCallSiteFlags();
final IdentNode identNode = varNode.getName();
final Type type = identNode.getType();
- if (varSymbol.isFastScope(getCurrentFunctionNode())) {
+ if (isFastScope(varSymbol)) {
storeFastScopeVar(type, varSymbol, flags);
} else {
method.dynamicSet(type, identNode.getName(), flags);
@@ -2069,7 +2091,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
if (whileNode.testResolved()) {
return null;
}
@@ -2102,7 +2124,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
if (withNode.testResolved()) {
return null;
}
@@ -2868,7 +2890,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* Ternary visits.
*/
@Override
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
if (ternaryNode.testResolved()) {
return null;
}
@@ -3064,7 +3086,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
target.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
if (targetSymbol.isScope()) {
method.load(scopeSymbol);
depth++;
@@ -3087,13 +3109,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
enterBaseNode();
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
enterBaseNode();
final Node index = node.getIndex();
@@ -3159,8 +3181,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void epilogue() {
- final FunctionNode currentFunction = getCurrentFunctionNode();
-
/**
* Take the original target args from the stack and use them
* together with the value to be stored to emit the store code
@@ -3178,7 +3198,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final UnaryNode node) {
+ public Node enterUnaryNode(final UnaryNode node) {
if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
method.convert(node.rhs().getType());
}
@@ -3186,11 +3206,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
assert symbol != null;
if (symbol.isScope()) {
- if (symbol.isFastScope(currentFunction)) {
+ if (isFastScope(symbol)) {
storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
} else {
method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
@@ -3203,13 +3223,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
method.dynamicSetIndex(getCallSiteFlags());
return null;
}
@@ -3234,42 +3254,22 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void newFunctionObject(final FunctionNode functionNode) {
- final boolean isLazy = functionNode.isLazy();
- final Class<?>[] cparams = new Class<?>[] { ScriptFunctionData.class, ScriptObject.class, MethodHandle.class };
+ final boolean isLazy = functionNode.isLazy();
new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) {
@Override
- protected void makeObject(final MethodEmitter method) {
- final String className = isLazy ? SCRIPTFUNCTION_TRAMPOLINE_OBJECT : SCRIPTFUNCTION_IMPL_OBJECT;
+ protected void makeObject(final MethodEmitter m) {
+ final String className = SCRIPTFUNCTION_IMPL_OBJECT;
- method._new(className).dup();
- if (isLazy) {
- loadConstant(compiler.getCodeInstaller());
- loadConstant(functionNode);
- } else {
- final String signature = new FunctionSignature(true, functionNode.needsCallee(), functionNode.getReturnType(), functionNode.isVarArg() ? null : functionNode.getParameters()).toString();
- method.loadHandle(functionNode.getCompileUnit().getUnitClassName(), functionNode.getName(), signature, EnumSet.of(HANDLE_STATIC)); // function
- }
- loadConstant(new ScriptFunctionData(functionNode, makeMap()));
+ m._new(className).dup();
+ loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap()));
if (isLazy || functionNode.needsParentScope()) {
- method.loadScope();
- } else {
- method.loadNull();
- }
-
- method.loadHandle(getClassName(), ALLOCATE.tag(), methodDescriptor(ScriptObject.class, PropertyMap.class), EnumSet.of(HANDLE_STATIC));
-
- final List<Class<?>> cparamList = new ArrayList<>();
- if (isLazy) {
- cparamList.add(CodeInstaller.class);
- cparamList.add(FunctionNode.class);
+ m.loadScope();
} else {
- cparamList.add(MethodHandle.class);
+ m.loadNull();
}
- cparamList.addAll(Arrays.asList(cparams));
-
- method.invoke(constructorNoLookup(className, cparamList.toArray(new Class<?>[cparamList.size()])));
+ m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
}
}.makeObject(method);
}
diff --git a/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index e22454cc..8b905f87 100644
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -2,10 +2,10 @@ package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.ATTR;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.EMITTED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED;
+import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
import java.io.File;
@@ -14,16 +14,16 @@ import java.io.IOException;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.Timing;
@@ -39,7 +39,7 @@ enum CompilationPhase {
* default policy. The will get trampolines and only be generated when
* called
*/
- LAZY_INITIALIZATION_PHASE(EnumSet.of(FunctionNode.CompilationState.INITIALIZED)) {
+ LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
@@ -65,23 +65,25 @@ enum CompilationPhase {
outermostFunctionNode.accept(new NodeVisitor() {
// self references are done with invokestatic and thus cannot have trampolines - never lazy
@Override
- public Node enter(final CallNode node) {
+ public Node enterCallNode(final CallNode node) {
final Node callee = node.getFunction();
- if (callee instanceof ReferenceNode) {
- neverLazy.add(((ReferenceNode)callee).getReference());
+ if (callee instanceof FunctionNode) {
+ neverLazy.add(((FunctionNode)callee));
return null;
}
return node;
}
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
if (node == outermostFunctionNode) {
return node;
}
- assert Compiler.LAZY_JIT;
+ assert compiler.isLazy();
lazy.add(node);
+ //also needs scope, potentially needs arguments etc etc
+
return node;
}
});
@@ -92,15 +94,24 @@ enum CompilationPhase {
lazy.remove(node);
}
- for (final FunctionNode node : lazy) {
- Compiler.LOG.fine("Marking " + node.getName() + " as lazy");
- node.setIsLazy(true);
- final FunctionNode parent = node.findParentFunction();
- if (parent != null) {
- Compiler.LOG.fine("Marking " + parent.getName() + " as having lazy children - it needs scope for all variables");
- parent.setHasLazyChildren();
+ outermostFunctionNode.accept(new NodeOperatorVisitor() {
+ private final LexicalContext lexicalContext = new LexicalContext();
+ @Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ lexicalContext.push(functionNode);
+ if(lazy.contains(functionNode)) {
+ Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy");
+ functionNode.setIsLazy(true);
+ lexicalContext.getParentFunction(functionNode).setHasLazyChildren();
+ }
+ return functionNode;
}
- }
+ @Override
+ public Node leaveFunctionNode(FunctionNode functionNode) {
+ lexicalContext.pop(functionNode);
+ return functionNode;
+ }
+ });
}
@Override
@@ -113,7 +124,7 @@ enum CompilationPhase {
* Constant folding pass
* Simple constant folding that will make elementary constructs go away
*/
- CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED), CONSTANT_FOLDED) {
+ CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
fn.accept(new FoldConstants());
@@ -134,7 +145,7 @@ enum CompilationPhase {
* as runtime nodes where applicable.
*
*/
- LOWERING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED), LOWERED) {
+ LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
fn.accept(new Lower());
@@ -150,19 +161,10 @@ enum CompilationPhase {
* Attribution
* Assign symbols and types to all nodes.
*/
- ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED), ATTR) {
+ ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
- final ScriptEnvironment env = compiler.getEnv();
-
fn.accept(new Attr());
- if (env._print_lower_ast) {
- env.getErr().println(new ASTWriter(fn));
- }
-
- if (env._print_lower_parse) {
- env.getErr().println(new PrintVisitor(fn));
- }
}
@Override
@@ -178,7 +180,7 @@ enum CompilationPhase {
* a + b a ScriptRuntime.ADD with call overhead or a dadd with much
* less). Split IR can lead to scope information being changed.
*/
- SPLITTING_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR), SPLIT) {
+ SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
@@ -212,10 +214,20 @@ enum CompilationPhase {
* Contract: all variables must have slot assignments and scope assignments
* before type finalization.
*/
- TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT), FINALIZED) {
+ TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
+ final ScriptEnvironment env = compiler.getEnv();
+
fn.accept(new FinalizeTypes());
+
+ if (env._print_lower_ast) {
+ env.getErr().println(new ASTWriter(fn));
+ }
+
+ if (env._print_lower_parse) {
+ env.getErr().println(new PrintVisitor(fn));
+ }
}
@Override
@@ -229,7 +241,7 @@ enum CompilationPhase {
*
* Generate the byte code class(es) resulting from the compiled FunctionNode
*/
- BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED), EMITTED) {
+ BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) {
@Override
void transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv();
@@ -238,6 +250,16 @@ enum CompilationPhase {
final CodeGenerator codegen = new CodeGenerator(compiler);
fn.accept(codegen);
codegen.generateScopeCalls();
+ fn.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ if(functionNode.isLazy()) {
+ functionNode.resetResolved();
+ return null;
+ }
+ return fn;
+ }
+ });
} catch (final VerifyError e) {
if (env._verify_code || env._print_code) {
@@ -306,18 +328,12 @@ enum CompilationPhase {
};
private final EnumSet<CompilationState> pre;
- private final CompilationState post;
private long startTime;
private long endTime;
private boolean isFinished;
private CompilationPhase(final EnumSet<CompilationState> pre) {
- this(pre, null);
- }
-
- private CompilationPhase(final EnumSet<CompilationState> pre, final CompilationState post) {
- this.pre = pre;
- this.post = post;
+ this.pre = pre;
}
boolean isApplicable(final FunctionNode functionNode) {
@@ -343,10 +359,6 @@ enum CompilationPhase {
endTime = System.currentTimeMillis();
Timing.accumulateTime(toString(), endTime - startTime);
- if (post != null) {
- functionNode.setState(post);
- }
-
isFinished = true;
}
diff --git a/src/jdk/nashorn/internal/codegen/CompileUnit.java b/src/jdk/nashorn/internal/codegen/CompileUnit.java
index 5e62116b..ff88fa99 100644
--- a/src/jdk/nashorn/internal/codegen/CompileUnit.java
+++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java
@@ -37,6 +37,8 @@ public class CompileUnit {
private long weight;
+ private Class<?> clazz;
+
CompileUnit(final String className, final ClassEmitter classEmitter) {
this(className, classEmitter, 0L);
}
@@ -48,6 +50,24 @@ public class CompileUnit {
}
/**
+ * Return the class that contains the code for this unit, null if not
+ * generated yet
+ *
+ * @return class with compile unit code
+ */
+ public Class<?> getCode() {
+ return clazz;
+ }
+
+ /**
+ * Set class when it exists. Only accessible from compiler
+ * @param clazz class with code for this compile unit
+ */
+ void setCode(final Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
* Add weight to this compile unit
* @param w weight to add
*/
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index ca23c428..397f39a5 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -45,11 +45,14 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.logging.Level;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -71,8 +74,6 @@ public final class Compiler {
/** Name of the objects package */
public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
- static final boolean LAZY_JIT = Options.getBooleanProperty("nashorn.compiler.lazy");
-
private final Map<String, byte[]> bytecode;
private final Set<CompileUnit> compileUnits;
@@ -164,7 +165,7 @@ public final class Compiler {
* and JIT it at once. This can lead to long startup time and fewer type
* specializations
*/
- final static CompilationSequence SEQUENCE_NORMAL = new CompilationSequence(
+ final static CompilationSequence SEQUENCE_EAGER = new CompilationSequence(
CompilationPhase.CONSTANT_FOLDING_PHASE,
CompilationPhase.LOWERING_PHASE,
CompilationPhase.ATTRIBUTION_PHASE,
@@ -173,12 +174,15 @@ public final class Compiler {
CompilationPhase.BYTECODE_GENERATION_PHASE);
final static CompilationSequence SEQUENCE_LAZY =
- SEQUENCE_NORMAL.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE);
+ SEQUENCE_EAGER.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE);
+
+ private static CompilationSequence sequence(final boolean lazy) {
+ return lazy ? SEQUENCE_LAZY : SEQUENCE_EAGER;
+ }
- final static CompilationSequence SEQUENCE_DEFAULT =
- LAZY_JIT ?
- SEQUENCE_LAZY :
- SEQUENCE_NORMAL;
+ boolean isLazy() {
+ return sequence == SEQUENCE_LAZY;
+ }
private static String lazyTag(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
@@ -212,11 +216,6 @@ public final class Compiler {
append(safeSourceName(functionNode.getSource()));
this.scriptName = sb.toString();
-
- LOG.info("Initializing compiler for '" + functionNode.getName() + "' scriptName = " + scriptName + ", root function: '" + functionNode.getName() + "'");
- if (functionNode.isLazy()) {
- LOG.info(">>> This is a lazy recompilation triggered by a trampoline");
- }
}
/**
@@ -227,7 +226,7 @@ public final class Compiler {
* @param strict should this compilation use strict mode semantics
*/
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) {
- this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, strict);
+ this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict);
}
/**
@@ -237,7 +236,7 @@ public final class Compiler {
* @param functionNode function node (in any available {@link CompilationState}) to compile
*/
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) {
- this(installer.getOwner(), installer, functionNode, SEQUENCE_DEFAULT, installer.getOwner()._strict);
+ this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
}
/**
@@ -247,28 +246,104 @@ public final class Compiler {
* @param functionNode functionNode to compile
*/
public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) {
- this(env, null, functionNode, SEQUENCE_DEFAULT, env._strict);
+ this(env, null, functionNode, sequence(env._lazy_compilation), env._strict);
+ }
+
+ /**
+ * Execute the compilation this Compiler was created with
+ * @params param types if known, for specialization
+ * @throws CompilationException if something goes wrong
+ * @return this compiler, for possible chaining
+ */
+ public Compiler compile() throws CompilationException {
+ return compile(null);
}
/**
* Execute the compilation this Compiler was created with
+ * @param paramTypes param types if known, for specialization
* @throws CompilationException if something goes wrong
+ * @return this compiler, for possible chaining
*/
- public void compile() throws CompilationException {
+ public Compiler compile(final Class<?> paramTypes) throws CompilationException {
for (final String reservedName : RESERVED_NAMES) {
functionNode.uniqueName(reservedName);
}
+ final boolean fine = !LOG.levelAbove(Level.FINE);
+ final boolean info = !LOG.levelAbove(Level.INFO);
+
+ long time = 0L;
+
for (final CompilationPhase phase : sequence) {
phase.apply(this, functionNode);
- final String end = phase.toString() + " done for function '" + functionNode.getName() + "'";
- if (Timing.isEnabled()) {
- final long duration = phase.getEndTime() - phase.getStartTime();
- LOG.info(end + " in " + duration + " ms");
- } else {
- LOG.info(end);
+
+ final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
+ time += duration;
+
+ if (fine) {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(phase.toString()).
+ append(" done for function '").
+ append(functionNode.getName()).
+ append('\'');
+
+ if (duration > 0L) {
+ sb.append(" in ").
+ append(duration).
+ append(" ms ");
+ }
+
+ LOG.fine(sb.toString());
}
}
+
+ if (info) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Compile job for '").
+ append(functionNode.getName()).
+ append("' finished");
+
+ if (time > 0L) {
+ sb.append(" in ").
+ append(time).
+ append(" ms");
+ }
+
+ LOG.info(sb.toString());
+ }
+
+ return this;
+ }
+
+ private Class<?> install(final String className, final byte[] code) {
+ LOG.fine("Installing class " + className);
+
+ final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
+
+ try {
+ final Source source = getSource();
+ final Object[] constants = getConstantData().toArray();
+ // Need doPrivileged because these fields are private
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ //use reflection to write source and constants table to installed classes
+ final Field sourceField = clazz.getDeclaredField(SOURCE.tag());
+ final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag());
+ sourceField.setAccessible(true);
+ constantsField.setAccessible(true);
+ sourceField.set(null, source);
+ constantsField.set(null, constants);
+ return null;
+ }
+ });
+ } catch (final PrivilegedActionException e) {
+ throw new RuntimeException(e);
+ }
+
+ return clazz;
}
/**
@@ -280,46 +355,68 @@ public final class Compiler {
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
- Class<?> rootClass = null;
+ final Map<String, Class<?>> installedClasses = new HashMap<>();
- for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
- final String className = entry.getKey();
- LOG.fine("Installing class " + className);
+ final String rootClassName = firstCompileUnitName();
+ final byte[] rootByteCode = bytecode.get(rootClassName);
+ final Class<?> rootClass = install(rootClassName, rootByteCode);
- final byte[] code = entry.getValue();
- final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
+ int length = rootByteCode.length;
- if (rootClass == null && firstCompileUnitName().equals(className)) {
- rootClass = clazz;
+ installedClasses.put(rootClassName, rootClass);
+
+ for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
+ final String className = entry.getKey();
+ if (className.equals(rootClassName)) {
+ continue;
}
+ final byte[] code = entry.getValue();
+ length += code.length;
- try {
- final Source source = getSource();
- final Object[] constants = getConstantData().toArray();
- // Need doPrivileged because these fields are private
- AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
- @Override
- public Void run() throws Exception {
- //use reflection to write source and constants table to installed classes
- final Field sourceField = clazz.getDeclaredField(SOURCE.tag());
- final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag());
- sourceField.setAccessible(true);
- constantsField.setAccessible(true);
- sourceField.set(null, source);
- constantsField.set(null, constants);
- return null;
- }
- });
- } catch (final PrivilegedActionException e) {
- throw new RuntimeException(e);
+ installedClasses.put(className, install(className, code));
+ }
+
+ for (final CompileUnit unit : compileUnits) {
+ unit.setCode(installedClasses.get(unit.getUnitClassName()));
+ }
+
+ functionNode.accept(new NodeVisitor() {
+ @Override
+ public Node enterFunctionNode(final FunctionNode node) {
+ if (node.isLazy()) {
+ return null;
+ }
+ node.setState(CompilationState.INSTALLED);
+ return node;
+ }
+ });
+
+ final StringBuilder sb;
+ if (LOG.isEnabled()) {
+ sb = new StringBuilder();
+ sb.append("Installed class '").
+ append(rootClass.getSimpleName()).
+ append('\'').
+ append(" bytes=").
+ append(length).
+ append('.');
+ if (bytecode.size() > 1) {
+ sb.append(' ').append(bytecode.size()).append(" compile units.");
}
+ } else {
+ sb = null;
}
- LOG.info("Installed root class: " + rootClass + " and " + bytecode.size() + " compile unit classes");
if (Timing.isEnabled()) {
final long duration = System.currentTimeMillis() - t0;
Timing.accumulateTime("[Code Installation]", duration);
- LOG.info("Installation time: " + duration + " ms");
+ if (sb != null) {
+ sb.append(" Install time: ").append(duration).append(" ms");
+ }
+ }
+
+ if (sb != null) {
+ LOG.info(sb.toString());
}
return rootClass;
@@ -444,8 +541,6 @@ public final class Compiler {
* TODO: We currently generate no overflow checks so this is
* disabled
*
- * @see #shouldUseIntegers()
- *
* @return true if arithmetic operations should not widen integer
* operands by default.
*/
@@ -460,4 +555,5 @@ public final class Compiler {
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
}
+
}
diff --git a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
index 28dfda7d..cd185240 100644
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
@@ -40,13 +40,14 @@ import jdk.nashorn.internal.ir.DoWhileNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -84,11 +85,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private static final DebugLogger LOG = new DebugLogger("finalize");
+ private final LexicalContext lexicalContext = new LexicalContext();
+
FinalizeTypes() {
}
@Override
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
final EvalArgs evalArgs = callNode.getEvalArgs();
if (evalArgs != null) {
evalArgs.setCode(evalArgs.getCode().accept(this));
@@ -96,15 +99,14 @@ final class FinalizeTypes extends NodeOperatorVisitor {
// AccessSpecializer - call return type may change the access for this location
final Node function = callNode.getFunction();
- if (function instanceof ReferenceNode) {
- setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType());
+ if (function instanceof FunctionNode) {
+ return setTypeOverride(callNode, ((FunctionNode)function).getReturnType());
}
return callNode;
}
private Node leaveUnary(final UnaryNode unaryNode) {
- unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
- return unaryNode;
+ return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
}
@Override
@@ -125,8 +127,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
- specialize(unaryNode);
- return unaryNode;
+ return specialize(unaryNode).node;
}
@Override
@@ -158,9 +159,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
- binaryNode.setLHS(convert(lhs, type));
- binaryNode.setRHS(convert(rhs, type));
- return binaryNode;
+ return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type));
}
@Override
@@ -170,12 +169,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveASSIGN(final BinaryNode binaryNode) {
- Type destType = specialize(binaryNode);
+ final SpecializedNode specialized = specialize(binaryNode);
+ final BinaryNode specBinaryNode = (BinaryNode)specialized.node;
+ Type destType = specialized.type;
if (destType == null) {
- destType = binaryNode.getType();
+ destType = specBinaryNode.getType();
}
- binaryNode.setRHS(convert(binaryNode.rhs(), destType));
- return binaryNode;
+ return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
}
@Override
@@ -235,40 +235,40 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveBIT_AND(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : binaryNode.getSymbol();
+ assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@Override
public Node leaveBIT_OR(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger();
+ assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@Override
public Node leaveBIT_XOR(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger();
+ assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- binaryNode.setRHS(discard(binaryNode.rhs()));
- // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
+ final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs()));
+ // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(binaryNode, binaryNode.lhs().getType());
- return binaryNode;
+ propagateType(newBinaryNode, newBinaryNode.lhs().getType());
+ return newBinaryNode;
}
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- binaryNode.setLHS(discard(binaryNode.lhs()));
+ final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
// AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(binaryNode, binaryNode.rhs().getType());
- return binaryNode;
+ propagateType(newBinaryNode, newBinaryNode.rhs().getType());
+ return newBinaryNode;
}
@Override
@@ -344,7 +344,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveSHR(final BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong();
+ assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol();
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@@ -354,13 +354,20 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
+ lexicalContext.push(block);
updateSymbols(block);
return block;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveBlock(Block block) {
+ lexicalContext.pop(block);
+ return super.leaveBlock(block);
+ }
+
+ @Override
+ public Node leaveCatchNode(final CatchNode catchNode) {
final Node exceptionCondition = catchNode.getExceptionCondition();
if (exceptionCondition != null) {
catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
@@ -369,23 +376,23 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
- return leave((WhileNode)doWhileNode);
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
+ return leaveWhileNode(doWhileNode);
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
executeNode.setExpression(discard(executeNode.getExpression()));
return executeNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
final Node init = forNode.getInit();
final Node test = forNode.getTest();
final Node modify = forNode.getModify();
@@ -413,11 +420,12 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return null;
}
+ lexicalContext.push(functionNode);
// If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
// this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
// need for the callee.
@@ -432,18 +440,26 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
updateSymbols(functionNode);
+ functionNode.setState(CompilationState.FINALIZED);
+
return functionNode;
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveFunctionNode(FunctionNode functionNode) {
+ lexicalContext.pop(functionNode);
+ return super.leaveFunctionNode(functionNode);
+ }
+
+ @Override
+ public Node leaveIfNode(final IfNode ifNode) {
ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
return ifNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
if (literalNode instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] array = arrayLiteralNode.getValue();
@@ -461,7 +477,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
if (expr != null) {
returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType()));
@@ -470,7 +486,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
final List<Node> args = runtimeNode.getArgs();
for (final Node arg : args) {
assert !arg.getType().isUnknown();
@@ -479,7 +495,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
final Node expression = switchNode.getExpression();
final List<CaseNode> cases = switchNode.getCases();
final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
@@ -498,34 +514,34 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
- ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
- return ternaryNode;
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
+ return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
return throwNode;
}
@Override
- public Node leave(final VarNode varNode) {
-
+ public Node leaveVarNode(final VarNode varNode) {
final Node rhs = varNode.getInit();
if (rhs != null) {
- Type destType = specialize(varNode);
+ final SpecializedNode specialized = specialize(varNode);
+ final VarNode specVarNode = (VarNode)specialized.node;
+ Type destType = specialized.type;
if (destType == null) {
- destType = varNode.getType();
+ destType = specVarNode.getType();
}
- assert varNode.hasType() : varNode + " doesn't have a type";
- varNode.setInit(convert(rhs, destType));
+ assert specVarNode.hasType() : specVarNode + " doesn't have a type";
+ return specVarNode.setInit(convert(rhs, destType));
}
return varNode;
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
if (test != null) {
whileNode.setTest(convert(test, Type.BOOLEAN));
@@ -534,7 +550,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
return withNode;
}
@@ -553,14 +569,14 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* that scope and slot information is correct for every symbol
* @param block block for which to to finalize type info.
*/
- private static void updateSymbols(final Block block) {
+ private void updateSymbols(final Block block) {
if (!block.needsScope()) {
return; // nothing to do
}
- assert !(block instanceof FunctionNode) || block.getFunction() == block;
+ final FunctionNode functionNode = lexicalContext.getFunction(block);
+ assert !(block instanceof FunctionNode) || functionNode == block;
- final FunctionNode functionNode = block.getFunction();
final List<Symbol> symbols = block.getFrame().getSymbols();
final boolean allVarsInScope = functionNode.allVarsInScope();
final boolean isVarArg = functionNode.isVarArg();
@@ -629,10 +645,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
break;
}
- binaryNode.setLHS(convert(lhs, widest));
- binaryNode.setRHS(convert(rhs, widest));
-
- return binaryNode;
+ return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest));
}
/**
@@ -654,9 +667,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
- binaryNode.setLHS(convert(binaryNode.lhs(), lhsType));
- binaryNode.setRHS(convert(binaryNode.rhs(), rhsType));
- return binaryNode;
+ return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
}
/**
@@ -677,7 +688,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
if (!exclude.contains(identNode)) {
setCanBePrimitive(identNode.getSymbol());
}
@@ -685,26 +696,36 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
setCanBePrimitive(accessNode.getProperty().getSymbol());
return null;
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
return indexNode;
}
});
}
- private static Type specialize(final Assignment<?> assignment) {
+ private static class SpecializedNode {
+ final Node node;
+ final Type type;
+
+ SpecializedNode(Node node, Type type) {
+ this.node = node;
+ this.type = type;
+ }
+ }
+
+ private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
final Node node = ((Node)assignment);
- final Node lhs = assignment.getAssignmentDest();
+ final T lhs = assignment.getAssignmentDest();
final Node rhs = assignment.getAssignmentSource();
if (!canHaveCallSiteType(lhs)) {
- return null;
+ return new SpecializedNode(node, null);
}
final Type to;
@@ -716,13 +737,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
if (!isSupportedCallSiteType(to)) {
//meaningless to specialize to boolean or object
- return null;
+ return new SpecializedNode(node, null);
}
- setTypeOverride(lhs, to);
- propagateType(node, to);
+ final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
+ propagateType(newNode, to);
- return to;
+ return new SpecializedNode(newNode, to);
}
@@ -734,7 +755,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @return true if node can have a callsite type
*/
private static boolean canHaveCallSiteType(final Node node) {
- return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
+ return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType();
}
/**
@@ -760,7 +781,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @param node node for which to change type
* @param to new type
*/
- private static void setTypeOverride(final Node node, final Type to) {
+ @SuppressWarnings("unchecked")
+ private static <T extends Node> T setTypeOverride(final T node, final Type to) {
final Type from = node.getType();
if (!node.getType().equals(to)) {
LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to);
@@ -769,7 +791,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
LOG.info("Type override for lhs in '" + node + "' => " + to);
- ((TypeOverride)node).setType(to);
+ return ((TypeOverride<T>)node).setType(to);
}
/**
@@ -814,8 +836,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
} else {
if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
- setTypeOverride(node, to);
- return resultNode;
+ assert node instanceof TypeOverride;
+ return setTypeOverride(node, to);
}
resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
}
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 4ea53a04..fbc62644 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -30,6 +30,8 @@ import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
@@ -52,7 +54,7 @@ final class FoldConstants extends NodeVisitor {
}
@Override
- public Node leave(final UnaryNode unaryNode) {
+ public Node leaveUnaryNode(final UnaryNode unaryNode) {
final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
if (literalNode != null) {
LOG.info("Unary constant folded " + unaryNode + " to " + literalNode);
@@ -62,7 +64,7 @@ final class FoldConstants extends NodeVisitor {
}
@Override
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
if (literalNode != null) {
LOG.info("Binary constant folded " + binaryNode + " to " + literalNode);
@@ -72,7 +74,21 @@ final class FoldConstants extends NodeVisitor {
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
+ if (functionNode.isLazy()) {
+ return null;
+ }
+ return functionNode;
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ functionNode.setState(CompilationState.CONSTANT_FOLDED);
+ return functionNode;
+ }
+
+ @Override
+ public Node leaveIfNode(final IfNode ifNode) {
final Node test = ifNode.getTest();
if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
@@ -85,7 +101,7 @@ final class FoldConstants extends NodeVisitor {
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node test = ternaryNode.lhs();
if (test instanceof LiteralNode) {
return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
diff --git a/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/src/jdk/nashorn/internal/codegen/FunctionSignature.java
index ded12b0c..057d2d4e 100644
--- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java
+++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java
@@ -146,7 +146,7 @@ public final class FunctionSignature {
/**
* Create a function signature given a function node, using as much
- * type information for parameters and return types that is availabe
+ * type information for parameters and return types that is available
*
* @param functionNode the function node
*/
@@ -155,7 +155,7 @@ public final class FunctionSignature {
true,
functionNode.needsCallee(),
functionNode.getReturnType(),
- (functionNode.isVarArg() && !functionNode.isScript()) ?
+ (functionNode.isVarArg() && !functionNode.isProgram()) ?
null :
functionNode.getParameters());
}
@@ -202,6 +202,14 @@ public final class FunctionSignature {
return methodType;
}
+ /**
+ * Return the return type for this function signature
+ * @return the return type
+ */
+ public Type getReturnType() {
+ return returnType;
+ }
+
private static Type[] objectArgs(final int nArgs) {
final Type[] array = new Type[nArgs];
for (int i = 0; i < nArgs; i++) {
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 7a83469b..715ddc6f 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -37,8 +37,8 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
+import java.util.Iterator;
import java.util.List;
-import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
@@ -52,11 +52,12 @@ import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LabeledNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
@@ -102,6 +103,8 @@ final class Lower extends NodeOperatorVisitor {
private List<Node> statements;
+ private LexicalContext lexicalContext = new LexicalContext();
+
/**
* Constructor.
*
@@ -113,14 +116,15 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
final Node savedLastStatement = lastStatement;
final List<Node> savedStatements = statements;
-
+ lexicalContext.push(block);
try {
this.statements = new ArrayList<>();
+ NodeVisitor visitor = this;
for (final Node statement : block.getStatements()) {
- statement.accept(this);
+ statement.accept(visitor);
/*
* This is slightly unsound, for example if we have a loop with
* a guarded statement like if (x) continue in the body and the
@@ -132,7 +136,7 @@ final class Lower extends NodeOperatorVisitor {
*/
if (lastStatement != null && lastStatement.isTerminal()) {
copyTerminal(block, lastStatement);
- break;
+ visitor = new DeadCodeVarDeclarationVisitor();
}
}
block.setStatements(statements);
@@ -140,18 +144,19 @@ final class Lower extends NodeOperatorVisitor {
} finally {
this.statements = savedStatements;
this.lastStatement = savedLastStatement;
+ lexicalContext.pop(block);
}
return null;
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
return enterBreakOrContinue(breakNode);
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
final Node function = markerFunction(callNode.getFunction());
callNode.setFunction(function);
checkEval(callNode); //check if this is an eval call and store the information
@@ -159,44 +164,44 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final CaseNode caseNode) {
+ public Node leaveCaseNode(final CaseNode caseNode) {
caseNode.copyTerminalFlags(caseNode.getBody());
return caseNode;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
catchNode.copyTerminalFlags(catchNode.getBody());
addStatement(catchNode);
return catchNode;
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
return enterBreakOrContinue(continueNode);
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
- return leave((WhileNode)doWhileNode);
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
+ return leaveWhileNode(doWhileNode);
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return null;
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
final Node expr = executeNode.getExpression();
- if (getCurrentFunctionNode().isScript()) {
- if (!(expr instanceof Block)) {
+ if (getCurrentFunctionNode().isProgram()) {
+ if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN),
getCurrentFunctionNode().getResultNode(),
@@ -212,13 +217,13 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
nest(forNode);
return forNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
final Node test = forNode.getTest();
final Block body = forNode.getBody();
@@ -236,6 +241,7 @@ final class Lower extends NodeOperatorVisitor {
if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
forNode.setTest(null);
+ setHasGoto(forNode);
setTerminal(forNode, !escapes);
}
@@ -245,18 +251,16 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
LOG.info("START FunctionNode: " + functionNode.getName());
if (functionNode.isLazy()) {
LOG.info("LAZY: " + functionNode.getName());
return null;
}
-
+ lexicalContext.push(functionNode);
initFunctionNode(functionNode);
- Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
-
nest(functionNode);
/*
@@ -270,60 +274,40 @@ final class Lower extends NodeOperatorVisitor {
statements = new ArrayList<>();
lastStatement = null;
- // for initial eval result is the last declared function
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final IdentNode ident = nestedFunction.getIdent();
- if (ident != null && nestedFunction.isStatement()) {
- initialEvalResult = new IdentNode(ident);
- }
- }
-
if (functionNode.needsSelfSymbol()) {
//function needs to start with var funcIdent = __callee_;
statements.add(functionNode.getSelfSymbolInit().accept(this));
}
+ NodeVisitor visitor = this;
try {
- // Every nested function needs a definition in the outer function with its name. Add these.
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final VarNode varNode = nestedFunction.getFunctionVarNode();
- if (varNode != null) {
- final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode();
- if (lineNumberNode != null) {
- lineNumberNode.accept(this);
- }
- varNode.accept(this);
- varNode.setIsFunctionVarNode();
- }
- }
-
- if (functionNode.isScript()) {
- new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
- }
-
//do the statements - this fills the block with code
+ boolean needsInitialEvalResult = functionNode.isProgram();
for (final Node statement : functionNode.getStatements()) {
- statement.accept(this);
+ // If this function is a program, then insert an assignment to the initial eval result after all
+ // function declarations.
+ if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) {
+ addInitialEvalResult(functionNode);
+ needsInitialEvalResult = false;
+ }
+ statement.accept(visitor);
//If there are unused terminated endpoints in the function, we need
// to add a "return undefined" in those places for correct semantics
LOG.info("Checking lastStatement="+lastStatement+" for terminal flags");
if (lastStatement != null && lastStatement.hasTerminalFlags()) {
copyTerminal(functionNode, lastStatement);
- break;
+ assert !needsInitialEvalResult;
+ visitor = new DeadCodeVarDeclarationVisitor();
}
}
-
+ if(needsInitialEvalResult) {
+ addInitialEvalResult(functionNode);
+ }
functionNode.setStatements(statements);
if (!functionNode.isTerminal()) {
guaranteeReturn(functionNode);
}
-
- //lower all nested functions
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- nestedFunction.accept(this);
- }
-
} finally {
statements = savedStatements;
lastStatement = savedLastStatement;
@@ -331,17 +315,67 @@ final class Lower extends NodeOperatorVisitor {
LOG.info("END FunctionNode: " + functionNode.getName());
unnest(functionNode);
+ lexicalContext.pop(functionNode);
+
+ functionNode.setState(CompilationState.LOWERED);
return null;
}
+ /**
+ * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the
+ * var declarations in them still have the effect of declaring a local variable on the function level. Therefore,
+ * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their
+ * initializers are wiped out as those are, in fact, dead code.
+ */
+ private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor {
+ DeadCodeVarDeclarationVisitor() {
+ }
+
+ @Override
+ public Node enterVarNode(VarNode varNode) {
+ // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was
+ // encountered, and all function declarations precede any terminal statements.
+ assert !varNode.isFunctionDeclaration();
+ if(varNode.getInit() == null) {
+ // No initializer, just pass it to Lower.
+ return varNode.accept(Lower.this);
+ }
+ // Wipe out the initializer and then pass it to Lower.
+ return varNode.setInit(null).accept(Lower.this);
+ }
+ }
+
+ private void addInitialEvalResult(final FunctionNode functionNode) {
+ new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(),
+ getInitialEvalResult(functionNode)).accept(this);
+ }
+
+ /**
+ * Result of initial result of evaluating a particular program, which is either the last function it declares, or
+ * undefined if it doesn't declare any functions.
+ * @param program
+ * @return the initial result of evaluating the program
+ */
+ private static Node getInitialEvalResult(final FunctionNode program) {
+ IdentNode lastFnName = null;
+ for (final FunctionNode fn : program.getDeclaredFunctions()) {
+ assert fn.isDeclared();
+ final IdentNode fnName = fn.getIdent();
+ if(fnName != null) {
+ lastFnName = fnName;
+ }
+ }
+ return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED);
+ }
+
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
return nest(ifNode);
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
final Node pass = ifNode.getPass();
final Node fail = ifNode.getFail();
@@ -356,7 +390,7 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node enter(LabelNode labelNode) {
+ public Node enterLabelNode(LabelNode labelNode) {
final Block body = labelNode.getBody();
body.accept(this);
copyTerminal(labelNode, body);
@@ -365,13 +399,13 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
addStatement(lineNumberNode, false); // don't put it in lastStatement cache
return null;
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
final TryNode tryNode = returnNode.getTryChain();
final Node expr = returnNode.getExpression();
@@ -409,19 +443,19 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
return returnNode;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
nest(switchNode);
return switchNode;
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
unnest(switchNode);
final List<CaseNode> cases = switchNode.getCases();
@@ -442,13 +476,13 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor
return throwNode;
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
final Block finallyBody = tryNode.getFinallyBody();
final long token = tryNode.getToken();
final int finish = tryNode.getFinish();
@@ -534,26 +568,19 @@ final class Lower extends NodeOperatorVisitor {
// set outer tryNode's body to innerTryNode
final Block outerBody;
- outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode());
+ outerBody = new Block(source, token, finish);
outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
tryNode.setBody(outerBody);
tryNode.setCatchBlocks(null);
-
- // now before we go on, we have to fix the block parents
- // (we repair the block tree after the insertion so that all references are intact)
- innerTryNode.getBody().setParent(tryNode.getBody());
- for (final Block block : innerTryNode.getCatchBlocks()) {
- block.setParent(tryNode.getBody());
- }
}
// create a catch-all that inlines finally and rethrows
- final Block catchBlock = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode());
+ final Block catchBlock = new Block(source, token, finish);
//this catch block should get define symbol
- final Block catchBody = new Block(source, token, finish, catchBlock, getCurrentFunctionNode());
- final Node catchAllFinally = finallyBody.clone();
+ final Block catchBody = new Block(source, token, finish);
+ final Node catchAllFinally = finallyBody.copy();
catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
setTerminal(catchBody, true);
@@ -580,7 +607,7 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
final Block finallyBody = tryNode.getFinallyBody();
boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
@@ -604,18 +631,18 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
return varNode;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
return nest(whileNode);
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
if (test == null) {
@@ -636,7 +663,7 @@ final class Lower extends NodeOperatorVisitor {
} else if (conservativeAlwaysTrue(test)) {
node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish());
((ForNode)node).setBody(body);
- ((ForNode)node).accept(this);
+ node.accept(this);
setTerminal(node, !escapes);
}
}
@@ -649,7 +676,7 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
if (withNode.getBody().isTerminal()) {
setTerminal(withNode, true);
}
@@ -678,28 +705,10 @@ final class Lower extends NodeOperatorVisitor {
*/
private static Node markerFunction(final Node function) {
if (function instanceof IdentNode) {
- return new IdentNode((IdentNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
- } else if (function instanceof AccessNode) {
- return new AccessNode((AccessNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
- } else if (function instanceof IndexNode) {
- return new IndexNode((IndexNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
+ return ((IdentNode)function).setIsFunction();
+ } else if (function instanceof BaseNode) {
+ return ((BaseNode)function).setIsFunction();
}
-
return function;
}
@@ -742,7 +751,7 @@ final class Lower extends NodeOperatorVisitor {
if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
final CallNode.EvalArgs evalArgs =
new CallNode.EvalArgs(
- args.get(0).clone().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
+ args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
getCurrentFunctionNode().getThisNode(),
evalLocation(callee),
getCurrentFunctionNode().isStrictMode());
@@ -769,13 +778,13 @@ final class Lower extends NodeOperatorVisitor {
loopBody.accept(new NodeVisitor() {
@Override
- public Node leave(final BreakNode node) {
+ public Node leaveBreakNode(final BreakNode node) {
escapes.add(node);
return node;
}
@Override
- public Node leave(final ContinueNode node) {
+ public Node leaveContinueNode(final ContinueNode node) {
// all inner loops have been popped.
if (nesting.contains(node.getTargetNode())) {
escapes.add(node);
@@ -790,7 +799,7 @@ final class Lower extends NodeOperatorVisitor {
private void guaranteeReturn(final FunctionNode functionNode) {
Node resultNode;
- if (functionNode.isScript()) {
+ if (functionNode.isProgram()) {
resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
} else {
if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
@@ -855,18 +864,15 @@ final class Lower extends NodeOperatorVisitor {
* @return true if try block is inside the target, false otherwise.
*/
private boolean isNestedTry(final TryNode tryNode, final Block target) {
- for (Block current = getCurrentBlock(); current != target; current = current.getParent()) {
- if (tryNode.getBody() == current) {
- return true;
+ for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) {
+ final Block block = blocks.next();
+ if(block == target) {
+ return false;
}
-
- for (final Block catchBlock : tryNode.getCatchBlocks()) {
- if (catchBlock == current) {
- return true;
- }
+ if(tryNode.isChildBlock(block)) {
+ return true;
}
}
-
return false;
}
@@ -895,7 +901,7 @@ final class Lower extends NodeOperatorVisitor {
continue;
}
- finallyBody = (Block)finallyBody.clone();
+ finallyBody = (Block)finallyBody.copy();
final boolean hasTerminalFlags = finallyBody.hasTerminalFlags();
new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this);
@@ -970,6 +976,3 @@ final class Lower extends NodeOperatorVisitor {
}
}
-
-
-
diff --git a/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index 4cd0f524..ae40ed33 100644
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -651,11 +651,10 @@ public class MethodEmitter implements Emitter {
/**
* Load the constants array
- * @param unitClassName name of the compile unit from which to load constants
* @return this method emitter
*/
- MethodEmitter loadConstants(final String unitClassName) {
- getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor());
+ MethodEmitter loadConstants() {
+ getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor());
assert peekType().isArray() : peekType();
return this;
}
diff --git a/src/jdk/nashorn/internal/codegen/Splitter.java b/src/jdk/nashorn/internal/codegen/Splitter.java
index b92f2383..f9a84f91 100644
--- a/src/jdk/nashorn/internal/codegen/Splitter.java
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java
@@ -39,7 +39,9 @@ import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.DoWhileNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
@@ -48,6 +50,7 @@ import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.WhileNode;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.Source;
@@ -69,6 +72,8 @@ final class Splitter extends NodeVisitor {
/** Cache for calculated block weights. */
private final Map<Node, Long> weightCache = new HashMap<>();
+ private final LexicalContext lexicalContext = new LexicalContext();
+
/** Weight threshold for when to start a split. */
public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
@@ -92,15 +97,16 @@ final class Splitter extends NodeVisitor {
*/
void split() {
if (functionNode.isLazy()) {
- LOG.fine("Postponing split of '" + functionNode.getName() + "' as it's lazy");
+ LOG.finest("Postponing split of '" + functionNode.getName() + "' as it's lazy");
return;
}
- LOG.fine("Initiating split of '" + functionNode.getName() + "'");
+
+ LOG.finest("Initiating split of '" + functionNode.getName() + "'");
long weight = WeighNodes.weigh(functionNode);
if (weight >= SPLIT_THRESHOLD) {
- LOG.fine("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD);
+ LOG.finest("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD);
functionNode.accept(this);
@@ -110,7 +116,7 @@ final class Splitter extends NodeVisitor {
}
if (weight >= SPLIT_THRESHOLD) {
- weight = splitBlock(functionNode);
+ weight = splitBlock(functionNode, functionNode);
}
if (functionNode.isSplit()) {
@@ -130,9 +136,22 @@ final class Splitter extends NodeVisitor {
}
// Recursively split nested functions
- for (final FunctionNode function : functionNode.getFunctions()) {
- new Splitter(compiler, function, outermostCompileUnit).split();
- }
+ functionNode.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode function) {
+ if(function == functionNode) {
+ // Don't process outermost function (it was already processed) but descend into it to find nested
+ // functions.
+ return function;
+ }
+ // Process a nested function
+ new Splitter(compiler, function, outermostCompileUnit).split();
+ // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions.
+ return null;
+ }
+ });
+
+ functionNode.setState(CompilationState.SPLIT);
}
/**
@@ -151,7 +170,7 @@ final class Splitter extends NodeVisitor {
*
* @return new weight for the resulting block.
*/
- private long splitBlock(final Block block) {
+ private long splitBlock(final Block block, final FunctionNode function) {
functionNode.setIsSplit();
final List<Node> splits = new ArrayList<>();
@@ -163,7 +182,7 @@ final class Splitter extends NodeVisitor {
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
if (!statements.isEmpty()) {
- splits.add(createBlockSplitNode(block, statements, statementsWeight));
+ splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
statements = new ArrayList<>();
statementsWeight = 0;
}
@@ -179,7 +198,7 @@ final class Splitter extends NodeVisitor {
}
if (!statements.isEmpty()) {
- splits.add(createBlockSplitNode(block, statements, statementsWeight));
+ splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
}
block.setStatements(splits);
@@ -195,13 +214,13 @@ final class Splitter extends NodeVisitor {
*
* @return New split node.
*/
- private SplitNode createBlockSplitNode(final Block parent, final List<Node> statements, final long weight) {
+ private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
final Source source = parent.getSource();
final long token = parent.getToken();
final int finish = parent.getFinish();
- final String name = parent.getFunction().uniqueName(SPLIT_PREFIX.tag());
+ final String name = function.uniqueName(SPLIT_PREFIX.tag());
- final Block newBlock = new Block(source, token, finish, parent, functionNode);
+ final Block newBlock = new Block(source, token, finish);
newBlock.setFrame(new Frame(parent.getFrame()));
newBlock.setStatements(statements);
@@ -213,15 +232,17 @@ final class Splitter extends NodeVisitor {
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (block.isCatchBlock()) {
return null;
}
+ lexicalContext.push(block);
final long weight = WeighNodes.weigh(block, weightCache);
if (weight < SPLIT_THRESHOLD) {
weightCache.put(block, weight);
+ lexicalContext.pop(block);
return null;
}
@@ -229,23 +250,24 @@ final class Splitter extends NodeVisitor {
}
@Override
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
assert !block.isCatchBlock();
// Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
// been split already, so weigh again before splitting.
long weight = WeighNodes.weigh(block, weightCache);
if (weight >= SPLIT_THRESHOLD) {
- weight = splitBlock(block);
+ weight = splitBlock(block, lexicalContext.getFunction(block));
}
weightCache.put(block, weight);
+ lexicalContext.pop(block);
return block;
}
@SuppressWarnings("rawtypes")
@Override
- public Node leave(final LiteralNode literal) {
+ public Node leaveLiteralNode(final LiteralNode literal) {
long weight = WeighNodes.weigh(literal);
if (weight < SPLIT_THRESHOLD) {
@@ -290,17 +312,12 @@ final class Splitter extends NodeVisitor {
}
@Override
- public Node enter(final FunctionNode node) {
- if (node.isLazy()) {
- return null;
+ public Node enterFunctionNode(final FunctionNode node) {
+ if(node == functionNode && !node.isLazy()) {
+ lexicalContext.push(node);
+ node.visitStatements(this);
+ lexicalContext.pop(node);
}
-
- final List<Node> statements = node.getStatements();
-
- for (final Node statement : statements) {
- statement.accept(this);
- }
-
return null;
}
@@ -317,38 +334,38 @@ final class Splitter extends NodeVisitor {
}
@Override
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
registerJumpTarget(labelNode.getBreakNode());
registerJumpTarget(labelNode.getContinueNode());
return labelNode;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
registerJumpTarget(whileNode);
return whileNode;
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
registerJumpTarget(doWhileNode);
return doWhileNode;
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
registerJumpTarget(forNode);
return forNode;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
registerJumpTarget(switchNode);
return switchNode;
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
for (final SplitNode split : splitStack) {
split.setHasReturn(true);
}
@@ -356,25 +373,25 @@ final class Splitter extends NodeVisitor {
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel());
return continueNode;
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel());
return breakNode;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
splitStack.addFirst(splitNode);
return splitNode;
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
assert splitNode == splitStack.peekFirst();
splitStack.removeFirst();
return splitNode;
diff --git a/src/jdk/nashorn/internal/codegen/WeighNodes.java b/src/jdk/nashorn/internal/codegen/WeighNodes.java
index 9f2e8be4..18bd9552 100644
--- a/src/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -47,7 +47,6 @@ import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -80,7 +79,7 @@ final class WeighNodes extends NodeOperatorVisitor {
private static final long LITERAL_WEIGHT = 10;
private static final long LOOP_WEIGHT = 4;
private static final long NEW_WEIGHT = 6;
- private static final long REFERENCE_WEIGHT = 20;
+ private static final long FUNC_EXPR_WEIGHT = 20;
private static final long RETURN_WEIGHT = 2;
private static final long SPLIT_WEIGHT = 40;
private static final long SWITCH_WEIGHT = 8;
@@ -94,36 +93,37 @@ final class WeighNodes extends NodeOperatorVisitor {
/** Optional cache for weight of block nodes. */
private final Map<Node, Long> weightCache;
- /*
+ private final FunctionNode topFunction;
+
+ /**
* Constructor
*
* @param weightCache cache of already calculated block weights
*/
- private WeighNodes(final Map<Node, Long> weightCache) {
+ private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) {
super(null, null);
+ this.topFunction = topFunction;
this.weightCache = weightCache;
}
static long weigh(final Node node) {
- final WeighNodes weighNodes = new WeighNodes(null);
- node.accept(weighNodes);
- return weighNodes.weight;
+ return weigh(node, null);
}
static long weigh(final Node node, final Map<Node, Long> weightCache) {
- final WeighNodes weighNodes = new WeighNodes(weightCache);
+ final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
node.accept(weighNodes);
return weighNodes.weight;
}
@Override
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
weight += ACCESS_WEIGHT;
return accessNode;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (weightCache != null && weightCache.containsKey(block)) {
weight += weightCache.get(block);
return null;
@@ -133,78 +133,79 @@ final class WeighNodes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final BreakNode breakNode) {
+ public Node leaveBreakNode(final BreakNode breakNode) {
weight += BREAK_WEIGHT;
return breakNode;
}
@Override
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
weight += CALL_WEIGHT;
return callNode;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
weight += CATCH_WEIGHT;
return catchNode;
}
@Override
- public Node leave(final ContinueNode continueNode) {
+ public Node leaveContinueNode(final ContinueNode continueNode) {
weight += CONTINUE_WEIGHT;
return continueNode;
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
weight += LOOP_WEIGHT;
return doWhileNode;
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
return executeNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
weight += LOOP_WEIGHT;
return forNode;
}
@Override
- public Node enter(final FunctionNode functionNode) {
- final List<Node> statements = functionNode.getStatements();
-
- for (final Node statement : statements) {
- statement.accept(this);
+ public Node enterFunctionNode(final FunctionNode functionNode) {
+ if(functionNode == topFunction) {
+ // the function being weighted; descend into its statements
+ functionNode.visitStatements(this);
+ } else {
+ // just a reference to inner function from outer function
+ weight += FUNC_EXPR_WEIGHT;
}
-
return null;
}
@Override
- public Node leave(final IdentNode identNode) {
+ public Node leaveIdentNode(final IdentNode identNode) {
weight += ACCESS_WEIGHT + identNode.getName().length() * 2;
return identNode;
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
weight += IF_WEIGHT;
return ifNode;
}
@Override
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
weight += ACCESS_WEIGHT;
return indexNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
weight += LITERAL_WEIGHT;
if (literalNode instanceof ArrayLiteralNode) {
@@ -230,67 +231,61 @@ final class WeighNodes extends NodeOperatorVisitor {
}
@Override
- public Node leave(final PropertyNode propertyNode) {
+ public Node leavePropertyNode(final PropertyNode propertyNode) {
weight += LITERAL_WEIGHT;
return propertyNode;
}
@Override
- public Node leave(final ReferenceNode referenceNode) {
- weight += REFERENCE_WEIGHT;
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
weight += RETURN_WEIGHT;
return returnNode;
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
weight += CALL_WEIGHT;
return runtimeNode;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
weight += SPLIT_WEIGHT;
return null;
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
weight += SWITCH_WEIGHT;
return switchNode;
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
weight += THROW_WEIGHT;
return throwNode;
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
weight += THROW_WEIGHT;
return tryNode;
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
weight += VAR_WEIGHT;
return varNode;
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
weight += LOOP_WEIGHT;
return whileNode;
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
weight += WITH_WEIGHT;
return withNode;
}
diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index d36dd20d..77558835 100644
--- a/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -647,21 +647,20 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
private static void swap(final MethodVisitor method, final Type above, final Type below) {
- final MethodVisitor mv = method;
if (below.isCategory2()) {
if (above.isCategory2()) {
- mv.visitInsn(DUP2_X2);
- mv.visitInsn(POP2);
+ method.visitInsn(DUP2_X2);
+ method.visitInsn(POP2);
} else {
- mv.visitInsn(DUP_X2);
- mv.visitInsn(POP);
+ method.visitInsn(DUP_X2);
+ method.visitInsn(POP);
}
} else {
if (above.isCategory2()) {
- mv.visitInsn(DUP2_X1);
- mv.visitInsn(POP2);
+ method.visitInsn(DUP2_X1);
+ method.visitInsn(POP2);
} else {
- mv.visitInsn(SWAP);
+ method.visitInsn(SWAP);
}
}
diff --git a/src/jdk/nashorn/internal/ir/AccessNode.java b/src/jdk/nashorn/internal/ir/AccessNode.java
index 481e3855..b7b76684 100644
--- a/src/jdk/nashorn/internal/ir/AccessNode.java
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java
@@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation of a property access (period operator.)
*
*/
-public class AccessNode extends BaseNode implements TypeOverride {
+public class AccessNode extends BaseNode implements TypeOverride<AccessNode> {
/** Property ident. */
private IdentNode property;
@@ -56,9 +56,7 @@ public class AccessNode extends BaseNode implements TypeOverride {
super(source, token, finish, base);
this.start = base.getStart();
- this.property = property;
-
- this.property.setIsPropertyName();
+ this.property = property.setIsPropertyName();
}
/**
@@ -106,10 +104,10 @@ public class AccessNode extends BaseNode implements TypeOverride {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterAccessNode(this) != null) {
base = base.accept(visitor);
property = (IdentNode)property.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveAccessNode(this);
}
return this;
@@ -150,13 +148,14 @@ public class AccessNode extends BaseNode implements TypeOverride {
}
@Override
- public void setType(final Type type) {
+ public AccessNode setType(final Type type) {
if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
- property.setType(type);
+ property = property.setType(type);
getSymbol().setTypeOverride(type); //always a temp so this is fine.
hasCallSiteType = true;
+ return this;
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/Assignment.java b/src/jdk/nashorn/internal/ir/Assignment.java
index 8107a872..0c531bc2 100644
--- a/src/jdk/nashorn/internal/ir/Assignment.java
+++ b/src/jdk/nashorn/internal/ir/Assignment.java
@@ -46,4 +46,11 @@ public interface Assignment<D extends Node> {
* @return get the assignment source node
*/
public Node getAssignmentSource();
+
+ /**
+ * Set assignment destination node.
+ * @param n the assignment destination node.
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public Node setAssignmentDest(D n);
}
diff --git a/src/jdk/nashorn/internal/ir/BaseNode.java b/src/jdk/nashorn/internal/ir/BaseNode.java
index ea632d1b..26a28368 100644
--- a/src/jdk/nashorn/internal/ir/BaseNode.java
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java
@@ -38,6 +38,8 @@ public abstract class BaseNode extends Node implements FunctionCall {
/** Base Node. */
protected Node base;
+ private boolean function;
+
/**
* Constructor
*
@@ -96,6 +98,15 @@ public abstract class BaseNode extends Node implements FunctionCall {
@Override
public boolean isFunction() {
- return false;
+ return function;
+ }
+
+ /**
+ * Mark this node as being the callee operand of a {@link CallNode}.
+ * @return a base node identical to this one in all aspects except with its function flag set.
+ */
+ public BaseNode setIsFunction() {
+ function = true;
+ return this;
}
}
diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java
index 26964ba5..42c7a6cc 100644
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java
@@ -35,7 +35,7 @@ import jdk.nashorn.internal.runtime.Source;
*/
public class BinaryNode extends UnaryNode {
/** Left hand side argument. */
- protected Node lhs;
+ private Node lhs;
/**
* Constructor
@@ -140,6 +140,11 @@ public class BinaryNode extends UnaryNode {
}
@Override
+ public Node setAssignmentDest(Node n) {
+ return setLHS(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return rhs();
}
@@ -163,10 +168,9 @@ public class BinaryNode extends UnaryNode {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- lhs = lhs.accept(visitor);
- rhs = rhs.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterBinaryNode(this) != null) {
+ // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers
+ return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor)));
}
return this;
@@ -229,8 +233,12 @@ public class BinaryNode extends UnaryNode {
/**
* Set the left hand side expression for this node
* @param lhs new left hand side expression
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setLHS(final Node lhs) {
- this.lhs = lhs;
+ public BinaryNode setLHS(final Node lhs) {
+ if(this.lhs == lhs) return this;
+ final BinaryNode n = (BinaryNode)clone();
+ n.lhs = lhs;
+ return n;
}
}
diff --git a/src/jdk/nashorn/internal/ir/Block.java b/src/jdk/nashorn/internal/ir/Block.java
index 9449be5b..6f138f85 100644
--- a/src/jdk/nashorn/internal/ir/Block.java
+++ b/src/jdk/nashorn/internal/ir/Block.java
@@ -25,41 +25,24 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
-import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
-import static jdk.nashorn.internal.ir.Symbol.IS_LET;
-import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
-import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
-import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
-import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import jdk.nashorn.internal.codegen.Frame;
import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.ir.annotations.Ignore;
-import jdk.nashorn.internal.ir.annotations.ParentNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a list of statements and functions. All provides the
* basis for script body.
- *
*/
public class Block extends Node {
- /** Parent context */
- @ParentNode @Ignore
- private Block parent;
-
- /** Owning function. */
- @Ignore //don't print it, it is apparent in the tree
- protected FunctionNode function;
-
/** List of statements */
protected List<Node> statements;
@@ -84,14 +67,10 @@ public class Block extends Node {
* @param source source code
* @param token token
* @param finish finish
- * @param parent reference to parent block
- * @param function function node this block is in
*/
- public Block(final Source source, final long token, final int finish, final Block parent, final FunctionNode function) {
+ public Block(final Source source, final long token, final int finish) {
super(source, token, finish);
- this.parent = parent;
- this.function = function;
this.statements = new ArrayList<>();
this.symbols = new HashMap<>();
this.entryLabel = new Label("block_entry");
@@ -107,8 +86,6 @@ public class Block extends Node {
protected Block(final Block block, final CopyState cs) {
super(block);
- this.parent = block.parent;
- this.function = block.function;
this.statements = new ArrayList<>();
for (final Node statement : block.getStatements()) {
statements.add(cs.existingOrCopy(statement));
@@ -123,55 +100,7 @@ public class Block extends Node {
@Override
protected Node copy(final CopyState cs) {
- return fixBlockChain(new Block(this, cs));
- }
-
- /**
- * Whenever a clone that contains a hierarchy of blocks is created,
- * this function has to be called to ensure that the parents point
- * to the correct parent blocks or two different ASTs would not
- * be completely separated.
- *
- * @return the argument
- */
- static Block fixBlockChain(final Block root) {
- root.accept(new NodeVisitor() {
- private Block parent = root.getParent();
- private final FunctionNode function = root.getFunction();
-
- @Override
- public Node enter(final Block block) {
- assert block.getFunction() == function;
- block.setParent(parent);
- parent = block;
-
- return block;
- }
-
- @Override
- public Node leave(final Block block) {
- parent = block.getParent();
-
- return block;
- }
-
- @Override
- public Node enter(final FunctionNode functionNode) {
- assert functionNode.getFunction() == function;
-
- return enter((Block)functionNode);
- }
-
- @Override
- public Node leave(final FunctionNode functionNode) {
- assert functionNode.getFunction() == function;
-
- return leave((Block)functionNode);
- }
-
- });
-
- return root;
+ return new Block(this, cs);
}
/**
@@ -189,17 +118,12 @@ public class Block extends Node {
}
/**
- * Prepend a statement to the statement list
+ * Prepend statements to the statement list
*
- * @param statement Statement node to add
+ * @param prepended statement to add
*/
- public void prependStatement(final Node statement) {
- if (statement != null) {
- final List<Node> newStatements = new ArrayList<>();
- newStatements.add(statement);
- newStatements.addAll(statements);
- setStatements(newStatements);
- }
+ public void prependStatements(final List<Node> prepended) {
+ statements.addAll(0, prepended);
}
/**
@@ -212,39 +136,6 @@ public class Block extends Node {
}
/**
- * Add a new function to the function list.
- *
- * @param functionNode Function node to add.
- */
- public void addFunction(final FunctionNode functionNode) {
- assert parent != null : "Parent context missing.";
-
- parent.addFunction(functionNode);
- }
-
- /**
- * Add a list of functions to the function list.
- *
- * @param functionNodes Function nodes to add.
- */
- public void addFunctions(final List<FunctionNode> functionNodes) {
- assert parent != null : "Parent context missing.";
-
- parent.addFunctions(functionNodes);
- }
-
- /**
- * Set the function list to a new one
- *
- * @param functionNodes the nodes to set
- */
- public void setFunctions(final List<FunctionNode> functionNodes) {
- assert parent != null : "Parent context missing.";
-
- parent.setFunctions(functionNodes);
- }
-
- /**
* Assist in IR navigation.
*
* @param visitor IR navigating visitor.
@@ -258,13 +149,9 @@ public class Block extends Node {
try {
// Ignore parent to avoid recursion.
- if (visitor.enter(this) != null) {
- for (int i = 0, count = statements.size(); i < count; i++) {
- final Node statement = statements.get(i);
- statements.set(i, statement.accept(visitor));
- }
-
- return visitor.leave(this);
+ if (visitor.enterBlock(this) != null) {
+ visitStatements(visitor);
+ return visitor.leaveBlock(this);
}
} finally {
visitor.setCurrentBlock(saveBlock);
@@ -274,51 +161,21 @@ public class Block extends Node {
}
/**
- * Search for symbol.
- *
- * @param name Symbol name.
- *
- * @return Found symbol or null if not found.
+ * Get an iterator for all the symbols defined in this block
+ * @return symbol iterator
*/
- public Symbol findSymbol(final String name) {
- // Search up block chain to locate symbol.
-
- for (Block block = this; block != null; block = block.getParent()) {
- // Find name.
- final Symbol symbol = block.symbols.get(name);
- // If found then we are good.
- if (symbol != null) {
- return symbol;
- }
- }
- return null;
+ public Iterator<Symbol> symbolIterator() {
+ return symbols.values().iterator();
}
/**
- * Search for symbol in current function.
- *
- * @param name Symbol name.
- *
- * @return Found symbol or null if not found.
+ * Retrieves an existing symbol defined in the current block.
+ * @param name the name of the symbol
+ * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
+ * define a symbol with this name.
*/
- public Symbol findLocalSymbol(final String name) {
- // Search up block chain to locate symbol.
- for (Block block = this; block != null; block = block.getParent()) {
- // Find name.
- final Symbol symbol = block.symbols.get(name);
- // If found then we are good.
- if (symbol != null) {
- return symbol;
- }
-
- // If searched function then we are done.
- if (block == block.function) {
- break;
- }
- }
-
- // Not found.
- return null;
+ public Symbol getExistingSymbol(final String name) {
+ return symbols.get(name);
}
/**
@@ -331,122 +188,6 @@ public class Block extends Node {
return statements.size() == 1 && statements.get(0) instanceof CatchNode;
}
- /**
- * Test to see if a symbol is local to the function.
- *
- * @param symbol Symbol to test.
- * @return True if a local symbol.
- */
- public boolean isLocal(final Symbol symbol) {
- // some temp symbols have no block, so can be assumed local
- final Block block = symbol.getBlock();
- return block == null || block.getFunction() == function;
- }
-
- /**
- * Declare the definition of a new symbol.
- *
- * @param name Name of symbol.
- * @param symbolFlags Symbol flags.
- * @param node Defining Node.
- *
- * @return Symbol for given name or null for redefinition.
- */
- public Symbol defineSymbol(final String name, final int symbolFlags, final Node node) {
- int flags = symbolFlags;
- Symbol symbol = findSymbol(name); // Locate symbol.
-
- if ((flags & KINDMASK) == IS_GLOBAL) {
- flags |= IS_SCOPE;
- }
-
- if (symbol != null) {
- // Symbol was already defined. Check if it needs to be redefined.
- if ((flags & KINDMASK) == IS_PARAM) {
- if (!function.isLocal(symbol)) {
- // Not defined in this function. Create a new definition.
- symbol = null;
- } else if (symbol.isParam()) {
- // Duplicate parameter. Null return will force an error.
- assert false : "duplicate parameter";
- return null;
- }
- } else if ((flags & KINDMASK) == IS_VAR) {
- if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & Symbol.IS_LET) == Symbol.IS_LET) {
- assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == this) : "duplicate let variable in block";
- // Always create a new definition.
- symbol = null;
- } else {
- // Not defined in this function. Create a new definition.
- if (!function.isLocal(symbol) || symbol.less(IS_VAR)) {
- symbol = null;
- }
- }
- }
- }
-
- if (symbol == null) {
- // If not found, then create a new one.
- Block symbolBlock;
-
- // Determine where to create it.
- if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
- symbolBlock = this;
- } else {
- symbolBlock = getFunction();
- }
-
- // Create and add to appropriate block.
- symbol = new Symbol(name, flags, node, symbolBlock);
- symbolBlock.putSymbol(name, symbol);
-
- if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
- symbolBlock.getFrame().addSymbol(symbol);
- symbol.setNeedsSlot(true);
- }
- } else if (symbol.less(flags)) {
- symbol.setFlags(flags);
- }
-
- if (node != null) {
- node.setSymbol(symbol);
- }
-
- return symbol;
- }
-
- /**
- * Declare the use of a symbol.
- *
- * @param name Name of symbol.
- * @param node Using node
- *
- * @return Symbol for given name.
- */
- public Symbol useSymbol(final String name, final Node node) {
- Symbol symbol = findSymbol(name);
-
- if (symbol == null) {
- // If not found, declare as a free var.
- symbol = defineSymbol(name, IS_GLOBAL, node);
- } else {
- node.setSymbol(symbol);
- }
-
- return symbol;
- }
-
- /**
- * Add parent name to the builder.
- *
- * @param sb String bulder.
- */
- public void addParentName(final StringBuilder sb) {
- if (parent != null) {
- parent.addParentName(sb);
- }
- }
-
@Override
public void toString(final StringBuilder sb) {
for (final Node statement : statements) {
@@ -505,16 +246,6 @@ public class Block extends Node {
}
/**
- * Get the FunctionNode for this block, i.e. the function it
- * belongs to
- *
- * @return the function node
- */
- public FunctionNode getFunction() {
- return function;
- }
-
- /**
* Reset the frame for this block
*
* @param frame the new frame
@@ -524,24 +255,6 @@ public class Block extends Node {
}
/**
- * Get the parent block
- *
- * @return parent block, or null if none exists
- */
- public Block getParent() {
- return parent;
- }
-
- /**
- * Set the parent block
- *
- * @param parent the new parent block
- */
- public void setParent(final Block parent) {
- this.parent = parent;
- }
-
- /**
* Get the list of statements in this block
*
* @return a list of statements
@@ -551,6 +264,15 @@ public class Block extends Node {
}
/**
+ * Applies the specified visitor to all statements in the block.
+ * @param visitor the visitor.
+ */
+ public void visitStatements(NodeVisitor visitor) {
+ for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) {
+ stmts.set(stmts.next().accept(visitor));
+ }
+ }
+ /**
* Reset the statement list for this block
*
* @param statements new statement list
@@ -585,4 +307,29 @@ public class Block extends Node {
needsScope = true;
}
+ /**
+ * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not
+ * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol
+ * will be marked as one that needs to have its own scope.
+ * @param symbol the symbol being used.
+ * @param ancestors the iterator over block's containing lexical context
+ */
+ public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
+ if(symbol.getBlock() == this) {
+ setNeedsScope();
+ } else {
+ setUsesParentScopeSymbol(symbol, ancestors);
+ }
+ }
+
+ /**
+ * Invoked when this block uses a scope symbol defined in one of its ancestors.
+ * @param symbol the scope symbol being used
+ * @param ancestors iterator over ancestor blocks
+ */
+ void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
+ if(ancestors.hasNext()) {
+ ancestors.next().setUsesScopeSymbol(symbol, ancestors);
+ }
+ }
}
diff --git a/src/jdk/nashorn/internal/ir/BreakNode.java b/src/jdk/nashorn/internal/ir/BreakNode.java
index 81c572d4..7ad0dc6d 100644
--- a/src/jdk/nashorn/internal/ir/BreakNode.java
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java
@@ -64,8 +64,8 @@ public class BreakNode extends LabeledNode {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterBreakNode(this) != null) {
+ return visitor.leaveBreakNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java
index 387369e6..3410709c 100644
--- a/src/jdk/nashorn/internal/ir/CallNode.java
+++ b/src/jdk/nashorn/internal/ir/CallNode.java
@@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation for a function call.
*
*/
-public class CallNode extends Node implements TypeOverride {
+public class CallNode extends Node implements TypeOverride<CallNode> {
private Type type;
@@ -176,13 +176,13 @@ public class CallNode extends Node implements TypeOverride {
if (hasCallSiteType()) {
return type;
}
- assert !function.getType().isUnknown();
- return function.getType();
+ return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT;
}
@Override
- public void setType(final Type type) {
+ public CallNode setType(final Type type) {
this.type = type;
+ return this;
}
private boolean hasCallSiteType() {
@@ -208,14 +208,14 @@ public class CallNode extends Node implements TypeOverride {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCallNode(this) != null) {
function = function.accept(visitor);
for (int i = 0, count = args.size(); i < count; i++) {
args.set(i, args.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveCallNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/CaseNode.java b/src/jdk/nashorn/internal/ir/CaseNode.java
index 928ba5be..61b89217 100644
--- a/src/jdk/nashorn/internal/ir/CaseNode.java
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java
@@ -79,7 +79,7 @@ public class CaseNode extends BreakableNode {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCaseNode(this) != null) {
if (test != null) {
test = test.accept(visitor);
}
@@ -87,7 +87,7 @@ public class CaseNode extends BreakableNode {
body = (Block)body.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveCaseNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk/nashorn/internal/ir/CatchNode.java
index 187c3949..005ffa8e 100644
--- a/src/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java
@@ -84,7 +84,7 @@ public class CatchNode extends Node {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCatchNode(this) != null) {
exception = (IdentNode)exception.accept(visitor);
if (exceptionCondition != null) {
@@ -92,7 +92,7 @@ public class CatchNode extends Node {
}
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveCatchNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/ContinueNode.java b/src/jdk/nashorn/internal/ir/ContinueNode.java
index 2063d6b2..cbc7bff2 100644
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java
@@ -61,8 +61,8 @@ public class ContinueNode extends LabeledNode {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterContinueNode(this) != null) {
+ return visitor.leaveContinueNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/DoWhileNode.java b/src/jdk/nashorn/internal/ir/DoWhileNode.java
index 476643a1..3939795e 100644
--- a/src/jdk/nashorn/internal/ir/DoWhileNode.java
+++ b/src/jdk/nashorn/internal/ir/DoWhileNode.java
@@ -63,11 +63,11 @@ public class DoWhileNode extends WhileNode {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterDoWhileNode(this) != null) {
body = (Block)body.accept(visitor);
test = test.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveDoWhileNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/EmptyNode.java b/src/jdk/nashorn/internal/ir/EmptyNode.java
index 0bfacd5d..15330a37 100644
--- a/src/jdk/nashorn/internal/ir/EmptyNode.java
+++ b/src/jdk/nashorn/internal/ir/EmptyNode.java
@@ -57,8 +57,8 @@ public class EmptyNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterEmptyNode(this) != null) {
+ return visitor.leaveEmptyNode(this);
}
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/ExecuteNode.java b/src/jdk/nashorn/internal/ir/ExecuteNode.java
index 501468bb..8ae7d556 100644
--- a/src/jdk/nashorn/internal/ir/ExecuteNode.java
+++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java
@@ -85,9 +85,9 @@ public class ExecuteNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterExecuteNode(this) != null) {
setExpression(expression.accept(visitor));
- return visitor.leave(this);
+ return visitor.leaveExecuteNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java
index 53b56752..e55054dd 100644
--- a/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/src/jdk/nashorn/internal/ir/ForNode.java
@@ -76,7 +76,7 @@ public class ForNode extends WhileNode {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterForNode(this) != null) {
if (init != null) {
init = init.accept(visitor);
}
@@ -91,7 +91,7 @@ public class ForNode extends WhileNode {
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveForNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/FunctionNode.java b/src/jdk/nashorn/internal/ir/FunctionNode.java
index d928aa71..2b0e109b 100644
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -33,8 +33,10 @@ import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Stack;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
@@ -45,16 +47,18 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Parser;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
/**
* IR representation for function (or script.)
- *
*/
public class FunctionNode extends Block {
+ private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
+
/** Function kinds */
public enum Kind {
/** a normal function - nothing special */
@@ -86,7 +90,9 @@ public class FunctionNode extends Block {
/** method has had its types finalized */
FINALIZED,
/** method has been emitted to bytecode */
- EMITTED
+ EMITTED,
+ /** code installed in a class loader */
+ INSTALLED
}
/** External function identifier. */
@@ -108,9 +114,6 @@ public class FunctionNode extends Block {
/** List of parameters. */
private List<IdentNode> parameters;
- /** List of nested functions. */
- private List<FunctionNode> functions;
-
/** First token of function. **/
private long firstToken;
@@ -153,10 +156,6 @@ public class FunctionNode extends Block {
/** Pending control list. */
private final Stack<Node> controlStack;
- /** Variable declarations in the function's scope */
- @Ignore
- private final List<VarNode> declarations;
-
/** VarNode for this function statement */
@Ignore //this is explicit code anyway and should not be traversed after lower
private VarNode funcVarNode;
@@ -173,37 +172,42 @@ public class FunctionNode extends Block {
@Ignore
private final EnumSet<CompilationState> compilationState;
+ /** Type hints, e.g based on parameters at call site */
+ private final Map<IdentNode, Type> specializedTypes;
+
/** Function flags. */
private int flags;
/** Is anonymous function flag. */
- private static final int IS_ANONYMOUS = 0b0000_0000_0000_0001;
- /** Is statement flag */
- private static final int IS_STATEMENT = 0b0000_0000_0000_0010;
+ private static final int IS_ANONYMOUS = 1 << 0;
+ /** Is the function created in a function declaration (as opposed to a function expression) */
+ private static final int IS_DECLARED = 1 << 1;
/** is this a strict mode function? */
- private static final int IS_STRICT_MODE = 0b0000_0000_0000_0100;
+ private static final int IS_STRICT_MODE = 1 << 2;
/** Does the function use the "arguments" identifier ? */
- private static final int USES_ARGUMENTS = 0b0000_0000_0000_1000;
+ private static final int USES_ARGUMENTS = 1 << 3;
/** Are we lowered ? */
- private static final int IS_LOWERED = 0b0000_0000_0001_0000;
+ private static final int IS_LOWERED = 1 << 4;
/** Has this node been split because it was too large? */
- private static final int IS_SPLIT = 0b0000_0000_0010_0000;
+ private static final int IS_SPLIT = 1 << 5;
/** Does the function call eval? */
- private static final int HAS_EVAL = 0b0000_0000_0100_0000;
+ private static final int HAS_EVAL = 1 << 6;
/** Does the function contain a with block ? */
- private static final int HAS_WITH = 0b0000_0000_1000_0000;
+ private static final int HAS_WITH = 1 << 7;
/** Does a descendant function contain a with or eval? */
- private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0001_0000_0000;
+ private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8;
/** Does the function define "arguments" identifier as a parameter of nested function name? */
- private static final int DEFINES_ARGUMENTS = 0b0000_0010_0000_0000;
+ private static final int DEFINES_ARGUMENTS = 1 << 9;
/** Does the function need a self symbol? */
- private static final int NEEDS_SELF_SYMBOL = 0b0000_0100_0000_0000;
+ private static final int NEEDS_SELF_SYMBOL = 1 << 10;
/** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
- private static final int USES_ANCESTOR_SCOPE = 0b0000_1000_0000_0000;
+ private static final int USES_ANCESTOR_SCOPE = 1 << 11;
/** Is this function lazily compiled? */
- private static final int IS_LAZY = 0b0001_0000_0000_0000;
+ private static final int IS_LAZY = 1 << 12;
/** Does this function have lazy, yet uncompiled children */
- private static final int HAS_LAZY_CHILDREN = 0b0010_0000_0000_0000;
+ private static final int HAS_LAZY_CHILDREN = 1 << 13;
+ /** Does this function have lazy, yet uncompiled children */
+ private static final int IS_PROGRAM = 1 << 14;
/** Does this function or any nested functions contain a with or an eval? */
private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
@@ -211,54 +215,39 @@ public class FunctionNode extends Block {
private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
/** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
- /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval. */
- private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL;
+ /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval.
+ * We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
+ private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN;
/** What is the return type of this function? */
private Type returnType = Type.UNKNOWN;
/**
- * Used to keep track of a function's parent blocks.
- * This is needed when a (finally body) block is cloned than contains inner functions.
- * Does not include function.getParent().
- */
- @Ignore
- private List<Block> referencingParentBlocks;
-
- /**
* Constructor
*
* @param source the source
* @param token token
* @param finish finish
* @param namespace the namespace
- * @param parent the parent block
* @param ident the identifier
* @param name the name of the function
*/
- @SuppressWarnings("LeakingThisInConstructor")
- public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) {
- super(source, token, finish, parent, null);
+ public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) {
+ super(source, token, finish);
this.ident = ident;
this.name = name;
this.kind = Kind.NORMAL;
this.parameters = new ArrayList<>();
- this.functions = new ArrayList<>();
this.firstToken = token;
this.lastToken = token;
this.namespace = namespace;
this.labelStack = new Stack<>();
this.controlStack = new Stack<>();
- this.declarations = new ArrayList<>();
- // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
- // it as such a leak - this is a false positive as we're setting this into a field of the object being
- // constructed, so it can't be seen from other threads.
- this.function = this;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
+ this.specializedTypes = new HashMap<>();
}
- @SuppressWarnings("LeakingThisInConstructor")
private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
super(functionNode, cs);
@@ -268,10 +257,9 @@ public class FunctionNode extends Block {
this.parameters = new ArrayList<>();
for (final IdentNode param : functionNode.getParameters()) {
- this.parameters.add((IdentNode) cs.existingOrCopy(param));
+ this.parameters.add((IdentNode)cs.existingOrCopy(param));
}
- this.functions = new ArrayList<>();
this.firstToken = functionNode.firstToken;
this.lastToken = functionNode.lastToken;
this.namespace = functionNode.getNamespace();
@@ -283,43 +271,34 @@ public class FunctionNode extends Block {
this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
this.labelStack = new Stack<>();
this.controlStack = new Stack<>();
- this.declarations = new ArrayList<>();
-
- for (final VarNode decl : functionNode.getDeclarations()) {
- declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same?
- }
this.flags = functionNode.flags;
this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
/** VarNode for this function statement */
- // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
- // it as such a leak - this is a false positive as we're setting this into a field of the object being
- // constructed, so it can't be seen from other threads.
- this.function = this;
-
this.compilationState = EnumSet.copyOf(functionNode.compilationState);
+ this.specializedTypes = new HashMap<>();
}
@Override
protected Node copy(final CopyState cs) {
// deep clone all parent blocks
- return fixBlockChain(new FunctionNode(this, cs));
+ return new FunctionNode(this, cs);
}
@Override
public Node accept(final NodeVisitor visitor) {
- final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
- final Block saveBlock = visitor.getCurrentBlock();
+ final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
+ final Block saveBlock = visitor.getCurrentBlock();
+ final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter();
+ final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit();
visitor.setCurrentFunctionNode(this);
- visitor.setCurrentCompileUnit(getCompileUnit());
- visitor.setCurrentMethodEmitter(getMethodEmitter());
visitor.setCurrentBlock(this);
try {
- if (visitor.enter(this) != null) {
+ if (visitor.enterFunctionNode(this) != null) {
if (ident != null) {
ident = (IdentNode)ident.accept(visitor);
}
@@ -328,51 +307,25 @@ public class FunctionNode extends Block {
parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
}
- for (int i = 0, count = functions.size(); i < count; i++) {
- functions.set(i, (FunctionNode)functions.get(i).accept(visitor));
- }
-
for (int i = 0, count = statements.size(); i < count; i++) {
statements.set(i, statements.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveFunctionNode(this);
}
} finally {
visitor.setCurrentBlock(saveBlock);
visitor.setCurrentFunctionNode(saveFunctionNode);
- visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null);
- visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null);
+ visitor.setCurrentCompileUnit(saveCompileUnit);
+ visitor.setCurrentMethodEmitter(saveMethodEmitter);
}
return this;
}
- /**
- * Locate the parent function.
- *
- * @return Parent function.
- */
- public FunctionNode findParentFunction() {
- return getParent() != null ? getParent().getFunction() : null;
- }
-
- /**
- * Add parent name to the builder.
- *
- * @param sb String builder.
- */
- @Override
- public void addParentName(final StringBuilder sb) {
- if (!isScript()) {
- sb.append(getName());
- sb.append("$");
- }
- }
-
@Override
public boolean needsScope() {
- return super.needsScope() || isScript();
+ return super.needsScope() || isProgram();
}
/**
@@ -530,12 +483,18 @@ public class FunctionNode extends Block {
}
/**
- * Determine if script function.
- *
- * @return True if script function.
+ * Returns true if the function is the top-level program.
+ * @return True if this function node represents the top-level program.
+ */
+ public boolean isProgram() {
+ return (flags & IS_PROGRAM) != 0;
+ }
+
+ /**
+ * Marks the function as representing the top-level program.
*/
- public boolean isScript() {
- return getParent() == null;
+ public void setProgram() {
+ flags |= IS_PROGRAM;
}
/**
@@ -575,31 +534,31 @@ public class FunctionNode extends Block {
/**
* Flag this function as using the {@code with} keyword
+ * @param ancestors the iterator over functions in this functions's containing lexical context
*/
- public void setHasWith() {
+ public void setHasWith(final Iterator<FunctionNode> ancestors) {
if(!hasWith()) {
this.flags |= HAS_WITH;
// with requires scope in parents.
// TODO: refine this. with should not force all variables in parents to be in scope, only those that are
// actually referenced as identifiers by name
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
- private void markParentForWithOrEval() {
+ private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) {
// If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
setNeedsScope();
- final FunctionNode parentFunction = findParentFunction();
- if(parentFunction != null) {
- parentFunction.setDescendantHasWithOrEval();
+ if(ancestors.hasNext()) {
+ ancestors.next().setDescendantHasWithOrEval(ancestors);
}
}
- private void setDescendantHasWithOrEval() {
+ private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) {
if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
flags |= HAS_DESCENDANT_WITH_OR_EVAL;
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
@@ -614,11 +573,12 @@ public class FunctionNode extends Block {
/**
* Flag this function as calling the {@code eval} function
+ * @param ancestors the iterator over functions in this functions's containing lexical context
*/
- public void setHasEval() {
+ public void setHasEval(final Iterator<FunctionNode> ancestors) {
if(!hasEval()) {
this.flags |= HAS_EVAL;
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
@@ -651,11 +611,34 @@ public class FunctionNode extends Block {
}
/**
- * Get all nested functions
- * @return list of nested functions in this function
- */
- public List<FunctionNode> getFunctions() {
- return Collections.unmodifiableList(functions);
+ * Returns a list of functions declared by this function. Only includes declared functions, and does not include any
+ * function expressions that might occur in its body.
+ * @return a list of functions declared by this function.
+ */
+ public List<FunctionNode> getDeclaredFunctions() {
+ // Note that the function does not have a dedicated list of declared functions, but rather relies on the
+ // invariant that all function declarations are at the beginning of the statement list as VarNode with a
+ // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a
+ // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors.
+ final List<FunctionNode> fns = new ArrayList<>();
+ for (final Node stmt : statements) {
+ if(stmt instanceof LineNumberNode) {
+ continue;
+ } else if(stmt instanceof VarNode) {
+ final Node init = ((VarNode)stmt).getInit();
+ if(init instanceof FunctionNode) {
+ final FunctionNode fn = (FunctionNode)init;
+ if(fn.isDeclared()) {
+ fns.add(fn);
+ continue;
+ }
+ }
+ }
+ // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are
+ // at the start of the function, we've reached the end of function declarations.
+ break;
+ }
+ return fns;
}
/**
@@ -710,6 +693,7 @@ public class FunctionNode extends Block {
* Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to
* their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object
* (since it exposes {@code arguments.callee} property) will need to have a callee parameter.
+ *
* @return true if the function's generated Java method needs a {@code callee} parameter.
*/
public boolean needsCallee() {
@@ -786,7 +770,7 @@ public class FunctionNode extends Block {
public boolean needsArguments() {
// uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
// for top-level script, "arguments" is picked up from Context by Global.init() instead.
- return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript();
+ return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram();
}
/**
@@ -805,7 +789,7 @@ public class FunctionNode extends Block {
* @return true if the function needs parent scope.
*/
public boolean needsParentScope() {
- return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript();
+ return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram();
}
/**
@@ -865,7 +849,7 @@ public class FunctionNode extends Block {
* @return true if all variables should be in scope
*/
public boolean allVarsInScope() {
- return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
+ return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
}
/**
@@ -919,6 +903,27 @@ public class FunctionNode extends Block {
}
/**
+ * Get a specialized type for an identity, if one exists
+ * @param node node to check specialized type for
+ * @return null if no specialization exists, otherwise type
+ */
+ public Type getSpecializedType(final IdentNode node) {
+ return specializedTypes.get(node);
+ }
+
+ /**
+ * Set parameter type hints for specialization.
+ * @param types types array of length equal to parameter list size
+ */
+ public void setParameterTypes(final Class<?>[] types) {
+ assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types";
+ //diff - skip the callee and this etc, they are not explicit params in the parse tree
+ for (int i = 0; i < types.length ; i++) {
+ specializedTypes.put(parameters.get(i), Type.typeFor(types[i]));
+ }
+ }
+
+ /**
* Get the identifier for the variable in which the function return value
* should be stored
* @return an IdentNode representing the return value
@@ -953,19 +958,19 @@ public class FunctionNode extends Block {
}
/**
- * Check if this function is a statement
- * @return true if function is a statement
+ * Check if this function is created as a function declaration (as opposed to function expression)
+ * @return true if function is declared.
*/
- public boolean isStatement() {
- return (flags & IS_STATEMENT) != 0;
+ public boolean isDeclared() {
+ return (flags & IS_DECLARED) != 0;
}
/**
- * Flag this function as a statement
+ * Flag this function as being created as a function declaration (as opposed to a function expression).
* @see Parser
*/
- public void setIsStatement() {
- this.flags |= IS_STATEMENT;
+ public void setIsDeclared() {
+ this.flags |= IS_DECLARED;
}
/**
@@ -1013,35 +1018,16 @@ public class FunctionNode extends Block {
}
/**
- * Marks this function as one using any global symbol. The function and all its parent functions will all be marked
- * as needing parent scope.
- * @see #needsParentScope()
+ * Marks this function as using any of its ancestors' scopes.
*/
- public void setUsesGlobalSymbol() {
+ public void setUsesAncestorScope() {
this.flags |= USES_ANCESTOR_SCOPE;
- final FunctionNode parentFn = findParentFunction();
- if(parentFn != null) {
- parentFn.setUsesGlobalSymbol();
- }
}
- /**
- * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not
- * including the function defining the symbol will be marked as needing parent scope. The function defining the
- * symbol will be marked as one that needs to have its own scope.
- * @param symbol the symbol being used.
- * @see #needsParentScope()
- */
- public void setUsesScopeSymbol(final Symbol symbol) {
- if(symbol.getBlock() == this) {
- setNeedsScope();
- } else {
- this.flags |= USES_ANCESTOR_SCOPE;
- final FunctionNode parentFn = findParentFunction();
- if(parentFn != null) {
- parentFn.setUsesScopeSymbol(symbol);
- }
- }
+ @Override
+ void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) {
+ setUsesAncestorScope();
+ super.setUsesParentScopeSymbol(symbol, ancestors);
}
/**
@@ -1116,7 +1102,7 @@ public class FunctionNode extends Block {
@Override
public Type getType() {
- return getReturnType();
+ return FUNCTION_TYPE;
}
/**
@@ -1176,56 +1162,6 @@ public class FunctionNode extends Block {
}
/**
- * Add a new function to the function list.
- *
- * @param functionNode Function node to add.
- */
- @Override
- public void addFunction(final FunctionNode functionNode) {
- assert functionNode != null;
- functions.add(functionNode);
- }
-
- /**
- * Add a list of functions to the function list.
- *
- * @param functionNodes Function nodes to add.
- */
- @Override
- public void addFunctions(final List<FunctionNode> functionNodes) {
- functions.addAll(functionNodes);
- }
-
- /**
- * Set a function list
- *
- * @param functionNodes to set
- */
- @Override
- public void setFunctions(final List<FunctionNode> functionNodes) {
- this.functions = functionNodes;
- }
-
- /**
- * Add a variable declaration that should be visible to the entire function
- * scope. Parser does this.
- *
- * @param varNode a var node
- */
- public void addDeclaration(final VarNode varNode) {
- declarations.add(varNode);
- }
-
- /**
- * Return all variable declarations from this function scope
- *
- * @return all VarNodes in scope
- */
- public List<VarNode> getDeclarations() {
- return Collections.unmodifiableList(declarations);
- }
-
- /**
* Get the compile unit used to compile this function
* @see Compiler
* @return the compile unit
@@ -1258,32 +1194,4 @@ public class FunctionNode extends Block {
public void setMethodEmitter(final MethodEmitter method) {
this.method = method;
}
-
- /**
- * Each FunctionNode maintains a list of reference to its parent blocks.
- * Add a parent block to this function.
- *
- * @param parentBlock a block to remember as parent
- */
- public void addReferencingParentBlock(final Block parentBlock) {
- assert parentBlock.getFunction() == function.findParentFunction(); // all parent blocks must be in the same function
- if (parentBlock != function.getParent()) {
- if (referencingParentBlocks == null) {
- referencingParentBlocks = new LinkedList<>();
- }
- referencingParentBlocks.add(parentBlock);
- }
- }
-
- /**
- * Get the known parent blocks to this function
- *
- * @return list of parent blocks
- */
- public List<Block> getReferencingParentBlocks() {
- if (referencingParentBlocks == null) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(referencingParentBlocks);
- }
}
diff --git a/src/jdk/nashorn/internal/ir/IdentNode.java b/src/jdk/nashorn/internal/ir/IdentNode.java
index b0570a25..889a8700 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -38,18 +38,18 @@ import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for an identifier.
*/
-public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall {
+public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
+ private static final int PROPERTY_NAME = 1 << 0;
+ private static final int INITIALIZED_HERE = 1 << 1;
+ private static final int FUNCTION = 1 << 2;
+
/** Identifier. */
private final String name;
/** Type for a callsite, e.g. X in a get()X or a set(X)V */
private Type callSiteType;
- /** flag for an ident that is the property name of an AccessNode. */
- private boolean isPropertyName;
-
- /** flag for an ident on the left hand side of <code>var lhs = rhs;</code>. */
- private boolean isInitializedHere;
+ private byte flags;
/**
* Constructor
@@ -71,9 +71,8 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
*/
public IdentNode(final IdentNode identNode) {
super(identNode);
- this.name = identNode.getName();
- this.isPropertyName = identNode.isPropertyName;
- this.isInitializedHere = identNode.isInitializedHere;
+ this.name = identNode.getName();
+ this.flags = identNode.flags;
}
@Override
@@ -92,12 +91,17 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
}
@Override
- public void setType(final Type type) {
+ public IdentNode setType(final Type type) {
if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
- this.callSiteType = type;
// do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
+ if(this.callSiteType == type) {
+ return this;
+ }
+ final IdentNode n = (IdentNode)clone();
+ n.callSiteType = type;
+ return n;
}
@Override
@@ -131,8 +135,8 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterIdentNode(this) != null) {
+ return visitor.leaveIdentNode(this);
}
return this;
@@ -179,14 +183,18 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
* @return true if this is a property name
*/
public boolean isPropertyName() {
- return isPropertyName;
+ return (flags & PROPERTY_NAME) != 0;
}
/**
* Flag this IdentNode as a property name
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setIsPropertyName() {
- isPropertyName = true;
+ public IdentNode setIsPropertyName() {
+ if(isPropertyName()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= PROPERTY_NAME;
+ return n;
}
/**
@@ -194,14 +202,18 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
* @return true if IdentNode is initialized on creation
*/
public boolean isInitializedHere() {
- return isInitializedHere;
+ return (flags & INITIALIZED_HERE) != 0;
}
/**
* Flag IdentNode to be initialized on creation
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setIsInitializedHere() {
- isInitializedHere = true;
+ public IdentNode setIsInitializedHere() {
+ if(isInitializedHere()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= INITIALIZED_HERE;
+ return n;
}
/**
@@ -216,6 +228,17 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
@Override
public boolean isFunction() {
- return false;
+ return (flags & FUNCTION) != 0;
+ }
+
+ /**
+ * Mark this node as being the callee operand of a {@link CallNode}.
+ * @return an ident node identical to this one in all aspects except with its function flag set.
+ */
+ public IdentNode setIsFunction() {
+ if(isFunction()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= FUNCTION;
+ return n;
}
}
diff --git a/src/jdk/nashorn/internal/ir/IfNode.java b/src/jdk/nashorn/internal/ir/IfNode.java
index 81148c38..3ddcf1dc 100644
--- a/src/jdk/nashorn/internal/ir/IfNode.java
+++ b/src/jdk/nashorn/internal/ir/IfNode.java
@@ -75,7 +75,7 @@ public class IfNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterIfNode(this) != null) {
test = test.accept(visitor);
pass = (Block)pass.accept(visitor);
@@ -84,7 +84,7 @@ public class IfNode extends Node {
fail = (Block)fail.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveIfNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/IndexNode.java b/src/jdk/nashorn/internal/ir/IndexNode.java
index 9feb5ebf..4745bf64 100644
--- a/src/jdk/nashorn/internal/ir/IndexNode.java
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java
@@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation of an indexed access (brackets operator.)
*
*/
-public class IndexNode extends BaseNode implements TypeOverride {
+public class IndexNode extends BaseNode implements TypeOverride<IndexNode> {
/** Property ident. */
private Node index;
@@ -92,10 +92,10 @@ public class IndexNode extends BaseNode implements TypeOverride {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterIndexNode(this) != null) {
base = base.accept(visitor);
index = index.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveIndexNode(this);
}
return this;
@@ -144,12 +144,13 @@ public class IndexNode extends BaseNode implements TypeOverride {
}
@Override
- public void setType(final Type type) {
+ public IndexNode setType(final Type type) {
if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
hasCallSiteType = true;
getSymbol().setTypeOverride(type);
+ return this;
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/LabelNode.java b/src/jdk/nashorn/internal/ir/LabelNode.java
index c61bfcbd..756ea2df 100644
--- a/src/jdk/nashorn/internal/ir/LabelNode.java
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java
@@ -81,10 +81,10 @@ public class LabelNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLabelNode(this) != null) {
label = (IdentNode)label.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveLabelNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
new file mode 100644
index 00000000..2db1f796
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -0,0 +1,198 @@
+package jdk.nashorn.internal.ir;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special
+ * methods to retrieve useful subsets of the context.
+ */
+public class LexicalContext implements Cloneable {
+ private final Deque<Block> lexicalContext;
+
+ /**
+ * Creates a new empty lexical context.
+ */
+ public LexicalContext() {
+ lexicalContext = new ArrayDeque<>();
+ }
+
+ /**
+ * Pushes a new block on top of the context, making it the innermost open block.
+ * @param block the new block
+ */
+ public void push(Block block) {
+ //new Exception(block.toString()).printStackTrace();
+ lexicalContext.push(block);
+ }
+
+ /**
+ * Pops the innermost block off the context.
+ * @param the block expected to be popped, used to detect unbalanced pushes/pops
+ */
+ public void pop(Block block) {
+ final Block popped = lexicalContext.pop();
+ assert popped == block;
+ }
+
+ /**
+ * 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<Block> getBlocks() {
+ return lexicalContext.iterator();
+ }
+
+ /**
+ * 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<FunctionNode> getFunctions() {
+ return new FunctionIterator(getBlocks());
+ }
+
+ private static final class FunctionIterator implements Iterator<FunctionNode> {
+ private final Iterator<Block> it;
+ private FunctionNode next;
+
+ FunctionIterator(Iterator<Block> it) {
+ this.it = it;
+ next = findNext();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public FunctionNode next() {
+ if(next == null) {
+ throw new NoSuchElementException();
+ }
+ FunctionNode lnext = next;
+ next = findNext();
+ return lnext;
+ }
+
+ private FunctionNode findNext() {
+ while(it.hasNext()) {
+ final Block block = it.next();
+ if(block instanceof FunctionNode) {
+ return ((FunctionNode)block);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Returns an iterator over all ancestors block of the given block, with its parent block first.
+ * @param block the block whose ancestors are returned
+ * @return an iterator over all ancestors block of the given block.
+ */
+ public Iterator<Block> getAncestorBlocks(Block block) {
+ final Iterator<Block> it = getBlocks();
+ while(it.hasNext()) {
+ final Block b = it.next();
+ if(block == b) {
+ return it;
+ }
+ }
+ throw new AssertionError("Block is not on the current lexical context stack");
+ }
+
+ /**
+ * Returns an iterator over a block and all its ancestors blocks, with the block first.
+ * @param block the block that is the starting point of the iteration.
+ * @return an iterator over a block and all its ancestors.
+ */
+ public Iterator<Block> getBlocks(final Block block) {
+ final Iterator<Block> it = getAncestorBlocks(block);
+ return new Iterator<Block>() {
+ boolean blockReturned = false;
+ @Override
+ public boolean hasNext() {
+ return it.hasNext() || !blockReturned;
+ }
+ @Override
+ public Block next() {
+ if(blockReturned) {
+ return it.next();
+ }
+ blockReturned = true;
+ return block;
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Returns the closest function node to the block. If the block is itself a function, it is returned.
+ * @param block the block
+ * @return the function closest to the block.
+ * @see #getParentFunction(Block)
+ */
+ public FunctionNode getFunction(Block block) {
+ if(block instanceof FunctionNode) {
+ return (FunctionNode)block;
+ }
+ return getParentFunction(block);
+ }
+
+ /**
+ * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function,
+ * it is returned too.
+ * @param block the block
+ * @return the closest function node to the block and all its ancestor functions.
+ */
+ public Iterator<FunctionNode> getFunctions(final Block block) {
+ return new FunctionIterator(getBlocks(block));
+ }
+
+ /**
+ * Returns the containing function of the block. If the block is itself a function, its parent function is returned.
+ * @param block the block
+ * @return the containing function of the block.
+ * @see #getFunction(Block)
+ */
+ public FunctionNode getParentFunction(Block block) {
+ return getFirstFunction(getAncestorBlocks(block));
+ }
+
+ private static FunctionNode getFirstFunction(Iterator<Block> it) {
+ while(it.hasNext()) {
+ final Block ancestor = it.next();
+ if(ancestor instanceof FunctionNode) {
+ return (FunctionNode)ancestor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the innermost block in the context.
+ * @return the innermost block in the context.
+ */
+ public Block getCurrentBlock() {
+ return lexicalContext.element();
+ }
+
+ /**
+ * Returns the innermost function in the context.
+ * @return the innermost function in the context.
+ */
+ public FunctionNode getCurrentFunction() {
+ return getFirstFunction(getBlocks());
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/LineNumberNode.java b/src/jdk/nashorn/internal/ir/LineNumberNode.java
index ef1c05e1..c7912ff0 100644
--- a/src/jdk/nashorn/internal/ir/LineNumberNode.java
+++ b/src/jdk/nashorn/internal/ir/LineNumberNode.java
@@ -63,8 +63,8 @@ public class LineNumberNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterLineNumberNode(this) != null) {
+ return visitor.leaveLineNumberNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index f1bf1b80..cc424b7a 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -46,7 +46,7 @@ import jdk.nashorn.internal.runtime.Undefined;
*/
public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** Literal value */
- protected T value;
+ protected final T value;
/**
* Constructor
@@ -67,8 +67,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @param literalNode source node
*/
protected LiteralNode(final LiteralNode<T> literalNode) {
+ this(literalNode, literalNode.value);
+ }
+
+ /**
+ * A copy constructor with value change.
+ * @param literalNode the original literal node
+ * @param newValue new value for this node
+ */
+ protected LiteralNode(final LiteralNode<T> literalNode, final T newValue) {
super(literalNode);
- this.value = literalNode.value;
+ this.value = newValue;
}
@Override
@@ -217,8 +226,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterLiteralNode(this) != null) {
+ return visitor.leaveLiteralNode(this);
}
return this;
@@ -544,6 +553,10 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
super(literalNode);
}
+ private NodeLiteralNode(final LiteralNode<Node> literalNode, final Node value) {
+ super(literalNode, value);
+ }
+
@Override
protected Node copy(final CopyState cs) {
return new NodeLiteralNode(this);
@@ -551,11 +564,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLiteralNode(this) != null) {
if (value != null) {
- value = value.accept(visitor);
+ final Node newValue = value.accept(visitor);
+ if(value != newValue) {
+ return visitor.leaveLiteralNode(new NodeLiteralNode(this, newValue));
+ }
}
- return visitor.leave(this);
+ return visitor.leaveLiteralNode(this);
}
return this;
@@ -878,14 +894,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLiteralNode(this) != null) {
for (int i = 0; i < value.length; i++) {
final Node element = value[i];
if (element != null) {
value[i] = element.accept(visitor);
}
}
- return visitor.leave(this);
+ return visitor.leaveLiteralNode(this);
}
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/Location.java b/src/jdk/nashorn/internal/ir/Location.java
index 16ee680d..c8e01dd3 100644
--- a/src/jdk/nashorn/internal/ir/Location.java
+++ b/src/jdk/nashorn/internal/ir/Location.java
@@ -65,7 +65,11 @@ public class Location implements Cloneable {
@Override
protected Object clone() {
- return new Location(this);
+ try {
+ return super.clone();
+ } catch(CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/Node.java b/src/jdk/nashorn/internal/ir/Node.java
index 24ad8793..c5f01337 100644
--- a/src/jdk/nashorn/internal/ir/Node.java
+++ b/src/jdk/nashorn/internal/ir/Node.java
@@ -165,12 +165,19 @@ public abstract class Node extends Location {
return true;
}
- setIsResolved();
+ setIsResolved(true);
return false;
}
/**
+ * Reset the resolved flag.
+ */
+ public void resetResolved() {
+ setIsResolved(false);
+ }
+
+ /**
* Is this a debug info node like LineNumberNode etc?
*
* @return true if this is a debug node
@@ -234,8 +241,7 @@ public abstract class Node extends Location {
*
* @return Deep copy of the Node.
*/
- @Override
- public final Node clone() {
+ public final Node copy() {
return copy(new CopyState());
}
@@ -349,10 +355,10 @@ public abstract class Node extends Location {
}
/**
- * Flag this node as resolved, i.e. code has been generated for it
+ * Flag this node as resolved or not, i.e. code has been generated for it
*/
- public void setIsResolved() {
- this.isResolved = true;
+ private void setIsResolved(boolean isResolved) {
+ this.isResolved = isResolved;
}
/**
diff --git a/src/jdk/nashorn/internal/ir/ObjectNode.java b/src/jdk/nashorn/internal/ir/ObjectNode.java
index ab7e49e4..f6724a62 100644
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
@@ -36,9 +35,6 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation of an object literal.
*/
public class ObjectNode extends Node {
- /** Literal context. */
- @Ignore
- private Block context;
/** Literal elements. */
private final List<Node> elements;
@@ -49,13 +45,11 @@ public class ObjectNode extends Node {
* @param source the source
* @param token token
* @param finish finish
- * @param context the block for this ObjectNode
* @param elements the elements used to initialize this ObjectNode
*/
- public ObjectNode(final Source source, final long token, final int finish, final Block context, final List<Node> elements) {
+ public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) {
super(source, token, finish);
- this.context = context;
this.elements = elements;
}
@@ -68,7 +62,6 @@ public class ObjectNode extends Node {
newElements.add(cs.existingOrCopy(element));
}
- this.context = (Block)cs.existingOrCopy(objectNode.context);
this.elements = newElements;
}
@@ -79,16 +72,12 @@ public class ObjectNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- if (context != null) {
- context = (Block)context.accept(visitor);
- }
-
+ if (visitor.enterObjectNode(this) != null) {
for (int i = 0, count = elements.size(); i < count; i++) {
elements.set(i, elements.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveObjectNode(this);
}
return this;
@@ -117,14 +106,6 @@ public class ObjectNode extends Node {
}
/**
- * Get the block that is this ObjectNode's literal context
- * @return the block
- */
- public Block getContext() {
- return context;
- }
-
- /**
* Get the elements of this literal node
* @return a list of elements
*/
diff --git a/src/jdk/nashorn/internal/ir/PropertyNode.java b/src/jdk/nashorn/internal/ir/PropertyNode.java
index 75103377..a6bc49de 100644
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java
@@ -88,7 +88,7 @@ public class PropertyNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterPropertyNode(this) != null) {
key = (PropertyKey)((Node)key).accept(visitor);
if (value != null) {
@@ -103,7 +103,7 @@ public class PropertyNode extends Node {
setter = setter.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leavePropertyNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/ReferenceNode.java b/src/jdk/nashorn/internal/ir/ReferenceNode.java
deleted file mode 100644
index 3cae7b52..00000000
--- a/src/jdk/nashorn/internal/ir/ReferenceNode.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.ir;
-
-import jdk.nashorn.internal.ir.annotations.Reference;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * IR representation of a reference to another entity (function.)
- */
-public class ReferenceNode extends Node {
- /** Node referenced. */
- @Reference
- private final FunctionNode reference;
-
- /**
- * Constructor
- *
- * @param source the source
- * @param token token
- * @param finish finish
- * @param reference the function node to reference
- */
- public ReferenceNode(final Source source, final long token, final int finish, final FunctionNode reference) {
- super(source, token, finish);
-
- this.reference = reference;
- }
-
- private ReferenceNode(final ReferenceNode referenceNode) {
- super(referenceNode);
-
- this.reference = referenceNode.reference;
- }
-
- @Override
- protected Node copy(final CopyState cs) {
- return new ReferenceNode(this);
- }
-
- @Override
- public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
- }
-
- return this;
- }
-
- @Override
- public void toString(final StringBuilder sb) {
- if (reference == null) {
- sb.append("null");
- } else {
- reference.toString(sb);
- }
- }
-
- /**
- * Get there function node reference that this node points tp
- * @return a function node reference
- */
- public FunctionNode getReference() {
- return reference;
- }
-
-}
diff --git a/src/jdk/nashorn/internal/ir/ReturnNode.java b/src/jdk/nashorn/internal/ir/ReturnNode.java
index 35395b30..1400f395 100644
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java
@@ -100,12 +100,12 @@ public class ReturnNode extends Node {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterReturnNode(this) != null) {
if (expression != null) {
expression = expression.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveReturnNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java
index bfc47d18..461007cd 100644
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java
@@ -38,7 +38,7 @@ import jdk.nashorn.internal.runtime.Source;
* IR representation for a runtime call.
*
*/
-public class RuntimeNode extends Node implements TypeOverride {
+public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/**
* Request enum used for meta-information about the runtime request
@@ -393,8 +393,9 @@ public class RuntimeNode extends Node implements TypeOverride {
}
@Override
- public void setType(final Type type) {
+ public RuntimeNode setType(final Type type) {
this.callSiteType = type;
+ return this;
}
@Override
@@ -408,12 +409,12 @@ public class RuntimeNode extends Node implements TypeOverride {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterRuntimeNode(this) != null) {
for (int i = 0, count = args.size(); i < count; i++) {
args.set(i, args.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveRuntimeNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/SplitNode.java b/src/jdk/nashorn/internal/ir/SplitNode.java
index c09a4f02..b751cdcb 100644
--- a/src/jdk/nashorn/internal/ir/SplitNode.java
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java
@@ -108,10 +108,10 @@ public class SplitNode extends Node {
visitor.setCurrentMethodEmitter(getMethodEmitter());
try {
- if (visitor.enter(this) != null) {
+ if (visitor.enterSplitNode(this) != null) {
body = body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveSplitNode(this);
}
} finally {
visitor.setCurrentCompileUnit(saveCompileUnit);
diff --git a/src/jdk/nashorn/internal/ir/SwitchNode.java b/src/jdk/nashorn/internal/ir/SwitchNode.java
index 068398ee..23d9c7ea 100644
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java
@@ -85,7 +85,7 @@ public class SwitchNode extends BreakableNode {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterSwitchNode(this) != null) {
expression = expression.accept(visitor);
for (int i = 0, count = cases.size(); i < count; i++) {
@@ -94,7 +94,7 @@ public class SwitchNode extends BreakableNode {
//the default case is in the cases list and should not be explicitly traversed!
- return visitor.leave(this);
+ return visitor.leaveSwitchNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index a58a7c14..603b8b08 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -38,31 +38,31 @@ import jdk.nashorn.internal.runtime.options.Options;
*/
public final class Symbol implements Comparable<Symbol> {
- /** Symbol flags. Kind ordered by precedence. */
- public static final int IS_TEMP = 0b0000_0001;
+ /** Symbol kinds. Kind ordered by precedence. */
+ public static final int IS_TEMP = 1;
/** Is this Global */
- public static final int IS_GLOBAL = 0b0000_0010;
+ public static final int IS_GLOBAL = 2;
/** Is this a variable */
- public static final int IS_VAR = 0b0000_0011;
+ public static final int IS_VAR = 3;
/** Is this a parameter */
- public static final int IS_PARAM = 0b0000_0100;
+ public static final int IS_PARAM = 4;
/** Is this a constant */
- public static final int IS_CONSTANT = 0b0000_0101;
-
- static final int KINDMASK = 0b0000_1111;
+ public static final int IS_CONSTANT = 5;
+ /** Mask for kind flags */
+ public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
/** Is this scope */
- public static final int IS_SCOPE = 0b0000_0001_0000;
+ public static final int IS_SCOPE = 1 << 4;
/** Is this a this symbol */
- public static final int IS_THIS = 0b0000_0010_0000;
+ public static final int IS_THIS = 1 << 5;
/** Can this symbol ever be undefined */
- public static final int CAN_BE_UNDEFINED = 0b0000_0100_0000;
+ public static final int CAN_BE_UNDEFINED = 1 << 6;
/** Can this symbol ever have primitive types */
- public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000;
+ public static final int CAN_BE_PRIMITIVE = 1 << 7;
/** Is this a let */
- public static final int IS_LET = 0b0001_0000_0000;
+ public static final int IS_LET = 1 << 8;
/** Is this an internal symbol, never represented explicitly in source code */
- public static final int IS_INTERNAL = 0b0010_0000_0000;
+ public static final int IS_INTERNAL = 1 << 9;
/** Null or name identifying symbol. */
private final String name;
@@ -269,15 +269,6 @@ public final class Symbol implements Comparable<Symbol> {
return type.isCategory2() ? 2 : 1;
}
- /**
- * Return the defining function (scope.)
- *
- * @return Defining function.
- */
- public FunctionNode findFunction() {
- return block != null ? block.getFunction() : null;
- }
-
@Override
public boolean equals(final Object other) {
if (!(other instanceof Symbol)) {
@@ -487,27 +478,6 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
- * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
- *
- * @param currentFunction function to check for fast scope
- * @return true if fast scope
- */
- public boolean isFastScope(final FunctionNode currentFunction) {
- if (!isScope() || !block.needsScope()) {
- return false;
- }
- // Allow fast scope access if no parent function contains with or eval
- FunctionNode func = currentFunction;
- while (func != null) {
- if (func.hasWith() || func.hasEval()) {
- return false;
- }
- func = func.findParentFunction();
- }
- return true;
- }
-
- /**
* Get the block in which the symbol is defined
* @return a block
*/
@@ -651,7 +621,7 @@ public final class Symbol implements Comparable<Symbol> {
* @return true if this this is a global scope symbol
*/
public boolean isTopLevel() {
- return block instanceof FunctionNode && ((FunctionNode) block).isScript();
+ return block instanceof FunctionNode && ((FunctionNode) block).isProgram();
}
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index a82991f9..de333851 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -77,11 +77,11 @@ public class TernaryNode extends BinaryNode {
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- lhs = lhs.accept(visitor);
- rhs = rhs.accept(visitor);
- third = third.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterTernaryNode(this) != null) {
+ final Node newLhs = lhs().accept(visitor);
+ final Node newRhs = rhs().accept(visitor);
+ final Node newThird = third.accept(visitor);
+ return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs));
}
return this;
@@ -133,8 +133,12 @@ public class TernaryNode extends BinaryNode {
/**
* Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
* @param third a node
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setThird(final Node third) {
- this.third = third;
+ public TernaryNode setThird(final Node third) {
+ if(this.third == third) return this;
+ final TernaryNode n = (TernaryNode)clone();
+ n.third = third;
+ return n;
}
}
diff --git a/src/jdk/nashorn/internal/ir/ThrowNode.java b/src/jdk/nashorn/internal/ir/ThrowNode.java
index efa63d96..ab6d59e2 100644
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java
@@ -75,9 +75,9 @@ public class ThrowNode extends Node {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterThrowNode(this) != null) {
setExpression(expression.accept(visitor));
- return visitor.leave(this);
+ return visitor.leaveThrowNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/TryNode.java b/src/jdk/nashorn/internal/ir/TryNode.java
index b6aa439d..7d3864bc 100644
--- a/src/jdk/nashorn/internal/ir/TryNode.java
+++ b/src/jdk/nashorn/internal/ir/TryNode.java
@@ -101,7 +101,7 @@ public class TryNode extends Node {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterTryNode(this) != null) {
// Need to do first for termination analysis.
if (finallyBody != null) {
finallyBody = (Block)finallyBody.accept(visitor);
@@ -115,7 +115,7 @@ public class TryNode extends Node {
}
this.catchBlocks = newCatchBlocks;
- return visitor.leave(this);
+ return visitor.leaveTryNode(this);
}
return this;
@@ -155,6 +155,15 @@ public class TryNode extends Node {
}
/**
+ * Returns true if the specified block is the body of this try block, or any of its catch blocks.
+ * @param block the block
+ * @return true if the specified block is the body of this try block, or any of its catch blocks.
+ */
+ public boolean isChildBlock(Block block) {
+ return body == block || catchBlocks.contains(block);
+ }
+
+ /**
* Get the catch blocks for this try block
* @return a list of blocks
*/
diff --git a/src/jdk/nashorn/internal/ir/TypeOverride.java b/src/jdk/nashorn/internal/ir/TypeOverride.java
index 8321318a..61c1fe20 100644
--- a/src/jdk/nashorn/internal/ir/TypeOverride.java
+++ b/src/jdk/nashorn/internal/ir/TypeOverride.java
@@ -36,15 +36,17 @@ import jdk.nashorn.internal.codegen.types.Type;
* by using JSType.toInt32. Especially in scenarios where the field is already stored
* as a primitive, this will be much faster than the "object is all I see" scope
* available in the method
+ * @param <T> the type of the node implementing the interface
*/
-public interface TypeOverride {
+public interface TypeOverride<T extends Node> {
/**
* Set the override type
*
* @param type the type
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setType(final Type type);
+ public T setType(final Type type);
/**
* Returns true if this node can have a callsite override, e.g. all scope ident nodes
diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index 7b608edf..d823c058 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -41,7 +41,7 @@ import jdk.nashorn.internal.runtime.Source;
*/
public class UnaryNode extends Node implements Assignment<Node> {
/** Right hand side argument. */
- protected Node rhs;
+ private Node rhs;
/**
* Constructor
@@ -104,6 +104,11 @@ public class UnaryNode extends Node implements Assignment<Node> {
}
@Override
+ public Node setAssignmentDest(Node n) {
+ return setRHS(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return getAssignmentDest();
}
@@ -132,9 +137,8 @@ public class UnaryNode extends Node implements Assignment<Node> {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- rhs = rhs.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterUnaryNode(this) != null) {
+ return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
}
return this;
@@ -152,9 +156,9 @@ public class UnaryNode extends Node implements Assignment<Node> {
if (isConvert) {
convertPos = sb.length();
- sb.append("((");
+ sb.append("(");
sb.append(getType());
- sb.append(")");
+ sb.append(")(");
}
if (!isPostfix && !isConvert) {
@@ -191,8 +195,6 @@ public class UnaryNode extends Node implements Assignment<Node> {
sb.setCharAt(convertPos, ' ');
}
}
-
- //TODO - conversions still have too many parenthesis - makes --print-lower-parse hard to read
}
/**
@@ -214,10 +216,12 @@ public class UnaryNode extends Node implements Assignment<Node> {
* @see BinaryNode
*
* @param rhs right hand side or expression node
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setRHS(final Node rhs) {
- this.rhs = rhs;
+ public UnaryNode setRHS(final Node rhs) {
+ if(this.rhs == rhs) return this;
+ final UnaryNode n = (UnaryNode)clone();
+ n.rhs = rhs;
+ return n;
}
-
-
}
diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java
index 07b6f8ec..b719c99d 100644
--- a/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/src/jdk/nashorn/internal/ir/VarNode.java
@@ -38,8 +38,8 @@ public class VarNode extends Node implements Assignment<IdentNode> {
/** Initialization expression. */
private Node init;
- /** Is this a function var node */
- private boolean isFunctionVarNode;
+ /** Is this a var statement (as opposed to a "var" in a for loop statement) */
+ private final boolean isStatement;
/**
* Constructor
@@ -51,20 +51,34 @@ public class VarNode extends Node implements Assignment<IdentNode> {
* @param init init node or null if just a declaration
*/
public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
+ this(source, token, finish, name, init, true);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param source the source
+ * @param token token
+ * @param finish finish
+ * @param name name of variable
+ * @param init init node or null if just a declaration
+ * @param isStatement if this is a var statement (true), or a for-loop initializer (false)
+ */
+ public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) {
super(source, token, finish);
- this.name = name;
+ this.name = init == null ? name : name.setIsInitializedHere();
this.init = init;
- if (init != null) {
- this.name.setIsInitializedHere();
- }
+ this.isStatement = isStatement;
}
+
private VarNode(final VarNode varNode, final CopyState cs) {
super(varNode);
this.name = (IdentNode)cs.existingOrCopy(varNode.name);
this.init = cs.existingOrCopy(varNode.init);
+ this.isStatement = varNode.isStatement;
}
@Override
@@ -83,6 +97,11 @@ public class VarNode extends Node implements Assignment<IdentNode> {
}
@Override
+ public Node setAssignmentDest(IdentNode n) {
+ return setName(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return isAssignment() ? getInit() : null;
}
@@ -127,16 +146,19 @@ public class VarNode extends Node implements Assignment<IdentNode> {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- name = (IdentNode)name.accept(visitor);
-
- if (init != null) {
- init = init.accept(visitor);
+ if (visitor.enterVarNode(this) != null) {
+ final IdentNode newName = (IdentNode)name.accept(visitor);
+ final Node newInit = init == null ? null : init.accept(visitor);
+ final VarNode newThis;
+ if(name != newName || init != newInit) {
+ newThis = (VarNode)clone();
+ newThis.init = newInit;
+ newThis.name = newInit == null ? newName : newName.setIsInitializedHere();
+ } else {
+ newThis = this;
}
-
- return visitor.leave(this);
+ return visitor.leaveVarNode(newThis);
}
-
return this;
}
@@ -162,9 +184,13 @@ public class VarNode extends Node implements Assignment<IdentNode> {
/**
* Reset the initialization expression
* @param init new initialization expression
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setInit(final Node init) {
- this.init = init;
+ public VarNode setInit(final Node init) {
+ if(this.init == init) return this;
+ final VarNode n = (VarNode)clone();
+ n.init = init;
+ return n;
}
/**
@@ -179,30 +205,26 @@ public class VarNode extends Node implements Assignment<IdentNode> {
* Reset the identifier for this VarNode
* @param name new IdentNode representing the variable being set or declared
*/
- public void setName(final IdentNode name) {
- this.name = name;
+ private VarNode setName(final IdentNode name) {
+ if(this.name == name) return this;
+ final VarNode n = (VarNode)clone();
+ n.name = name;
+ return n;
}
/**
- * Check if this is a virtual assignment of a function node. Function nodes declared
- * with a name are hoisted to the top of the scope and appear as symbols too. This is
- * implemented by representing them as virtual VarNode assignments added to the code
- * during lowering
- *
- * @see FunctionNode
- *
- * @return true if this is a virtual function declaration
+ * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
+ * @return true if this is a var statement (as opposed to a var initializer in a for loop).
*/
- public boolean isFunctionVarNode() {
- return isFunctionVarNode;
+ public boolean isStatement() {
+ return isStatement;
}
/**
- * Flag this var node as a virtual function var node assignment as described in
- * {@link VarNode#isFunctionVarNode()}
+ * Returns true if this is a function declaration.
+ * @return true if this is a function declaration.
*/
- public void setIsFunctionVarNode() {
- this.isFunctionVarNode = true;
+ public boolean isFunctionDeclaration() {
+ return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
}
-
}
diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java
index c51659b8..8db31c08 100644
--- a/src/jdk/nashorn/internal/ir/WhileNode.java
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java
@@ -88,11 +88,11 @@ public class WhileNode extends BreakableNode {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterWhileNode(this) != null) {
test = test.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveWhileNode(this);
}
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/WithNode.java b/src/jdk/nashorn/internal/ir/WithNode.java
index 52f4e9b5..f5ad3b13 100644
--- a/src/jdk/nashorn/internal/ir/WithNode.java
+++ b/src/jdk/nashorn/internal/ir/WithNode.java
@@ -73,10 +73,10 @@ public class WithNode extends Node {
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterWithNode(this) != null) {
expression = expression.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveWithNode(this);
}
return this;
diff --git a/src/jdk/nashorn/internal/ir/annotations/ChildNode.java b/src/jdk/nashorn/internal/ir/annotations/ChildNode.java
deleted file mode 100644
index 181c63d8..00000000
--- a/src/jdk/nashorn/internal/ir/annotations/ChildNode.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.ir.annotations;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This is a child node, a real node, not a reference, to an IR node that should
- * be traversed.
- * <p>
- * TODO Currently not in use. Would make e.g. accept methods simple and unified
- * @see jdk.nashorn.internal.ir.Node
- */
-@Retention(value=RetentionPolicy.RUNTIME)
-public @interface ChildNode {
- /** order of traversal compared to other children */
- public int order() default -1;
-}
diff --git a/src/jdk/nashorn/internal/ir/annotations/ParentNode.java b/src/jdk/nashorn/internal/ir/annotations/ParentNode.java
deleted file mode 100644
index 6a9de3a4..00000000
--- a/src/jdk/nashorn/internal/ir/annotations/ParentNode.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.ir.annotations;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Signifies a parent of a node, i.e. node that should not be traversed if we
- * go down the AST. In automatic parsing this can be handled by @Reference
- * annotations instead, as all parents are references.
- * <p>
- * TODO The use case is automating and creating one implementation of something like
- * Node.getParent()
- *
- * @see jdk.nashorn.internal.ir.Node
- */
-@Retention(value=RetentionPolicy.RUNTIME)
-public @interface ParentNode {
- // EMPTY
-}
diff --git a/src/jdk/nashorn/internal/ir/annotations/Reference.java b/src/jdk/nashorn/internal/ir/annotations/Reference.java
index 1dd002c1..20c8ffca 100644
--- a/src/jdk/nashorn/internal/ir/annotations/Reference.java
+++ b/src/jdk/nashorn/internal/ir/annotations/Reference.java
@@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy;
* AST traversal and cloning. Cloning currently as a rule uses
* existingOrSame for references and otherwise existingOrCopy
* <p>
- * TODO this could probably be automated using the @Reference annotation.
*/
@Retention(value=RetentionPolicy.RUNTIME)
diff --git a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
index 3c66aa12..7bbe3836 100644
--- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir.debug;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
@@ -36,10 +37,10 @@ import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.annotations.Ignore;
-import jdk.nashorn.internal.ir.annotations.ParentNode;
import jdk.nashorn.internal.ir.annotations.Reference;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.Debug;
/**
* AST-as-text visualizer. Sometimes you want tree form and not source
@@ -47,7 +48,6 @@ import jdk.nashorn.internal.runtime.Context;
*
* see the flags --print-ast and --print-ast-lower
*/
-
public final class ASTWriter {
/** Root node from which to start the traversal */
private final Node root;
@@ -71,12 +71,22 @@ public final class ASTWriter {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- printAST(sb, null, "root", root, 0);
+ printAST(sb, null, null, "root", root, 0);
return sb.toString();
}
+ /**
+ * Return the visited nodes in an ordered list
+ * @return the list of nodes in order
+ */
+ public Node[] toArray() {
+ final List<Node> preorder = new ArrayList<>();
+ printAST(new StringBuilder(), preorder, null, "root", root, 0);
+ return preorder.toArray(new Node[preorder.size()]);
+ }
+
@SuppressWarnings("unchecked")
- private void printAST(final StringBuilder sb, final Field field, final String name, final Node node, final int indent) {
+ private void printAST(final StringBuilder sb, final List<Node> preorder, final Field field, final String name, final Node node, final int indent) {
ASTWriter.indent(sb, indent);
if (node == null) {
sb.append("[Object ");
@@ -85,13 +95,23 @@ public final class ASTWriter {
return;
}
+ if (preorder != null) {
+ preorder.add(node);
+ }
+
final boolean isReference = field != null && field.getAnnotation(Reference.class) != null;
Class<?> clazz = node.getClass();
String type = clazz.getName();
type = type.substring(type.lastIndexOf('.') + 1, type.length());
-// type += "@" + Debug.id(node) + "#" + node.getSymbol();
+ if (isReference) {
+ type = "ref: " + type;
+ }
+ type += "@" + Debug.id(node);
+ if (node.getSymbol() != null) {
+ type += "#" + node.getSymbol();
+ }
final List<Field> children = new LinkedList<>();
@@ -153,9 +173,7 @@ public final class ASTWriter {
append('\n');
for (final Field child : children) {
- if (child.getAnnotation(ParentNode.class) != null) {
- continue;
- } else if (child.getAnnotation(Ignore.class) != null) {
+ if (child.getAnnotation(Ignore.class) != null) {
continue;
}
@@ -168,7 +186,7 @@ public final class ASTWriter {
}
if (value instanceof Node) {
- printAST(sb, child, child.getName(), (Node)value, indent + 1);
+ printAST(sb, preorder, child, child.getName(), (Node)value, indent + 1);
} else if (value instanceof Collection) {
int pos = 0;
ASTWriter.indent(sb, indent + 1);
@@ -180,7 +198,7 @@ public final class ASTWriter {
append('\n');
for (final Node member : (Collection<Node>)value) {
- printAST(sb, child, child.getName() + "[" + pos++ + "]", member, indent + 2);
+ printAST(sb, preorder, child, child.getName() + "[" + pos++ + "]", member, indent + 2);
}
}
}
diff --git a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
index 68fb68b0..a8c3c4a4 100644
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
@@ -112,7 +112,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
enterDefault(accessNode);
type("MemberExpression");
@@ -132,7 +132,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
enterDefault(block);
type("BlockStatement");
@@ -154,7 +154,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final BinaryNode binaryNode) {
+ public Node enterBinaryNode(final BinaryNode binaryNode) {
enterDefault(binaryNode);
final String name;
@@ -183,7 +183,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
enterDefault(breakNode);
type("BreakStatement");
@@ -201,7 +201,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
enterDefault(callNode);
type("CallExpression");
@@ -217,7 +217,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final CaseNode caseNode) {
+ public Node enterCaseNode(final CaseNode caseNode) {
enterDefault(caseNode);
type("SwitchCase");
@@ -238,7 +238,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
enterDefault(catchNode);
type("CatchClause");
@@ -264,7 +264,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
enterDefault(continueNode);
type("ContinueStatement");
@@ -282,7 +282,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
enterDefault(doWhileNode);
type("DoWhileStatement");
@@ -299,7 +299,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
enterDefault(emptyNode);
type("EmptyStatement");
@@ -308,7 +308,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
enterDefault(executeNode);
type("ExpressionStatement");
@@ -321,7 +321,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
enterDefault(forNode);
if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) {
@@ -384,14 +384,14 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
enterDefault(functionNode);
- final boolean program = functionNode.isScript();
+ final boolean program = functionNode.isProgram();
final String name;
if (program) {
name = "Program";
- } else if (functionNode.isStatement()) {
+ } else if (functionNode.isDeclared()) {
name = "FunctionDeclaration";
} else {
name = "FunctionExpression";
@@ -419,20 +419,11 @@ public final class JSONWriter extends NodeVisitor {
}
// body consists of nested functions and statements
- final List<FunctionNode> funcs = functionNode.getFunctions();
final List<Node> stats = functionNode.getStatements();
- final int size = stats.size() + funcs.size();
+ final int size = stats.size();
int idx = 0;
arrayStart("body");
- for (final Node func : funcs) {
- func.accept(this);
- if (idx != (size - 1)) {
- comma();
- }
- idx++;
- }
-
for (final Node stat : stats) {
if (! stat.isDebug()) {
stat.accept(this);
@@ -448,7 +439,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
enterDefault(identNode);
final String name = identNode.getName();
@@ -464,7 +455,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
enterDefault(ifNode);
type("IfStatement");
@@ -490,7 +481,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
enterDefault(indexNode);
type("MemberExpression");
@@ -510,7 +501,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
enterDefault(labelNode);
type("LabeledStatement");
@@ -527,13 +518,13 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
return null;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
enterDefault(literalNode);
if (literalNode instanceof LiteralNode.ArrayLiteralNode) {
@@ -569,7 +560,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
enterDefault(objectNode);
type("ObjectExpression");
@@ -581,7 +572,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
final Node key = propertyNode.getKey();
final Node value = propertyNode.getValue();
@@ -647,7 +638,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
enterDefault(returnNode);
type("ReturnStatement");
@@ -665,7 +656,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
final RuntimeNode.Request req = runtimeNode.getRequest();
if (req == RuntimeNode.Request.DEBUGGER) {
@@ -680,12 +671,12 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
return null;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
enterDefault(switchNode);
type("SwitchStatement");
@@ -701,7 +692,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
enterDefault(ternaryNode);
type("ConditionalExpression");
@@ -722,7 +713,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
enterDefault(throwNode);
type("ThrowStatement");
@@ -735,7 +726,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
enterDefault(tryNode);
type("TryStatement");
@@ -760,7 +751,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final UnaryNode unaryNode) {
+ public Node enterUnaryNode(final UnaryNode unaryNode) {
enterDefault(unaryNode);
final TokenType tokenType = unaryNode.tokenType();
@@ -816,7 +807,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
enterDefault(varNode);
type("VariableDeclaration");
@@ -852,7 +843,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
enterDefault(whileNode);
type("WhileStatement");
@@ -869,7 +860,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
enterDefault(withNode);
type("WithStatement");
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 11b8dbd5..d2f40d1a 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -138,13 +137,13 @@ public final class PrintVisitor extends NodeVisitor {
* Visits.
*/
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
accessNode.toString(sb);
return null;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
sb.append(' ');
sb.append('{');
@@ -152,21 +151,6 @@ public final class PrintVisitor extends NodeVisitor {
final boolean isFunction = block instanceof FunctionNode;
- if (isFunction) {
- final FunctionNode function = (FunctionNode)block;
- final List<FunctionNode> functions = function.getFunctions();
-
- for (final FunctionNode f : functions) {
- sb.append(EOLN);
- indent();
- f.accept(this);
- }
-
- if (!functions.isEmpty()) {
- sb.append(EOLN);
- }
- }
-
final List<Node> statements = block.getStatements();
boolean lastLineNumber = false;
@@ -224,25 +208,25 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
breakNode.toString(sb);
return null;
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
callNode.toString(sb);
return null;
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
continueNode.toString(sb);
return null;
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
sb.append("do");
doWhileNode.getBody().accept(this);
sb.append(' ');
@@ -252,7 +236,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
final Node expression = executeNode.getExpression();
if (expression instanceof UnaryNode) {
@@ -265,7 +249,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
forNode.toString(sb);
forNode.getBody().accept(this);
@@ -273,15 +257,15 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
functionNode.toString(sb);
- enter((Block)functionNode);
+ enterBlock(functionNode);
return null;
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
ifNode.toString(sb);
ifNode.getPass().accept(this);
@@ -296,13 +280,13 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
indexNode.toString(sb);
return null;
}
@Override
- public Node enter(final LabelNode labeledNode) {
+ public Node enterLabelNode(final LabelNode labeledNode) {
indent -= TABWIDTH;
indent();
indent += TABWIDTH;
@@ -313,7 +297,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (printLineNumbers) {
lineNumberNode.toString(sb);
}
@@ -323,25 +307,19 @@ public final class PrintVisitor extends NodeVisitor {
@Override
- public Node enter(final ReferenceNode referenceNode) {
- referenceNode.toString(sb);
- return null;
- }
-
- @Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
returnNode.toString(sb);
return null;
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
runtimeNode.toString(sb);
return null;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
splitNode.toString(sb);
sb.append(EOLN);
indent += TABWIDTH;
@@ -350,7 +328,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
sb.append("</split>");
sb.append(EOLN);
indent -= TABWIDTH;
@@ -359,7 +337,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
switchNode.toString(sb);
sb.append(" {");
@@ -383,13 +361,13 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
throwNode.toString(sb);
return null;
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
tryNode.toString(sb);
tryNode.getBody().accept(this);
@@ -412,13 +390,19 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final VarNode varNode) {
- varNode.toString(sb);
+ public Node enterVarNode(final VarNode varNode) {
+ sb.append("var ");
+ varNode.getName().toString(sb);
+ final Node init = varNode.getInit();
+ if(init != null) {
+ sb.append(" = ");
+ init.accept(this);
+ }
return null;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
whileNode.toString(sb);
whileNode.getBody().accept(this);
@@ -426,7 +410,7 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
withNode.toString(sb);
withNode.getBody().accept(this);
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 6856282e..0021b7d2 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -53,7 +53,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
}
@Override
- public final Node enter(final UnaryNode unaryNode) {
+ public final Node enterUnaryNode(final UnaryNode unaryNode) {
switch (unaryNode.tokenType()) {
case ADD:
return enterADD(unaryNode);
@@ -81,12 +81,12 @@ public class NodeOperatorVisitor extends NodeVisitor {
case INCPOSTFIX:
return enterDECINC(unaryNode);
default:
- return super.enter(unaryNode);
+ return super.enterUnaryNode(unaryNode);
}
}
@Override
- public final Node leave(final UnaryNode unaryNode) {
+ public final Node leaveUnaryNode(final UnaryNode unaryNode) {
switch (unaryNode.tokenType()) {
case ADD:
return leaveADD(unaryNode);
@@ -114,12 +114,12 @@ public class NodeOperatorVisitor extends NodeVisitor {
case INCPOSTFIX:
return leaveDECINC(unaryNode);
default:
- return super.leave(unaryNode);
+ return super.leaveUnaryNode(unaryNode);
}
}
@Override
- public final Node enter(final BinaryNode binaryNode) {
+ public final Node enterBinaryNode(final BinaryNode binaryNode) {
switch (binaryNode.tokenType()) {
case ADD:
return enterADD(binaryNode);
@@ -198,12 +198,12 @@ public class NodeOperatorVisitor extends NodeVisitor {
case SUB:
return enterSUB(binaryNode);
default:
- return super.enter(binaryNode);
+ return super.enterBinaryNode(binaryNode);
}
}
@Override
- public final Node leave(final BinaryNode binaryNode) {
+ public final Node leaveBinaryNode(final BinaryNode binaryNode) {
switch (binaryNode.tokenType()) {
case ADD:
return leaveADD(binaryNode);
@@ -282,7 +282,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
case SUB:
return leaveSUB(binaryNode);
default:
- return super.leave(binaryNode);
+ return super.leaveBinaryNode(binaryNode);
}
}
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
index 9ce6fd02..f10d8c03 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
@@ -49,7 +49,6 @@ import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -153,7 +152,7 @@ public abstract class NodeVisitor {
* @param accessNode the node
* @return processed node, null if traversal should end, null if traversal should end
*/
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
return enterDefault(accessNode);
}
@@ -163,7 +162,7 @@ public abstract class NodeVisitor {
* @param accessNode the node
* @return processed node, null if traversal should end
*/
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
return leaveDefault(accessNode);
}
@@ -173,7 +172,7 @@ public abstract class NodeVisitor {
* @param block the node
* @return processed node, null if traversal should end
*/
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
return enterDefault(block);
}
@@ -183,7 +182,7 @@ public abstract class NodeVisitor {
* @param block the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
return leaveDefault(block);
}
@@ -193,7 +192,7 @@ public abstract class NodeVisitor {
* @param binaryNode the node
* @return processed node
*/
- public Node enter(final BinaryNode binaryNode) {
+ public Node enterBinaryNode(final BinaryNode binaryNode) {
return enterDefault(binaryNode);
}
@@ -203,7 +202,7 @@ public abstract class NodeVisitor {
* @param binaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
return leaveDefault(binaryNode);
}
@@ -213,7 +212,7 @@ public abstract class NodeVisitor {
* @param breakNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
return enterDefault(breakNode);
}
@@ -223,7 +222,7 @@ public abstract class NodeVisitor {
* @param breakNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final BreakNode breakNode) {
+ public Node leaveBreakNode(final BreakNode breakNode) {
return leaveDefault(breakNode);
}
@@ -233,7 +232,7 @@ public abstract class NodeVisitor {
* @param callNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
return enterDefault(callNode);
}
@@ -243,7 +242,7 @@ public abstract class NodeVisitor {
* @param callNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
return leaveDefault(callNode);
}
@@ -253,7 +252,7 @@ public abstract class NodeVisitor {
* @param caseNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CaseNode caseNode) {
+ public Node enterCaseNode(final CaseNode caseNode) {
return enterDefault(caseNode);
}
@@ -263,7 +262,7 @@ public abstract class NodeVisitor {
* @param caseNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CaseNode caseNode) {
+ public Node leaveCaseNode(final CaseNode caseNode) {
return leaveDefault(caseNode);
}
@@ -273,7 +272,7 @@ public abstract class NodeVisitor {
* @param catchNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
return enterDefault(catchNode);
}
@@ -283,7 +282,7 @@ public abstract class NodeVisitor {
* @param catchNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
return leaveDefault(catchNode);
}
@@ -293,7 +292,7 @@ public abstract class NodeVisitor {
* @param continueNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
return enterDefault(continueNode);
}
@@ -303,7 +302,7 @@ public abstract class NodeVisitor {
* @param continueNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ContinueNode continueNode) {
+ public Node leaveContinueNode(final ContinueNode continueNode) {
return leaveDefault(continueNode);
}
@@ -313,7 +312,7 @@ public abstract class NodeVisitor {
* @param doWhileNode the node
* @return processed node
*/
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
return enterDefault(doWhileNode);
}
@@ -323,7 +322,7 @@ public abstract class NodeVisitor {
* @param doWhileNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final DoWhileNode doWhileNode) {
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
return leaveDefault(doWhileNode);
}
@@ -333,7 +332,7 @@ public abstract class NodeVisitor {
* @param emptyNode the node
* @return processed node
*/
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return enterDefault(emptyNode);
}
@@ -343,7 +342,7 @@ public abstract class NodeVisitor {
* @param emptyNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final EmptyNode emptyNode) {
+ public Node leaveEmptyNode(final EmptyNode emptyNode) {
return leaveDefault(emptyNode);
}
@@ -353,7 +352,7 @@ public abstract class NodeVisitor {
* @param executeNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
return enterDefault(executeNode);
}
@@ -363,7 +362,7 @@ public abstract class NodeVisitor {
* @param executeNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
return leaveDefault(executeNode);
}
@@ -373,7 +372,7 @@ public abstract class NodeVisitor {
* @param forNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
return enterDefault(forNode);
}
@@ -383,7 +382,7 @@ public abstract class NodeVisitor {
* @param forNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
return leaveDefault(forNode);
}
@@ -393,7 +392,7 @@ public abstract class NodeVisitor {
* @param functionNode the node
* @return processed node
*/
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
return enterDefault(functionNode);
}
@@ -403,7 +402,7 @@ public abstract class NodeVisitor {
* @param functionNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final FunctionNode functionNode) {
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
return leaveDefault(functionNode);
}
@@ -413,7 +412,7 @@ public abstract class NodeVisitor {
* @param identNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
return enterDefault(identNode);
}
@@ -423,7 +422,7 @@ public abstract class NodeVisitor {
* @param identNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IdentNode identNode) {
+ public Node leaveIdentNode(final IdentNode identNode) {
return leaveDefault(identNode);
}
@@ -433,7 +432,7 @@ public abstract class NodeVisitor {
* @param ifNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
return enterDefault(ifNode);
}
@@ -443,7 +442,7 @@ public abstract class NodeVisitor {
* @param ifNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
return leaveDefault(ifNode);
}
@@ -453,7 +452,7 @@ public abstract class NodeVisitor {
* @param indexNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
return enterDefault(indexNode);
}
@@ -463,7 +462,7 @@ public abstract class NodeVisitor {
* @param indexNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
return leaveDefault(indexNode);
}
@@ -473,7 +472,7 @@ public abstract class NodeVisitor {
* @param labelNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
return enterDefault(labelNode);
}
@@ -483,7 +482,7 @@ public abstract class NodeVisitor {
* @param labelNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final LabelNode labelNode) {
+ public Node leaveLabelNode(final LabelNode labelNode) {
return leaveDefault(labelNode);
}
@@ -493,7 +492,7 @@ public abstract class NodeVisitor {
* @param lineNumberNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
return enterDefault(lineNumberNode);
}
@@ -503,7 +502,7 @@ public abstract class NodeVisitor {
* @param lineNumberNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final LineNumberNode lineNumberNode) {
+ public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
return leaveDefault(lineNumberNode);
}
@@ -513,8 +512,7 @@ public abstract class NodeVisitor {
* @param literalNode the node
* @return processed node
*/
- @SuppressWarnings("rawtypes")
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode<?> literalNode) {
return enterDefault(literalNode);
}
@@ -524,8 +522,7 @@ public abstract class NodeVisitor {
* @param literalNode the node
* @return processed node, which will replace the original one, or the original node
*/
- @SuppressWarnings("rawtypes")
- public Node leave(final LiteralNode literalNode) {
+ public Node leaveLiteralNode(final LiteralNode<?> literalNode) {
return leaveDefault(literalNode);
}
@@ -535,7 +532,7 @@ public abstract class NodeVisitor {
* @param objectNode the node
* @return processed node
*/
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
return enterDefault(objectNode);
}
@@ -545,7 +542,7 @@ public abstract class NodeVisitor {
* @param objectNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ObjectNode objectNode) {
+ public Node leaveObjectNode(final ObjectNode objectNode) {
return leaveDefault(objectNode);
}
@@ -555,7 +552,7 @@ public abstract class NodeVisitor {
* @param propertyNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
return enterDefault(propertyNode);
}
@@ -565,37 +562,17 @@ public abstract class NodeVisitor {
* @param propertyNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final PropertyNode propertyNode) {
+ public Node leavePropertyNode(final PropertyNode propertyNode) {
return leaveDefault(propertyNode);
}
/**
- * Callback for entering a ReferenceNode
- *
- * @param referenceNode the node
- * @return processed node, null if traversal should end
- */
- public Node enter(final ReferenceNode referenceNode) {
- return enterDefault(referenceNode);
- }
-
- /**
- * Callback for leaving a ReferenceNode
- *
- * @param referenceNode the node
- * @return processed node, which will replace the original one, or the original node
- */
- public Node leave(final ReferenceNode referenceNode) {
- return leaveDefault(referenceNode);
- }
-
- /**
* Callback for entering a ReturnNode
*
* @param returnNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
return enterDefault(returnNode);
}
@@ -605,7 +582,7 @@ public abstract class NodeVisitor {
* @param returnNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
return leaveDefault(returnNode);
}
@@ -615,7 +592,7 @@ public abstract class NodeVisitor {
* @param runtimeNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
return enterDefault(runtimeNode);
}
@@ -625,7 +602,7 @@ public abstract class NodeVisitor {
* @param runtimeNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
return leaveDefault(runtimeNode);
}
@@ -635,7 +612,7 @@ public abstract class NodeVisitor {
* @param splitNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
return enterDefault(splitNode);
}
@@ -645,7 +622,7 @@ public abstract class NodeVisitor {
* @param splitNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
return leaveDefault(splitNode);
}
@@ -655,7 +632,7 @@ public abstract class NodeVisitor {
* @param switchNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
return enterDefault(switchNode);
}
@@ -665,7 +642,7 @@ public abstract class NodeVisitor {
* @param switchNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
return leaveDefault(switchNode);
}
@@ -675,7 +652,7 @@ public abstract class NodeVisitor {
* @param ternaryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
return enterDefault(ternaryNode);
}
@@ -685,7 +662,7 @@ public abstract class NodeVisitor {
* @param ternaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
return leaveDefault(ternaryNode);
}
@@ -695,7 +672,7 @@ public abstract class NodeVisitor {
* @param throwNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
return enterDefault(throwNode);
}
@@ -705,7 +682,7 @@ public abstract class NodeVisitor {
* @param throwNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
return leaveDefault(throwNode);
}
@@ -715,7 +692,7 @@ public abstract class NodeVisitor {
* @param tryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
return enterDefault(tryNode);
}
@@ -725,7 +702,7 @@ public abstract class NodeVisitor {
* @param tryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
return leaveDefault(tryNode);
}
@@ -735,7 +712,7 @@ public abstract class NodeVisitor {
* @param unaryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final UnaryNode unaryNode) {
+ public Node enterUnaryNode(final UnaryNode unaryNode) {
return enterDefault(unaryNode);
}
@@ -745,7 +722,7 @@ public abstract class NodeVisitor {
* @param unaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final UnaryNode unaryNode) {
+ public Node leaveUnaryNode(final UnaryNode unaryNode) {
return leaveDefault(unaryNode);
}
@@ -755,7 +732,7 @@ public abstract class NodeVisitor {
* @param varNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
return enterDefault(varNode);
}
@@ -765,7 +742,7 @@ public abstract class NodeVisitor {
* @param varNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
return leaveDefault(varNode);
}
@@ -775,7 +752,7 @@ public abstract class NodeVisitor {
* @param whileNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
return enterDefault(whileNode);
}
@@ -785,7 +762,7 @@ public abstract class NodeVisitor {
* @param whileNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
return leaveDefault(whileNode);
}
@@ -795,7 +772,7 @@ public abstract class NodeVisitor {
* @param withNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
return enterDefault(withNode);
}
@@ -805,7 +782,7 @@ public abstract class NodeVisitor {
* @param withNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
return leaveDefault(withNode);
}
diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java
index b89d2073..e079248b 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -34,6 +34,9 @@ import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -256,13 +259,29 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Property(name = "Packages", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object packages;
+ /** Nashorn extension: Java access - global.com */
+ @Property(attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object com;
+
+ /** Nashorn extension: Java access - global.edu */
+ @Property(attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object edu;
+
/** Nashorn extension: Java access - global.java */
@Property(attributes = Attribute.NOT_ENUMERABLE)
public volatile Object java;
+ /** Nashorn extension: Java access - global.javafx */
+ @Property(attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object javafx;
+
/** Nashorn extension: Java access - global.javax */
@Property(attributes = Attribute.NOT_ENUMERABLE)
- public Object javax;
+ public volatile Object javax;
+
+ /** Nashorn extension: Java access - global.org */
+ @Property(attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object org;
/** Nashorn extension: Java access - global.javaImporter */
@Property(name = "JavaImporter", attributes = Attribute.NOT_ENUMERABLE)
@@ -317,8 +336,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private ScriptFunction builtinTypeError;
private ScriptFunction builtinURIError;
private ScriptObject builtinPackages;
+ private ScriptObject builtinCom;
+ private ScriptObject builtinEdu;
private ScriptObject builtinJava;
+ private ScriptObject builtinJavafx;
private ScriptObject builtinJavax;
+ private ScriptObject builtinOrg;
private ScriptObject builtinJavaImporter;
private ScriptObject builtinJavaApi;
private ScriptObject builtinArrayBuffer;
@@ -1479,8 +1502,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private void initJavaAccess() {
final ScriptObject objectProto = getObjectPrototype();
this.builtinPackages = new NativeJavaPackage("", objectProto);
+ this.builtinCom = new NativeJavaPackage("com", objectProto);
+ this.builtinEdu = new NativeJavaPackage("edu", objectProto);
this.builtinJava = new NativeJavaPackage("java", objectProto);
+ this.builtinJavafx = new NativeJavaPackage("javafx", objectProto);
this.builtinJavax = new NativeJavaPackage("javax", objectProto);
+ this.builtinOrg = new NativeJavaPackage("org", objectProto);
this.builtinJavaImporter = initConstructor("JavaImporter");
this.builtinJavaApi = initConstructor("Java");
}
@@ -1503,8 +1530,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
// Nashorn extension: global.$OPTIONS (scripting-mode-only)
- value = context.getEnv();
- addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, value);
+ final ScriptObject options = newEmptyInstance();
+ final ScriptEnvironment scriptEnv = context.getEnv();
+ copyOptions(options, scriptEnv);
+ addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, options);
// Nashorn extension: global.$ENV (scripting-mode-only)
if (System.getSecurityManager() == null) {
@@ -1523,6 +1552,22 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
addOwnProperty(ScriptingFunctions.EXIT_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
}
+ private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ for (Field f : scriptEnv.getClass().getFields()) {
+ try {
+ options.set(f.getName(), f.get(scriptEnv), false);
+ } catch (final IllegalArgumentException | IllegalAccessException exp) {
+ throw new RuntimeException(exp);
+ }
+ }
+ return null;
+ }
+ });
+ }
+
private void initTypedArray() {
this.builtinArrayBuffer = initConstructor("ArrayBuffer");
this.builtinInt8Array = initConstructor("Int8Array");
@@ -1545,8 +1590,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
this.function = this.builtinFunction;
this.jsadapter = this.builtinJSAdapter;
this.json = this.builtinJSON;
+ this.com = this.builtinCom;
+ this.edu = this.builtinEdu;
this.java = this.builtinJava;
+ this.javafx = this.builtinJavafx;
this.javax = this.builtinJavax;
+ this.org = this.builtinOrg;
this.javaImporter = this.builtinJavaImporter;
this.javaApi = this.builtinJavaApi;
this.math = this.builtinMath;
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index 31c1d972..16e237ba 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -605,7 +605,7 @@ public final class NativeArray extends ScriptObject {
final boolean strict = sobj.isStrictContext();
if (bulkable(sobj)) {
- return ((NativeArray)sobj).getArray().pop();
+ return sobj.getArray().pop();
}
final long len = JSType.toUint32(sobj.getLength());
@@ -725,7 +725,7 @@ public final class NativeArray extends ScriptObject {
first = sobj.get(0);
if (bulkable(sobj)) {
- ((NativeArray) sobj).getArray().shiftLeft(1);
+ sobj.getArray().shiftLeft(1);
} else {
for (long k = 1; k < len; k++) {
sobj.set(k - 1, sobj.get(k), strict);
diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java
index 3d6fcbc8..b311981e 100644
--- a/src/jdk/nashorn/internal/objects/NativeDebug.java
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java
@@ -66,7 +66,7 @@ public final class NativeDebug extends ScriptObject {
public static Object getContext(final Object self) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new RuntimePermission("getNashornContext"));
+ sm.checkPermission(new RuntimePermission("nashorn.getContext"));
}
return Global.getThisContext();
}
@@ -162,21 +162,6 @@ public final class NativeDebug extends ScriptObject {
}
/**
- * Nashorn extension: get invocation handle from {@link ScriptFunction}
- *
- * @param self self reference
- * @param obj script function
- * @return the invocation handle for the given ScriptFunction
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object methodHandle(final Object self, final Object obj) {
- if (obj instanceof ScriptFunction) {
- return ((ScriptFunction)obj).getInvokeHandle();
- }
- return UNDEFINED;
- }
-
- /**
* Check object identity comparison regardless of type
*
* @param self self reference
diff --git a/src/jdk/nashorn/internal/objects/NativeError.java b/src/jdk/nashorn/internal/objects/NativeError.java
index 8cea0c70..433f9317 100644
--- a/src/jdk/nashorn/internal/objects/NativeError.java
+++ b/src/jdk/nashorn/internal/objects/NativeError.java
@@ -317,7 +317,7 @@ public final class NativeError extends ScriptObject {
return name;
}
// Step 10 : return name + ": " + msg
- return (String)name + ": " + (String)msg;
+ return name + ": " + msg;
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
diff --git a/src/jdk/nashorn/internal/objects/NativeJava.java b/src/jdk/nashorn/internal/objects/NativeJava.java
index fc16962e..2519c028 100644
--- a/src/jdk/nashorn/internal/objects/NativeJava.java
+++ b/src/jdk/nashorn/internal/objects/NativeJava.java
@@ -223,6 +223,23 @@ public final class NativeJava {
}
/**
+ * Returns name of a java type {@link StaticClass}.
+ * @param self not used
+ * @param type the type whose name is returned
+ * @return name of the given type
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+ public static Object typeName(final Object self, final Object type) {
+ if (type instanceof StaticClass) {
+ return ((StaticClass)type).getRepresentedClass().getName();
+ } else if (type instanceof Class) {
+ return ((Class<?>)type).getName();
+ } else {
+ return UNDEFINED;
+ }
+ }
+
+ /**
* Given a JavaScript array and a Java type, returns a Java array with the same initial contents, and with the
* specified component type. Example:
* <pre>
diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java
index b2b1cf2b..5f48ad98 100644
--- a/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk/nashorn/internal/objects/NativeString.java
@@ -122,6 +122,19 @@ public final class NativeString extends ScriptObject {
return value.length();
}
+ // This is to support length as method call as well.
+ @Override
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ final String name = desc.getNameToken(2);
+
+ // if str.length(), then let the bean linker handle it
+ if ("length".equals(name) && "getMethod".equals(operator)) {
+ return null;
+ }
+
+ return super.findGetMethod(desc, request, operator);
+ }
+
// This is to provide array-like access to string characters without creating a NativeString wrapper.
@Override
protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index 0514bd25..46b353f1 100644
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -31,6 +31,7 @@ import java.lang.invoke.MethodHandle;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -86,8 +87,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param builtin is this a built-in function
* @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
*/
- ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
- super(name, methodHandle, getMap(strict), scope, specs, strict, builtin, isConstructor);
+ ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+ super(name, methodHandle, getMap(isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
init();
}
@@ -95,14 +96,10 @@ public class ScriptFunctionImpl extends ScriptFunction {
* Constructor called by (compiler) generated code for {@link ScriptObject}s.
*
* @param data static function data
- * @param methodHandle handle for invocation
* @param scope scope object
- * @param allocator instance constructor for function
*/
- public ScriptFunctionImpl(final MethodHandle methodHandle, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) {
+ public ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope) {
super(data, getMap(data.isStrict()), scope);
- // Set method handles in script data
- data.setMethodHandles(methodHandle, allocator);
init();
}
diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java
deleted file mode 100644
index 4d3df509..00000000
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionTrampolineImpl.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package jdk.nashorn.internal.objects;
-
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import jdk.nashorn.internal.codegen.CompilationException;
-import jdk.nashorn.internal.codegen.Compiler;
-import jdk.nashorn.internal.codegen.FunctionSignature;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.runtime.CodeInstaller;
-import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.ScriptEnvironment;
-import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-
-/**
- * A trampoline is a promise to compile a {@link ScriptFunction} later. It just looks like
- * the call to the script function, but when invoked it will compile the script function
- * (in a new compile unit) and invoke it
- */
-public final class ScriptFunctionTrampolineImpl extends ScriptFunctionImpl {
-
- private CodeInstaller<ScriptEnvironment> installer;
-
- /** Function node to lazily recompile when trampoline is hit */
- private FunctionNode functionNode;
-
- /**
- * Constructor
- *
- * @param installer opaque code installer from context
- * @param functionNode function node to lazily compile when trampoline is hit
- * @param data {@link ScriptFunctionData} for function
- * @param scope scope
- * @param allocator allocator
- */
- public ScriptFunctionTrampolineImpl(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final ScriptFunctionData data, final ScriptObject scope, final MethodHandle allocator) {
- super(null, data, scope, allocator);
-
- this.installer = installer;
- this.functionNode = functionNode;
-
- data.setMethodHandles(makeTrampoline(), allocator);
- }
-
- private final MethodHandle makeTrampoline() {
- final MethodType mt =
- new FunctionSignature(
- true,
- functionNode.needsCallee(),
- Type.OBJECT,
- functionNode.getParameters().size()).
- getMethodType();
-
- return
- MH.bindTo(
- MH.asCollector(
- findOwnMH(
- "trampoline",
- Object.class,
- Object[].class),
- Object[].class,
- mt.parameterCount()),
- this);
- }
-
- private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- return MH.findVirtual(MethodHandles.lookup(), ScriptFunctionTrampolineImpl.class, name, MH.type(rtype, types));
- }
-
- @Override
- protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) {
- //prevent trampoline recompilation cycle if a function is bound before use
- compile();
- return super.makeBoundFunction(data);
- }
-
- private MethodHandle compile() throws CompilationException {
- final Compiler compiler = new Compiler(installer, functionNode);
-
- compiler.compile();
-
- final Class<?> clazz = compiler.install();
- /* compute function signature for lazy method. this can be done first after compilation, as only then do we know
- * the final state about callees, scopes and specialized parameter types */
- final FunctionSignature signature = new FunctionSignature(true, functionNode.needsCallee(), Type.OBJECT, functionNode.getParameters().size());
- final MethodType mt = signature.getMethodType();
-
- MethodHandle mh = MH.findStatic(MethodHandles.publicLookup(), clazz, functionNode.getName(), mt);
- if (functionNode.needsCallee()) {
- mh = MH.bindTo(mh, this);
- }
-
- // now the invoker method looks like the one our superclass is expecting
- resetInvoker(mh);
-
- return mh;
- }
-
- @SuppressWarnings("unused")
- private Object trampoline(final Object... args) throws CompilationException {
- Compiler.LOG.info(">>> TRAMPOLINE: Hitting trampoline for '" + functionNode.getName() + "'");
- MethodHandle mh = compile();
-
- Compiler.LOG.info("<<< COMPILED TO: " + mh);
- // spread the array to invididual args of the correct type
- mh = MH.asSpreader(mh, Object[].class, mh.type().parameterCount());
-
- try {
- //invoke the real method the trampoline points to. this only happens once
- return mh.invoke(args);
- } catch (final RuntimeException | Error e) {
- throw e;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
- }
-}
diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java
index 39cf549e..5468ca3d 100644
--- a/src/jdk/nashorn/internal/parser/JSONParser.java
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java
@@ -313,7 +313,7 @@ loop:
}
// Construct new object literal.
- return new ObjectNode(source, objectToken, finish, null, elements);
+ return new ObjectNode(source, objectToken, finish, elements);
}
/**
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index 41149e4b..b810043e 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -56,6 +56,7 @@ import static jdk.nashorn.internal.parser.TokenType.WHILE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
@@ -75,17 +76,18 @@ import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyKey;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SwitchNode;
@@ -96,7 +98,6 @@ import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSErrorType;
@@ -116,19 +117,13 @@ public class Parser extends AbstractParser {
/** Is scripting mode. */
private final boolean scripting;
- /** Top level script being parsed. */
- private FunctionNode script;
-
- /** Current function being parsed. */
- private FunctionNode function;
-
- /** Current parsing block. */
- private Block block;
+ private final LexicalContext lexicalContext = new LexicalContext();
+ private List<Node> functionDeclarations;
/** Namespace for function names where not explicitly given */
private final Namespace namespace;
- private static DebugLogger LOG = new DebugLogger("parser");
+ private static final DebugLogger LOG = new DebugLogger("parser");
/**
* Constructor
@@ -279,7 +274,9 @@ loop:
* @return New block.
*/
private Block newBlock() {
- return block = new Block(source, token, Token.descPosition(token), block, function);
+ final Block block = new Block(source, token, Token.descPosition(token));
+ lexicalContext.push(block);
+ return block;
}
/**
@@ -292,18 +289,23 @@ loop:
// Build function name.
final StringBuilder sb = new StringBuilder();
- if (block != null) {
- block.addParentName(sb);
+ final FunctionNode parentFunction = getFunction();
+ if(parentFunction != null && !parentFunction.isProgram()) {
+ sb.append(parentFunction.getName()).append('$');
}
sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
final String name = namespace.uniqueName(sb.toString());
- assert function != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript().
+ assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript().
// Start new block.
- final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name);
- block = function = functionBlock;
- function.setStrictMode(isStrictMode);
+ final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
+ if(parentFunction == null) {
+ functionBlock.setProgram();
+ }
+ functionBlock.setStrictMode(isStrictMode);
+ functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+ lexicalContext.push(functionBlock);
return functionBlock;
}
@@ -311,9 +313,8 @@ loop:
/**
* Restore the current block.
*/
- private void restoreBlock() {
- block = block.getParent();
- function = block.getFunction();
+ private void restoreBlock(Block block) {
+ lexicalContext.pop(block);
}
/**
@@ -323,22 +324,25 @@ loop:
private Block getBlock(final boolean needsBraces) {
// Set up new block. Captures LBRACE.
final Block newBlock = newBlock();
- pushControlNode(newBlock);
+ try {
+ pushControlNode(newBlock);
- // Block opening brace.
- if (needsBraces) {
- expect(LBRACE);
- }
+ // Block opening brace.
+ if (needsBraces) {
+ expect(LBRACE);
+ }
- try {
- // Accumulate block statements.
- statementList();
+ try {
+ // Accumulate block statements.
+ statementList();
+ } finally {
+ popControlNode();
+ }
} finally {
- restoreBlock();
- popControlNode();
+ restoreBlock(newBlock);
}
- final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
+ final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
// Block closing brace.
if (needsBraces) {
@@ -365,7 +369,7 @@ loop:
// Accumulate statements.
statement();
} finally {
- restoreBlock();
+ restoreBlock(newBlock);
}
return newBlock;
@@ -379,7 +383,10 @@ loop:
final String name = ident.getName();
if (EVAL.tag().equals(name)) {
- function.setHasEval();
+ final Iterator<FunctionNode> it = lexicalContext.getFunctions();
+ if(it.hasNext()) {
+ it.next().setHasEval(it);
+ }
}
}
@@ -391,7 +398,7 @@ loop:
final String name = ident.getName();
if (ARGUMENTS.tag().equals(name)) {
- function.setUsesArguments();
+ getFunction().setUsesArguments();
}
}
@@ -438,7 +445,7 @@ loop:
}
if (lhs instanceof IdentNode) {
- if (! checkIdentLValue((IdentNode)lhs)) {
+ if (!checkIdentLValue((IdentNode)lhs)) {
return referenceError(lhs, rhs);
}
verifyStrictIdent((IdentNode)lhs, "assignment");
@@ -482,7 +489,7 @@ loop:
* @return null or the found label node.
*/
private LabelNode findLabel(final IdentNode ident) {
- for (final LabelNode labelNode : function.getLabelStack()) {
+ for (final LabelNode labelNode : getFunction().getLabelStack()) {
if (labelNode.getLabel().equals(ident)) {
return labelNode;
}
@@ -496,14 +503,14 @@ loop:
* @param labelNode Label to add.
*/
private void pushLabel(final LabelNode labelNode) {
- function.getLabelStack().push(labelNode);
+ getFunction().getLabelStack().push(labelNode);
}
/**
* Remove a label from the label stack.
*/
private void popLabel() {
- function.getLabelStack().pop();
+ getFunction().getLabelStack().pop();
}
/**
@@ -513,6 +520,7 @@ loop:
private void pushControlNode(final Node node) {
final boolean isLoop = node instanceof WhileNode;
final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
+ final FunctionNode function = getFunction();
function.getControlStack().push(node);
for (final LabelNode labelNode : function.getLabelStack()) {
@@ -531,7 +539,7 @@ loop:
*/
private void popControlNode() {
// Get control stack.
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
// Can be empty if missing brace.
if (!controlStack.isEmpty()) {
@@ -541,7 +549,7 @@ loop:
private void popControlNode(final Node node) {
// Get control stack.
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
// Can be empty if missing brace.
if (!controlStack.isEmpty() && controlStack.peek() == node) {
@@ -550,7 +558,7 @@ loop:
}
private boolean isInWithBlock() {
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -563,7 +571,7 @@ loop:
}
private <T extends Node> T findControl(final Class<T> ctype) {
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -577,7 +585,7 @@ loop:
private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
final List<T> nodes = new ArrayList<>();
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -621,15 +629,16 @@ loop:
// Make a fake token for the script.
final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
// Set up the script to append elements.
- script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
- // set kind to be SCRIPT
+
+ final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
+
script.setKind(FunctionNode.Kind.SCRIPT);
- // Set the first token of the script.
script.setFirstToken(functionToken);
- // Gather source elements.
+ functionDeclarations = new ArrayList<>();
sourceElements();
+ script.prependStatements(functionDeclarations);
+ functionDeclarations = null;
expect(EOF);
- // Set the last token of the script.
script.setLastToken(token);
script.setFinish(source.getLength() - 1);
@@ -707,7 +716,7 @@ loop:
// check for directive prologues
if (checkDirective) {
// skip any debug statement like line number to get actual first line
- final Node lastStatement = lastStatement(block.getStatements());
+ final Node lastStatement = lastStatement(getBlock().getStatements());
// get directive prologue, if any
final String directive = getDirective(lastStatement);
@@ -727,6 +736,7 @@ loop:
// handle use strict directive
if ("use strict".equals(directive)) {
isStrictMode = true;
+ final FunctionNode function = getFunction();
function.setStrictMode(true);
// We don't need to check these, if lexical environment is already strict
@@ -799,11 +809,11 @@ loop:
if (isStrictMode && !topLevel) {
error(AbstractParser.message("strict.no.func.here"), token);
}
- functionExpression(true);
+ functionExpression(true, topLevel);
return;
}
- block.addStatement(lineNumberNode);
+ getBlock().addStatement(lineNumberNode);
switch (type) {
case LBRACE:
@@ -889,7 +899,7 @@ loop:
// Force block execution.
final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
- block.addStatement(executeNode);
+ getBlock().addStatement(executeNode);
}
/**
@@ -984,13 +994,9 @@ loop:
// Allocate var node.
final VarNode var = new VarNode(source, varToken, finish, name, init);
- if (isStatement) {
- function.addDeclaration(var);
- }
-
vars.add(var);
// Add to current block.
- block.addStatement(var);
+ getBlock().addStatement(var);
if (type != COMMARIGHT) {
break;
@@ -1003,7 +1009,7 @@ loop:
boolean semicolon = type == SEMICOLON;
endOfLine();
if (semicolon) {
- block.setFinish(finish);
+ getBlock().setFinish(finish);
}
}
@@ -1020,7 +1026,7 @@ loop:
*/
private void emptyStatement() {
if (env._empty_statements) {
- block.addStatement(new EmptyNode(source, token,
+ getBlock().addStatement(new EmptyNode(source, token,
Token.descPosition(token) + Token.descLength(token)));
}
@@ -1046,7 +1052,7 @@ loop:
ExecuteNode executeNode = null;
if (expression != null) {
executeNode = new ExecuteNode(source, expressionToken, finish, expression);
- block.addStatement(executeNode);
+ getBlock().addStatement(executeNode);
} else {
expect(null);
}
@@ -1055,7 +1061,7 @@ loop:
if (executeNode != null) {
executeNode.setFinish(finish);
- block.setFinish(finish);
+ getBlock().setFinish(finish);
}
}
@@ -1097,7 +1103,7 @@ loop:
// Construct and add new if node.
final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
- block.addStatement(ifNode);
+ getBlock().addStatement(ifNode);
}
/**
@@ -1146,13 +1152,13 @@ loop:
outer.setFinish(body.getFinish());
// Add for to current block.
- block.addStatement(forNode);
+ getBlock().addStatement(forNode);
} finally {
- restoreBlock();
+ restoreBlock(outer);
popControlNode();
}
- block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1231,7 +1237,7 @@ loop:
}
if (init instanceof IdentNode) {
- if (! checkIdentLValue((IdentNode)init)) {
+ if (!checkIdentLValue((IdentNode)init)) {
error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
}
verifyStrictIdent((IdentNode)init, "for-in iterator");
@@ -1286,7 +1292,7 @@ loop:
whileNode.setFinish(statements.getFinish());
// Add WHILE node.
- block.addStatement(whileNode);
+ getBlock().addStatement(whileNode);
} finally {
popControlNode();
}
@@ -1333,7 +1339,7 @@ loop:
doWhileNode.setFinish(finish);
// Add DO node.
- block.addStatement(doWhileNode);
+ getBlock().addStatement(doWhileNode);
} finally {
popControlNode();
}
@@ -1385,7 +1391,7 @@ loop:
final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
- block.addStatement(continueNode);
+ getBlock().addStatement(continueNode);
}
/**
@@ -1433,7 +1439,7 @@ loop:
final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
- block.addStatement(breakNode);
+ getBlock().addStatement(breakNode);
}
/**
@@ -1446,7 +1452,7 @@ loop:
*/
private void returnStatement() {
// check for return outside function
- if (function.getKind() == FunctionNode.Kind.SCRIPT) {
+ if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
error(AbstractParser.message("invalid.return"));
}
@@ -1473,7 +1479,7 @@ loop:
// Construct and add RETURN node.
final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
- block.addStatement(returnNode);
+ getBlock().addStatement(returnNode);
}
/**
@@ -1508,7 +1514,7 @@ loop:
// Construct and add YIELD node.
final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
- block.addStatement(yieldNode);
+ getBlock().addStatement(yieldNode);
}
/**
@@ -1532,7 +1538,10 @@ loop:
// Get WITH expression.
final WithNode withNode = new WithNode(source, withToken, finish, null, null);
- function.setHasWith();
+ final Iterator<FunctionNode> it = lexicalContext.getFunctions();
+ if(it.hasNext()) {
+ it.next().setHasWith(it);
+ }
try {
pushControlNode(withNode);
@@ -1552,7 +1561,7 @@ loop:
popControlNode(withNode);
}
- block.addStatement(withNode);
+ getBlock().addStatement(withNode);
}
/**
@@ -1652,7 +1661,7 @@ loop:
switchNode.setFinish(finish);
- block.addStatement(switchNode);
+ getBlock().addStatement(switchNode);
} finally {
popControlNode();
}
@@ -1687,7 +1696,7 @@ loop:
labelNode.setBody(statements);
labelNode.setFinish(finish);
- block.addStatement(labelNode);
+ getBlock().addStatement(labelNode);
} finally {
// Remove label.
popLabel();
@@ -1730,7 +1739,7 @@ loop:
// Construct and add THROW node.
final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
- block.addStatement(throwNode);
+ getBlock().addStatement(throwNode);
}
/**
@@ -1796,18 +1805,18 @@ loop:
expect(RPAREN);
+ final Block catchBlock = newBlock();
try {
- final Block catchBlock = newBlock();
// Get CATCH body.
final Block catchBody = getBlock(true);
// Create and add catch.
final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
- block.addStatement(catchNode);
+ getBlock().addStatement(catchNode);
catchBlocks.add(catchBlock);
} finally {
- restoreBlock();
+ restoreBlock(catchBlock);
}
// If unconditional catch then should to be the end.
@@ -1843,11 +1852,11 @@ loop:
outer.addStatement(tryNode);
} finally {
popControlNode(tryNode);
- restoreBlock();
+ restoreBlock(outer);
popControlNode(outer);
}
- block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1867,7 +1876,7 @@ loop:
endOfLine();
final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
- block.addStatement(runtimeNode);
+ getBlock().addStatement(runtimeNode);
}
/**
@@ -2026,7 +2035,7 @@ loop:
break;
default:
- if (! elision) {
+ if (!elision) {
error(AbstractParser.message("expected.comma", type.getNameOrType()));
}
// Add expression element.
@@ -2067,15 +2076,11 @@ loop:
next();
// Object context.
- Block objectContext = null;
// Prepare to accumulate elements.
final List<Node> elements = new ArrayList<>();
final Map<Object, PropertyNode> map = new HashMap<>();
- try {
- // Create a block for the object literal.
- objectContext = newBlock();
-
+ // Create a block for the object literal.
boolean commaSeen = true;
loop:
while (true) {
@@ -2090,97 +2095,90 @@ loop:
break;
default:
- if (! commaSeen) {
+ if (!commaSeen) {
error(AbstractParser.message("expected.comma", type.getNameOrType()));
- }
-
- commaSeen = false;
- // Get and add the next property.
- final PropertyNode property = propertyAssignment();
- final Object key = property.getKeyName();
- final PropertyNode existingProperty = map.get(key);
-
- if (existingProperty != null) {
- // ECMA section 11.1.5 Object Initialiser
- // point # 4 on property assignment production
- final Node value = property.getValue();
- final Node getter = property.getGetter();
- final Node setter = property.getSetter();
-
- final Node prevValue = existingProperty.getValue();
- final Node prevGetter = existingProperty.getGetter();
- final Node prevSetter = existingProperty.getSetter();
-
- boolean redefinitionOk = true;
- // ECMA 11.1.5 strict mode restrictions
- if (isStrictMode) {
- if (value != null && prevValue != null) {
- redefinitionOk = false;
- }
- }
-
- final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
- final boolean isAccessor = getter != null || setter != null;
+ }
- // data property redefined as accessor property
- if (prevValue != null && isAccessor) {
+ commaSeen = false;
+ // Get and add the next property.
+ final PropertyNode property = propertyAssignment();
+ final Object key = property.getKeyName();
+ final PropertyNode existingProperty = map.get(key);
+
+ if (existingProperty != null) {
+ // ECMA section 11.1.5 Object Initialiser
+ // point # 4 on property assignment production
+ final Node value = property.getValue();
+ final Node getter = property.getGetter();
+ final Node setter = property.getSetter();
+
+ final Node prevValue = existingProperty.getValue();
+ final Node prevGetter = existingProperty.getGetter();
+ final Node prevSetter = existingProperty.getSetter();
+
+ boolean redefinitionOk = true;
+ // ECMA 11.1.5 strict mode restrictions
+ if (isStrictMode) {
+ if (value != null && prevValue != null) {
redefinitionOk = false;
}
+ }
- // accessor property redefined as data
- if (isPrevAccessor && value != null) {
- redefinitionOk = false;
- }
+ final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
+ final boolean isAccessor = getter != null || setter != null;
- if (isAccessor && isPrevAccessor) {
- if (getter != null && prevGetter != null ||
- setter != null && prevSetter != null) {
- redefinitionOk = false;
- }
- }
+ // data property redefined as accessor property
+ if (prevValue != null && isAccessor) {
+ redefinitionOk = false;
+ }
+
+ // accessor property redefined as data
+ if (isPrevAccessor && value != null) {
+ redefinitionOk = false;
+ }
- if (! redefinitionOk) {
- error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
+ if (isAccessor && isPrevAccessor) {
+ if (getter != null && prevGetter != null ||
+ setter != null && prevSetter != null) {
+ redefinitionOk = false;
}
+ }
- if (value != null) {
- final Node existingValue = existingProperty.getValue();
+ if (!redefinitionOk) {
+ error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
+ }
- if (existingValue == null) {
- existingProperty.setValue(value);
- } else {
- final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
- existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
- }
+ if (value != null) {
+ final Node existingValue = existingProperty.getValue();
- existingProperty.setGetter(null);
- existingProperty.setSetter(null);
+ if (existingValue == null) {
+ existingProperty.setValue(value);
+ } else {
+ final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
+ existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
}
- if (getter != null) {
- existingProperty.setGetter(getter);
- }
+ existingProperty.setGetter(null);
+ existingProperty.setSetter(null);
+ }
- if (setter != null) {
- existingProperty.setSetter(setter);
- }
- } else {
- map.put(key, property);
- elements.add(property);
+ if (getter != null) {
+ existingProperty.setGetter(getter);
}
- break;
+ if (setter != null) {
+ existingProperty.setSetter(setter);
+ }
+ } else {
+ map.put(key, property);
+ elements.add(property);
}
+
+ break;
}
- } finally {
- restoreBlock();
}
- // Construct new object literal.
- objectContext.setFinish(finish);
- objectContext.setStart(Token.descPosition(objectToken));
-
- return new ObjectNode(source, objectToken, finish, objectContext, elements);
+ return new ObjectNode(source, objectToken, finish, elements);
}
/**
@@ -2258,7 +2256,7 @@ loop:
parameters = new ArrayList<>();
functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
- propertyNode.setGetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+ propertyNode.setGetter(functionNode);
return propertyNode;
case "set":
@@ -2273,7 +2271,7 @@ loop:
parameters.add(argIdent);
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
- propertyNode.setSetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+ propertyNode.setSetter(functionNode);
return propertyNode;
default:
@@ -2454,7 +2452,7 @@ loop:
case FUNCTION:
// Get function expression.
- lhs = functionExpression(false);
+ lhs = functionExpression(false, false);
break;
default:
@@ -2559,7 +2557,7 @@ loop:
*
* @return Expression node.
*/
- private Node functionExpression(final boolean isStatement) {
+ private Node functionExpression(final boolean isStatement, final boolean topLevel) {
final LineNumberNode lineNumber = lineNumber();
final long functionToken = token;
@@ -2594,10 +2592,12 @@ loop:
final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
- if (isStatement && !isInWithBlock()) {
- functionNode.setIsStatement();
+ if (isStatement) {
+ if(topLevel) {
+ functionNode.setIsDeclared();
+ }
if(ARGUMENTS.tag().equals(name.getName())) {
- functionNode.findParentFunction().setDefinesArguments();
+ getFunction().setDefinesArguments();
}
}
@@ -2605,8 +2605,6 @@ loop:
functionNode.setIsAnonymous();
}
- final ReferenceNode referenceNode = new ReferenceNode(source, functionToken, finish, functionNode);
-
final int arity = parameters.size();
final boolean strict = functionNode.isStrictMode();
@@ -2642,17 +2640,18 @@ loop:
}
if (isStatement) {
- final VarNode var = new VarNode(source, functionToken, finish, name, referenceNode);
- if (isInWithBlock()) {
- function.addDeclaration(var);
- // Add to current block.
- block.addStatement(var);
+ final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
+ if(topLevel) {
+ functionDeclarations.add(lineNumber);
+ functionDeclarations.add(varNode);
} else {
- functionNode.setFunctionVarNode(var, lineNumber);
+ final Block block = getBlock();
+ block.addStatement(lineNumber);
+ block.addStatement(varNode);
}
}
- return referenceNode;
+ return functionNode;
}
/**
@@ -2735,7 +2734,14 @@ loop:
expect(LBRACE);
// Gather the function elements.
- sourceElements();
+ final List<Node> prevFunctionDecls = functionDeclarations;
+ functionDeclarations = new ArrayList<>();
+ try {
+ sourceElements();
+ functionNode.prependStatements(functionDeclarations);
+ } finally {
+ functionDeclarations = prevFunctionDecls;
+ }
functionNode.setLastToken(token);
expect(RBRACE);
@@ -2743,12 +2749,9 @@ loop:
}
} finally {
- restoreBlock();
+ restoreBlock(functionNode);
}
- // Add the body of the function to the current block.
- block.addFunction(functionNode);
-
return functionNode;
}
@@ -2845,7 +2848,7 @@ loop:
}
if (lhs instanceof IdentNode) {
- if (! checkIdentLValue((IdentNode)lhs)) {
+ if (!checkIdentLValue((IdentNode)lhs)) {
return referenceError(lhs, null);
}
verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
@@ -2872,7 +2875,7 @@ loop:
return referenceError(lhs, null);
}
if (lhs instanceof IdentNode) {
- if (! checkIdentLValue((IdentNode)lhs)) {
+ if (!checkIdentLValue((IdentNode)lhs)) {
next();
return referenceError(lhs, null);
}
@@ -3083,4 +3086,12 @@ loop:
public String toString() {
return "[JavaScript Parsing]";
}
+
+ private Block getBlock() {
+ return lexicalContext.getCurrentBlock();
+ }
+
+ private FunctionNode getFunction() {
+ return lexicalContext.getCurrentFunction();
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index 9f6867dd..996bea35 100644
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -164,7 +164,6 @@ public class AccessorProperty extends Property {
super(key, flags, slot);
/*
- *
* primitiveGetter and primitiveSetter are only used in dual fields mode. Setting them to null also
* works in dual field mode, it only means that the property never has a primitive
* representation.
@@ -348,11 +347,10 @@ public class AccessorProperty extends Property {
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
if (DEBUG_FIELDS) {
- final MethodHandle mhd = MethodHandleFactory.addDebugPrintout(
+ return MethodHandleFactory.addDebugPrintout(
LOG,
mh,
tag + " '" + getKey() + "' (property="+ Debug.id(this) + ", forType=" + stripName(forType) + ", type=" + stripName(type) + ')');
- return mhd;
}
return mh;
}
diff --git a/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
index 5fd16528..80fac179 100644
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
@@ -25,6 +25,8 @@
package jdk.nashorn.internal.runtime;
+import jdk.nashorn.internal.codegen.ClassEmitter;
+
/**
* Interface for installing classes passed to the compiler.
* As only the code generating package (i.e. Context) knows about
@@ -52,12 +54,12 @@ public interface CodeInstaller<T> {
*/
public Class<?> install(final String className, final byte[] bytecode);
- /*
+ /**
* Verify generated bytecode before emission. This is called back from the
* {@link ClassEmitter} or the {@link Compiler}. If the "--verify-code" parameter
* hasn't been given, this is a nop
*
- * @param bytecode bytecode to verify
+ * @param code bytecode to verify
*/
public void verify(final byte[] code);
}
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
new file mode 100644
index 00000000..3cc9f09d
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2010, 2013, 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.runtime;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+
+import jdk.nashorn.internal.codegen.types.Type;
+
+/**
+ * An version of a JavaScript function, native or JavaScript.
+ * Supports lazily generating a constructor version of the invocation.
+ */
+final class CompiledFunction implements Comparable<CompiledFunction> {
+
+ private final MethodHandle invoker;
+ private MethodHandle constructor;
+
+ CompiledFunction(final MethodHandle invoker) {
+ this(invoker, null);
+ }
+
+ CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
+ this.invoker = invoker;
+ this.constructor = constructor; //isConstructor
+ }
+
+ @Override
+ public String toString() {
+ return "<invoker=" + invoker + " ctor=" + constructor + ">";
+ }
+
+ MethodHandle getInvoker() {
+ return invoker;
+ }
+
+ MethodHandle getConstructor() {
+ return constructor;
+ }
+
+ void setConstructor(final MethodHandle constructor) {
+ this.constructor = constructor;
+ }
+
+ boolean hasConstructor() {
+ return constructor != null;
+ }
+
+ MethodType type() {
+ return invoker.type();
+ }
+
+ @Override
+ public int compareTo(final CompiledFunction o) {
+ return weight() - o.weight();
+ }
+
+ private int weight() {
+ return weight(type());
+ }
+
+ private static int weight(final MethodType type) {
+ if (isVarArgsType(type)) {
+ return Integer.MAX_VALUE; //if there is a varargs it should be the heavist and last fallback
+ }
+
+ int weight = Type.typeFor(type.returnType()).getWeight();
+ for (final Class<?> paramType : type.parameterArray()) {
+ final int pweight = Type.typeFor(paramType).getWeight();
+ weight += pweight;
+ }
+ return weight;
+ }
+
+ private static boolean isVarArgsType(final MethodType type) {
+ assert type.parameterCount() >= 1 : type;
+ return type.parameterType(type.parameterCount() - 1) == Object[].class;
+ }
+
+ boolean moreGenericThan(final CompiledFunction o) {
+ return weight() > o.weight();
+ }
+
+ boolean moreGenericThan(final MethodType type) {
+ return weight() > weight(type);
+ }
+
+ /**
+ * Check whether a given method descriptor is compatible with this invocation.
+ * It is compatible if the types are narrower than the invocation type so that
+ * a semantically equivalent linkage can be performed.
+ *
+ * @param typesc
+ * @return
+ */
+ boolean typeCompatible(final MethodType type) {
+ final Class<?>[] wantedParams = type.parameterArray();
+ final Class<?>[] existingParams = type().parameterArray();
+
+ //if we are not examining a varargs type, the number of parameters must be the same
+ if (wantedParams.length != existingParams.length && !isVarArgsType(type)) {
+ return false;
+ }
+
+ //we only go as far as the shortest array. the only chance to make this work if
+ //parameters lengths do not match is if our type ends with a varargs argument.
+ //then every trailing parameter in the given callsite can be folded into it, making
+ //us compatible (albeit slower than a direct specialization)
+ final int lastParamIndex = Math.min(wantedParams.length, existingParams.length);
+ for (int i = 0; i < lastParamIndex; i++) {
+ final Type w = Type.typeFor(wantedParams[i]);
+ final Type e = Type.typeFor(existingParams[i]);
+
+ //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
+ //we also currently don't support boolean as a javascript function callsite type.
+ //it will always box.
+ if (w.isBoolean()) {
+ return false;
+ }
+
+ //This callsite type has a vararg here. it will swallow all remaining args.
+ //for consistency, check that it's the last argument
+ if (e.isArray()) {
+ return true;
+ }
+
+ //Our arguments must be at least as wide as the wanted one, if not wider
+ if (Type.widest(w, e) != e) {
+ //e.g. this invocation takes double and callsite says "object". reject. won't fit
+ //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine
+ return false;
+ }
+ }
+
+ return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
+ }
+
+
+
+}
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
new file mode 100644
index 00000000..ff660d3d
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2010, 2013, 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.runtime;
+
+import java.lang.invoke.MethodType;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+/**
+ * This is a list of code versions of a function.
+ * The list is sorted in ascending order of generic descriptors
+ */
+@SuppressWarnings("serial")
+final class CompiledFunctions extends TreeSet<CompiledFunction> {
+
+ CompiledFunction best(final MethodType type) {
+ final Iterator<CompiledFunction> iter = iterator();
+ while (iter.hasNext()) {
+ final CompiledFunction next = iter.next();
+ if (next.typeCompatible(type)) {
+ return next;
+ }
+ }
+ return mostGeneric();
+ }
+
+ boolean needsCallee() {
+ for (final CompiledFunction inv : this) {
+ assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
+ }
+ return ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
+ }
+
+ CompiledFunction mostGeneric() {
+ return last();
+ }
+
+ /**
+ * Is the given type even more specific than this entire list? That means
+ * we have an opportunity for more specific versions of the method
+ * through lazy code generation
+ *
+ * @param type type to check against
+ * @return true if the given type is more specific than all invocations available
+ */
+ boolean isLessSpecificThan(final MethodType type) {
+ return best(type).moreGenericThan(type);
+ }
+
+
+}
diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java
index 1c4a08c8..448df143 100644
--- a/src/jdk/nashorn/internal/runtime/Context.java
+++ b/src/jdk/nashorn/internal/runtime/Context.java
@@ -27,9 +27,9 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.io.File;
import java.io.IOException;
@@ -39,10 +39,13 @@ import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSigner;
import java.security.CodeSource;
+import java.security.Permissions;
import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.internal.codegen.Compiler;
@@ -77,7 +80,7 @@ public final class Context {
/**
* Return the context for this installer
- * @return context
+ * @return ScriptEnvironment
*/
@Override
public ScriptEnvironment getOwner() {
@@ -123,7 +126,7 @@ public final class Context {
if (callerLoader != myLoader &&
!(callerLoader instanceof StructureLoader) &&
!(JavaAdapterFactory.isAdapterClass(caller))) {
- sm.checkPermission(new RuntimePermission("getNashornGlobal"));
+ sm.checkPermission(new RuntimePermission("nashorn.getGlobal"));
}
}
@@ -137,7 +140,7 @@ public final class Context {
public static void setGlobal(final ScriptObject global) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new RuntimePermission("setNashornGlobal"));
+ sm.checkPermission(new RuntimePermission("nashorn.setGlobal"));
}
if (global != null && !(global instanceof GlobalObject)) {
@@ -154,7 +157,7 @@ public final class Context {
public static Context getContext() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new RuntimePermission("getNashornContext"));
+ sm.checkPermission(new RuntimePermission("nashorn.getContext"));
}
return getContextTrusted();
}
@@ -267,7 +270,7 @@ public final class Context {
public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new RuntimePermission("createNashornContext"));
+ sm.checkPermission(new RuntimePermission("nashorn.createContext"));
}
this.env = new ScriptEnvironment(options, out, err);
@@ -533,7 +536,13 @@ public final class Context {
if (index != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPackageAccess(fullName.substring(0, index));
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ sm.checkPackageAccess(fullName.substring(0, index));
+ return null;
+ }
+ }, createNoPermissionsContext());
}
}
@@ -599,7 +608,7 @@ public final class Context {
public ScriptObject newGlobal() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPermission(new RuntimePermission("createNashornGlobal"));
+ sm.checkPermission(new RuntimePermission("nashorn.newGlobal"));
}
return newGlobalTrusted();
@@ -676,6 +685,10 @@ public final class Context {
return (context != null) ? context : Context.getContextTrusted();
}
+ private static AccessControlContext createNoPermissionsContext() {
+ return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
+ }
+
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
ScriptFunction script = null;
@@ -731,6 +744,7 @@ public final class Context {
global = (GlobalObject)Context.getGlobalTrusted();
script = global.findCachedClass(source);
if (script != null) {
+ Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile.");
return script;
}
}
diff --git a/src/jdk/nashorn/internal/runtime/ECMAException.java b/src/jdk/nashorn/internal/runtime/ECMAException.java
index a07fb580..a32e721c 100644
--- a/src/jdk/nashorn/internal/runtime/ECMAException.java
+++ b/src/jdk/nashorn/internal/runtime/ECMAException.java
@@ -237,7 +237,7 @@ public final class ECMAException extends NashornException {
return (String)name;
}
- return (String)name + ": " + (String)msg;
+ return name + ": " + msg;
}
private static Throwable asThrowable(final Object obj) {
diff --git a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
new file mode 100644
index 00000000..ed54b2e9
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, 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.runtime;
+
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+
+/**
+ * This is a subclass that represents a script function that may not be regenerated.
+ * This is used for example for bound functions and builtins.
+ */
+public final class FinalScriptFunctionData extends ScriptFunctionData {
+
+ /**
+ * Constructor - used for bind
+ *
+ * @param name name
+ * @param arity arity
+ * @param list precompiled code
+ * @param isStrict strict
+ * @param isBuiltin builtin
+ * @param isConstructor constructor
+ */
+ FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+ super(name, arity, isStrict, isBuiltin, isConstructor);
+ code.addAll(functions);
+ }
+
+ /**
+ * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the
+ * method (typically a native method) and possibly specializations.
+ *
+ * @param name name
+ * @param mh method handle for generic version of method
+ * @param specs specializations
+ * @param isStrict strict
+ * @param isBuiltin builtin
+ * @param isConstructor constructor
+ */
+ FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+ super(name, arity(mh), isStrict, isBuiltin, isConstructor);
+
+ addInvoker(mh);
+ if (specs != null) {
+ for (final MethodHandle spec : specs) {
+ addInvoker(spec);
+ }
+ }
+ }
+
+ private void addInvoker(final MethodHandle mh) {
+ boolean needsCallee = needsCallee(mh);
+ if (isConstructor(mh)) {
+ //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
+ //is too conservative a check. However, isConstructor(mh) always implies isConstructor param
+ assert isConstructor();
+ code.add(new CompiledFunction(MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
+ } else {
+ code.add(new CompiledFunction(mh));
+ }
+ }
+
+ private static int arity(final MethodHandle mh) {
+ if (isVarArg(mh)) {
+ return -1;
+ }
+
+ //drop self, callee and boolean constructor flag to get real arity
+ return mh.type().parameterCount() - 1 - (needsCallee(mh) ? 1 : 0) - (isConstructor(mh) ? 1 : 0);
+ }
+
+ private static boolean isConstructor(final MethodHandle mh) {
+ return mh.type().parameterCount() >= 1 && mh.type().parameterType(0) == boolean.class;
+ }
+
+}
diff --git a/src/jdk/nashorn/internal/runtime/NashornLoader.java b/src/jdk/nashorn/internal/runtime/NashornLoader.java
index 80a0b8e6..5ce31008 100644
--- a/src/jdk/nashorn/internal/runtime/NashornLoader.java
+++ b/src/jdk/nashorn/internal/runtime/NashornLoader.java
@@ -30,6 +30,10 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
import java.security.SecureClassLoader;
import jdk.nashorn.tools.Shell;
@@ -40,6 +44,28 @@ import jdk.nashorn.tools.Shell;
*
*/
abstract class NashornLoader extends SecureClassLoader {
+ private static final String OBJECTS_PKG = "jdk.nashorn.internal.objects";
+ private static final String RUNTIME_PKG = "jdk.nashorn.internal.runtime";
+ private static final String RUNTIME_LINKER_PKG = "jdk.nashorn.internal.runtime.linker";
+ private static final String SCRIPTS_PKG = "jdk.nashorn.internal.scripts";
+
+ private static final Permission[] SCRIPT_PERMISSIONS;
+ static {
+ SCRIPT_PERMISSIONS = new Permission[4];
+
+ /*
+ * Generated classes get access to runtime, runtime.linker, objects, scripts packages.
+ * Note that the actual scripts can not access these because Java.type, Packages
+ * prevent these restricted packages. And Java reflection and JSR292 access is prevented
+ * for scripts. In other words, nashorn generated portions of script classes can access
+ * clases in these implementation packages.
+ */
+ SCRIPT_PERMISSIONS[0] = new RuntimePermission("accessClassInPackage." + RUNTIME_PKG);
+ SCRIPT_PERMISSIONS[1] = new RuntimePermission("accessClassInPackage." + RUNTIME_LINKER_PKG);
+ SCRIPT_PERMISSIONS[2] = new RuntimePermission("accessClassInPackage." + OBJECTS_PKG);
+ SCRIPT_PERMISSIONS[3] = new RuntimePermission("accessClassInPackage." + SCRIPTS_PKG);
+ }
+
private final Context context;
final Context getContext() {
@@ -68,11 +94,30 @@ abstract class NashornLoader extends SecureClassLoader {
if (i != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- sm.checkPackageAccess(name.substring(0, i));
+ final String pkgName = name.substring(0, i);
+ switch (pkgName) {
+ case RUNTIME_PKG:
+ case RUNTIME_LINKER_PKG:
+ case OBJECTS_PKG:
+ case SCRIPTS_PKG:
+ // allow it.
+ break;
+ default:
+ sm.checkPackageAccess(pkgName);
+ }
}
}
}
+ @Override
+ protected PermissionCollection getPermissions(CodeSource codesource) {
+ final Permissions permCollection = new Permissions();
+ for (final Permission perm : SCRIPT_PERMISSIONS) {
+ permCollection.add(perm);
+ }
+ return permCollection;
+ }
+
/**
* Create a secure URL class loader for the given classpath
* @param classPath classpath for the loader to search from
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
new file mode 100644
index 00000000..03f0ab5d
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2010, 2013, 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.runtime;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import jdk.nashorn.internal.codegen.Compiler;
+import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.codegen.FunctionSignature;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.parser.Token;
+import jdk.nashorn.internal.parser.TokenType;
+
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+/**
+ * This is a subclass that represents a script function that may be regenerated,
+ * for example with specialization based on call site types, or lazily generated.
+ * The common denominator is that it can get new invokers during its lifespan,
+ * unlike {@link FinalScriptFunctionData}
+ */
+public final class RecompilableScriptFunctionData extends ScriptFunctionData {
+
+ private final FunctionNode functionNode;
+ private final PropertyMap allocatorMap;
+ private final CodeInstaller<ScriptEnvironment> installer;
+ private final String allocatorClassName;
+
+ /** lazily generated allocator */
+ private MethodHandle allocator;
+
+ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+ /**
+ * Constructor - public as scripts use it
+ *
+ * @param functionNode functionNode that represents this function code
+ * @param installer installer for code regeneration versions of this function
+ * @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
+ * @param allocatorMap allocator map to seed instances with, when constructing
+ */
+ public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller<ScriptEnvironment> installer, final String allocatorClassName, final PropertyMap allocatorMap) {
+ super(functionNode.isAnonymous() ?
+ "" :
+ functionNode.getIdent().getName(),
+ functionNode.getParameters().size(),
+ functionNode.isStrictMode(),
+ false,
+ true);
+
+ this.functionNode = functionNode;
+ this.installer = installer;
+ this.allocatorClassName = allocatorClassName;
+ this.allocatorMap = allocatorMap;
+ }
+
+ @Override
+ String toSource() {
+ final Source source = functionNode.getSource();
+ final long token = tokenFor(functionNode);
+
+ if (source != null && token != 0) {
+ return source.getString(Token.descPosition(token), Token.descLength(token));
+ }
+
+ return "function " + (name == null ? "" : name) + "() { [native code] }";
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ final Source source = functionNode.getSource();
+ final long token = tokenFor(functionNode);
+
+ if (source != null) {
+ sb.append(source.getName())
+ .append(':')
+ .append(source.getLine(Token.descPosition(token)))
+ .append(' ');
+ }
+
+ return sb.toString() + super.toString();
+ }
+
+ private static long tokenFor(final FunctionNode fn) {
+ final int position = Token.descPosition(fn.getFirstToken());
+ final int length = Token.descPosition(fn.getLastToken()) - position + Token.descLength(fn.getLastToken());
+
+ return Token.toDesc(TokenType.FUNCTION, position, length);
+ }
+
+ @Override
+ ScriptObject allocate() {
+ try {
+ ensureHasAllocator(); //if allocatorClass name is set to null (e.g. for bound functions) we don't even try
+ return allocator == null ? null : (ScriptObject)allocator.invokeExact(allocatorMap);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ private void ensureHasAllocator() throws ClassNotFoundException {
+ if (allocator == null && allocatorClassName != null) {
+ this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.tag(), MH.type(ScriptObject.class, PropertyMap.class));
+ }
+ }
+
+ @Override
+ protected void ensureCodeGenerated() {
+ if (!code.isEmpty()) {
+ return; // nothing to do, we have code, at least some.
+ }
+
+ // check if function node is lazy, need to compile it.
+ // note that currently function cloning is not working completely, which
+ // means that the compiler will mutate the function node it has been given
+ // once it has been compiled, it cannot be recompiled. This means that
+ // lazy compilation works (not compiled yet) but e.g. specializations won't
+ // until the copy-on-write changes for IR are in, making cloning meaningless.
+ // therefore, currently method specialization is disabled. TODO
+
+ if (functionNode.isLazy()) {
+ Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '" + functionNode.getName() + "'");
+ new Compiler(installer, functionNode).compile().install();
+
+ // we don't need to update any flags - varArgs and needsCallee are instrincic
+ // in the function world we need to get a destination node from the compile instead
+ // and replace it with our function node. TODO
+ }
+
+ // we can't get here unless we have bytecode, either from eager compilation or from
+ // running a lazy compile on the lines above
+
+ assert functionNode.hasState(CompilationState.INSTALLED);
+
+ // code exists - look it up and add it into the automatically sorted invoker list
+ code.add(
+ new CompiledFunction(
+ MH.findStatic(
+ LOOKUP,
+ functionNode.getCompileUnit().getCode(),
+ functionNode.getName(),
+ new FunctionSignature(functionNode).
+ getMethodType())));
+ }
+
+ @Override
+ MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
+ final MethodHandle mh = super.getBestInvoker(callSiteType, args);
+ if (code.isLessSpecificThan(callSiteType)) {
+ // opportunity for code specialization - we can regenerate a better version of this method
+ }
+ return mh;
+ }
+
+}
+
diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
index def0313f..36a1d2ac 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@@ -82,6 +82,9 @@ public final class ScriptEnvironment {
/** Show full Nashorn version */
public final boolean _fullversion;
+ /** Should lazy compilation take place */
+ public final boolean _lazy_compilation;
+
/** Create a new class loaded for each compilation */
public final boolean _loader_per_compile;
@@ -155,6 +158,7 @@ public final class ScriptEnvironment {
_early_lvalue_error = options.getBoolean("early.lvalue.error");
_empty_statements = options.getBoolean("empty.statements");
_fullversion = options.getBoolean("fullversion");
+ _lazy_compilation = options.getBoolean("lazy.compilation");
_loader_per_compile = options.getBoolean("loader.per.compile");
_no_syntax_extensions = options.getBoolean("no.syntax.extensions");
_package = options.getString("package");
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index 2d28f91e..512a0b16 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -33,11 +33,11 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
-import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -48,16 +48,16 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards;
public abstract class ScriptFunction extends ScriptObject {
/** Method handle for prototype getter for this ScriptFunction */
- public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class);
+ public static final MethodHandle G$PROTOTYPE = findOwnMH("G$prototype", Object.class, Object.class);
/** Method handle for prototype setter for this ScriptFunction */
- public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class);
+ public static final MethodHandle S$PROTOTYPE = findOwnMH("S$prototype", void.class, Object.class, Object.class);
/** Method handle for length getter for this ScriptFunction */
- public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class);
+ public static final MethodHandle G$LENGTH = findOwnMH("G$length", int.class, Object.class);
/** Method handle for name getter for this ScriptFunction */
- public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
+ public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
/** Method handle for allocate function for this ScriptFunction */
static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
@@ -67,7 +67,9 @@ public abstract class ScriptFunction extends ScriptObject {
/** method handle to scope getter for this ScriptFunction */
public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
- private final ScriptFunctionData data;
+ private static final MethodHandle IS_FUNCTION_MH = findOwnMH("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
+
+ private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
/** Reference to constructor prototype. */
protected Object prototype;
@@ -75,6 +77,8 @@ public abstract class ScriptFunction extends ScriptObject {
/** The parent scope. */
private final ScriptObject scope;
+ private final ScriptFunctionData data;
+
/**
* Constructor
*
@@ -97,7 +101,7 @@ public abstract class ScriptFunction extends ScriptObject {
final boolean builtin,
final boolean isConstructor) {
- this (new ScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
+ this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
}
/**
@@ -118,8 +122,8 @@ public abstract class ScriptFunction extends ScriptObject {
constructorCount++;
}
- this.data = data;
- this.scope = scope;
+ this.data = data;
+ this.scope = scope;
}
@Override
@@ -295,20 +299,20 @@ public abstract class ScriptFunction extends ScriptObject {
/**
* Return the most appropriate invoke handle if there are specializations
* @param type most specific method type to look for invocation with
+ * @param callsite args for trampoline invocation
* @return invoke method handle
*/
- private final MethodHandle getBestInvoker(final MethodType type) {
- return data.getBestInvoker(type);
+ private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
+ return data.getBestInvoker(type, args);
}
/**
- * Get the invoke handle - the most generic (and if no specializations are in place, only) invocation
- * method handle for this ScriptFunction
- * @see SpecializedFunction
- * @return invokeHandle
+ * Return the most appropriate invoke handle if there are specializations
+ * @param type most specific method type to look for invocation with
+ * @return invoke method handle
*/
- public final MethodHandle getInvokeHandle() {
- return data.getInvoker();
+ public MethodHandle getBestInvoker(final MethodType type) {
+ return getBestInvoker(type, null);
}
/**
@@ -319,7 +323,7 @@ public abstract class ScriptFunction extends ScriptObject {
* @return bound invoke handle
*/
public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
- return MH.bindTo(bindToCalleeIfNeeded(getInvokeHandle()), self);
+ return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self);
}
/**
@@ -329,7 +333,8 @@ public abstract class ScriptFunction extends ScriptObject {
* @return the potentially bound method handle
*/
private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
- return data.needsCallee() ? MH.bindTo(methodHandle, this) : methodHandle;
+ return ScriptFunctionData.needsCallee(methodHandle) ? MH.bindTo(methodHandle, this) : methodHandle;
+
}
/**
@@ -340,15 +345,6 @@ public abstract class ScriptFunction extends ScriptObject {
return data.getName();
}
- /**
- * Does this script function need to be compiled. This determined by
- * null checking invokeHandle
- *
- * @return true if this needs compilation
- */
- public final boolean needsCompilation() {
- return data.getInvoker() == null;
- }
/**
* Get the scope for this function
@@ -359,15 +355,6 @@ public abstract class ScriptFunction extends ScriptObject {
}
/**
- * Reset the invoker handle. This is used by trampolines for
- * lazy code generation
- * @param invoker new invoker
- */
- protected void resetInvoker(final MethodHandle invoker) {
- data.resetInvoker(invoker);
- }
-
- /**
* Prototype getter for this ScriptFunction - follows the naming convention
* used by Nasgen and the code generator
*
@@ -464,7 +451,7 @@ public abstract class ScriptFunction extends ScriptObject {
@Override
protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc) {
final MethodType type = desc.getMethodType();
- return new GuardedInvocation(pairArguments(data.getBestConstructor(type), type), null, NashornGuards.getFunctionGuard(this));
+ return new GuardedInvocation(pairArguments(data.getBestConstructor(type.changeParameterType(0, ScriptFunction.class), null), type), null, getFunctionGuard(this));
}
@SuppressWarnings("unused")
@@ -472,7 +459,7 @@ public abstract class ScriptFunction extends ScriptObject {
if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
return obj;
}
- return ((GlobalObject) Context.getGlobalTrusted()).wrapAsObject(obj);
+ return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
}
/**
@@ -506,8 +493,7 @@ public abstract class ScriptFunction extends ScriptObject {
MethodHandle guard = null;
if (data.needsCallee()) {
- final MethodHandle callHandle = getBestInvoker(type);
-
+ final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
if (NashornCallSiteDescriptor.isScope(desc)) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (callee, this, args...) => (callee, args...)
@@ -525,13 +511,12 @@ public abstract class ScriptFunction extends ScriptObject {
if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) {
boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER);
} else {
- guard = NashornGuards.getNonStrictFunctionGuard(this);
+ guard = getNonStrictFunctionGuard(this);
}
}
}
} else {
- final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1));
-
+ final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments());
if (NashornCallSiteDescriptor.isScope(desc)) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (this, args...) => (args...)
@@ -545,7 +530,8 @@ public abstract class ScriptFunction extends ScriptObject {
}
boundHandle = pairArguments(boundHandle, type);
- return new GuardedInvocation(boundHandle, guard == null ? NashornGuards.getFunctionGuard(this) : guard);
+
+ return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard);
}
/**
@@ -554,13 +540,50 @@ public abstract class ScriptFunction extends ScriptObject {
* These don't want a callee parameter, so bind that. Name binding is optional.
*/
MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
- return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type)), bindName), type);
+ return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(getBestInvoker(type, null)), bindName), type);
}
private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName);
}
+ /**
+ * Get the guard that checks if a {@link ScriptFunction} is equal to
+ * a known ScriptFunction, using reference comparison
+ *
+ * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+ *
+ * @return method handle for guard
+ */
+ private static MethodHandle getFunctionGuard(final ScriptFunction function) {
+ assert function.data != null;
+ return MH.insertArguments(IS_FUNCTION_MH, 1, function.data);
+ }
+
+ /**
+ * Get a guard that checks if a {@link ScriptFunction} is equal to
+ * a known ScriptFunction using reference comparison, and whether the type of
+ * the second argument (this-object) is not a JavaScript primitive type.
+ *
+ * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+ *
+ * @return method handle for guard
+ */
+ private static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
+ assert function.data != null;
+ return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.data);
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
+ return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
+ return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
final Class<?> own = ScriptFunction.class;
final MethodType mt = MH.type(rtype, types);
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index 8f8193e4..f83cfa2c 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -32,151 +32,109 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.parser.TokenType;
+
+import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
/**
* A container for data needed to instantiate a specific {@link ScriptFunction} at runtime.
* Instances of this class are created during codegen and stored in script classes'
* constants array to reduce function instantiation overhead during runtime.
*/
-public final class ScriptFunctionData {
- private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
- private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
+public abstract class ScriptFunctionData {
- // per-function object flags
- private static final int IS_STRICT = 0b0000_0001;
- private static final int IS_BUILTIN = 0b0000_0010;
- private static final int HAS_CALLEE = 0b0000_0100;
- private static final int IS_VARARGS = 0b0000_1000;
- private static final int IS_CONSTRUCTOR = 0b0001_0000;
-
- /** Name of the function or "" */
- private final String name;
- /** Source of this function, or null */
- private final Source source;
- /** Map for new instance constructor */
- private PropertyMap allocatorMap;
- /** Start position and length in source */
- private final long token;
- /** Number of expected arguments, either taken from FunctionNode or calculated from method handle signature*/
- private int arity;
- private final int flags;
-
- /** Reference to code for this method. */
- private MethodHandle invoker;
- /** Reference to code for this method when called to create "new" object. This must always be populated with a
- * result of calling {@link #composeConstructor(MethodHandle)} on the value of the {@link #invoker} field. */
- private MethodHandle constructor;
- /** Constructor to create a new instance. */
- private MethodHandle allocator;
- /** Generic invoker to used in {@link ScriptFunction#invoke(Object, Object...)}. */
- private MethodHandle genericInvoker;
- /** Specializations - see @SpecializedFunction */
- private MethodHandle[] invokeSpecializations;
- /** Specializations - see @SpecializedFunction. Same restrictions as for {@link #constructor} apply; only populate
- * with method handles returned from {@link #composeConstructor(MethodHandle)}. */
- private MethodHandle[] constructSpecializations;
+ /** Name of the function or "" for anonynous functions */
+ protected final String name;
- /**
- * Constructor
- * @param fn the function node
- * @param allocatorMap the allocator property map
- */
- public ScriptFunctionData(final FunctionNode fn, final PropertyMap allocatorMap) {
+ /** All versions of this function that have been generated to code */
+ protected final CompiledFunctions code;
- final long firstToken = fn.getFirstToken();
- final long lastToken = fn.getLastToken();
- final int position = Token.descPosition(firstToken);
- final int length = Token.descPosition(lastToken) - position + Token.descLength(lastToken);
+ private int arity;
- this.name = fn.isAnonymous() ? "" : fn.getIdent().getName();
- this.source = fn.getSource();
- this.allocatorMap = allocatorMap;
- this.token = Token.toDesc(TokenType.FUNCTION, position, length);
- this.arity = fn.getParameters().size();
- this.flags = makeFlags(fn.needsCallee(), fn.isVarArg(), fn.isStrictMode(), false, true);
- }
+ private final boolean isStrict;
+
+ private final boolean isBuiltin;
+
+ private final boolean isConstructor;
+
+ private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
+ private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
/**
* Constructor
*
- * @param name the function name
- * @param methodHandle the method handle
- * @param specs array of specialized method handles
- * @param strict strict flag
- * @param builtin builtin flag
- * @param isConstructor constructor flags
+ * @param name script function name
+ * @param arity arity
+ * @param isStrict is the function strict
+ * @param isBuiltin is the function built in
+ * @param isConstructor is the function a constructor
*/
- public ScriptFunctionData(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
- this(name, null, 0L, methodHandle, specs, strict, builtin, isConstructor);
+ protected ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
+ this.name = name;
+ this.arity = arity;
+ this.code = new CompiledFunctions();
+ this.isStrict = isStrict;
+ this.isBuiltin = isBuiltin;
+ this.isConstructor = isConstructor;
}
- private ScriptFunctionData(final String name, final Source source, final long token, final MethodHandle methodHandle, final MethodHandle[] specs, final boolean strict, final boolean builtin, final boolean isConstructor) {
- this.name = name;
- this.source = source;
- this.token = token;
+ final int getArity() {
+ return arity;
+ }
- final boolean isVarArg = isVarArg(methodHandle);
- final boolean needsCallee = needsCallee(methodHandle);
+ /**
+ * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
+ * @param arity new arity
+ */
+ void setArity(final int arity) {
+ this.arity = arity;
+ }
- this.flags = makeFlags(needsCallee, isVarArg, strict, builtin, isConstructor);
- int lArity = isVarArg ? -1 : methodHandle.type().parameterCount() - 1; //drop the self param for arity
+ CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
+ final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
- if (needsCallee && !isVarArg) {
- lArity--;
+ if (isConstructor()) {
+ ensureConstructor(originalInv);
+ return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
}
- if (isConstructor(methodHandle)) {
- assert isConstructor;
- if (!isVarArg) {
- lArity--; // drop the boolean flag for arity
- }
- /*
- * We insert a boolean argument to tell if the method was invoked as constructor or not if the method
- * handle's first argument is boolean.
- */
- this.invoker = MH.insertArguments(methodHandle, 0, false);
- this.constructor = composeConstructor(MH.insertArguments(methodHandle, 0, true));
-
- if (specs != null) {
- this.invokeSpecializations = new MethodHandle[specs.length];
- this.constructSpecializations = new MethodHandle[specs.length];
- for (int i = 0; i < specs.length; i++) {
- this.invokeSpecializations[i] = MH.insertArguments(specs[i], 0, false);
- this.constructSpecializations[i] = composeConstructor(MH.insertArguments(specs[i], 0, true));
- }
- }
- } else {
- this.invoker = methodHandle;
- this.constructor = null; // delay composition of the constructor
- this.invokeSpecializations = specs;
- this.constructSpecializations = null; // delay composition of the constructors
- }
- this.arity = lArity;
+ return new CompiledFunction(boundInvoker);
}
/**
- * Get the arity of the function.
- * @return the arity
+ * Is this a ScriptFunction generated with strict semantics?
+ * @return true if strict, false otherwise
*/
- int getArity() {
- return arity;
+ public boolean isStrict() {
+ return isStrict;
}
- /**
- * Set the arity of the function.
- * @param arity the arity
- */
- void setArity(int arity) {
- this.arity = arity;
+ boolean isBuiltin() {
+ return isBuiltin;
+ }
+
+ boolean isConstructor() {
+ return isConstructor;
+ }
+
+ boolean needsCallee() {
+ // we don't know if we need a callee or not unless we are generated
+ ensureCodeGenerated();
+ return code.needsCallee();
}
/**
- * Get the function name.
- * @return function name
+ * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
+ * according to ECMA 10.4.3.
+ * @return true if this argument must be an object
*/
+ boolean needsWrappedThis() {
+ return !isStrict && !isBuiltin;
+ }
+
+ String toSource() {
+ return "function " + (name == null ? "" : name) + "() { [native code] }";
+ }
+
String getName() {
return name;
}
@@ -184,327 +142,178 @@ public final class ScriptFunctionData {
/**
* Get this function as a String containing its source code. If no source code
* exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
- * @return string representation of this function's source
+ *
+ * @return string representation of this function
*/
- String toSource() {
- if (source != null && token != 0) {
- return source.getString(Token.descPosition(token), Token.descLength(token));
- }
-
- return "function " + (name == null ? "" : name) + "() { [native code] }";
- }
-
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- sb.append(super.toString())
- .append(" [ ")
- .append(invoker)
- .append(", ")
- .append((name == null || name.isEmpty()) ? "<anonymous>" : name);
-
- if (source != null) {
- sb.append(" @ ")
- .append(source.getName())
- .append(':')
- .append(source.getLine(Token.descPosition(token)));
- }
- sb.append(" ]");
+ sb.append("name='").
+ append(name.isEmpty() ? "<anonymous>" : name).
+ append("' ").
+ append(code.size()).
+ append(" invokers=").
+ append(code);
return sb.toString();
}
/**
- * Returns true if the function needs a callee argument.
- * @return the needsCallee flag
+ * Pick the best invoker, i.e. the one version of this method with as narrow and specific
+ * types as possible. If the call site arguments are objects, but boxed primitives we can
+ * also try to get a primitive version of the method and do an unboxing filter, but then
+ * we need to insert a guard that checks the argument is really always a boxed primitive
+ * and not suddenly a "real" object
+ *
+ * @param callSiteType callsite type
+ * @param args arguments at callsite on first trampoline invocation
+ * @return method handle to best invoker
*/
- boolean needsCallee() {
- return (flags & HAS_CALLEE) != 0;
+ MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
+ return getBest(callSiteType).getInvoker();
}
- /**
- * Returns true if this is a strict-mode function.
- * @return the strict flag
- */
- public boolean isStrict() {
- return (flags & IS_STRICT) != 0;
+ MethodHandle getBestInvoker(final MethodType callSiteType) {
+ return getBestInvoker(callSiteType, null);
}
- /**
- * Returns true if this is a built-in function.
- * @return the built-in flag
- */
- private boolean isBuiltin() {
- return (flags & IS_BUILTIN) != 0;
+ MethodHandle getBestConstructor(final MethodType callSiteType, final Object[] args) {
+ if (!isConstructor()) {
+ throw typeError("not.a.constructor", toSource());
+ }
+ ensureCodeGenerated();
+
+ final CompiledFunction best = getBest(callSiteType);
+ ensureConstructor(best);
+ return best.getConstructor();
}
- /**
- * Returns true if this function can be used as a constructor.
- * @return the constructor flag
- */
- private boolean isConstructor() {
- return (flags & IS_CONSTRUCTOR) != 0;
+ MethodHandle getBestConstructor(final MethodType callSiteType) {
+ return getBestConstructor(callSiteType, null);
}
/**
- * Returns true if this is a var-arg function.
- * @return the var-arg flag
+ * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that
+ * code exists before performing an operation.
*/
- private boolean isVarArg() {
- return (flags & IS_VARARGS) != 0;
+ protected void ensureCodeGenerated() {
+ //empty
}
/**
- * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
- * according to ECMA 10.4.3.
- * @return true if this argument must be an object
+ * Return a generic Object/Object invoker for this method. It will ensure code
+ * is generated, get the most generic of all versions of this function and adapt it
+ * to Objects.
+ *
+ * TODO this is only public because {@link JavaAdapterFactory} can't supply us with
+ * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed
+ *
+ * @return generic invoker of this script function
*/
- boolean needsWrappedThis() {
- return (flags & (IS_STRICT | IS_BUILTIN)) == 0;
+ public final MethodHandle getGenericInvoker() {
+ ensureCodeGenerated();
+ return composeGenericMethod(code.mostGeneric().getInvoker());
}
- /**
- * Get the method handle used to invoke this function.
- * @return the invoke handle
- */
- MethodHandle getInvoker() {
- return invoker;
+ private CompiledFunction getBest(final MethodType callSiteType) {
+ ensureCodeGenerated();
+ return code.best(callSiteType);
}
- MethodHandle getBestInvoker(final MethodType type) {
- return SpecializedMethodChooser.candidateWithLowestWeight(type, invoker, invokeSpecializations);
+ /**
+ * Allocates an object using this function's allocator.
+ * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
+ */
+ ScriptObject allocate() {
+ return null;
}
/**
- * Get the method handle used to invoke this function as a constructor.
- * @return the constructor handle
+ * This method is used to create the immutable portion of a bound function.
+ * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
+ *
+ * @param fn the original function being bound
+ * @param self this reference to bind. Can be null.
+ * @param args additional arguments to bind. Can be null.
*/
- private MethodHandle getConstructor() {
- if (constructor == null) {
- constructor = composeConstructor(invoker);
- }
+ ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
+ ensureCodeGenerated();
- return constructor;
- }
+ final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
+ final int length = args == null ? 0 : args.length;
- MethodHandle getBestConstructor(MethodType descType) {
- if (!isConstructor()) {
- throw typeError("not.a.constructor", toSource());
+ CompiledFunctions boundList = new CompiledFunctions();
+ for (final CompiledFunction inv : code) {
+ boundList.add(bind(inv, fn, self, allArgs));
}
- return SpecializedMethodChooser.candidateWithLowestWeight(descType, getConstructor(), getConstructSpecializations());
+ ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
+ return boundData;
}
- private MethodHandle composeConstructor(MethodHandle ctor) {
+ /**
+ * Compose a constructor given a primordial constructor handle
+ *
+ * @param ctor primordial constructor handle
+ * @param needsCallee do we need to pass a callee
+ *
+ * @return the composed constructor
+ */
+ protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) {
// If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having
// "this" in the first argument position is what allows the elegant folded composition of
// (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor
// always returns Object.
- MethodHandle composedCtor = changeReturnTypeToObject(swapCalleeAndThis(ctor));
+ MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor;
+
+ composedCtor = changeReturnTypeToObject(composedCtor);
final MethodType ctorType = composedCtor.type();
+
// Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually
// captured as "allocation" parameter of NEWFILTER after we fold the constructor into it.
// (this, [callee, ]args...) => ([callee, ]args...)
final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray();
+
// Fold constructor into newFilter that replaces the return value from the constructor with the originally
// allocated value when the originally allocated value is a primitive.
// (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...)
composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor);
// allocate() takes a ScriptFunction and returns a newly allocated ScriptObject...
- if (needsCallee()) {
+ if (needsCallee) {
// ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and
// the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...),
// or...
return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE);
}
+
// ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee
// (this, args...) filter (callee) => (callee, args...)
return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE);
}
/**
- * Get an adapted version of the invoker handle that only uses {@code Object} as parameter and return types.
- * @return the generic invoke handle
- */
- private MethodHandle getGenericInvoker() {
- if (genericInvoker == null) {
- assert invoker != null : "invoker is null";
- genericInvoker = makeGenericMethod(invoker);
- }
- return genericInvoker;
- }
-
- /**
- * Execute this script function.
- * @param self Target object.
- * @param arguments Call arguments.
- * @return ScriptFunction result.
- * @throws Throwable if there is an exception/error with the invocation or thrown from it
- */
- Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable {
- final MethodHandle genInvoker = getGenericInvoker();
- final Object selfObj = convertThisObject(self);
- final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
-
- if (isVarArg()) {
- if (needsCallee()) {
- return genInvoker.invokeExact(fn, selfObj, args);
- }
- return genInvoker.invokeExact(selfObj, args);
- }
-
- final int paramCount = genInvoker.type().parameterCount();
- if (needsCallee()) {
- switch (paramCount) {
- case 2:
- return genInvoker.invokeExact(fn, selfObj);
- case 3:
- return genInvoker.invokeExact(fn, selfObj, getArg(args, 0));
- case 4:
- return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1));
- case 5:
- return genInvoker.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
- default:
- return genInvoker.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
- }
- }
-
- switch (paramCount) {
- case 1:
- return genInvoker.invokeExact(selfObj);
- case 2:
- return genInvoker.invokeExact(selfObj, getArg(args, 0));
- case 3:
- return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
- case 4:
- return genInvoker.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
- default:
- return genInvoker.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
- }
- }
-
- private static Object getArg(final Object[] args, final int i) {
- return i < args.length ? args[i] : UNDEFINED;
- }
-
- private Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) {
- final Object[] finalArgs = new Object[argCount];
-
- int nextArg = 0;
- if (needsCallee()) {
- assert fn != null;
- finalArgs[nextArg++] = fn;
- } else {
- assert fn == null;
- }
- finalArgs[nextArg++] = self;
-
- // Don't add more args that there is argCount in the handle (including self and callee).
- for (int i = 0; i < args.length && nextArg < argCount;) {
- finalArgs[nextArg++] = args[i++];
- }
-
- // If we have fewer args than argCount, pad with undefined.
- while (nextArg < argCount) {
- finalArgs[nextArg++] = UNDEFINED;
- }
-
- return finalArgs;
- }
-
- /**
- * Get the specialized construct handles for this function.
- * @return array of specialized construct handles
- */
- private MethodHandle[] getConstructSpecializations() {
- if(constructSpecializations == null && invokeSpecializations != null) {
- final MethodHandle[] ctors = new MethodHandle[invokeSpecializations.length];
- for(int i = 0; i < ctors.length; ++i) {
- ctors[i] = composeConstructor(invokeSpecializations[i]);
- }
- constructSpecializations = ctors;
- }
- return constructSpecializations;
- }
-
- /**
- * Set the method handles for this function.
- * @param invoker the invoker handle
- * @param allocator the allocator handle
- */
- public void setMethodHandles(final MethodHandle invoker, final MethodHandle allocator) {
- // We can't make method handle fields final because they're not available during codegen
- // and they're set when first called, so we enforce set-once here.
- if (this.invoker == null) {
- this.invoker = invoker;
- this.constructor = null; // delay constructor composition
- this.allocator = allocator;
- }
- }
-
- /**
- * Used by the trampoline. Must not be any wider than package
- * private
- * @param invoker new invoker
- */
- void resetInvoker(final MethodHandle invoker) {
- this.invoker = invoker;
- this.constructor = null; //delay constructor composition
- }
-
- /**
- * Allocates an object using this function's allocator.
- * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
- */
- ScriptObject allocate() {
- if (allocator == null) {
- return null;
- }
-
- try {
- return (ScriptObject)allocator.invokeExact(allocatorMap);
- } catch (final RuntimeException | Error e) {
- throw e;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- /**
- * This method is used to create the immutable portion of a bound function.
- * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
+ * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed
+ * method handle. If this function's method handles don't need a callee parameter, returns the original method
+ * handle unchanged.
*
- * @param fn the original function being bound
- * @param self this reference to bind. Can be null.
- * @param args additional arguments to bind. Can be null.
+ * @param mh a method handle with order of arguments {@code (callee, this, args...)}
+ *
+ * @return a method handle with order of arguments {@code (this, callee, args...)}
*/
- ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
- final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
-
- final boolean isConstructor = isConstructor();
- // Note that the new ScriptFunctionData's method handle will not need a callee regardless of whether the
- // original did.
- final ScriptFunctionData boundData = new ScriptFunctionData(name, source, token,
- bindInvokeHandle(invoker, fn, self, allArgs), bindInvokeSpecializations(fn, self, allArgs), isStrict(), isBuiltin(), isConstructor);
- if(isConstructor) {
- // Can't just rely on bound invoke as a basis for constructor, as it ignores the passed "this" in favor of the
- // bound "this"; constructor on the other hand must see the actual "this" received from the allocator.
-
- // Binding a function will force constructor composition in getConstructor(); not really any way around that
- // as it's the composed constructor that has to be bound to the function.
- boundData.constructor = bindConstructHandle(getConstructor(), fn, allArgs);
- boundData.constructSpecializations = bindConstructorSpecializations(fn, allArgs);
- }
- assert boundData.allocator == null;
- final int thisArity = getArity();
- if(thisArity != -1) {
- boundData.setArity(Math.max(0, thisArity - args.length));
- } else {
- assert boundData.getArity() == -1;
+ private static MethodHandle swapCalleeAndThis(final MethodHandle mh) {
+ final MethodType type = mh.type();
+ assert type.parameterType(0) == ScriptFunction.class : type;
+ assert type.parameterType(1) == Object.class : type;
+ final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class);
+ final int[] reorder = new int[type.parameterCount()];
+ reorder[0] = 1;
+ assert reorder[1] == 0;
+ for (int i = 2; i < reorder.length; ++i) {
+ reorder[i] = i;
}
- return boundData;
+ return MethodHandles.permuteArguments(mh, newType, reorder);
}
/**
@@ -514,7 +323,7 @@ public final class ScriptFunctionData {
*
* @return the converted this object
*/
- Object convertThisObject(final Object thiz) {
+ private Object convertThisObject(final Object thiz) {
if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
if (JSType.nullOrUndefined(thiz)) {
return Context.getGlobalTrusted();
@@ -528,18 +337,20 @@ public final class ScriptFunctionData {
return thiz;
}
- static boolean isPrimitiveThis(Object obj) {
+ static boolean isPrimitiveThis(final Object obj) {
return obj instanceof String || obj instanceof ConsString ||
obj instanceof Number || obj instanceof Boolean;
}
/**
* Creates an invoker method handle for a bound function.
+ *
* @param targetFn the function being bound
* @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or
* any of its specializations.
* @param self the "this" value being bound
* @param args additional arguments being bound
+ *
* @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting
* invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting
* invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed
@@ -549,16 +360,22 @@ public final class ScriptFunctionData {
// Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound
// in the target and will be ignored anyway.
final boolean isTargetBound = targetFn.isBoundFunction();
- assert !(isTargetBound && needsCallee()); // already bound functions don't need a callee
+
+ final boolean needsCallee = needsCallee(originalInvoker);
+ assert needsCallee == needsCallee() : "callee contract violation 2";
+ assert !(isTargetBound && needsCallee); // already bound functions don't need a callee
+
final Object boundSelf = isTargetBound ? null : convertThisObject(self);
final MethodHandle boundInvoker;
- if(isVarArg(originalInvoker)) {
+
+ if (isVarArg(originalInvoker)) {
// First, bind callee and this without arguments
final MethodHandle noArgBoundInvoker;
- if(isTargetBound) {
+
+ if (isTargetBound) {
// Don't bind either callee or this
noArgBoundInvoker = originalInvoker;
- } else if(needsCallee()) {
+ } else if (needsCallee) {
// Bind callee and this
noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf);
} else {
@@ -566,17 +383,16 @@ public final class ScriptFunctionData {
noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf);
}
// Now bind arguments
- if(args.length > 0) {
+ if (args.length > 0) {
boundInvoker = varArgBinder(noArgBoundInvoker, args);
} else {
boundInvoker = noArgBoundInvoker;
}
} else {
- final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(),
- args.length + (isTargetBound ? 0 : (needsCallee() ? 2 : 1)))];
+ final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))];
int next = 0;
- if(!isTargetBound) {
- if(needsCallee()) {
+ if (!isTargetBound) {
+ if (needsCallee) {
boundArgs[next++] = targetFn;
}
boundArgs[next++] = boundSelf;
@@ -589,51 +405,44 @@ public final class ScriptFunctionData {
// start at position 1. If the function is not bound, we start inserting arguments at position 0.
boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs);
}
- if(isTargetBound) {
+
+ if (isTargetBound) {
return boundInvoker;
}
+
// If the target is not already bound, add a dropArguments that'll throw away the passed this
return MH.dropArguments(boundInvoker, 0, Object.class);
}
- private MethodHandle[] bindInvokeSpecializations(final ScriptFunction fn, final Object self, final Object[] args) {
- if(invokeSpecializations == null) {
- return null;
- }
- final MethodHandle[] boundSpecializations = new MethodHandle[invokeSpecializations.length];
- for(int i = 0; i < invokeSpecializations.length; ++i) {
- boundSpecializations[i] = bindInvokeHandle(invokeSpecializations[i], fn, self, args);
- }
- return boundSpecializations;
- }
-
/**
* Creates a constructor method handle for a bound function using the passed constructor handle.
+ *
* @param originalConstructor the constructor handle to bind. It must be a composed constructor.
* @param fn the function being bound
* @param args arguments being bound
+ *
* @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never
* needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor
* still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if
* this script function data object has no constructor handle, null is returned.
*/
private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) {
- if(originalConstructor == null) {
- return null;
- }
+ assert originalConstructor != null;
// If target function is already bound, don't bother binding the callee.
final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor :
MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class);
- if(args.length == 0) {
+
+ if (args.length == 0) {
return calleeBoundConstructor;
}
- if(isVarArg(calleeBoundConstructor)) {
+ if (isVarArg(calleeBoundConstructor)) {
return varArgBinder(calleeBoundConstructor, args);
}
final Object[] boundArgs;
+
final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1;
if (args.length <= maxArgCount) {
boundArgs = args;
@@ -641,27 +450,123 @@ public final class ScriptFunctionData {
boundArgs = new Object[maxArgCount];
System.arraycopy(args, 0, boundArgs, 0, maxArgCount);
}
+
return MH.insertArguments(calleeBoundConstructor, 1, boundArgs);
}
- private MethodHandle[] bindConstructorSpecializations(final ScriptFunction fn, final Object[] args) {
- final MethodHandle[] ctorSpecs = getConstructSpecializations();
- if(ctorSpecs == null) {
- return null;
+ /**
+ * Takes a method handle, and returns a potentially different method handle that can be used in
+ * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}.
+ * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
+ * {@code Object} as well, except for the following ones:
+ * <ul>
+ * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
+ * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
+ * (callee) as an argument.</li>
+ * </ul>
+ *
+ * @param mh the original method handle
+ *
+ * @return the new handle, conforming to the rules above.
+ */
+ protected MethodHandle composeGenericMethod(final MethodHandle mh) {
+ final MethodType type = mh.type();
+ MethodType newType = type.generic();
+ if (isVarArg(mh)) {
+ newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
+ }
+ if (needsCallee(mh)) {
+ newType = newType.changeParameterType(0, ScriptFunction.class);
+ }
+ return type.equals(newType) ? mh : mh.asType(newType);
+ }
+
+ /**
+ * Execute this script function.
+ *
+ * @param self Target object.
+ * @param arguments Call arguments.
+ * @return ScriptFunction result.
+ *
+ * @throws Throwable if there is an exception/error with the invocation or thrown from it
+ */
+ Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable {
+ final MethodHandle mh = getGenericInvoker();
+
+ final Object selfObj = convertThisObject(self);
+ final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
+
+ if (isVarArg(mh)) {
+ if (needsCallee(mh)) {
+ return mh.invokeExact(fn, selfObj, args);
+ }
+ return mh.invokeExact(selfObj, args);
}
- final MethodHandle[] boundSpecializations = new MethodHandle[ctorSpecs.length];
- for(int i = 0; i < ctorSpecs.length; ++i) {
- boundSpecializations[i] = bindConstructHandle(ctorSpecs[i], fn, args);
+
+ final int paramCount = mh.type().parameterCount();
+ if (needsCallee(mh)) {
+ switch (paramCount) {
+ case 2:
+ return mh.invokeExact(fn, selfObj);
+ case 3:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0));
+ case 4:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1));
+ case 5:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
+ default:
+ return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
+ }
+ }
+
+ switch (paramCount) {
+ case 1:
+ return mh.invokeExact(selfObj);
+ case 2:
+ return mh.invokeExact(selfObj, getArg(args, 0));
+ case 3:
+ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
+ case 4:
+ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
+ default:
+ return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
}
- return boundSpecializations;
}
+ private static Object getArg(final Object[] args, final int i) {
+ return i < args.length ? args[i] : UNDEFINED;
+ }
+
+ private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) {
+ final Object[] finalArgs = new Object[argCount];
+
+ int nextArg = 0;
+ if (fn != null) {
+ //needs callee
+ finalArgs[nextArg++] = fn;
+ }
+ finalArgs[nextArg++] = self;
+
+ // Don't add more args that there is argCount in the handle (including self and callee).
+ for (int i = 0; i < args.length && nextArg < argCount;) {
+ finalArgs[nextArg++] = args[i++];
+ }
+
+ // If we have fewer args than argCount, pad with undefined.
+ while (nextArg < argCount) {
+ finalArgs[nextArg++] = UNDEFINED;
+ }
+
+ return finalArgs;
+ }
/**
* Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the
* vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on
* invocation
+ *
* @param mh the handle
* @param args the bound arguments
+ *
* @return the bound method handle
*/
private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) {
@@ -671,41 +576,20 @@ public final class ScriptFunctionData {
}
/**
- * Convert boolean flags to int.
- * @param needsCallee needs-callee flag
- * @param isVarArg var-arg flag
- * @param isStrict strict flag
- * @param isBuiltin builtin flag
- * @return int flags
+ * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already
+ * {@code Object}, the handle is returned unchanged.
+ *
+ * @param mh the handle to adapt
+ * @return the adapted handle
*/
- private static int makeFlags(final boolean needsCallee, final boolean isVarArg, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- int flags = 0;
- if (needsCallee) {
- flags |= HAS_CALLEE;
- }
- if (isVarArg) {
- flags |= IS_VARARGS;
- }
- if (isStrict) {
- flags |= IS_STRICT;
- }
- if (isBuiltin) {
- flags |= IS_BUILTIN;
- }
- if (isConstructor) {
- flags |= IS_CONSTRUCTOR;
- }
-
- return flags;
+ private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) {
+ return MH.asType(mh, mh.type().changeReturnType(Object.class));
}
- /**
- * Test if a methodHandle refers to a constructor.
- * @param methodHandle MethodHandle to test.
- * @return True if method is a constructor.
- */
- private static boolean isConstructor(final MethodHandle methodHandle) {
- return methodHandle.type().parameterCount() >= 1 && methodHandle.type().parameterType(0) == boolean.class;
+ private void ensureConstructor(final CompiledFunction inv) {
+ if (!inv.hasConstructor()) {
+ inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker())));
+ }
}
/**
@@ -713,102 +597,56 @@ public final class ScriptFunctionData {
* {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
* a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
* assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
- * they also always receive a callee.
- * @param methodHandle the examined method handle
+ * they also always receive a callee).
+ *
+ * @param mh the examined method handle
+ *
* @return true if the method handle expects a callee, false otherwise
*/
- private static boolean needsCallee(MethodHandle methodHandle) {
- final MethodType type = methodHandle.type();
- final int len = type.parameterCount();
- if(len == 0) {
+ protected static boolean needsCallee(final MethodHandle mh) {
+ final MethodType type = mh.type();
+ final int length = type.parameterCount();
+
+ if (length == 0) {
return false;
}
- if(type.parameterType(0) == boolean.class) {
- return len > 1 && type.parameterType(1) == ScriptFunction.class;
- }
- return type.parameterType(0) == ScriptFunction.class;
- }
- private static boolean isVarArg(MethodHandle methodHandle) {
- final MethodType type = methodHandle.type();
- return type.parameterType(type.parameterCount() - 1).isArray();
- }
-
- /**
- * Takes a method handle, and returns a potentially different method handle that can be used in
- * {@link ScriptFunction#invoke(Object, Object...)} or {@link ScriptFunction#construct(Object, Object...)}.
- * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
- * {@code Object} as well, except for the following ones:
- * <ul>
- * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
- * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
- * (callee) as an argument.</li>
- * </ul>
- *
- * @param handle the original method handle
- * @return the new handle, conforming to the rules above.
- */
- private MethodHandle makeGenericMethod(final MethodHandle handle) {
- final MethodType type = handle.type();
- MethodType newType = type.generic();
- if (isVarArg()) {
- newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
- }
- if (needsCallee()) {
- newType = newType.changeParameterType(0, ScriptFunction.class);
+ if (type.parameterType(0) == boolean.class) {
+ return length > 1 && type.parameterType(1) == ScriptFunction.class;
}
- return type.equals(newType) ? handle : handle.asType(newType);
- }
- /**
- * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already
- * {@code Object}, the handle is returned unchanged.
- * @param mh the handle to adapt
- * @return the adapted handle
- */
- private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) {
- return MH.asType(mh, mh.type().changeReturnType(Object.class));
+ return type.parameterType(0) == ScriptFunction.class;
}
-
/**
- * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed
- * method handle. If this function's method handles don't need a callee parameter, returns the original method
- * handle unchanged.
- * @param mh a method handle with order of arguments {@code (callee, this, args...)}
- * @return a method handle with order of arguments {@code (this, callee, args...)}
+ * Check if a javascript function methodhandle is a vararg handle
+ *
+ * @param mh method handle to check
+ *
+ * @return true if vararg
*/
- private MethodHandle swapCalleeAndThis(final MethodHandle mh) {
- if (!needsCallee()) {
- return mh;
- }
+ protected static boolean isVarArg(final MethodHandle mh) {
final MethodType type = mh.type();
- assert type.parameterType(0) == ScriptFunction.class;
- assert type.parameterType(1) == Object.class;
- final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class);
- final int[] reorder = new int[type.parameterCount()];
- reorder[0] = 1;
- assert reorder[1] == 0;
- for (int i = 2; i < reorder.length; ++i) {
- reorder[i] = i;
- }
- return MethodHandles.permuteArguments(mh, newType, reorder);
+ return type.parameterType(type.parameterCount() - 1).isArray();
}
@SuppressWarnings("unused")
private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) {
- if(array2 == null) {
+ if (array2 == null) {
// Must clone it, as we can't allow the receiving method to alter the array
return array1.clone();
}
+
final int l2 = array2.length;
- if(l2 == 0) {
+ if (l2 == 0) {
return array1.clone();
}
+
final int l1 = array1.length;
final Object[] concat = new Object[l1 + l2];
System.arraycopy(array1, 0, concat, 0, l1);
System.arraycopy(array2, 0, concat, l1, l2);
+
return concat;
}
@@ -820,5 +658,4 @@ public final class ScriptFunctionData {
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types));
}
-
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptLoader.java b/src/jdk/nashorn/internal/runtime/ScriptLoader.java
index d6321662..370faf31 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import java.security.CodeSource;
+import java.security.ProtectionDomain;
/**
* Responsible for loading script generated classes.
@@ -57,6 +58,9 @@ final class ScriptLoader extends NashornLoader {
* @return Installed class.
*/
synchronized Class<?> installClass(final String name, final byte[] data, final CodeSource cs) {
+ if (cs == null) {
+ return defineClass(name, data, 0, data.length, new ProtectionDomain(null, getPermissions(null)));
+ }
return defineClass(name, data, 0, data.length, cs);
}
}
diff --git a/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java b/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java
deleted file mode 100644
index 2853cdf2..00000000
--- a/src/jdk/nashorn/internal/runtime/SpecializedMethodChooser.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.runtime;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.runtime.options.Options;
-
-class SpecializedMethodChooser {
- /** Should specialized function and specialized constructors for the builtin be used if available? */
- private static final boolean DISABLE_SPECIALIZATION = Options.getBooleanProperty("nashorn.scriptfunction.specialization.disable");
-
- static MethodHandle candidateWithLowestWeight(final MethodType descType, final MethodHandle initialCandidate, final MethodHandle[] specs) {
- if (DISABLE_SPECIALIZATION || specs == null) {
- return initialCandidate;
- }
-
- int minimumWeight = Integer.MAX_VALUE;
- MethodHandle candidate = initialCandidate;
-
- for (final MethodHandle spec : specs) {
- final MethodType specType = spec.type();
-
- if (!typeCompatible(descType, specType)) {
- continue;
- }
-
- //return type is ok. we want a wider or equal one for our callsite.
- final int specWeight = weigh(specType);
- if (specWeight < minimumWeight) {
- candidate = spec;
- minimumWeight = specWeight;
- }
- }
-
- return candidate;
- }
-
- private static boolean typeCompatible(final MethodType desc, final MethodType spec) {
- //spec must fit in desc
- final Class<?>[] dparray = desc.parameterArray();
- final Class<?>[] sparray = spec.parameterArray();
-
- if (dparray.length != sparray.length) {
- return false;
- }
-
- for (int i = 0; i < dparray.length; i++) {
- final Type dp = Type.typeFor(dparray[i]);
- final Type sp = Type.typeFor(sparray[i]);
-
- if (dp.isBoolean()) {
- return false; //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
- }
-
- //specialization arguments must be at least as wide as dp, if not wider
- if (Type.widest(dp, sp) != sp) {
- //e.g. specialization takes double and callsite says "object". reject.
- //but if specialization says double and callsite says "int" or "long" or "double", that's fine
- return false;
- }
- }
-
- return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
- }
-
- private static int weigh(final MethodType t) {
- int weight = Type.typeFor(t.returnType()).getWeight();
- for (final Class<?> paramType : t.parameterArray()) {
- final int pweight = Type.typeFor(paramType).getWeight();
- weight += pweight;
- }
- return weight;
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/StructureLoader.java b/src/jdk/nashorn/internal/runtime/StructureLoader.java
index da64655f..35786b0b 100644
--- a/src/jdk/nashorn/internal/runtime/StructureLoader.java
+++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java
@@ -38,6 +38,7 @@ import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
/**
@@ -129,6 +130,6 @@ final class StructureLoader extends NashornLoader {
}
final byte[] code = new ObjectClassGenerator(context).generate(descriptor);
- return defineClass(name, code, 0, code.length);
+ return defineClass(name, code, 0, code.length, new ProtectionDomain(null, getPermissions(null)));
}
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index 3c5e2d81..6b55656b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -57,7 +57,7 @@ public final class Bootstrap {
static {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
- new JSObjectLinker());
+ new JSObjectLinker(), new ReflectionCheckLinker());
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
factory.setSyncOnRelink(true);
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
index a9e4bd01..7b0d6d76 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
@@ -54,6 +54,7 @@ import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.security.SecureClassLoader;
import java.security.SecureRandom;
@@ -410,9 +411,14 @@ public final class JavaAdapterFactory {
*/
public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType) throws Exception {
final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType });
- return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get(
- "dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false,
- adapterClass, null)).getInvocation(), adapterClass);
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<MethodHandle>() {
+ @Override
+ public MethodHandle run() throws Exception {
+ return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get(
+ "dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false,
+ adapterClass, null)).getInvocation(), adapterClass);
+ }
+ });
}
/**
@@ -456,9 +462,26 @@ public final class JavaAdapterFactory {
private static ClassLoader createClassLoader(final ClassLoader parentLoader, final String className,
final byte[] classBytes, final String privilegedActionClassName) {
return new AdapterLoader(parentLoader) {
+ private final ClassLoader myLoader = getClass().getClassLoader();
private final ProtectionDomain myProtectionDomain = getClass().getProtectionDomain();
@Override
+ public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
+ try {
+ return super.loadClass(name, resolve);
+ } catch (final SecurityException se) {
+ // we may be implementing an interface or extending a class that was
+ // loaded by a loader that prevents package.access. If so, it'd throw
+ // SecurityException for nashorn's classes!. For adapter's to work, we
+ // should be able to refer to nashorn classes.
+ if (name.startsWith("jdk.nashorn.internal.")) {
+ return myLoader.loadClass(name);
+ }
+ throw se;
+ }
+ }
+
+ @Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
if(name.equals(className)) {
final byte[] bytes = classBytes;
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
index 3d8363e1..834898af 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
@@ -39,7 +39,7 @@ import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
- * Utility class shared by {@link NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java
+ * Utility class shared by {@code NashornLinker} and {@code NashornPrimitiveLinker} for converting JS values to Java
* types.
*/
public class JavaArgumentConverters {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
index ed152485..a8e79184 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
@@ -40,8 +40,6 @@ public final class NashornGuards {
private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class);
private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
- private static final MethodHandle IS_FUNCTION_MH = findOwnMH("isFunctionMH", boolean.class, Object.class, MethodHandle.class);
- private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, MethodHandle.class);
private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
// don't create me!
@@ -87,33 +85,6 @@ public final class NashornGuards {
return MH.insertArguments(IS_INSTANCEOF_2, 1, class1, class2);
}
- /**
- * Get the guard that checks if a {@link ScriptFunction} is equal to
- * a known ScriptFunction, using reference comparison
- *
- * @param function The ScriptFunction to check against. This will be bound to the guard method handle
- *
- * @return method handle for guard
- */
- public static MethodHandle getFunctionGuard(final ScriptFunction function) {
- assert function.getInvokeHandle() != null;
- return MH.insertArguments(IS_FUNCTION_MH, 1, function.getInvokeHandle());
- }
-
- /**
- * Get a guard that checks if a {@link ScriptFunction} is equal to
- * a known ScriptFunction using reference comparison, and whether the type of
- * the second argument (this-object) is not a JavaScript primitive type.
- *
- * @param function The ScriptFunction to check against. This will be bound to the guard method handle
- *
- * @return method handle for guard
- */
- public static MethodHandle getNonStrictFunctionGuard(final ScriptFunction function) {
- assert function.getInvokeHandle() != null;
- return MH.insertArguments(IS_NONSTRICT_FUNCTION, 2, function.getInvokeHandle());
- }
-
@SuppressWarnings("unused")
private static boolean isScriptObject(final Object self) {
return self instanceof ScriptObject;
@@ -130,16 +101,6 @@ public final class NashornGuards {
}
@SuppressWarnings("unused")
- private static boolean isFunctionMH(final Object self, final MethodHandle mh) {
- return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh;
- }
-
- @SuppressWarnings("unused")
- private static boolean isNonStrictFunction(final Object self, final Object arg, final MethodHandle mh) {
- return self instanceof ScriptFunction && ((ScriptFunction)self).getInvokeHandle() == mh && arg instanceof ScriptObject;
- }
-
- @SuppressWarnings("unused")
private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) {
return class1.isInstance(self) || class2.isInstance(self);
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
index 968dba91..eaba64f4 100644
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
@@ -109,7 +109,6 @@ public class PrimitiveLookup {
}
return new GuardedInvocation(method, guard, link.getSwitchPoint());
}
- assert desc.getNameTokenCount() <= 2; // Named operations would hit the return null after findProperty
return null;
}
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
new file mode 100644
index 00000000..eb8837a8
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, 2013, 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.runtime.linker;
+
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
+
+/**
+ * Check java reflection permission for java reflective and java.lang.invoke access from scripts
+ */
+final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
+ @Override
+ public boolean canLinkType(final Class<?> type) {
+ return canLinkTypeStatic(type);
+ }
+
+ private static boolean canLinkTypeStatic(final Class<?> type) {
+ if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) {
+ return true;
+ }
+ final String name = type.getName();
+ return name.startsWith("java.lang.reflect.") || name.startsWith("java.lang.invoke.");
+ }
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices)
+ throws Exception {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
+ }
+ // let the next linker deal with actual linking
+ return null;
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
index 82b6edbc..16ff04ea 100644
--- a/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
+++ b/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
@@ -278,7 +278,7 @@ public class OptionTemplate implements Comparable<OptionTemplate> {
this.valueNextArg = Boolean.parseBoolean(arg);
break;
default:
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(keyToken);
}
}
diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java
index 0f30b1a1..3e09fa57 100644
--- a/src/jdk/nashorn/internal/runtime/options/Options.java
+++ b/src/jdk/nashorn/internal/runtime/options/Options.java
@@ -66,6 +66,9 @@ public final class Options {
/** The options map of enabled options */
private final TreeMap<String, Option<?>> options;
+ /** System property that can be used for command line option propagation */
+ private static final String NASHORN_ARGS_PROPERTY = "nashorn.args";
+
/**
* Constructor
*
@@ -386,6 +389,14 @@ public final class Options {
final LinkedList<String> argList = new LinkedList<>();
Collections.addAll(argList, args);
+ final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null);
+ if (extra != null) {
+ final StringTokenizer st = new StringTokenizer(extra);
+ while (st.hasMoreTokens()) {
+ argList.add(st.nextToken());
+ }
+ }
+
while (!argList.isEmpty()) {
final String arg = argList.remove(0);
diff --git a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
index 7c1dd8b4..ecbc8bc9 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
@@ -95,14 +95,14 @@ public class DefaultRegExp extends RegExp {
return null; // never matches or similar, e.g. a[]
}
- RegExpMatcher matcher = this.matcher;
+ RegExpMatcher currentMatcher = this.matcher;
- if (matcher == null || matcher.getInput() != str) {
- matcher = new DefaultMatcher(str);
- this.matcher = matcher;
+ if (currentMatcher == null || matcher.getInput() != str) {
+ currentMatcher = new DefaultMatcher(str);
+ this.matcher = currentMatcher;
}
- return matcher;
+ return currentMatcher;
}
class DefaultMatcher implements RegExpMatcher {
diff --git a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
index f8c35bfe..719f6c39 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
@@ -97,14 +97,14 @@ public class JoniRegExp extends RegExp {
return null;
}
- RegExpMatcher matcher = this.matcher;
+ RegExpMatcher currentMatcher = this.matcher;
- if (matcher == null || input != matcher.getInput()) {
- matcher = new JoniMatcher(input);
- this.matcher = matcher;
+ if (currentMatcher == null || input != currentMatcher.getInput()) {
+ currentMatcher = new JoniMatcher(input);
+ this.matcher = currentMatcher;
}
- return matcher;
+ return currentMatcher;
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExp.java b/src/jdk/nashorn/internal/runtime/regexp/RegExp.java
index a4274f6a..ff694b90 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExp.java
@@ -156,7 +156,7 @@ public abstract class RegExp {
*
* @param key the message key
* @param str string argument
- * @throws jdk.nashorn.internal.runtime.ParserException
+ * @throws jdk.nashorn.internal.runtime.ParserException unconditionally
*/
protected static void throwParserException(final String key, final String str) throws ParserException {
throw new ParserException(ECMAErrors.getMessage("parser.error.regex." + key, str));
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
index 367cc85b..6ff66f21 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.runtime.regexp;
-import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.options.Options;
@@ -35,7 +34,6 @@ import jdk.nashorn.internal.runtime.options.Options;
*/
public class RegExpFactory {
-
private final static RegExpFactory instance;
private final static String JDK = "jdk";
@@ -60,7 +58,8 @@ public class RegExpFactory {
* Creates a Regular expression from the given {@code pattern} and {@code flags} strings.
*
* @param pattern RegExp pattern string
- * @param flags RegExp flags string
+ * @param flags RegExp flags string
+ * @return new RegExp
* @throws ParserException if flags is invalid or pattern string has syntax error.
*/
protected RegExp compile(final String pattern, final String flags) throws ParserException {
@@ -71,8 +70,8 @@ public class RegExpFactory {
* Compile a regexp with the given {@code source} and {@code flags}.
*
* @param pattern RegExp pattern string
- * @param flags flag string
- *
+ * @param flags flag string
+ * @return new RegExp
* @throws ParserException if invalid source or flags
*/
public static RegExp create(final String pattern, final String flags) {
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java
index ff838b6f..cd81be3c 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpResult.java
@@ -80,11 +80,11 @@ public final class RegExpResult {
/**
* Get the group with the given index or the empty string if group index is not valid.
- * @param index the group index
+ * @param groupIndex the group index
* @return the group or ""
*/
- public Object getGroup(int index) {
- return index >= 0 && index < groups.length ? groups[index] : "";
+ public Object getGroup(final int groupIndex) {
+ return groupIndex >= 0 && groupIndex < groups.length ? groups[groupIndex] : "";
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
index b579865b..e8c60c4a 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
@@ -182,8 +182,6 @@ final class RegExpScanner extends Scanner {
* @return Committed token
*/
private boolean commit(final int n) {
- final int startIn = position;
-
switch (n) {
case 1:
sb.append(ch0);
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
index 8aaabe2d..43cc5188 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java
@@ -1459,4 +1459,4 @@ class ByteCodeMachine extends StackMachine {
private int finish() {
return bestLen;
}
-} \ No newline at end of file
+}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java b/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java
index 77eba2de..3dec4ba2 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/joni/encoding/AsciiTables.java
@@ -154,4 +154,4 @@ public class AsciiTables {
{0x59, 0x79},
{0x5a, 0x7a}
};
-} \ No newline at end of file
+}
diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties
index 4547e444..43a7ff62 100644
--- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -42,6 +42,8 @@ parser.error.expected.stmt=Expected statement but found {0}
parser.error.expected.comma=Expected comma but found {0}
parser.error.expected=Expected {0} but found {1}
parser.error.invalid.return=Invalid return statement
+parser.error.no.func.decl.here=Function declarations can only occur at program or function body level. You should use a function expression here instead.
+parser.error.no.func.decl.here.warn=Function declarations should only occur at program or function body level. Function declaration in nested block was converted to a function expression.
parser.error.property.redefinition=Property "{0}" already defined
parser.error.unexpected.token=Unexpected token: {0}
parser.error.many.vars.in.for.in.loop=Only one variable allowed in for..in loop
@@ -57,7 +59,7 @@ parser.error.strict.name="{0}" cannot be used as {1} in strict mode
parser.error.strict.cant.delete.ident=cannot delete identifier "{0}" in strict mode
parser.error.strict.param.redefinition=strict mode function cannot have duplicate parameter name "{0}"
parser.error.strict.no.octal=cannot use octal value in strict mode
-parser.error.strict.no.func.here=In strict mode, functions can only be declared at top-level or immediately within a function
+parser.error.strict.no.func.decl.here=In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead.
type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "arguments" properties can not be accessed on functions or the arguments object
# not the expected type in a given context
diff --git a/src/jdk/nashorn/internal/runtime/resources/Options.properties b/src/jdk/nashorn/internal/runtime/resources/Options.properties
index 534eb177..e63f7a37 100644
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties
@@ -165,6 +165,12 @@ nashorn.option.debug.locals = { \
desc="Generate local variable table in .class files." \
}
+nashorn.option.lazy.compilation = { \
+ name="--lazy-compilation", \
+ is_undocumented=true, \
+ desc="EXPERIMENTAL: Use lazy code generation strategies - do not compile the entire script at once." \
+}
+
nashorn.option.loader.per.compile = { \
name="--loader-per-compile", \
is_undocumented=true, \
diff --git a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
index 15c67f94..0b967d69 100644
--- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
+++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2010, 2013, 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.
@@ -34,7 +34,7 @@ Object.defineProperty(this, "JavaAdapter", {
if (arguments.length < 2) {
throw new TypeError("JavaAdapter requires atleast two arguments");
}
-
+
var types = Array.prototype.slice.call(arguments, 0, arguments.length - 1);
var NewType = Java.extend.apply(Java, types);
return new NewType(arguments[arguments.length - 1]);
@@ -56,10 +56,10 @@ Object.defineProperty(this, "importPackage", {
return type;
} catch (e) {}
}
-
+
return oldNoSuchProperty? oldNoSuchProperty(name) : undefined;
}
-
+
var prefix = "[JavaPackage ";
return function() {
for (var i in arguments) {
@@ -343,7 +343,9 @@ Object.defineProperty(this, "importClass", {
configurable: true, enumerable: false, writable: true,
value: function(clazz) {
if (Java.isType(clazz)) {
- this[clazz.class.getSimpleName()] = clazz;
+ var className = Java.typeName(clazz);
+ var simpleName = className.substring(className.lastIndexOf('.') + 1);
+ this[simpleName] = clazz;
} else {
throw new TypeError(clazz + " is not a Java class");
}
diff --git a/src/jdk/nashorn/internal/runtime/resources/parser.js b/src/jdk/nashorn/internal/runtime/resources/parser.js
index b89f7e12..8671d365 100644
--- a/src/jdk/nashorn/internal/runtime/resources/parser.js
+++ b/src/jdk/nashorn/internal/runtime/resources/parser.js
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2010, 2013, 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.
@@ -47,7 +47,7 @@ function parse(/*code, [name], [location]*/) {
code = arguments[0];
}
- var jsonStr = Packages.jdk.nashorn.internal.runtime.ScriptRuntime.parse(code, name, location);
+ var jsonStr = Packages.jdk.nashorn.api.scripting.ScriptUtils.parse(code, name, location);
return JSON.parse(jsonStr,
function (prop, value) {
if (typeof(value) == 'string' && prop == "value") {
diff --git a/test/script/basic/JDK-8006755.js b/test/script/basic/JDK-8006755.js
index 3012a4be..09243473 100644
--- a/test/script/basic/JDK-8006755.js
+++ b/test/script/basic/JDK-8006755.js
@@ -31,7 +31,7 @@
var scope = { x: "hello" };
with (scope) {
- function main() {
+ var main = function() {
if (x != "hello") {
fail("x != 'hello'");
}
diff --git a/test/script/basic/JDK-8008448.js b/test/script/basic/JDK-8008448.js
index d5ffbd4c..b30e3417 100644
--- a/test/script/basic/JDK-8008448.js
+++ b/test/script/basic/JDK-8008448.js
@@ -32,7 +32,7 @@
var File = Java.type("java.io.File");
var FilenameFilter = Java.type("java.io.FilenameFilter");
-var Source = Java.type("jdk.nashorn.internal.runtime.Source")
+var SourceHelper = Java.type("jdk.nashorn.test.models.SourceHelper")
// Filter out non .js files
var files = new File(__DIR__).listFiles(new FilenameFilter() {
@@ -44,5 +44,5 @@ load("nashorn:parser.js");
// parse each file to make sure it does not result in exception
for each (var f in files) {
- parse(new Source(f.toString(), f).getString());
+ parse(SourceHelper.readFully(f));
}
diff --git a/test/script/basic/JDK-8009868.js b/test/script/basic/JDK-8009868.js
new file mode 100644
index 00000000..ffbc8c21
--- /dev/null
+++ b/test/script/basic/JDK-8009868.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8009868: For loop with "true" as condition results in AssertionError in codegen
+ *
+ * @test
+ * @run
+ */
+
+// This used to crash with AssertionError in codegen
+for(; true;) {
+ break;
+}
diff --git a/test/script/basic/JDK-8010199.js b/test/script/basic/JDK-8010199.js
new file mode 100644
index 00000000..ddd3ba0f
--- /dev/null
+++ b/test/script/basic/JDK-8010199.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8010199: javax.script.Invocable implementation for nashorn does not return null when matching functions are missing
+ *
+ * @test
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+
+var iface = e.getInterface(java.lang.Runnable.class);
+
+if (iface != null) {
+ fail("Expected interface object to be null");
+}
+
+e.eval("var runcalled = false; function run() { runcalled = true }");
+
+iface = e.getInterface(java.lang.Runnable.class);
+if (iface == null) {
+ fail("Expected interface object to be non-null");
+}
+
+iface.run();
+
+if (e.get("runcalled") != true) {
+ fail("runcalled is not true");
+}
diff --git a/test/script/basic/JDK-8010709.js b/test/script/basic/JDK-8010709.js
new file mode 100644
index 00000000..d2ec87ae
--- /dev/null
+++ b/test/script/basic/JDK-8010709.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8010709 org on the top level doesn't resolve
+ *
+ * @test
+ * @run
+ */
+
+function check(pkgName) {
+ if (typeof this[pkgName] != 'object') {
+ fail(pkgName + " not defined");
+ }
+
+ if (String(this[pkgName]) != '[JavaPackage ' + pkgName + ']') {
+ fail(pkgName + " is not a JavaPackage");
+ }
+}
+
+check("com");
+check("edu");
+check("java");
+check("javafx");
+check("javax");
+check("org");
diff --git a/test/script/basic/JDK-8010720.js b/test/script/basic/JDK-8010720.js
new file mode 100644
index 00000000..1dddf22b
--- /dev/null
+++ b/test/script/basic/JDK-8010720.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8010720: Linkage problem with java.lang.String.length()
+ *
+ * @test
+ * @run
+ */
+
+var s = new java.lang.String("nashorn");
+
+if (s.length() != 7) {
+ fail("s.length() does not return expected value");
+}
+
+if (s.length != 7) {
+ fail("s.length does not return expected value");
+}
+
+
+if ('hello'.length() != 5) {
+ fail("'hello'.length() does not return expected value");
+}
+
+if ('hello'.length != 5) {
+ fail("'hello'.length does not return expected value");
+}
+
diff --git a/test/script/basic/JDK-8017010.js b/test/script/basic/JDK-8017010.js
new file mode 100644
index 00000000..aa6e61a9
--- /dev/null
+++ b/test/script/basic/JDK-8017010.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8010710 - slot/scope problem with temporary expressions
+ * as array index in self modifying assigns
+ *
+ * @test
+ * @run
+ */
+function zero() {
+ return 0;
+}
+
+//try complex self modifying assignment and force slots to temporary value index operators
+var a = [1, 2, 3, 4, 5];
+var b = [a, a];
+print(b[zero() + 1][2 + a[0]] += 10);
+
+//repro for NASHORN-258 that never made it
+function AddRoundKey() {
+ var r=0;
+ state[r][1] &= 17;
+}
+
+var srcFiles = [];
+for(i=0;i<100;i++) {
+ srcFiles.push('dummy');
+}
+var added = '';
+
+//this broke the javafx build system. verify it works
+function bouncingBall() {
+ for (j=0; j<100; j++) {
+ added += srcFiles[j];
+ }
+}
+bouncingBall();
+print(added);
+
+//this is how they should have done it for speed, that works always, verify this too
+function bouncingBall2() {
+ for (var k=0; k<100; k++) {
+ added += srcFiles[k];
+ }
+}
+bouncingBall2();
+print(added);
diff --git a/test/script/basic/JDK-8017010.js.EXPECTED b/test/script/basic/JDK-8017010.js.EXPECTED
new file mode 100644
index 00000000..296c81e5
--- /dev/null
+++ b/test/script/basic/JDK-8017010.js.EXPECTED
@@ -0,0 +1,3 @@
+14
+dummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummy
+dummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummydummy
diff --git a/test/script/basic/NASHORN-258.js b/test/script/basic/NASHORN-258.js
index 0f4f674b..6d71266a 100644
--- a/test/script/basic/NASHORN-258.js
+++ b/test/script/basic/NASHORN-258.js
@@ -29,6 +29,16 @@
*/
function test3(a) {
+ for (i = 0; i < a.length ; i++) {
+ for (j = 0; j < a[i].length ; j++) {
+ for (k = 0; k < a[i][j].length ; k++) {
+ a[i][j][k] *= 8;
+ }
+ }
+ }
+}
+
+function test3local(a) {
for (var i = 0; i < a.length ; i++) {
for (var j = 0; j < a[i].length ; j++) {
for (var k = 0; k < a[i][j].length ; k++) {
@@ -45,6 +55,8 @@ var array = [ [[1,1,1],[1,1,1],[1,1,1]],
test3(array);
print(array);
+test3local(array);
+print(array);
function outer() {
diff --git a/test/script/basic/NASHORN-258.js.EXPECTED b/test/script/basic/NASHORN-258.js.EXPECTED
index 8c95c914..5986c471 100644
--- a/test/script/basic/NASHORN-258.js.EXPECTED
+++ b/test/script/basic/NASHORN-258.js.EXPECTED
@@ -1,2 +1,3 @@
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8,1,1,8
diff --git a/test/script/basic/NASHORN-401.js b/test/script/basic/NASHORN-401.js
index b6058a9b..6a663e1a 100644
--- a/test/script/basic/NASHORN-401.js
+++ b/test/script/basic/NASHORN-401.js
@@ -28,7 +28,7 @@
* @run
*/
-var t = new Packages.jdk.nashorn.internal.runtime.Nashorn401TestSubject();
+var t = new Packages.jdk.nashorn.test.models.Nashorn401TestSubject();
print(t.method2(10));
print(t.method2(10.2));
diff --git a/test/script/basic/NASHORN-837.js b/test/script/basic/NASHORN-837.js
index 0632fb39..ef9ec64d 100644
--- a/test/script/basic/NASHORN-837.js
+++ b/test/script/basic/NASHORN-837.js
@@ -28,23 +28,13 @@
* @run
*/
-var failed = false;
-
try {
- try {
- throw new TypeError('error');
- } catch (iox) {
- function f() {
- print(iox.message);
- }
+ throw new TypeError('error');
+} catch (iox) {
+ var f = function() {
+ if(iox.message != 'error') {
+ print("Failure! iox did not throw correct exception");
+ }
}
- f();
-} catch (e) {
- failed = (e instanceof ReferenceError);
- //iox not defined should be thrown
-}
-
-if (!failed) {
- print("Failure! iox did not throw correct exception");
}
-
+f();
diff --git a/test/script/basic/compile-octane.js.EXPECTED b/test/script/basic/compile-octane.js.EXPECTED
index dab419e6..39f866c2 100644
--- a/test/script/basic/compile-octane.js.EXPECTED
+++ b/test/script/basic/compile-octane.js.EXPECTED
@@ -16,6 +16,9 @@ Compiled OK: earley-boyer.js
Compiling... gbemu.js
Compiled OK: gbemu.js
+Compiling... mandreel.js
+Compiled OK: mandreel.js
+
Compiling... navier-stokes.js
Compiled OK: navier-stokes.js
diff --git a/test/script/basic/consstring.js b/test/script/basic/consstring.js
index b8dc51d8..0cc8b1f8 100644
--- a/test/script/basic/consstring.js
+++ b/test/script/basic/consstring.js
@@ -37,4 +37,4 @@ list.add(String(new String(str + "2"))); // String() called as function with
list.add((str + "3").toString()); // toString() called on primitive string
list.add(new String(str + "4").toString()); // toString() called on String object
-Packages.jdk.nashorn.internal.test.models.StringArgs.checkString(list);
+Packages.jdk.nashorn.test.models.StringArgs.checkString(list);
diff --git a/test/script/basic/fileline.js b/test/script/basic/fileline.js
index 3323a126..ccf879b2 100644
--- a/test/script/basic/fileline.js
+++ b/test/script/basic/fileline.js
@@ -41,8 +41,8 @@ print(file + " : " + __LINE__);
load(__DIR__ + "loadedfile.js");
// Add check for base part of a URL. We can't test __DIR__ inside
-// a script that is downloaded from a URL. check for Source.baseURL
+// a script that is downloaded from a URL. check for SourceHelper.baseURL
// which is exposed as __DIR__ for URL case.
var url = new java.net.URL("http://www.acme.com:8080/foo/bar.js");
-print(Packages.jdk.nashorn.internal.runtime.Source.baseURL(url));
+print(Packages.jdk.nashorn.test.models.SourceHelper.baseURL(url));
diff --git a/test/script/basic/javainnerclasses.js b/test/script/basic/javainnerclasses.js
index df1e74df..c84571d7 100644
--- a/test/script/basic/javainnerclasses.js
+++ b/test/script/basic/javainnerclasses.js
@@ -29,25 +29,25 @@
*/
// Do it with Java.type()
-var outer = new (Java.type("jdk.nashorn.internal.test.models.OuterClass"))("apple")
+var outer = new (Java.type("jdk.nashorn.test.models.OuterClass"))("apple")
print(outer)
-var innerStatic = new (Java.type("jdk.nashorn.internal.test.models.OuterClass$InnerStaticClass"))("orange")
+var innerStatic = new (Java.type("jdk.nashorn.test.models.OuterClass$InnerStaticClass"))("orange")
print(innerStatic)
-var innerNonStatic = new (Java.type("jdk.nashorn.internal.test.models.OuterClass$InnerNonStaticClass"))(outer, "pear")
+var innerNonStatic = new (Java.type("jdk.nashorn.test.models.OuterClass$InnerNonStaticClass"))(outer, "pear")
print(innerNonStatic)
// Now do it with Packages and explicit $ names
-var outer = new Packages.jdk.nashorn.internal.test.models.OuterClass("red")
+var outer = new Packages.jdk.nashorn.test.models.OuterClass("red")
print(outer)
-var innerStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass$InnerStaticClass("green")
+var innerStatic = new Packages.jdk.nashorn.test.models.OuterClass$InnerStaticClass("green")
print(innerStatic)
-var innerNonStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass$InnerNonStaticClass(outer, "blue")
+var innerNonStatic = new Packages.jdk.nashorn.test.models.OuterClass$InnerNonStaticClass(outer, "blue")
print(innerNonStatic)
// Now do it with Packages and nested properties
-var outer = new Packages.jdk.nashorn.internal.test.models.OuterClass("sweet")
+var outer = new Packages.jdk.nashorn.test.models.OuterClass("sweet")
print(outer)
-var innerStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass.InnerStaticClass("sour")
+var innerStatic = new Packages.jdk.nashorn.test.models.OuterClass.InnerStaticClass("sour")
print(innerStatic)
-var innerNonStatic = new Packages.jdk.nashorn.internal.test.models.OuterClass.InnerNonStaticClass(outer, "bitter")
+var innerNonStatic = new Packages.jdk.nashorn.test.models.OuterClass.InnerNonStaticClass(outer, "bitter")
print(innerNonStatic)
diff --git a/test/script/basic/list.js b/test/script/basic/list.js
index 12e4071b..72ae0be7 100644
--- a/test/script/basic/list.js
+++ b/test/script/basic/list.js
@@ -28,7 +28,7 @@
* @run
*/
var l = new java.util.ArrayList();
-print("l.class.name=" + l.class.name) // Has "class" property like any POJO
+print("l.class.name=" + Java.typeName(l.class)) // Has "class" property like any POJO
l.add("foo")
l.add("bar")
diff --git a/test/script/basic/map.js b/test/script/basic/map.js
index 2ab27aba..c024f6eb 100644
--- a/test/script/basic/map.js
+++ b/test/script/basic/map.js
@@ -28,7 +28,7 @@
* @run
*/
var m = new (Java.type("java.util.LinkedHashMap"));
-print("m.class.name=" + m.class.name) // Has "class" property like any POJO
+print("m.class.name=" + Java.typeName(m.class)) // Has "class" property like any POJO
var empty_key = "empty"
diff --git a/test/script/basic/run-octane.js b/test/script/basic/run-octane.js
index 42bf77fa..315451cb 100644
--- a/test/script/basic/run-octane.js
+++ b/test/script/basic/run-octane.js
@@ -31,7 +31,8 @@ var tests = [
"crypto.js",
"deltablue.js",
"earley-boyer.js",
- "gbemu.js",
+ "gbemu.js",
+ "mandreel.js",
"navier-stokes.js",
"pdfjs.js",
"raytrace.js",
@@ -49,6 +50,12 @@ var ignoreTeardown = [
{ name: "gbemu.js" },
];
+
+//TODO mandreel can be compiled as a test, but not run multiple times unless modified to not have global state
+var compileOnly = {
+ "mandreel.js" : true
+};
+
var dir = (typeof(__DIR__) == 'undefined') ? "test/script/basic/" : __DIR__;
// TODO: why is this path hard coded when it's defined in project properties?
@@ -63,6 +70,10 @@ function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
+function should_compile_only(name) {
+ return (typeof compile_only !== 'undefined') || compileOnly[name] === true;
+}
+
function run_one_benchmark(arg, iters) {
var file_name;
@@ -77,14 +88,18 @@ function run_one_benchmark(arg, iters) {
}
file_name = file[file.length - 1];
- if (typeof compile_only !== 'undefined') {
+ var compile_and_return = should_compile_only(file_name);
+ if (compile_and_return) {
+ if (typeof compile_only === 'undefined') { //for a run, skip compile onlies, don't even compile them
+ return;
+ }
print("Compiling... " + file_name);
}
load(path + 'base.js');
load(arg);
- if (typeof compile_only !== 'undefined') {
+ if (compile_and_return) {
print("Compiled OK: " + file_name);
print("");
return;
@@ -164,7 +179,7 @@ function run_one_benchmark(arg, iters) {
function run_suite(tests, iters) {
for (var idx = 0; idx < tests.length; idx++) {
- run_one_benchmark(tests[idx], iters, false);
+ run_one_benchmark(tests[idx], iters);
}
}
diff --git a/test/script/basic/runsunspider-eager.js b/test/script/basic/runsunspider-eager.js
new file mode 100644
index 00000000..db358d28
--- /dev/null
+++ b/test/script/basic/runsunspider-eager.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * runsunspider : runs the sunspider tests and checks for compliance
+ *
+ * @test
+ * @option -timezone=PST
+ * @runif external.sunspider
+ */
+
+load(__DIR__ + "runsunspider.js");
+
diff --git a/test/script/basic/runsunspider.js.EXPECTED b/test/script/basic/runsunspider-eager.js.EXPECTED
index dd360839..dd360839 100644
--- a/test/script/basic/runsunspider.js.EXPECTED
+++ b/test/script/basic/runsunspider-eager.js.EXPECTED
diff --git a/test/script/basic/runsunspider-lazy.js b/test/script/basic/runsunspider-lazy.js
new file mode 100644
index 00000000..6e24c0c5
--- /dev/null
+++ b/test/script/basic/runsunspider-lazy.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * runsunspider : runs the sunspider tests and checks for compliance
+ *
+ * @test
+ * @option -timezone=PST
+ * @option --lazy-compilation
+ * @runif external.sunspider
+ */
+
+load(__DIR__ + "runsunspider.js");
+
diff --git a/test/script/basic/runsunspider-lazy.js.EXPECTED b/test/script/basic/runsunspider-lazy.js.EXPECTED
new file mode 100644
index 00000000..dd360839
--- /dev/null
+++ b/test/script/basic/runsunspider-lazy.js.EXPECTED
@@ -0,0 +1 @@
+Sunspider finished!
diff --git a/test/script/basic/runsunspider.js b/test/script/basic/runsunspider.js
index 7b0d732c..7f787975 100644
--- a/test/script/basic/runsunspider.js
+++ b/test/script/basic/runsunspider.js
@@ -24,39 +24,11 @@
/**
* runsunspider : runs the sunspider tests and checks for compliance
*
- * @test
- * @option -timezone=PST
- * @runif external.sunspider
- */
-
-/*
- * Copyright (c) 2010-2011, 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.
+ * @subtest
*/
/**
* This is not a test, but a test "framework" for running sunspider tests.
- *
*/
function assertEq(a, b) {
diff --git a/test/script/basic/stdin.js b/test/script/basic/stdin.js
index ba546d59..a3a93324 100644
--- a/test/script/basic/stdin.js
+++ b/test/script/basic/stdin.js
@@ -28,8 +28,8 @@
* @run
*/
-print(java.lang.System.in.class.name);
+print(Java.typeName(java.lang.System.in.class));
var prop = "in";
-print(java.lang.System[prop].class.name);
-print(java.lang.System["in"].class.name);
+print(Java.typeName(java.lang.System[prop].class));
+print(Java.typeName(java.lang.System["in"].class));
diff --git a/test/script/currently-failing/JDK-8006529.js b/test/script/currently-failing/JDK-8006529.js
index da08d2b5..ca21f0b9 100644
--- a/test/script/currently-failing/JDK-8006529.js
+++ b/test/script/currently-failing/JDK-8006529.js
@@ -39,12 +39,13 @@
* and FunctionNode because of package-access check and so reflective calls.
*/
-var Parser = Java.type("jdk.nashorn.internal.parser.Parser")
-var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler")
-var Context = Java.type("jdk.nashorn.internal.runtime.Context")
+var Parser = Java.type("jdk.nashorn.internal.parser.Parser")
+var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler")
+var Context = Java.type("jdk.nashorn.internal.runtime.Context")
var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment")
-var Source = Java.type("jdk.nashorn.internal.runtime.Source")
-var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode")
+var Source = Java.type("jdk.nashorn.internal.runtime.Source")
+var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode")
+var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager");
// Compiler class methods and fields
var parseMethod = Parser.class.getMethod("parse");
@@ -90,7 +91,7 @@ function getFirstFunction(functionNode) {
// representing it.
function compile(source) {
var source = new Source("<no name>", source);
- var parser = new Parser(Context.getContext().getEnv(), source, null);
+ var parser = new Parser(Context.getContext().getEnv(), source, new ThrowErrorManager());
var func = parseMethod.invoke(parser);
var compiler = new Compiler(Context.getContext().getEnv(), func);
diff --git a/test/script/currently-failing/clone_ir.js b/test/script/currently-failing/clone_ir.js
new file mode 100644
index 00000000..3c1eccf2
--- /dev/null
+++ b/test/script/currently-failing/clone_ir.js
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * clone_ir : Check that functionNode.clone copies all nodes and that they
+ * are not the same references
+ *
+ * @test
+ * @run
+ */
+
+var js1 = "var tuple = { func : function f(x) { if (x) { print('true'); { print('block_under-true'); } } else { print('false'); } } }";
+
+var Parser = Java.type("jdk.nashorn.internal.parser.Parser");
+var ASTWriter = Java.type("jdk.nashorn.internal.ir.debug.ASTWriter");
+var Context = Java.type("jdk.nashorn.internal.runtime.Context");
+var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment");
+var Source = Java.type("jdk.nashorn.internal.runtime.Source");
+var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode");
+var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager");
+var System = Java.type("java.lang.System");
+
+var toArrayMethod = ASTWriter.class.getMethod("toArray");
+var parseMethod = Parser.class.getMethod("parse");
+
+function toString(obj) {
+ var output = "{ ";
+ for (property in obj) {
+ output += property + ': ' + obj[property]+'; ';
+ }
+ return output + '}'
+}
+
+function flatten(func) {
+ var writer = new ASTWriter(func);
+ var funcList = toArrayMethod.invoke(writer);
+
+ var res = [];
+ for each (x in funcList) {
+ res.push({ name: x.getClass().getName(), id: System.identityHashCode(x) });
+ }
+ return res;
+}
+
+function check(contents) {
+ return check_src(new Source("<no name>", contents));
+}
+
+function check_src(src) {
+ var parser = new Parser(Context.getContext().getEnv(), src, new ThrowErrorManager());
+
+ var func = parseMethod.invoke(parser);
+ print(func);
+ var func2 = func.clone();
+
+ var f1 = flatten(func);
+ var f2 = flatten(func2);
+
+ print(f1.map(toString));
+ print(f2.map(toString));
+
+ if (f1.length != f2.length) {
+ print("length difference between original and clone " + f1.length + " != " + f2.length);
+ return false;
+ }
+
+ for (var i = 0; i < f1.length; i++) {
+ if (f1[i].name !== f2[i].name) {
+ print("name conflict at " + i + " " + f1[i].name + " != " + f2[i].name);
+ return false;
+ } else if (f1[i].id === f2[i].id) {
+ print("id problem at " + i + " " + toString(f1[i]) + " was not deep copied to " + toString(f2[i]) + " became " + f1[i].id + " != " + f2[i].id);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+print(check(js1));
diff --git a/test/script/sandbox/javaextend.js b/test/script/sandbox/javaextend.js
index 318a6794..33cc6b01 100644
--- a/test/script/sandbox/javaextend.js
+++ b/test/script/sandbox/javaextend.js
@@ -27,7 +27,7 @@
*/
function model(n) {
- return Java.type("jdk.nashorn.internal.test.models." + n)
+ return Java.type("jdk.nashorn.test.models." + n)
}
// Can't extend a final class
diff --git a/test/script/sandbox/javaextend.js.EXPECTED b/test/script/sandbox/javaextend.js.EXPECTED
index 2a5ad63a..69c78189 100644
--- a/test/script/sandbox/javaextend.js.EXPECTED
+++ b/test/script/sandbox/javaextend.js.EXPECTED
@@ -1,6 +1,6 @@
-TypeError: Can not extend final class jdk.nashorn.internal.test.models.FinalClass.
-TypeError: Can not extend class jdk.nashorn.internal.test.models.NoAccessibleConstructorClass as it has no public or protected constructors.
-TypeError: Can not extend/implement non-public class/interface jdk.nashorn.internal.test.models.NonPublicClass.
+TypeError: Can not extend final class jdk.nashorn.test.models.FinalClass.
+TypeError: Can not extend class jdk.nashorn.test.models.NoAccessibleConstructorClass as it has no public or protected constructors.
+TypeError: Can not extend/implement non-public class/interface jdk.nashorn.test.models.NonPublicClass.
TypeError: Can not extend multiple classes java.lang.Number and java.lang.Thread. At most one of the specified types can be a class, the rest must all be interfaces.
abcdabcd
run-object
diff --git a/test/script/sandbox/reflection.js b/test/script/sandbox/reflection.js
index 7364879d..e892c646 100644
--- a/test/script/sandbox/reflection.js
+++ b/test/script/sandbox/reflection.js
@@ -30,9 +30,7 @@
*/
function check(e) {
- if (e instanceof java.lang.SecurityException) {
- print(e);
- } else {
+ if (! (e instanceof java.lang.SecurityException)) {
fail("expected SecurityException, got " + e);
}
}
diff --git a/test/script/sandbox/reflection.js.EXPECTED b/test/script/sandbox/reflection.js.EXPECTED
deleted file mode 100644
index 202333ea..00000000
--- a/test/script/sandbox/reflection.js.EXPECTED
+++ /dev/null
@@ -1 +0,0 @@
-java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")
diff --git a/test/script/sandbox/unsafe.js b/test/script/sandbox/unsafe.js
index b273cd0b..6b3f43af 100644
--- a/test/script/sandbox/unsafe.js
+++ b/test/script/sandbox/unsafe.js
@@ -30,9 +30,7 @@
*/
function check(e) {
- if (e instanceof java.lang.SecurityException) {
- print(e);
- } else {
+ if (! (e instanceof java.lang.SecurityException)) {
fail("expected SecurityException, got " + e);
}
}
diff --git a/test/script/sandbox/unsafe.js.EXPECTED b/test/script/sandbox/unsafe.js.EXPECTED
deleted file mode 100644
index 3f1cbec0..00000000
--- a/test/script/sandbox/unsafe.js.EXPECTED
+++ /dev/null
@@ -1,4 +0,0 @@
-java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc")
-java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.misc")
-java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun")
-java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getClassLoader")
diff --git a/test/script/trusted/urlreader.js b/test/script/trusted/urlreader.js
index a5e06ee5..ca037306 100644
--- a/test/script/trusted/urlreader.js
+++ b/test/script/trusted/urlreader.js
@@ -9,7 +9,7 @@ var URLReader = Java.type("jdk.nashorn.api.scripting.URLReader");
var URL = Java.type("java.net.URL");
var File = Java.type("java.io.File");
var JString = Java.type("java.lang.String");
-var Source = Java.type("jdk.nashorn.internal.runtime.Source");
+var SourceHelper = Java.type("jdk.nashorn.test.models.SourceHelper");
var url = new File(__FILE__).toURI().toURL();
var reader = new URLReader(url);
@@ -19,9 +19,9 @@ var reader = new URLReader(url);
// check URL read
// read URL content by directly reading from URL
-var str = new Source(url.toString(), url).getString();
+var str = SourceHelper.readFully(url);
// read URL content via URLReader
-var content = new JString(Source.readFully(reader));
+var content = new JString(SourceHelper.readFully(reader));
// assert that the content is same
Assert.assertEquals(str, content);
diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
index f4fd114f..48277aa8 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
@@ -47,7 +47,6 @@ import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
-import jdk.nashorn.internal.runtime.Version;
import netscape.javascript.JSObject;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -129,7 +128,6 @@ public class ScriptEngineTest {
assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
assertEquals(fac.getLanguageVersion(), "ECMA - 262 Edition 5.1");
assertEquals(fac.getEngineName(), "Oracle Nashorn");
- assertEquals(fac.getEngineVersion(), Version.version());
assertEquals(fac.getOutputStatement("context"), "print(context)");
assertEquals(fac.getProgram("print('hello')", "print('world')"), "print('hello');print('world');");
assertEquals(fac.getParameter(ScriptEngine.NAME), "javascript");
@@ -285,50 +283,91 @@ public class ScriptEngineTest {
}
}
+ public interface Foo {
+ public void bar();
+ }
+
+ public interface Foo2 extends Foo {
+ public void bar2();
+ }
+
@Test
- public void accessGlobalTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
+ public void getInterfaceMissingTest() {
+ final ScriptEngineManager manager = new ScriptEngineManager();
+ final ScriptEngine engine = manager.getEngineByName("nashorn");
+ // don't define any function.
try {
- e.eval("var x = 'hello'");
- assertEquals(e.get("x"), "hello");
- } catch (final ScriptException exp) {
+ engine.eval("");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+
+ Runnable runnable = ((Invocable)engine).getInterface(Runnable.class);
+ if (runnable != null) {
+ fail("runnable is not null!");
+ }
+
+ // now define "run"
+ try {
+ engine.eval("function run() { print('this is run function'); }");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ runnable = ((Invocable)engine).getInterface(Runnable.class);
+ // should not return null now!
+ runnable.run();
+
+ // define only one method of "Foo2"
+ try {
+ engine.eval("function bar() { print('bar function'); }");
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+
+ Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class);
+ if (foo2 != null) {
+ throw new RuntimeException("foo2 is not null!");
+ }
+
+ // now define other method of "Foo2"
+ try {
+ engine.eval("function bar2() { print('bar2 function'); }");
+ } catch (final Exception exp) {
exp.printStackTrace();
fail(exp.getMessage());
}
+ foo2 = ((Invocable)engine).getInterface(Foo2.class);
+ foo2.bar();
+ foo2.bar2();
}
@Test
- public void exposeGlobalTest() {
+ public void accessGlobalTest() {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
try {
- e.put("y", "foo");
- e.eval("print(y)");
+ e.eval("var x = 'hello'");
+ assertEquals(e.get("x"), "hello");
} catch (final ScriptException exp) {
exp.printStackTrace();
fail(exp.getMessage());
}
}
- public static void alert(final Object msg) {
- System.out.println(msg);
- }
-
@Test
- public void exposeMethodTest() {
+ public void exposeGlobalTest() {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
try {
- final Method alert = ScriptEngineTest.class.getMethod("alert", Object.class);
- // expose a Method object as global var.
- e.put("alert", alert);
- // call the global var.
- e.eval("alert.invoke(null, 'alert! alert!!')");
- } catch (final NoSuchMethodException | SecurityException | ScriptException exp) {
+ e.put("y", "foo");
+ e.eval("print(y)");
+ } catch (final ScriptException exp) {
exp.printStackTrace();
fail(exp.getMessage());
}
@@ -593,13 +632,6 @@ public class ScriptEngineTest {
}
@Test
- public void versionTest() {
- final ScriptEngineManager m = new ScriptEngineManager();
- final ScriptEngine e = m.getEngineByName("nashorn");
- assertEquals(e.getFactory().getEngineVersion(), Version.version());
- }
-
- @Test
public void noEnumerablePropertiesTest() {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
@@ -874,26 +906,4 @@ public class ScriptEngineTest {
fail(se.getMessage());
}
}
-
- @Test
- public void factoryOptionsTest() {
- final ScriptEngineManager sm = new ScriptEngineManager();
- for (ScriptEngineFactory fac : sm.getEngineFactories()) {
- if (fac instanceof NashornScriptEngineFactory) {
- final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
- // specify --no-syntax-extensions flag
- final String[] options = new String[] { "--no-syntax-extensions" };
- final ScriptEngine e = nfac.getScriptEngine(options);
- try {
- // try nashorn specific extension
- e.eval("var f = funtion(x) 2*x;");
- fail("should have thrown exception!");
- } catch (final ScriptException se) {
- }
- return;
- }
- }
-
- fail("Cannot find nashorn factory!");
- }
}
diff --git a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java
index adf361f4..3cbe1ed4 100644
--- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java
+++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java
@@ -44,6 +44,7 @@ public class CompilerTest {
private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("compilertest.verbose"));
private static final boolean TEST262 = Boolean.valueOf(System.getProperty("compilertest.test262"));
private static final String TEST_BASIC_DIR = System.getProperty("test.basic.dir");
+ private static final String TEST_NODE_DIR = System.getProperty("test.node.dir");
private static final String TEST262_SUITE_DIR = System.getProperty("test262.suite.dir");
interface TestFilter {
@@ -81,21 +82,22 @@ public class CompilerTest {
@Test
public void compileAllTests() {
if (TEST262) {
- compileTestSet(TEST262_SUITE_DIR, new TestFilter() {
+ compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
@Override
public boolean exclude(final File file, final String content) {
return content.indexOf("@negative") != -1;
}
});
}
- compileTestSet(TEST_BASIC_DIR, null);
+ compileTestSet(new File(TEST_BASIC_DIR), null);
+ compileTestSet(new File(TEST_NODE_DIR, "node"), null);
+ compileTestSet(new File(TEST_NODE_DIR, "src"), null);
}
- private void compileTestSet(final String testSet, final TestFilter filter) {
+ private void compileTestSet(final File testSetDir, final TestFilter filter) {
passed = 0;
failed = 0;
skipped = 0;
- final File testSetDir = new File(testSet);
if (! testSetDir.isDirectory()) {
log("WARNING: " + testSetDir + " not found or not a directory");
return;
@@ -103,7 +105,7 @@ public class CompilerTest {
log(testSetDir.getAbsolutePath());
compileJSDirectory(testSetDir, filter);
- log(testSet + " compile done!");
+ log(testSetDir + " compile done!");
log("compile ok: " + passed);
log("compile failed: " + failed);
log("compile skipped: " + skipped);
diff --git a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java
index 0f147562..0f740a48 100644
--- a/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java
+++ b/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java
@@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime;
-
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@@ -40,6 +40,13 @@ import org.testng.annotations.Test;
* Tests for trusted client usage of nashorn script engine factory extension API
*/
public class TrustedScriptEngineTest {
+ @Test
+ public void versionTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ assertEquals(e.getFactory().getEngineVersion(), Version.version());
+ }
+
private static class MyClassLoader extends ClassLoader {
// to check if script engine uses the specified class loader
private final boolean[] reached = new boolean[1];
@@ -116,4 +123,26 @@ public class TrustedScriptEngineTest {
fail("Cannot find nashorn factory!");
}
+
+ @Test
+ public void factoryOptionsTest() {
+ final ScriptEngineManager sm = new ScriptEngineManager();
+ for (ScriptEngineFactory fac : sm.getEngineFactories()) {
+ if (fac instanceof NashornScriptEngineFactory) {
+ final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac;
+ // specify --no-syntax-extensions flag
+ final String[] options = new String[] { "--no-syntax-extensions" };
+ final ScriptEngine e = nfac.getScriptEngine(options);
+ try {
+ // try nashorn specific extension
+ e.eval("var f = funtion(x) 2*x;");
+ fail("should have thrown exception!");
+ } catch (final ScriptException se) {
+ }
+ return;
+ }
+ }
+
+ fail("Cannot find nashorn factory!");
+ }
}
diff --git a/test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java b/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java
index ba4a2163..9a201575 100644
--- a/test/src/jdk/nashorn/internal/test/models/ConstructorWithArgument.java
+++ b/test/src/jdk/nashorn/test/models/ConstructorWithArgument.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public abstract class ConstructorWithArgument {
private final String token;
diff --git a/test/src/jdk/nashorn/internal/test/models/DessertTopping.java b/test/src/jdk/nashorn/test/models/DessertTopping.java
index 8427c837..591e032d 100644
--- a/test/src/jdk/nashorn/internal/test/models/DessertTopping.java
+++ b/test/src/jdk/nashorn/test/models/DessertTopping.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public interface DessertTopping {
public String pourOnDessert();
diff --git a/test/src/jdk/nashorn/internal/test/models/DessertToppingFloorWaxDriver.java b/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java
index dc04a0d1..856029ad 100644
--- a/test/src/jdk/nashorn/internal/test/models/DessertToppingFloorWaxDriver.java
+++ b/test/src/jdk/nashorn/test/models/DessertToppingFloorWaxDriver.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public class DessertToppingFloorWaxDriver {
public void decorateDessert(DessertTopping dt) {
diff --git a/test/src/jdk/nashorn/internal/test/models/FinalClass.java b/test/src/jdk/nashorn/test/models/FinalClass.java
index b20257cb..8a3e8432 100644
--- a/test/src/jdk/nashorn/internal/test/models/FinalClass.java
+++ b/test/src/jdk/nashorn/test/models/FinalClass.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public final class FinalClass {
//empty
diff --git a/test/src/jdk/nashorn/internal/test/models/FloorWax.java b/test/src/jdk/nashorn/test/models/FloorWax.java
index c094ccf6..44ac96e9 100644
--- a/test/src/jdk/nashorn/internal/test/models/FloorWax.java
+++ b/test/src/jdk/nashorn/test/models/FloorWax.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public interface FloorWax {
public String shineUpTheFloor();
diff --git a/test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java b/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java
index ed6475de..2e7d9c6c 100644
--- a/test/src/jdk/nashorn/internal/runtime/Nashorn401TestSubject.java
+++ b/test/src/jdk/nashorn/test/models/Nashorn401TestSubject.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.runtime;
+package jdk.nashorn.test.models;
public class Nashorn401TestSubject {
public String method2(int arg) {
diff --git a/test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java b/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java
index c79edfbb..f0ddb1aa 100644
--- a/test/src/jdk/nashorn/internal/test/models/NoAccessibleConstructorClass.java
+++ b/test/src/jdk/nashorn/test/models/NoAccessibleConstructorClass.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public class NoAccessibleConstructorClass {
NoAccessibleConstructorClass() { }
diff --git a/test/src/jdk/nashorn/internal/test/models/NonPublicClass.java b/test/src/jdk/nashorn/test/models/NonPublicClass.java
index 046cdf24..d0a61856 100644
--- a/test/src/jdk/nashorn/internal/test/models/NonPublicClass.java
+++ b/test/src/jdk/nashorn/test/models/NonPublicClass.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
class NonPublicClass {
public NonPublicClass() { }
diff --git a/test/src/jdk/nashorn/internal/test/models/OuterClass.java b/test/src/jdk/nashorn/test/models/OuterClass.java
index cb9484b9..5db86f28 100644
--- a/test/src/jdk/nashorn/internal/test/models/OuterClass.java
+++ b/test/src/jdk/nashorn/test/models/OuterClass.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public class OuterClass {
private final String value;
diff --git a/test/src/jdk/nashorn/internal/test/models/OverloadedSam.java b/test/src/jdk/nashorn/test/models/OverloadedSam.java
index c63da54c..05736bca 100644
--- a/test/src/jdk/nashorn/internal/test/models/OverloadedSam.java
+++ b/test/src/jdk/nashorn/test/models/OverloadedSam.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public interface OverloadedSam {
public void sam(String s);
diff --git a/test/src/jdk/nashorn/internal/test/models/OverrideObject.java b/test/src/jdk/nashorn/test/models/OverrideObject.java
index 40cf7f97..5312ffbb 100644
--- a/test/src/jdk/nashorn/internal/test/models/OverrideObject.java
+++ b/test/src/jdk/nashorn/test/models/OverrideObject.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public class OverrideObject {
@Override
diff --git a/test/src/jdk/nashorn/test/models/SourceHelper.java b/test/src/jdk/nashorn/test/models/SourceHelper.java
new file mode 100644
index 00000000..46b1e488
--- /dev/null
+++ b/test/src/jdk/nashorn/test/models/SourceHelper.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010, 2013, 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.test.models;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import jdk.nashorn.internal.runtime.Source;
+
+/**
+ * Helper class to facilitate script access of nashorn Source class.
+ */
+public final class SourceHelper {
+ private SourceHelper() {}
+
+ public static String baseURL(final URL url) {
+ return Source.baseURL(url);
+ }
+
+ public static String readFully(final File file) throws IOException {
+ return new String(Source.readFully(file));
+ }
+
+ public static String readFully(final URL url) throws IOException {
+ return new Source(url.toString(), url).getString();
+ }
+
+ public static String readFully(final Reader reader) throws IOException {
+ return new String(Source.readFully(reader));
+ }
+}
diff --git a/test/src/jdk/nashorn/internal/test/models/StringArgs.java b/test/src/jdk/nashorn/test/models/StringArgs.java
index 8ecdbfd3..1fdcd5de 100644
--- a/test/src/jdk/nashorn/internal/test/models/StringArgs.java
+++ b/test/src/jdk/nashorn/test/models/StringArgs.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
import java.util.List;
diff --git a/test/src/jdk/nashorn/internal/test/models/Toothpaste.java b/test/src/jdk/nashorn/test/models/Toothpaste.java
index 0946eb35..7eae95f3 100644
--- a/test/src/jdk/nashorn/internal/test/models/Toothpaste.java
+++ b/test/src/jdk/nashorn/test/models/Toothpaste.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.test.models;
+package jdk.nashorn.test.models;
public abstract class Toothpaste {
public void applyToBrush() {