aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Nevill edward.nevill@linaro.org <Edward Nevill edward.nevill@linaro.org>2013-12-23 13:00:33 +0000
committerEdward Nevill edward.nevill@linaro.org <Edward Nevill edward.nevill@linaro.org>2013-12-23 13:00:33 +0000
commitd9c7bed615253d4d273f81faf9859f8f10f7cac9 (patch)
tree6917c0df28cda99c2bc4d23239045fa29a3f4858
parentdb1032c1f2e2b6e679849ae4c8b0e7dd7605fc53 (diff)
parent7f54e85e6d7f3767c4ad17e5e336f0562657435d (diff)
Remerge to jdk8-b117
-rw-r--r--.hgtags7
-rw-r--r--make/build.xml47
-rw-r--r--make/java.security.override14
-rw-r--r--make/project.properties29
-rw-r--r--makefiles/BuildNashorn.gmk63
-rw-r--r--makefiles/Makefile14
-rw-r--r--src/jdk/internal/dynalink/beans/SingleDynamicMethod.java70
-rw-r--r--src/jdk/internal/dynalink/support/Guards.java13
-rw-r--r--src/jdk/internal/dynalink/support/messages.properties12
-rw-r--r--src/jdk/nashorn/api/scripting/AbstractJSObject.java254
-rw-r--r--src/jdk/nashorn/api/scripting/JSObject.java101
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngine.java22
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptObjectMirror.java53
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptUtils.java114
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java184
-rw-r--r--src/jdk/nashorn/internal/codegen/BranchOptimizer.java41
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java381
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilationPhase.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/CompileUnit.java7
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java10
-rw-r--r--src/jdk/nashorn/internal/codegen/FinalizeTypes.java755
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java39
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java17
-rw-r--r--src/jdk/nashorn/internal/codegen/MapCreator.java4
-rw-r--r--src/jdk/nashorn/internal/codegen/MethodEmitter.java8
-rw-r--r--src/jdk/nashorn/internal/codegen/Namespace.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/SpillObjectCreator.java3
-rw-r--r--src/jdk/nashorn/internal/codegen/WeighNodes.java5
-rw-r--r--src/jdk/nashorn/internal/codegen/types/BooleanType.java3
-rw-r--r--src/jdk/nashorn/internal/codegen/types/ObjectType.java3
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java17
-rw-r--r--src/jdk/nashorn/internal/ir/AccessNode.java27
-rw-r--r--src/jdk/nashorn/internal/ir/BaseNode.java38
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java39
-rw-r--r--src/jdk/nashorn/internal/ir/CallNode.java44
-rw-r--r--src/jdk/nashorn/internal/ir/Expression.java12
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java67
-rw-r--r--src/jdk/nashorn/internal/ir/IndexNode.java27
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java4
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java67
-rw-r--r--src/jdk/nashorn/internal/ir/RuntimeNode.java63
-rw-r--r--src/jdk/nashorn/internal/ir/Symbol.java20
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/TypeOverride.java62
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java42
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java59
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java24
-rw-r--r--src/jdk/nashorn/internal/objects/Global.java16
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java99
-rw-r--r--src/jdk/nashorn/internal/objects/NativeError.java11
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFunction.java8
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJSAdapter.java3
-rw-r--r--src/jdk/nashorn/internal/objects/NativeObject.java4
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java14
-rw-r--r--src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java7
-rw-r--r--src/jdk/nashorn/internal/parser/AbstractParser.java2
-rw-r--r--src/jdk/nashorn/internal/parser/Lexer.java13
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java12
-rw-r--r--src/jdk/nashorn/internal/parser/TokenType.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeInstaller.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunction.java47
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunctions.java50
-rw-r--r--src/jdk/nashorn/internal/runtime/ConsString.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java123
-rw-r--r--src/jdk/nashorn/internal/runtime/DebugLogger.java14
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalObject.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java113
-rw-r--r--src/jdk/nashorn/internal/runtime/ListAdapter.java59
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java31
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java54
-rw-r--r--src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java29
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunction.java22
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java105
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptLoader.java19
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java375
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptRuntime.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptingFunctions.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/Source.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/WithObject.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayData.java18
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java30
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java89
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java5
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java5
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java127
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java38
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornLinker.java109
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/fx/base.js3
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js35
-rw-r--r--src/overview.html2
-rw-r--r--test/examples/array-micro.js18
-rw-r--r--test/script/assert.js19
-rw-r--r--test/script/basic/JDK-8015355.js4
-rw-r--r--test/script/basic/JDK-8019508.js2
-rw-r--r--test/script/basic/JDK-8019508.js.EXPECTED8
-rw-r--r--test/script/basic/JDK-8019553.js2
-rw-r--r--test/script/basic/JDK-8019553.js.EXPECTED8
-rw-r--r--test/script/basic/JDK-8019791.js4
-rw-r--r--test/script/basic/JDK-8019791.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8019805.js2
-rw-r--r--test/script/basic/JDK-8019805.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8023026.js2
-rw-r--r--test/script/basic/JDK-8024847.js6
-rw-r--r--test/script/basic/JDK-8024847.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8025213.js39
-rw-r--r--test/script/basic/JDK-8025213.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8025488.js43
-rw-r--r--test/script/basic/JDK-8025488.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8025515.js58
-rw-r--r--test/script/basic/JDK-8025520.js50
-rw-r--r--test/script/basic/JDK-8025589.js51
-rw-r--r--test/script/basic/JDK-8026008.js55
-rw-r--r--test/script/basic/JDK-8026008.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8026016.js68
-rw-r--r--test/script/basic/JDK-8026016.js.EXPECTED182
-rw-r--r--test/script/basic/JDK-8026033.js39
-rw-r--r--test/script/basic/JDK-8026033.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8026042.js43
-rw-r--r--test/script/basic/JDK-8026042.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8026048.js37
-rw-r--r--test/script/basic/JDK-8026112.js31
-rw-r--r--test/script/basic/JDK-8026125.js32
-rw-r--r--test/script/basic/JDK-8026137.js44
-rw-r--r--test/script/basic/JDK-8026137.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8026161.js32
-rw-r--r--test/script/basic/JDK-8026161.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8026162.js48
-rw-r--r--test/script/basic/JDK-8026167.js50
-rw-r--r--test/script/basic/JDK-8026248.js51
-rw-r--r--test/script/basic/JDK-8026248.js.EXPECTED10
-rw-r--r--test/script/basic/JDK-8026264.js54
-rw-r--r--test/script/basic/JDK-8026292.js65
-rw-r--r--test/script/basic/JDK-8026302.js48
-rw-r--r--test/script/basic/JDK-8026302.js.EXPECTED10
-rw-r--r--test/script/basic/JDK-8026317.js63
-rw-r--r--test/script/basic/JDK-8026317.js.EXPECTED2
-rw-r--r--test/script/basic/JDK-8026367.js61
-rw-r--r--test/script/basic/JDK-8026692.js32
-rw-r--r--test/script/basic/JDK-8026693.js33
-rw-r--r--test/script/basic/JDK-8026701.js72
-rw-r--r--test/script/basic/JDK-8026701.js.EXPECTED147
-rw-r--r--test/script/basic/JDK-8026805.js49
-rw-r--r--test/script/basic/JDK-8026858.js66
-rw-r--r--test/script/basic/JDK-8026955.js51
-rw-r--r--test/script/basic/JDK-8026955.js.EXPECTED22
-rw-r--r--test/script/basic/JDK-8027016.js42
-rw-r--r--test/script/basic/JDK-8027024.js58
-rw-r--r--test/script/basic/JDK-8027024.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8027042.js58
-rw-r--r--test/script/basic/JDK-8027042.js.EXPECTED88
-rw-r--r--test/script/basic/JDK-8027236.js37
-rw-r--r--test/script/basic/JDK-8027236.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8027562.js39
-rw-r--r--test/script/basic/JDK-8027562.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8027700.js54
-rw-r--r--test/script/basic/JDK-8027753.js50
-rw-r--r--test/script/basic/JDK-8027753.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8027828.js35
-rw-r--r--test/script/basic/JDK-8027828.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8028020.js40
-rw-r--r--test/script/basic/JDK-8028020.js.EXPECTED2
-rw-r--r--test/script/basic/NASHORN-100.js2
-rw-r--r--test/script/basic/NASHORN-100.js.EXPECTED2
-rw-r--r--test/script/basic/NASHORN-293.js6
-rw-r--r--test/script/basic/NASHORN-293.js.EXPECTED12
-rw-r--r--test/script/basic/NASHORN-397.js7
-rw-r--r--test/script/basic/NASHORN-40.js4
-rw-r--r--test/script/basic/NASHORN-40.js.EXPECTED4
-rw-r--r--test/script/basic/NASHORN-51.js8
-rw-r--r--test/script/basic/NASHORN-51.js.EXPECTED48
-rw-r--r--test/script/basic/NASHORN-98.js4
-rw-r--r--test/script/basic/NASHORN-98.js.EXPECTED4
-rw-r--r--test/script/basic/convert.js61
-rw-r--r--test/script/basic/convert.js.EXPECTED14
-rw-r--r--test/script/basic/eval.js2
-rw-r--r--test/script/basic/eval.js.EXPECTED2
-rw-r--r--test/script/basic/objects.js.EXPECTED8
-rw-r--r--test/script/error/JDK-8026039.js32
-rw-r--r--test/script/error/JDK-8026039.js.EXPECTED9
-rw-r--r--test/script/jfx.js103
-rw-r--r--test/script/jfx/flyingimage.js84
-rw-r--r--test/script/jfx/flyingimage/flyingimage.pngbin0 -> 1278 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/linux.pngbin0 -> 68179 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/macosx.pngbin0 -> 68361 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/windows.pngbin0 -> 68588 bytes
-rw-r--r--test/script/jfx/kaleidoscope.js167
-rw-r--r--test/script/jfx/kaleidoscope/golden/linux.pngbin0 -> 192428 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/macosx.pngbin0 -> 202987 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/windows.pngbin0 -> 192428 bytes
-rw-r--r--test/script/jfx/spread.js222
-rw-r--r--test/script/jfx/spread/golden/linux.pngbin0 -> 201159 bytes
-rw-r--r--test/script/jfx/spread/golden/macosx.pngbin0 -> 199251 bytes
-rw-r--r--test/script/jfx/spread/golden/windows.pngbin0 -> 201159 bytes
-rw-r--r--test/script/sandbox/arrayclass.js37
-rw-r--r--test/script/sandbox/arrayclass.js.EXPECTED1
-rw-r--r--test/script/sandbox/loadcompat.js4
-rw-r--r--test/script/trusted/JDK-8025629.js33
-rw-r--r--test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java235
-rw-r--r--test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java99
-rw-r--r--test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java6
-rw-r--r--test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java8
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java12
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java27
-rw-r--r--test/src/jdk/nashorn/api/scripting/Window.java19
-rw-r--r--test/src/jdk/nashorn/internal/runtime/resources/load_test.js (renamed from src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java)30
217 files changed, 6257 insertions, 2167 deletions
diff --git a/.hgtags b/.hgtags
index fd0c55be..56239d92 100644
--- a/.hgtags
+++ b/.hgtags
@@ -222,3 +222,10 @@ f35e1255024b66f7cf82517798f45f6e194e5567 jdk8-b107
6ec2f9e5ed5bd60c2900976e6a54fdcac2f37e9e jdk8-b109
4d291109480a3f99d18ef98398479a245f68ebf2 preview_rc1
b35e0d2e2a246475b6ca01820e20fda98c72fde6 preview_rc2
+d49a8c2173f5f90c9a39cc4af8e03cfa8f35ee4c jdk8-b110
+75fd3486e584f20475c064a2cd4d01ac6406a511 jdk8-b111
+6a4fdb3bb4e34af4c5bb8db467bb01e13b1a7e31 jdk8-b112
+676cd7bf5e092356f7ee2116c8cf88cdc12377c7 jdk8-b113
+79f7b79bf97b71c9b5c9b103dbdef5f269eeb86d jdk8-b114
+f0d3ac2474ee755b1180ec71bcdfa190845b17eb jdk8-b115
+0fb1a427fbf6e04c77cebbbf99b6631c664ed793 jdk8-b116
diff --git a/make/build.xml b/make/build.xml
index 4bc1a398..7d1f42ae 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -46,6 +46,16 @@
<available property="asm.available" classname="jdk.internal.org.objectweb.asm.Type"/>
<!-- check if testng.jar is avaiable -->
<available property="testng.available" file="${file.reference.testng.jar}"/>
+ <!-- check if Jemmy ang testng.jar are avaiable -->
+ <condition property="jemmy.jfx.testng.available" value="true">
+ <and>
+ <available file="${file.reference.jemmyfx.jar}"/>
+ <available file="${file.reference.jemmycore.jar}"/>
+ <available file="${file.reference.jemmyawtinput.jar}"/>
+ <available file="${file.reference.jfxrt.jar}"/>
+ <isset property="testng.available"/>
+ </and>
+ </condition>
<!-- enable/disable make code coverage -->
<condition property="cc.enabled">
@@ -236,6 +246,10 @@
<fileset dir="${test.src.dir}/META-INF/services/"/>
</copy>
+ <copy todir="${build.test.classes.dir}/jdk/nashorn/internal/runtime/resources">
+ <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/resources"/>
+ </copy>
+
<!-- tests that check nashorn internals and internal API -->
<jar jarfile="${nashorn.internal.tests.jar}">
<fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
@@ -245,6 +259,7 @@
<jar jarfile="${nashorn.api.tests.jar}">
<fileset dir="${build.test.classes.dir}" includes="**/api/**"/>
<fileset dir="${build.test.classes.dir}" includes="**/META-INF/**"/>
+ <fileset dir="${build.test.classes.dir}" includes="**/resources/*.js"/>
</jar>
</target>
@@ -346,6 +361,38 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" {
</java>
</target>
+ <target name="check-jemmy.jfx.testng" unless="jemmy.jfx.testng.available">
+ <echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/>
+ </target>
+
+ <target name="testjfx" depends="jar, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
+ <fileset id="test.classes" dir="${build.test.classes.dir}">
+ <include name="**/framework/*Test.class"/>
+ </fileset>
+
+ <copy file="${file.reference.jfxrt.jar}" todir="dist"/>
+
+ <condition property="jfx.prism.order" value="-Dprism.order=j2d" else=" ">
+ <not>
+ <os family="mac"/>
+ </not>
+ </condition>
+
+ <testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
+ verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
+ <jvmarg line="${ext.class.path}"/>
+ <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx}"/>
+ <propertyset>
+ <propertyref prefix="testjfx-test-sys-prop."/>
+ <mapper from="testjfx-test-sys-prop.*" to="*" type="glob"/>
+ </propertyset>
+ <sysproperty key="test.fork.jvm.options" value="${testjfx-test-sys-prop.test.fork.jvm.options} ${jfx.prism.order}"/>
+ <classpath>
+ <pathelement path="${testjfx.run.test.classpath}"/>
+ </classpath>
+ </testng>
+ </target>
+
<target name="test262" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/>
diff --git a/make/java.security.override b/make/java.security.override
deleted file mode 100644
index a7edf33b..00000000
--- a/make/java.security.override
+++ /dev/null
@@ -1,14 +0,0 @@
-# We would like to avoid references from anywhere outside nashorn
-# to codegen, IR and parser packages, in particular script generated classes.
-# 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 sensitive packages.
-
-#
-# List of comma-separated packages that start with or equal this string
-# will cause a security exception to be thrown when
-# 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.,jdk.nashorn.tools.
diff --git a/make/project.properties b/make/project.properties
index e6eea02e..c3ffca4e 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -118,6 +118,7 @@ test.trusted.dir=test/script/trusted
test.external.dir=test/script/external
test262.dir=${test.external.dir}/test262
test262.suite.dir=${test262.dir}/test/suite
+testjfx.dir=${test.script.dir}/jfx
test-sys-prop.test.dir=${test.dir}
test-sys-prop.test.js.roots=${test.basic.dir} ${test.error.dir} ${test.sandbox.dir} ${test.trusted.dir}
@@ -208,6 +209,32 @@ test262-test-sys-prop.test.js.framework=\
${test262.dir}/test/harness/framework.js \
${test262.dir}/test/harness/sta.js
+# testjfx test root
+testjfx-test-sys-prop.test.js.roots=${testjfx.dir}
+
+# execute testjfx tests in shared nashorn context or not?
+testjfx-test-sys-prop.test.js.shared.context=false
+
+# framework root for our script tests
+testjfx-test-sys-prop.test.js.framework=\
+ -fx \
+ ${test.script.dir}${file.separator}jfx.js
+
+file.reference.jemmyfx.jar=test${file.separator}lib${file.separator}JemmyFX.jar
+file.reference.jemmycore.jar=test${file.separator}lib${file.separator}JemmyCore.jar
+file.reference.jemmyawtinput.jar=test${file.separator}lib${file.separator}JemmyAWTInput.jar
+file.reference.jfxrt.jar=${java.home}${file.separator}lib${file.separator}ext${file.separator}jfxrt.jar
+testjfx.run.test.classpath=\
+ ${file.reference.jemmyfx.jar}${path.separator}\
+ ${file.reference.jemmycore.jar}${path.separator}\
+ ${file.reference.jemmyawtinput.jar}${path.separator}\
+ ${file.reference.testng.jar}${path.separator}\
+ ${nashorn.internal.tests.jar}${path.separator}\
+ ${nashorn.api.tests.jar}
+
+# testjfx VM options for script tests with @fork option
+testjfx-test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} -cp ${testjfx.run.test.classpath}
+
run.test.classpath=\
${file.reference.testng.jar}:\
${nashorn.internal.tests.jar}:\
@@ -234,7 +261,7 @@ run.test.jvmargs.main=${run.test.jvmargs.common} -ea
#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
run.test.jvmargs.octane.main=${run.test.jvmargs.common}
-run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
+run.test.jvmsecurityargs=-Xverify:all -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
# VM options for script tests with @fork option
test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs}
diff --git a/makefiles/BuildNashorn.gmk b/makefiles/BuildNashorn.gmk
index 96bedf44..fc870442 100644
--- a/makefiles/BuildNashorn.gmk
+++ b/makefiles/BuildNashorn.gmk
@@ -37,35 +37,35 @@ NASHORN_VERSION := $(JDK_VERSION)
NASHORN_FULL_VERSION := $(FULL_VERSION)
ifdef MILESTONE
- ifeq ($(MILESTONE),internal)
+ ifeq ($(MILESTONE), internal)
NASHORN_VERSION = $(FULL_VERSION)
endif
endif
# Need to use source and target 7 for nasgen to work.
-$(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG,\
- JVM:=$(JAVA),\
- JAVAC:=$(NEW_JAVAC),\
- FLAGS:=-g -source 7 -target 7 -bootclasspath $(JDK_CLASSES),\
- SERVER_DIR:=$(SJAVAC_SERVER_DIR),\
- SERVER_JVM:=$(SJAVAC_SERVER_JAVA)))
+$(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \
+ JVM := $(JAVA), \
+ JAVAC := $(NEW_JAVAC), \
+ FLAGS := -g -source 7 -target 7 -bootclasspath $(JDK_CLASSES), \
+ SERVER_DIR := $(SJAVAC_SERVER_DIR), \
+ SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
# Build nashorn into intermediate directory
-$(eval $(call SetupJavaCompilation,BUILD_NASHORN,\
- SETUP:=GENERATE_NEWBYTECODE_DEBUG,\
- SRC:=$(NASHORN_TOPDIR)/src,\
- COPY:=.properties .js,\
- BIN:=$(NASHORN_OUTPUTDIR)/nashorn_classes))
+$(eval $(call SetupJavaCompilation,BUILD_NASHORN, \
+ SETUP := GENERATE_NEWBYTECODE_DEBUG, \
+ SRC := $(NASHORN_TOPDIR)/src, \
+ COPY := .properties .js, \
+ BIN := $(NASHORN_OUTPUTDIR)/nashorn_classes))
NASGEN_SRC := $(NASHORN_TOPDIR)/buildtools/nasgen/src
ASM_SRC := $(JDK_TOPDIR)/src/share/classes/jdk/internal/org/objectweb/asm
# Build nasgen
-$(eval $(call SetupJavaCompilation,BUILD_NASGEN,\
- SETUP:=GENERATE_NEWBYTECODE_DEBUG,\
- SRC:=$(NASGEN_SRC) $(ASM_SRC), \
- BIN:=$(NASHORN_OUTPUTDIR)/nasgen_classes,\
- ADD_JAVAC_FLAGS:=-cp $(NASHORN_OUTPUTDIR)/nashorn_classes))
+$(eval $(call SetupJavaCompilation,BUILD_NASGEN, \
+ SETUP := GENERATE_NEWBYTECODE_DEBUG, \
+ SRC := $(NASGEN_SRC) $(ASM_SRC), \
+ BIN := $(NASHORN_OUTPUTDIR)/nasgen_classes, \
+ ADD_JAVAC_FLAGS := -cp $(NASHORN_OUTPUTDIR)/nashorn_classes))
# Nasgen needs nashorn classes
$(BUILD_NASGEN): $(BUILD_NASHORN)
@@ -77,35 +77,36 @@ $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
$(RM) -rf $(@D)/jdk $(@D)/netscape
$(CP) -R -p $(NASHORN_OUTPUTDIR)/nashorn_classes/* $(@D)/
$(FIXPATH) $(JAVA) \
- -cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
- jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
+ -cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
+ jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
$(TOUCH) $@
# Version file needs to be processed with version numbers
VERSION_FILE := $(NASHORN_OUTPUTDIR)/classes/jdk/nashorn/internal/runtime/resources/version.properties
+
# Needs to happen after nasgen run since nasgen run deletes it
$(VERSION_FILE): $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run
$(VERSION_FILE): $(NASHORN_TOPDIR)/src/jdk/nashorn/internal/runtime/resources/version.properties-template
$(ECHO) Creating version.properties
$(MKDIR) -p $(@D)
$(CAT) $< | $(SED) -e 's/$$(FULL_VERSION)/$(NASHORN_FULL_VERSION)/g' \
- -e 's/$$(RELEASE)/$(NASHORN_VERSION)/g' \
- -e '/^#.*$$/d' -e '/^$$/d' > $@
+ -e 's/$$(RELEASE)/$(NASHORN_VERSION)/g' \
+ -e '/^#.*$$/d' -e '/^$$/d' > $@
-MANIFEST_ATTRIBUTES:=Name: jdk/nashorn/\nImplementation-Title: Oracle Nashorn\nImplementation-Version: $(NASHORN_FULL_VERSION)
+MANIFEST_ATTRIBUTES := Name: jdk/nashorn/\nImplementation-Title: Oracle Nashorn\nImplementation-Version: $(NASHORN_FULL_VERSION)
# Create nashorn.jar from the final classes dir
-$(eval $(call SetupArchive,BUILD_NASHORN_JAR,\
+$(eval $(call SetupArchive,BUILD_NASHORN_JAR, \
$(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run \
- $(VERSION_FILE),\
- SRCS:=$(NASHORN_OUTPUTDIR)/classes,\
- SUFFIXES:=.class .js .properties Factory,\
- MANIFEST:=$(NASHORN_TOPDIR)/src/META-INF/MANIFEST.MF,\
- EXTRA_MANIFEST_ATTR:=$(MANIFEST_ATTRIBUTES),\
- SKIP_METAINF:=true,\
- JAR:=$(NASHORN_JAR)))
+ $(VERSION_FILE), \
+ SRCS := $(NASHORN_OUTPUTDIR)/classes, \
+ SUFFIXES := .class .js .properties Factory, \
+ MANIFEST := $(NASHORN_TOPDIR)/src/META-INF/MANIFEST.MF, \
+ EXTRA_MANIFEST_ATTR := $(MANIFEST_ATTRIBUTES), \
+ SKIP_METAINF := true, \
+ JAR := $(NASHORN_JAR)))
all: $(NASHORN_JAR)
-
+
.PHONY: all
diff --git a/makefiles/Makefile b/makefiles/Makefile
index 9539fe0e..c7d0dd00 100644
--- a/makefiles/Makefile
+++ b/makefiles/Makefile
@@ -24,19 +24,19 @@
#
# Locate this Makefile
-ifeq ($(filter /%,$(lastword $(MAKEFILE_LIST))),)
- makefile_path:=$(CURDIR)/$(lastword $(MAKEFILE_LIST))
+ifeq ($(filter /%, $(lastword $(MAKEFILE_LIST))), )
+ makefile_path := $(CURDIR)/$(lastword $(MAKEFILE_LIST))
else
- makefile_path:=$(lastword $(MAKEFILE_LIST))
+ makefile_path := $(lastword $(MAKEFILE_LIST))
endif
-repo_dir:=$(patsubst %/makefiles/Makefile,%,$(makefile_path))
+repo_dir := $(patsubst %/makefiles/Makefile, %, $(makefile_path))
# What is the name of this subsystem (langtools, corba, etc)?
-subsystem_name:=$(notdir $(repo_dir))
+subsystem_name := $(notdir $(repo_dir))
# Try to locate top-level makefile
-top_level_makefile:=$(repo_dir)/../common/makefiles/Makefile
-ifneq ($(wildcard $(top_level_makefile)),)
+top_level_makefile := $(repo_dir)/../common/makefiles/Makefile
+ifneq ($(wildcard $(top_level_makefile)), )
$(info Will run $(subsystem_name) target on top-level Makefile)
$(info WARNING: This is a non-recommended way of building!)
$(info ===================================================)
diff --git a/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java b/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
index d15fab99..6b55d81f 100644
--- a/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
+++ b/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
@@ -91,6 +91,7 @@ import java.util.StringTokenizer;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Guards;
+import jdk.internal.dynalink.support.Lookup;
/**
* Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
@@ -100,6 +101,9 @@ import jdk.internal.dynalink.support.Guards;
* @version $Id: $
*/
abstract class SingleDynamicMethod extends DynamicMethod {
+
+ private static final MethodHandle CAN_CONVERT_TO = Lookup.findOwnStatic(MethodHandles.lookup(), "canConvertTo", boolean.class, LinkerServices.class, Class.class, Object.class);
+
SingleDynamicMethod(String name) {
super(name);
}
@@ -201,23 +205,69 @@ abstract class SingleDynamicMethod extends DynamicMethod {
return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
callSiteLastArgType);
}
- if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
- // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
- // link immediately to a vararg-packing method handle.
- return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+
+ // This method handle takes the single argument and packs it into a newly allocated single-element array. It
+ // will be used when the incoming argument can't be converted to the vararg array type (the "vararg packer"
+ // method).
+ final MethodHandle varArgCollectingInvocation = createConvertingInvocation(collectArguments(fixTarget,
+ argsLen), linkerServices, callSiteType);
+
+ // Is call site type assignable from an array type (e.g. Object:int[], or Object[]:String[])
+ final boolean isAssignableFromArray = callSiteLastArgType.isAssignableFrom(varArgType);
+ // Do we have a custom conversion that can potentially convert the call site type to an array?
+ final boolean isCustomConvertible = linkerServices.canConvert(callSiteLastArgType, varArgType);
+ if(!isAssignableFromArray && !isCustomConvertible) {
+ // Call site signature guarantees the argument can definitely not be converted to an array (i.e. it is
+ // primitive), and no conversion can help with it either. Link immediately to a vararg-packing method
+ // handle.
+ return varArgCollectingInvocation;
}
- // Call site signature makes no guarantees that the single argument in the vararg position will be
- // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
- // method when it is not.
- return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
- createConvertingInvocation(fixTarget, linkerServices, callSiteType),
- createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
+
+ // This method handle employs language-specific conversions to convert the last argument into an array of
+ // vararg type.
+ final MethodHandle arrayConvertingInvocation = createConvertingInvocation(MethodHandles.filterArguments(
+ fixTarget, fixParamsLen, linkerServices.getTypeConverter(callSiteLastArgType, varArgType)),
+ linkerServices, callSiteType);
+
+ // This method handle determines whether the value can be converted to the array of vararg type using a
+ // language-specific conversion.
+ final MethodHandle canConvertArgToArray = MethodHandles.insertArguments(CAN_CONVERT_TO, 0, linkerServices,
+ varArgType);
+
+ // This one adjusts the previous one for the location of the argument and the call site type.
+ final MethodHandle canConvertLastArgToArray = MethodHandles.dropArguments(canConvertArgToArray, 0,
+ MethodType.genericMethodType(fixParamsLen).parameterList()).asType(callSiteType.changeReturnType(boolean.class));
+
+ // This one takes the previous ones and combines them into a method handle that converts the argument into
+ // a vararg array when it can, otherwise falls back to the vararg packer.
+ final MethodHandle convertToArrayWhenPossible = MethodHandles.guardWithTest(canConvertLastArgToArray,
+ arrayConvertingInvocation, varArgCollectingInvocation);
+
+ if(isAssignableFromArray) {
+ return MethodHandles.guardWithTest(
+ // Is incoming parameter already a compatible array?
+ Guards.isInstance(varArgType, fixParamsLen, callSiteType),
+ // Yes: just pass it to the method
+ createConvertingInvocation(fixTarget, linkerServices, callSiteType),
+ // No: either go through a custom conversion, or if it is not possible, go directly to the
+ // vararg packer.
+ isCustomConvertible ? convertToArrayWhenPossible : varArgCollectingInvocation);
+ }
+
+ // Just do the custom conversion with fallback to the vararg packer logic.
+ assert isCustomConvertible;
+ return convertToArrayWhenPossible;
}
// Remaining case: more than one vararg.
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
}
+ @SuppressWarnings("unused")
+ private static boolean canConvertTo(final LinkerServices linkerServices, Class<?> to, Object obj) {
+ return obj == null ? false : linkerServices.canConvert(obj.getClass(), to);
+ }
+
/**
* Creates a method handle out of the original target that will collect the varargs for the exact component type of
* the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
diff --git a/src/jdk/internal/dynalink/support/Guards.java b/src/jdk/internal/dynalink/support/Guards.java
index 661cf334..42aa6758 100644
--- a/src/jdk/internal/dynalink/support/Guards.java
+++ b/src/jdk/internal/dynalink/support/Guards.java
@@ -88,6 +88,7 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.logging.Level;
import java.util.logging.Logger;
+import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.linker.LinkerServices;
/**
@@ -115,11 +116,11 @@ public class Guards {
public static MethodHandle isOfClass(Class<?> clazz, MethodType type) {
final Class<?> declaredType = type.parameterType(0);
if(clazz == declaredType) {
- LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type });
+ LOG.log(Level.WARNING, "isOfClassGuardAlwaysTrue", new Object[] { clazz.getName(), 0, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(clazz)) {
- LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type });
+ LOG.log(Level.WARNING, "isOfClassGuardAlwaysFalse", new Object[] { clazz.getName(), 0, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return getClassBoundArgumentTest(IS_OF_CLASS, clazz, 0, type);
@@ -152,11 +153,11 @@ public class Guards {
public static MethodHandle isInstance(Class<?> clazz, int pos, MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(clazz.isAssignableFrom(declaredType)) {
- LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type });
+ LOG.log(Level.WARNING, "isInstanceGuardAlwaysTrue", new Object[] { clazz.getName(), pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(clazz)) {
- LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type });
+ LOG.log(Level.WARNING, "isInstanceGuardAlwaysFalse", new Object[] { clazz.getName(), pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return getClassBoundArgumentTest(IS_INSTANCE, clazz, pos, type);
@@ -174,11 +175,11 @@ public class Guards {
public static MethodHandle isArray(int pos, MethodType type) {
final Class<?> declaredType = type.parameterType(pos);
if(declaredType.isArray()) {
- LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type });
+ LOG.log(Level.WARNING, "isArrayGuardAlwaysTrue", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantTrue(type);
}
if(!declaredType.isAssignableFrom(Object[].class)) {
- LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type });
+ LOG.log(Level.WARNING, "isArrayGuardAlwaysFalse", new Object[] { pos, type, DynamicLinker.getLinkedCallSiteLocation() });
return constantFalse(type);
}
return asType(IS_ARRAY, pos, type);
diff --git a/src/jdk/internal/dynalink/support/messages.properties b/src/jdk/internal/dynalink/support/messages.properties
index eaf1f630..88d59908 100644
--- a/src/jdk/internal/dynalink/support/messages.properties
+++ b/src/jdk/internal/dynalink/support/messages.properties
@@ -76,11 +76,11 @@
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} will always return true
-isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} will always return false
+isInstanceGuardAlwaysTrue=isInstance guard for {0} in position {1} in method type {2} at {3} will always return true
+isInstanceGuardAlwaysFalse=isInstance guard for {0} in position {1} in method type {2} at {3} will always return false
-isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} will always return true
-isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} will always return false
+isOfClassGuardAlwaysTrue=isOfClass guard for {0} in position {1} in method type {2} at {3} will always return true
+isOfClassGuardAlwaysFalse=isOfClass guard for {0} in position {1} in method type {2} at {3} will always return false
-isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} will always return true
-isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} will always return false \ No newline at end of file
+isArrayGuardAlwaysTrue=isArray guard in position {0} in method type {1} at {2} will always return true
+isArrayGuardAlwaysFalse=isArray guard in position {0} in method type {1} at {2} will always return false \ No newline at end of file
diff --git a/src/jdk/nashorn/api/scripting/AbstractJSObject.java b/src/jdk/nashorn/api/scripting/AbstractJSObject.java
new file mode 100644
index 00000000..a7761645
--- /dev/null
+++ b/src/jdk/nashorn/api/scripting/AbstractJSObject.java
@@ -0,0 +1,254 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * This is the base class for nashorn ScriptObjectMirror class.
+ *
+ * This class can also be subclassed by an arbitrary Java class. Nashorn will
+ * treat objects of such classes just like nashorn script objects. Usual nashorn
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * to appropriate method call of this class.
+ */
+public abstract class AbstractJSObject implements JSObject {
+ /**
+ * Call this object as a JavaScript function. This is equivalent to
+ * 'func.apply(thiz, args)' in JavaScript.
+ *
+ * @param thiz 'this' object to be passed to the function
+ * @param args arguments to method
+ * @return result of call
+ */
+ @Override
+ public Object call(final Object thiz, final Object... args) {
+ throw new UnsupportedOperationException("call");
+ }
+
+ /**
+ * Call this 'constructor' JavaScript function to create a new object.
+ * This is equivalent to 'new func(arg1, arg2...)' in JavaScript.
+ *
+ * @param args arguments to method
+ * @return result of constructor call
+ */
+ @Override
+ public Object newObject(final Object... args) {
+ throw new UnsupportedOperationException("newObject");
+ }
+
+ /**
+ * Evaluate a JavaScript expression.
+ *
+ * @param s JavaScript expression to evaluate
+ * @return evaluation result
+ */
+ @Override
+ public Object eval(final String s) {
+ throw new UnsupportedOperationException("eval");
+ }
+
+ /**
+ * Retrieves a named member of this JavaScript object.
+ *
+ * @param name of member
+ * @return member
+ */
+ @Override
+ public Object getMember(final String name) {
+ return null;
+ }
+
+ /**
+ * Retrieves an indexed member of this JavaScript object.
+ *
+ * @param index index slot to retrieve
+ * @return member
+ */
+ @Override
+ public Object getSlot(final int index) {
+ return null;
+ }
+
+ /**
+ * Does this object have a named member?
+ *
+ * @param name name of member
+ * @return true if this object has a member of the given name
+ */
+ @Override
+ public boolean hasMember(final String name) {
+ return false;
+ }
+
+ /**
+ * Does this object have a indexed property?
+ *
+ * @param slot index to check
+ * @return true if this object has a slot
+ */
+ @Override
+ public boolean hasSlot(final int slot) {
+ return false;
+ }
+
+ /**
+ * Remove a named member from this JavaScript object
+ *
+ * @param name name of the member
+ */
+ @Override
+ public void removeMember(final String name) {
+ //empty
+ }
+
+ /**
+ * Set a named member in this JavaScript object
+ *
+ * @param name name of the member
+ * @param value value of the member
+ */
+ @Override
+ public void setMember(final String name, final Object value) {
+ //empty
+ }
+
+ /**
+ * Set an indexed member in this JavaScript object
+ *
+ * @param index index of the member slot
+ * @param value value of the member
+ */
+ @Override
+ public void setSlot(final int index, final Object value) {
+ //empty
+ }
+
+ // property and value iteration
+
+ /**
+ * Returns the set of all property names of this object.
+ *
+ * @return set of property names
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Set<String> keySet() {
+ return Collections.EMPTY_SET;
+ }
+
+ /**
+ * Returns the set of all property values of this object.
+ *
+ * @return set of property values.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Collection<Object> values() {
+ return Collections.EMPTY_SET;
+ }
+
+ // JavaScript instanceof check
+
+ /**
+ * Checking whether the given object is an instance of 'this' object.
+ *
+ * @param instance instace to check
+ * @return true if the given 'instance' is an instance of this 'function' object
+ */
+ @Override
+ public boolean isInstance(final Object instance) {
+ return false;
+ }
+
+ /**
+ * Checking whether this object is an instance of the given 'clazz' object.
+ *
+ * @param clazz clazz to check
+ * @return true if this object is an instance of the given 'clazz'
+ */
+ @Override
+ public boolean isInstanceOf(final Object clazz) {
+ if (clazz instanceof JSObject) {
+ return ((JSObject)clazz).isInstance(this);
+ }
+
+ return false;
+ }
+
+ /**
+ * ECMA [[Class]] property
+ *
+ * @return ECMA [[Class]] property value of this object
+ */
+ @Override
+ public String getClassName() {
+ return getClass().getName();
+ }
+
+ /**
+ * Is this a function object?
+ *
+ * @return if this mirror wraps a ECMAScript function instance
+ */
+ @Override
+ public boolean isFunction() {
+ return false;
+ }
+
+ /**
+ * Is this a 'use strict' function object?
+ *
+ * @return true if this mirror represents a ECMAScript 'use strict' function
+ */
+ @Override
+ public boolean isStrictFunction() {
+ return false;
+ }
+
+ /**
+ * Is this an array object?
+ *
+ * @return if this mirror wraps a ECMAScript array object
+ */
+ @Override
+ public boolean isArray() {
+ return false;
+ }
+
+ /**
+ * Returns this object's numeric value.
+ *
+ * @return this object's numeric value.
+ */
+ @Override
+ public double toNumber() {
+ return Double.NaN;
+ }
+}
diff --git a/src/jdk/nashorn/api/scripting/JSObject.java b/src/jdk/nashorn/api/scripting/JSObject.java
index 53b5790e..bd6e820b 100644
--- a/src/jdk/nashorn/api/scripting/JSObject.java
+++ b/src/jdk/nashorn/api/scripting/JSObject.java
@@ -30,14 +30,12 @@ import java.util.Collections;
import java.util.Set;
/**
- * This is the base class for nashorn ScriptObjectMirror class.
- *
- * This class can also be subclassed by an arbitrary Java class. Nashorn will
+ * This interface can be implemented by an arbitrary Java class. Nashorn will
* treat objects of such classes just like nashorn script objects. Usual nashorn
* operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
- * to appropriate method call of this class.
+ * to appropriate method call of this interface.
*/
-public abstract class JSObject {
+public interface JSObject {
/**
* Call this object as a JavaScript function. This is equivalent to
* 'func.apply(thiz, args)' in JavaScript.
@@ -46,9 +44,7 @@ public abstract class JSObject {
* @param args arguments to method
* @return result of call
*/
- public Object call(Object thiz, Object... args) {
- throw new UnsupportedOperationException("call");
- }
+ public Object call(final Object thiz, final Object... args);
/**
* Call this 'constructor' JavaScript function to create a new object.
@@ -57,9 +53,7 @@ public abstract class JSObject {
* @param args arguments to method
* @return result of constructor call
*/
- public Object newObject(Object... args) {
- throw new UnsupportedOperationException("newObject");
- }
+ public Object newObject(final Object... args);
/**
* Evaluate a JavaScript expression.
@@ -67,20 +61,7 @@ public abstract class JSObject {
* @param s JavaScript expression to evaluate
* @return evaluation result
*/
- public Object eval(String s) {
- throw new UnsupportedOperationException("eval");
- }
-
- /**
- * Call a JavaScript function member of this object.
- *
- * @param name name of the member function to call
- * @param args arguments to be passed to the member function
- * @return result of call
- */
- public Object callMember(String name, Object... args) {
- throw new UnsupportedOperationException("call");
- }
+ public Object eval(final String s);
/**
* Retrieves a named member of this JavaScript object.
@@ -88,9 +69,7 @@ public abstract class JSObject {
* @param name of member
* @return member
*/
- public Object getMember(String name) {
- return null;
- }
+ public Object getMember(final String name);
/**
* Retrieves an indexed member of this JavaScript object.
@@ -98,9 +77,7 @@ public abstract class JSObject {
* @param index index slot to retrieve
* @return member
*/
- public Object getSlot(int index) {
- return null;
- }
+ public Object getSlot(final int index);
/**
* Does this object have a named member?
@@ -108,9 +85,7 @@ public abstract class JSObject {
* @param name name of member
* @return true if this object has a member of the given name
*/
- public boolean hasMember(String name) {
- return false;
- }
+ public boolean hasMember(final String name);
/**
* Does this object have a indexed property?
@@ -118,17 +93,14 @@ public abstract class JSObject {
* @param slot index to check
* @return true if this object has a slot
*/
- public boolean hasSlot(int slot) {
- return false;
- }
+ public boolean hasSlot(final int slot);
/**
* Remove a named member from this JavaScript object
*
* @param name name of the member
*/
- public void removeMember(String name) {
- }
+ public void removeMember(final String name);
/**
* Set a named member in this JavaScript object
@@ -136,8 +108,7 @@ public abstract class JSObject {
* @param name name of the member
* @param value value of the member
*/
- public void setMember(String name, Object value) {
- }
+ public void setMember(final String name, final Object value);
/**
* Set an indexed member in this JavaScript object
@@ -145,8 +116,7 @@ public abstract class JSObject {
* @param index index of the member slot
* @param value value of the member
*/
- public void setSlot(int index, Object value) {
- }
+ public void setSlot(final int index, final Object value);
// property and value iteration
@@ -155,20 +125,14 @@ public abstract class JSObject {
*
* @return set of property names
*/
- @SuppressWarnings("unchecked")
- public Set<String> keySet() {
- return Collections.EMPTY_SET;
- }
+ public Set<String> keySet();
/**
* Returns the set of all property values of this object.
*
* @return set of property values.
*/
- @SuppressWarnings("unchecked")
- public Collection<Object> values() {
- return Collections.EMPTY_SET;
- }
+ public Collection<Object> values();
// JavaScript instanceof check
@@ -178,9 +142,7 @@ public abstract class JSObject {
* @param instance instace to check
* @return true if the given 'instance' is an instance of this 'function' object
*/
- public boolean isInstance(final Object instance) {
- return false;
- }
+ public boolean isInstance(final Object instance);
/**
* Checking whether this object is an instance of the given 'clazz' object.
@@ -188,47 +150,40 @@ public abstract class JSObject {
* @param clazz clazz to check
* @return true if this object is an instance of the given 'clazz'
*/
- public boolean isInstanceOf(final Object clazz) {
- if (clazz instanceof JSObject) {
- return ((JSObject)clazz).isInstance(this);
- }
-
- return false;
- }
+ public boolean isInstanceOf(final Object clazz);
/**
* ECMA [[Class]] property
*
* @return ECMA [[Class]] property value of this object
*/
- public String getClassName() {
- return getClass().getName();
- }
+ public String getClassName();
/**
* Is this a function object?
*
* @return if this mirror wraps a ECMAScript function instance
*/
- public boolean isFunction() {
- return false;
- }
+ public boolean isFunction();
/**
* Is this a 'use strict' function object?
*
* @return true if this mirror represents a ECMAScript 'use strict' function
*/
- public boolean isStrictFunction() {
- return false;
- }
+ public boolean isStrictFunction();
/**
* Is this an array object?
*
* @return if this mirror wraps a ECMAScript array object
*/
- public boolean isArray() {
- return false;
- }
+ public boolean isArray();
+
+ /**
+ * Returns this object's numeric value.
+ *
+ * @return this object's numeric value.
+ */
+ public double toNumber();
}
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index 4629665f..d0fb0c31 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -285,11 +285,10 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
final URL url = ((URLReader)reader).getURL();
final Charset cs = ((URLReader)reader).getCharset();
return new Source(url.toString(), url, cs);
- } else {
- return new Source(getScriptName(ctxt), Source.readFully(reader));
}
- } catch (final IOException ioExp) {
- throw new ScriptException(ioExp);
+ return new Source(getScriptName(ctxt), Source.readFully(reader));
+ } catch (final IOException e) {
+ throw new ScriptException(e);
}
}
@@ -313,7 +312,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
if (! Modifier.isPublic(clazz.getModifiers())) {
throw new SecurityException(getMessage("implementing.non.public.interface", clazz.getName()));
}
- Context.checkPackageAccess(clazz.getName());
+ Context.checkPackageAccess(clazz);
}
ScriptObject realSelf = null;
@@ -576,15 +575,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return new CompiledScript() {
@Override
public Object eval(final ScriptContext ctxt) throws ScriptException {
- final ScriptObject global = getNashornGlobalFrom(ctxt);
+ final ScriptObject globalObject = getNashornGlobalFrom(ctxt);
// Are we running the script in the correct global?
- if (func.getScope() == global) {
- return evalImpl(func, ctxt, global);
- } else {
- // ScriptContext with a different global. Compile again!
- // Note that we may still hit per-global compilation cache.
- return evalImpl(compileImpl(source, ctxt), ctxt, global);
+ if (func.getScope() == globalObject) {
+ return evalImpl(func, ctxt, globalObject);
}
+ // ScriptContext with a different global. Compile again!
+ // Note that we may still hit per-global compilation cache.
+ return evalImpl(compileImpl(source, ctxt), ctxt, globalObject);
}
@Override
public ScriptEngine getEngine() {
diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index 3a27d23e..911f1663 100644
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -41,8 +41,10 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.script.Bindings;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.GlobalObject;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -50,7 +52,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* Mirror object that wraps a given Nashorn Script object.
*/
-public final class ScriptObjectMirror extends JSObject implements Bindings {
+public final class ScriptObjectMirror extends AbstractJSObject implements Bindings {
private static AccessControlContext getContextAccCtxt() {
final Permissions perms = new Permissions();
perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT));
@@ -161,7 +163,6 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
});
}
- @Override
public Object callMember(final String functionName, final Object... args) {
functionName.getClass(); // null check
final ScriptObject oldGlobal = Context.getGlobal();
@@ -594,14 +595,35 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
}
/**
- * Make a script object mirror on given object if needed.
+ * Utilitity to convert this script object to the given type.
*
- * @param obj object to be wrapped
- * @param homeGlobal global to which this object belongs
- * @return wrapped object
+ * @param type destination type to convert to
+ * @return converted object
+ */
+ public <T> T to(final Class<T> type) {
+ return inGlobal(new Callable<T>() {
+ @Override
+ public T call() {
+ return type.cast(ScriptUtils.convert(sobj, type));
+ }
+ });
+ }
+
+ /**
+ * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+ *
+ * @param obj object to be wrapped/converted
+ * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+ * @return wrapped/converted object
*/
- public static Object wrap(final Object obj, final ScriptObject homeGlobal) {
- return (obj instanceof ScriptObject && homeGlobal != null) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj;
+ public static Object wrap(final Object obj, final Object homeGlobal) {
+ if(obj instanceof ScriptObject) {
+ return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj;
+ }
+ if(obj instanceof ConsString) {
+ return obj.toString();
+ }
+ return obj;
}
/**
@@ -611,7 +633,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
* @param homeGlobal global to which this object belongs
* @return unwrapped object
*/
- public static Object unwrap(final Object obj, final ScriptObject homeGlobal) {
+ public static Object unwrap(final Object obj, final Object homeGlobal) {
if (obj instanceof ScriptObjectMirror) {
final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
return (mirror.global == homeGlobal)? mirror.sobj : obj;
@@ -627,7 +649,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
* @param homeGlobal global to which this object belongs
* @return wrapped array
*/
- public static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) {
+ public static Object[] wrapArray(final Object[] args, final Object homeGlobal) {
if (args == null || args.length == 0) {
return args;
}
@@ -648,7 +670,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
* @param homeGlobal global to which this object belongs
* @return unwrapped array
*/
- public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
+ public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) {
if (args == null || args.length == 0) {
return args;
}
@@ -705,4 +727,13 @@ public final class ScriptObjectMirror extends JSObject implements Bindings {
}
}
}
+
+ @Override
+ public double toNumber() {
+ return inGlobal(new Callable<Double>() {
+ @Override public Double call() {
+ return JSType.toNumber(sobj);
+ }
+ });
+ }
}
diff --git a/src/jdk/nashorn/api/scripting/ScriptUtils.java b/src/jdk/nashorn/api/scripting/ScriptUtils.java
index ccd5879b..29d03db4 100644
--- a/src/jdk/nashorn/api/scripting/ScriptUtils.java
+++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java
@@ -25,10 +25,17 @@
package jdk.nashorn.api.scripting;
+import java.lang.invoke.MethodHandle;
+import jdk.internal.dynalink.beans.StaticClass;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
- * Utilities that are to be called from script code
+ * Utilities that are to be called from script code.
*/
public final class ScriptUtils {
private ScriptUtils() {}
@@ -57,4 +64,109 @@ public final class ScriptUtils {
public static String format(final String format, final Object[] args) {
return Formatter.format(format, args);
}
+
+ /**
+ * Create a wrapper function that calls {@code func} synchronized on {@code sync} or, if that is undefined,
+ * {@code self}. Used to implement "sync" function in resources/mozilla_compat.js.
+ *
+ * @param func the function to invoke
+ * @param sync the object to synchronize on
+ * @return a synchronizing wrapper function
+ */
+ public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
+ return func.makeSynchronizedFunction(sync);
+ }
+
+ /**
+ * Make a script object mirror on given object if needed.
+ *
+ * @param obj object to be wrapped
+ * @return wrapped object
+ */
+ public static Object wrap(final Object obj) {
+ if (obj instanceof ScriptObject) {
+ return ScriptObjectMirror.wrap(obj, Context.getGlobal());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Unwrap a script object mirror if needed.
+ *
+ * @param obj object to be unwrapped
+ * @return unwrapped object
+ */
+ public static Object unwrap(final Object obj) {
+ if (obj instanceof ScriptObjectMirror) {
+ return ScriptObjectMirror.unwrap(obj, Context.getGlobal());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Wrap an array of object to script object mirrors if needed.
+ *
+ * @param args array to be unwrapped
+ * @return wrapped array
+ */
+ public static Object[] wrapArray(final Object[] args) {
+ if (args == null || args.length == 0) {
+ return args;
+ }
+
+ return ScriptObjectMirror.wrapArray(args, Context.getGlobal());
+ }
+
+ /**
+ * Unwrap an array of script object mirrors if needed.
+ *
+ * @param args array to be unwrapped
+ * @return unwrapped array
+ */
+ public static Object[] unwrapArray(final Object[] args) {
+ if (args == null || args.length == 0) {
+ return args;
+ }
+
+ return ScriptObjectMirror.unwrapArray(args, Context.getGlobal());
+ }
+
+ /**
+ * Convert the given object to the given type.
+ *
+ * @param obj object to be converted
+ * @param type destination type to convert to
+ * @return converted object
+ */
+ public static Object convert(final Object obj, final Object type) {
+ if (obj == null) {
+ return null;
+ }
+
+ final Class<?> clazz;
+ if (type instanceof Class) {
+ clazz = (Class<?>)type;
+ } else if (type instanceof StaticClass) {
+ clazz = ((StaticClass)type).getRepresentedClass();
+ } else {
+ throw new IllegalArgumentException("type expected");
+ }
+
+ final LinkerServices linker = Bootstrap.getLinkerServices();
+ final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz);
+ if (converter == null) {
+ // no supported conversion!
+ throw new UnsupportedOperationException("conversion not supported");
+ }
+
+ try {
+ return converter.invoke(obj);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
}
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 55355c3e..f1ced8ad 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -271,6 +271,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
functionNode.addDeclaredSymbol(symbol);
if (varNode.isFunctionDeclaration()) {
newType(symbol, FunctionNode.FUNCTION_TYPE);
+ symbol.setIsFunctionDeclaration();
}
return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
}
@@ -480,6 +481,10 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
//unknown parameters are promoted to object type.
+ if (newFunctionNode.hasLazyChildren()) {
+ //the final body has already been assigned as we have left the function node block body by now
+ objectifySymbols(body);
+ }
newFunctionNode = finalizeParameters(newFunctionNode);
newFunctionNode = finalizeTypes(newFunctionNode);
for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
@@ -489,11 +494,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
}
- if (newFunctionNode.hasLazyChildren()) {
- //the final body has already been assigned as we have left the function node block body by now
- objectifySymbols(body);
- }
-
List<VarNode> syntheticInitializers = null;
if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
@@ -503,8 +503,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
syntheticInitializers.add(createSyntheticInitializer(newFunctionNode.getIdent(), CALLEE, newFunctionNode));
}
- if(newFunctionNode.needsArguments()) {
- if(syntheticInitializers == null) {
+ if (newFunctionNode.needsArguments()) {
+ if (syntheticInitializers == null) {
syntheticInitializers = new ArrayList<>(1);
}
// "var arguments = :arguments"
@@ -512,12 +512,12 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
ARGUMENTS, newFunctionNode));
}
- if(syntheticInitializers != null) {
- final List<Statement> stmts = body.getStatements();
+ if (syntheticInitializers != null) {
+ final List<Statement> stmts = newFunctionNode.getBody().getStatements();
final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size());
newStatements.addAll(syntheticInitializers);
newStatements.addAll(stmts);
- newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
+ newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setStatements(lc, newStatements));
}
if (returnTypes.peek().isUnknown()) {
@@ -558,12 +558,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- assert false : "There should be no convert operators in IR during Attribution";
- return end(unaryNode);
- }
-
- @Override
public Node leaveIdentNode(final IdentNode identNode) {
final String name = identNode.getName();
@@ -991,7 +985,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveNEW(final UnaryNode unaryNode) {
- return end(ensureSymbol(Type.OBJECT, unaryNode));
+ return end(ensureSymbol(Type.OBJECT, unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew())));
}
@Override
@@ -1082,24 +1076,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private boolean enterAssignmentNode(final BinaryNode binaryNode) {
start(binaryNode);
- final Node lhs = binaryNode.lhs();
-
- if (lhs instanceof IdentNode) {
- final Block block = lc.getCurrentBlock();
- final IdentNode ident = (IdentNode)lhs;
- final String name = ident.getName();
-
- Symbol symbol = findSymbol(block, name);
-
- if (symbol == null) {
- symbol = defineSymbol(block, name, IS_GLOBAL);
- } else {
- maybeForceScope(symbol);
- }
-
- addLocalDef(name);
- }
-
return true;
}
@@ -1112,20 +1088,33 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
* @param binaryNode assignment node
*/
private Node leaveAssignmentNode(final BinaryNode binaryNode) {
- BinaryNode newBinaryNode = binaryNode;
-
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type type;
+ if (lhs instanceof IdentNode) {
+ final Block block = lc.getCurrentBlock();
+ final IdentNode ident = (IdentNode)lhs;
+ final String name = ident.getName();
+ final Symbol symbol = findSymbol(block, name);
+
+ if (symbol == null) {
+ defineSymbol(block, name, IS_GLOBAL);
+ } else {
+ maybeForceScope(symbol);
+ }
+
+ addLocalDef(name);
+ }
+
if (rhs.getType().isNumeric()) {
- type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ type = Type.widest(lhs.getType(), rhs.getType());
} else {
type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
}
newType(lhs.getSymbol(), type);
- return end(ensureSymbol(type, newBinaryNode));
+ return end(ensureSymbol(type, binaryNode));
}
private boolean isLocal(FunctionNode function, Symbol symbol) {
@@ -1276,12 +1265,17 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
- return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode));
+ return leaveComma(binaryNode, binaryNode.rhs());
}
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
- return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode));
+ return leaveComma(binaryNode, binaryNode.lhs());
+ }
+
+ private Node leaveComma(final BinaryNode commaNode, final Expression effectiveExpr) {
+ ensureTypeNotUnknown(effectiveExpr);
+ return end(ensureSymbol(effectiveExpr.getType(), commaNode));
}
@Override
@@ -1292,7 +1286,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private Node leaveCmp(final BinaryNode binaryNode) {
ensureTypeNotUnknown(binaryNode.lhs());
ensureTypeNotUnknown(binaryNode.rhs());
-
+ Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ ensureSymbol(widest, binaryNode.lhs());
+ ensureSymbol(widest, binaryNode.rhs());
return end(ensureSymbol(Type.BOOLEAN, binaryNode));
}
@@ -1635,7 +1631,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
Symbol symbol = node.getSymbol();
- if(symbol.isShared() && symbol.wouldChangeType(to)) {
+ if (symbol.isShared() && symbol.wouldChangeType(to)) {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
}
newType(symbol, to);
@@ -1651,40 +1647,105 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return !node.isLazy();
}
- /**
- * Eg.
- *
- * var d = 17;
- * var e;
- * e = d; //initially typed as int for node type, should retype as double
- * e = object;
- *
- * var d = 17;
- * var e;
- * e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric
- * e = object;
- *
- */
+ //
+ // Eg.
+ //
+ // var d = 17;
+ // var e;
+ // e = d; //initially typed as int for node type, should retype as double
+ // e = object;
+ //
+ // var d = 17;
+ // var e;
+ // e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric
+ // e = object;
+ //
@SuppressWarnings("fallthrough")
@Override
public Node leaveBinaryNode(final BinaryNode binaryNode) {
final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
BinaryNode newBinaryNode = binaryNode;
- switch (binaryNode.tokenType()) {
- default:
- if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
+
+ if (isAdd(binaryNode)) {
+ newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
+ if (newBinaryNode.getType().isObject() && !isAddString(newBinaryNode)) {
+ return new RuntimeNode(newBinaryNode, Request.ADD);
+ }
+ } else if (binaryNode.isComparison()) {
+ final Expression lhs = newBinaryNode.lhs();
+ final Expression rhs = newBinaryNode.rhs();
+
+ Type cmpWidest = Type.widest(lhs.getType(), rhs.getType());
+
+ boolean newRuntimeNode = false, finalized = false;
+ switch (newBinaryNode.tokenType()) {
+ case EQ_STRICT:
+ case NE_STRICT:
+ if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
+ newRuntimeNode = true;
+ cmpWidest = Type.OBJECT;
+ finalized = true;
+ }
+ //fallthru
+ default:
+ if (newRuntimeNode || cmpWidest.isObject()) {
+ return new RuntimeNode(newBinaryNode, Request.requestFor(binaryNode)).setIsFinal(finalized);
+ }
break;
}
+
+ return newBinaryNode;
+ } else {
+ if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
+ return newBinaryNode;
+ }
+ checkThisAssignment(binaryNode);
newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest));
- case ADD:
newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
}
+
return newBinaryNode;
+
+ }
+
+ private boolean isAdd(final Node node) {
+ return node.isTokenType(TokenType.ADD);
+ }
+
+ /**
+ * Determine if the outcome of + operator is a string.
+ *
+ * @param node Node to test.
+ * @return true if a string result.
+ */
+ private boolean isAddString(final Node node) {
+ if (node instanceof BinaryNode && isAdd(node)) {
+ final BinaryNode binaryNode = (BinaryNode)node;
+ final Node lhs = binaryNode.lhs();
+ final Node rhs = binaryNode.rhs();
+
+ return isAddString(lhs) || isAddString(rhs);
+ }
+
+ return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString();
+ }
+
+ private void checkThisAssignment(final BinaryNode binaryNode) {
+ if (binaryNode.isAssignment()) {
+ if (binaryNode.lhs() instanceof AccessNode) {
+ final AccessNode accessNode = (AccessNode) binaryNode.lhs();
+
+ if (accessNode.getBase().getSymbol().isThis()) {
+ lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
+ }
+ }
+ }
}
});
lc.replace(currentFunctionNode, newFunctionNode);
currentFunctionNode = newFunctionNode;
} while (!changed.isEmpty());
+
return currentFunctionNode;
}
@@ -1697,7 +1758,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
final Expression lhs = binaryNode.lhs();
newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
-// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
return end(ensureSymbol(destType, binaryNode));
}
diff --git a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
index 02ea95f1..ad9bdb07 100644
--- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
+++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
@@ -56,10 +56,6 @@ final class BranchOptimizer {
branchOptimizer(node, label, state);
}
- private void load(final Expression node) {
- codegen.load(node);
- }
-
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
final Expression rhs = unaryNode.rhs();
@@ -67,19 +63,16 @@ final class BranchOptimizer {
case NOT:
branchOptimizer(rhs, label, !state);
return;
- case CONVERT:
+ default:
if (unaryNode.getType().isBoolean()) {
branchOptimizer(rhs, label, state);
return;
}
break;
- default:
- break;
}
// convert to boolean
- load(unaryNode);
- method.convert(Type.BOOLEAN);
+ codegen.load(unaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
@@ -118,45 +111,33 @@ final class BranchOptimizer {
case EQ:
case EQ_STRICT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? EQ : NE, true, label);
return;
case NE:
case NE_STRICT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? NE : EQ, true, label);
return;
case GE:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? GE : LT, !state, label);
return;
case GT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? GT : LE, !state, label);
return;
case LE:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol();
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? LE : GT, state, label);
return;
case LT:
- assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode;
- load(lhs);
- load(rhs);
+ codegen.loadBinaryOperands(lhs, rhs, Type.widest(lhs.getType(), rhs.getType()));
method.conditionalJump(state ? LT : GE, state, label);
return;
@@ -164,8 +145,7 @@ final class BranchOptimizer {
break;
}
- load(binaryNode);
- method.convert(Type.BOOLEAN);
+ codegen.load(binaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
@@ -187,8 +167,7 @@ final class BranchOptimizer {
}
}
- load(node);
- method.convert(Type.BOOLEAN);
+ codegen.load(node, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index d16a1e5b..f5c1fb87 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -43,7 +43,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup
import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticField;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
@@ -60,7 +59,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
@@ -111,7 +109,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.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.objects.Global;
@@ -217,12 +214,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param identNode an identity node to load
* @return the method generator used
*/
- private MethodEmitter loadIdent(final IdentNode identNode) {
+ private MethodEmitter loadIdent(final IdentNode identNode, final Type type) {
final Symbol symbol = identNode.getSymbol();
if (!symbol.isScope()) {
assert symbol.hasSlot() || symbol.isParam();
- return method.load(symbol);
+ return method.load(symbol).convert(type);
}
final String name = symbol.getName();
@@ -243,11 +240,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
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);
+ return loadSharedScopeVar(type, symbol, flags);
}
- return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction());
+ return loadFastScopeVar(type, symbol, flags, identNode.isFunction());
}
- return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction());
+ return method.dynamicGet(type, identNode.getName(), flags, identNode.isFunction());
}
}
@@ -313,9 +310,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod);
}
- private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) {
+ private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) {
loadFastScopeProto(symbol, true);
- method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE);
+ method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE);
return method;
}
@@ -359,18 +356,64 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @return the method emitter used
*/
MethodEmitter load(final Expression node) {
- return load(node, false);
+ return load(node, node.hasType() ? node.getType() : null, false);
+ }
+
+ // Test whether conversion from source to target involves a call of ES 9.1 ToPrimitive
+ // with possible side effects from calling an object's toString or valueOf methods.
+ private boolean noToPrimitiveConversion(final Type source, final Type target) {
+ // Object to boolean conversion does not cause ToPrimitive call
+ return source.isJSPrimitive() || !target.isJSPrimitive() || target.isBoolean();
+ }
+
+ MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) {
+ return loadBinaryOperands(lhs, rhs, type, false);
+ }
+
+ private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type, final boolean baseAlreadyOnStack) {
+ // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary
+ // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT
+ // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we
+ // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its
+ // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when
+ // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT.
+ // Basically, if we know that either LEFT already is a primitive value, or does not have to be converted to
+ // a primitive value, or RIGHT is an expression that loads without side effects, then we can do the
+ // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly
+ // separate operations to preserve specification semantics.
+ if (noToPrimitiveConversion(lhs.getType(), type) || rhs.isLocal()) {
+ // Can reorder. Combine load and convert into single operations.
+ load(lhs, type, baseAlreadyOnStack);
+ load(rhs, type, false);
+ } else {
+ // Can't reorder. Load and convert separately.
+ load(lhs, lhs.getType(), baseAlreadyOnStack);
+ load(rhs, rhs.getType(), false);
+ method.swap().convert(type).swap().convert(type);
+ }
+
+ return method;
+ }
+
+ MethodEmitter loadBinaryOperands(final BinaryNode node) {
+ return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false);
+ }
+
+ MethodEmitter load(final Expression node, final Type type) {
+ return load(node, type, false);
}
- private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) {
+ private MethodEmitter load(final Expression node, final Type type, final boolean baseAlreadyOnStack) {
final Symbol symbol = node.getSymbol();
// If we lack symbols, we just generate what we see.
- if (symbol == null) {
+ if (symbol == null || type == null) {
node.accept(this);
return method;
}
+ assert !type.isUnknown();
+
/*
* The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y"
* or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are
@@ -378,30 +421,30 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*/
final CodeGenerator codegen = this;
- node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ node.accept(new NodeVisitor<LexicalContext>(lc) {
@Override
public boolean enterIdentNode(final IdentNode identNode) {
- loadIdent(identNode);
+ loadIdent(identNode, type);
return false;
}
@Override
public boolean enterAccessNode(final AccessNode accessNode) {
if (!baseAlreadyOnStack) {
- load(accessNode.getBase()).convert(Type.OBJECT);
+ load(accessNode.getBase(), Type.OBJECT);
}
assert method.peekType().isObject();
- method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
+ method.dynamicGet(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
return false;
}
@Override
public boolean enterIndexNode(final IndexNode indexNode) {
if (!baseAlreadyOnStack) {
- load(indexNode.getBase()).convert(Type.OBJECT);
+ load(indexNode.getBase(), Type.OBJECT);
load(indexNode.getIndex());
}
- method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction());
+ method.dynamicGetIndex(type, getCallSiteFlags(), indexNode.isFunction());
return false;
}
@@ -409,14 +452,36 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterFunctionNode(FunctionNode functionNode) {
// function nodes will always leave a constructed function object on stack, no need to load the symbol
// separately as in enterDefault()
+ lc.pop(functionNode);
functionNode.accept(codegen);
+ // NOTE: functionNode.accept() will produce a different FunctionNode that we discard. This incidentally
+ // doesn't cause problems as we're never touching FunctionNode again after it's visited here - codegen
+ // is the last element in the compilation pipeline, the AST it produces is not used externally. So, we
+ // re-push the original functionNode.
+ lc.push(functionNode);
+ method.convert(type);
return false;
}
@Override
+ public boolean enterCallNode(CallNode callNode) {
+ return codegen.enterCallNode(callNode, type);
+ }
+
+ @Override
+ public boolean enterLiteralNode(LiteralNode<?> literalNode) {
+ return codegen.enterLiteralNode(literalNode, type);
+ }
+
+ @Override
public boolean enterDefault(final Node otherNode) {
+ final Node currentDiscard = codegen.lc.getCurrentDiscard();
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)
+ if(currentDiscard != otherNode) {
+ method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
+ assert method.peekType() != null;
+ method.convert(type);
+ }
return false;
}
});
@@ -566,11 +631,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Type[] params = signature == null ? null : Type.getMethodArguments(signature);
for (final Expression arg : args) {
assert arg != null;
- load(arg);
if (n >= argCount) {
+ load(arg);
method.pop(); // we had to load the arg for its side effects
} else if (params != null) {
- method.convert(params[n]);
+ load(arg, params[n]);
+ } else {
+ load(arg);
}
n++;
}
@@ -583,15 +650,19 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return argCount;
}
+
@Override
public boolean enterCallNode(final CallNode callNode) {
+ return enterCallNode(callNode, callNode.getType());
+ }
+
+ private boolean enterCallNode(final CallNode callNode, final Type callNodeType) {
lineNumber(callNode.getLineNumber());
final List<Expression> args = callNode.getArgs();
final Expression function = callNode.getFunction();
final Block currentBlock = lc.getCurrentBlock();
final CodeGeneratorLexicalContext codegenLexicalContext = lc;
- final Type callNodeType = callNode.getType();
function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@@ -612,16 +683,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void scopeCall(final IdentNode node, final int flags) {
- load(node);
- method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
+ load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3
// ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
method.loadNull(); //the 'this'
method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
}
private void evalCall(final IdentNode node, final int flags) {
- load(node);
- method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
+ load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3
final Label not_eval = new Label("not_eval");
final Label eval_done = new Label("eval_done");
@@ -638,8 +707,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
// load evaluated code
- load(evalArgs.getCode());
- method.convert(Type.OBJECT);
+ load(evalArgs.getCode(), Type.OBJECT);
+ // load second and subsequent args for side-effect
+ final List<Expression> args = callNode.getArgs();
+ final int numArgs = args.size();
+ for (int i = 1; i < numArgs; i++) {
+ load(args.get(i)).pop();
+ }
// special/extra 'eval' arguments
load(evalArgs.getThis());
method.load(evalArgs.getLocation());
@@ -690,13 +764,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterAccessNode(final AccessNode node) {
- load(node.getBase());
- method.convert(Type.OBJECT);
+ load(node.getBase(), Type.OBJECT);
method.dup();
method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true);
method.swap();
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
- assert method.peekType().equals(callNodeType);
return false;
}
@@ -727,18 +799,17 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterIndexNode(final IndexNode node) {
- load(node.getBase());
- method.convert(Type.OBJECT);
+ load(node.getBase(), Type.OBJECT);
method.dup();
- load(node.getIndex());
final Type indexType = node.getIndex().getType();
if (indexType.isObject() || indexType.isBoolean()) {
- method.convert(Type.OBJECT); //TODO
+ load(node.getIndex(), Type.OBJECT); //TODO
+ } else {
+ load(node.getIndex());
}
method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true);
method.swap();
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
- assert method.peekType().equals(callNode.getType());
return false;
}
@@ -746,11 +817,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
protected boolean enterDefault(final Node node) {
// Load up function.
- load(function);
- method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions
+ load(function, Type.OBJECT); //TODO, e.g. booleans can be used as functions
method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
- assert method.peekType().equals(callNode.getType());
return false;
}
@@ -853,8 +922,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Expression init = forNode.getInit();
- load(modify);
- assert modify.getType().isObject();
+ load(modify, Type.OBJECT);
method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR);
method.store(iter);
method._goto(forNode.getContinueLabel());
@@ -1203,8 +1271,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (element == null) {
method.loadEmpty(elementType);
} else {
- assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type";
- load(element);
+ load(element, elementType);
}
method.arraystore();
@@ -1217,7 +1284,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
for (int i = 0; i < args.size(); i++) {
method.dup();
method.load(i);
- load(args.get(i)).convert(Type.OBJECT); //has to be upcast to object or we fail
+ load(args.get(i), Type.OBJECT); //has to be upcast to object or we fail
method.arraystore();
}
@@ -1274,7 +1341,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
// literal values
- private MethodEmitter load(final LiteralNode<?> node) {
+ private MethodEmitter loadLiteral(final LiteralNode<?> node, final Type type) {
final Object value = node.getValue();
if (value == null) {
@@ -1294,15 +1361,26 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} else if (value instanceof Boolean) {
method.load((Boolean)value);
} else if (value instanceof Integer) {
- method.load((Integer)value);
+ if(type.isEquivalentTo(Type.NUMBER)) {
+ method.load(((Integer)value).doubleValue());
+ } else if(type.isEquivalentTo(Type.LONG)) {
+ method.load(((Integer)value).longValue());
+ } else {
+ method.load((Integer)value);
+ }
} else if (value instanceof Long) {
- method.load((Long)value);
+ if(type.isEquivalentTo(Type.NUMBER)) {
+ method.load(((Long)value).doubleValue());
+ } else {
+ method.load((Long)value);
+ }
} else if (value instanceof Double) {
method.load((Double)value);
} else if (node instanceof ArrayLiteralNode) {
- final ArrayType type = (ArrayType)node.getType();
- loadArray((ArrayLiteralNode)node, type);
- globalAllocateArray(type);
+ final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node;
+ final ArrayType atype = arrayLiteral.getArrayType();
+ loadArray(arrayLiteral, atype);
+ globalAllocateArray(atype);
} else {
assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value;
}
@@ -1346,8 +1424,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+ return enterLiteralNode(literalNode, literalNode.getType());
+ }
+
+ private boolean enterLiteralNode(final LiteralNode<?> literalNode, final Type type) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
- load(literalNode).store(literalNode.getSymbol());
+ loadLiteral(literalNode, type).convert(type).store(literalNode.getSymbol());
return false;
}
@@ -1622,10 +1704,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return enterCmp(lhs, rhs, Condition.GT, type, symbol);
case ADD:
Type widest = Type.widest(lhs.getType(), rhs.getType());
- load(lhs);
- method.convert(widest);
- load(rhs);
- method.convert(widest);
+ load(lhs, widest);
+ load(rhs, widest);
method.add();
method.convert(type);
method.store(symbol);
@@ -1638,15 +1718,15 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
- return false;
+ return false;
}
if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
- return false;
+ return false;
}
for (final Expression arg : args) {
- load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower
+ load(arg, Type.OBJECT);
}
method.invokestatic(
@@ -1827,6 +1907,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
if (cases.isEmpty()) {
+ // still evaluate expression for side-effects.
+ load(expression).pop();
method.label(breakLabel);
return false;
}
@@ -1901,24 +1983,15 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.lookupswitch(defaultLabel, ints, labels);
}
} else {
- load(expression);
-
- if (expression.getType().isInteger()) {
- method.convert(Type.NUMBER).dup();
- method.store(tag);
- method.conditionalJump(Condition.NE, true, defaultLabel);
- } else {
- assert tag.getSymbolType().isObject();
- method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object
- method.store(tag);
- }
+ load(expression, Type.OBJECT);
+ method.store(tag);
for (final CaseNode caseNode : cases) {
final Expression test = caseNode.getTest();
if (test != null) {
method.load(tag);
- load(test);
+ load(test, Type.OBJECT);
method.invoke(ScriptRuntime.EQ_STRICT);
method.ifne(caseNode.getEntry());
}
@@ -1956,11 +2029,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Expression expression = throwNode.getExpression();
final int position = throwNode.position();
- final int line = source.getLine(position);
+ final int line = throwNode.getLineNumber();
final int column = source.getColumn(position);
- load(expression);
- assert expression.getType().isObject();
+ load(expression, Type.OBJECT);
method.load(source.getName());
method.load(line);
@@ -2040,7 +2112,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (exceptionCondition != null) {
next = new Label("next");
- load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next);
+ load(exceptionCondition, Type.BOOLEAN).ifeq(next);
} else {
next = null;
}
@@ -2085,29 +2157,28 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lineNumber(varNode);
- final Symbol varSymbol = varNode.getName().getSymbol();
- assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol";
+ final IdentNode identNode = varNode.getName();
+ final Symbol identSymbol = identNode.getSymbol();
+ assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
assert method != null;
- final boolean needsScope = varSymbol.isScope();
+ final boolean needsScope = identSymbol.isScope();
if (needsScope) {
method.loadCompilerConstant(SCOPE);
}
- load(init);
if (needsScope) {
+ load(init);
int flags = CALLSITE_SCOPE | getCallSiteFlags();
- final IdentNode identNode = varNode.getName();
- final Type type = identNode.getType();
- if (isFastScope(varSymbol)) {
- storeFastScopeVar(type, varSymbol, flags);
+ if (isFastScope(identSymbol)) {
+ storeFastScopeVar(identSymbol, flags);
} else {
- method.dynamicSet(type, identNode.getName(), flags);
+ method.dynamicSet(identNode.getName(), flags);
}
} else {
- method.convert(varNode.getName().getType()); // aw: convert moved here
- method.store(varSymbol);
+ load(init, identNode.getType());
+ method.store(identSymbol);
}
return false;
@@ -2166,8 +2237,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
tryLabel = null;
}
- load(expression);
- assert expression.getType().isObject() : "with expression needs to be object: " + expression;
+ load(expression, Type.OBJECT);
if (hasScope) {
// Construct a WithObject if we have a scope
@@ -2209,54 +2279,15 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterADD(final UnaryNode unaryNode) {
- load(unaryNode.rhs());
- assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol();
+ load(unaryNode.rhs(), unaryNode.getType());
+ assert unaryNode.getType().isNumeric();
method.store(unaryNode.getSymbol());
-
return false;
}
@Override
public boolean enterBIT_NOT(final UnaryNode unaryNode) {
- load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol());
- return false;
- }
-
- // do this better with convert calls to method. TODO
- @Override
- public boolean enterCONVERT(final UnaryNode unaryNode) {
- final Expression rhs = unaryNode.rhs();
- final Type to = unaryNode.getType();
-
- if (to.isObject() && rhs instanceof LiteralNode) {
- final LiteralNode<?> literalNode = (LiteralNode<?>)rhs;
- final Object value = literalNode.getValue();
-
- if (value instanceof Number) {
- assert !to.isArray() : "type hygiene - cannot convert number to array: (" + to.getTypeClass().getSimpleName() + ')' + value;
- if (value instanceof Integer) {
- method.load((Integer)value);
- } else if (value instanceof Long) {
- method.load((Long)value);
- } else if (value instanceof Double) {
- method.load((Double)value);
- } else {
- assert false;
- }
- method.convert(Type.OBJECT);
- } else if (value instanceof Boolean) {
- method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class));
- } else {
- load(rhs);
- method.convert(unaryNode.getType());
- }
- } else {
- load(rhs);
- method.convert(unaryNode.getType());
- }
-
- method.store(unaryNode.getSymbol());
-
+ load(unaryNode.rhs(), Type.INT).load(-1).xor().store(unaryNode.getSymbol());
return false;
}
@@ -2274,9 +2305,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
protected void evaluate() {
- load(rhs, true);
-
- method.convert(type);
+ load(rhs, type, true);
if (!isPostfix) {
if (type.isInteger()) {
method.load(isIncrement ? 1 : -1);
@@ -2330,7 +2359,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final List<Expression> args = callNode.getArgs();
// Load function reference.
- load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error
+ load(callNode.getFunction(), Type.OBJECT); // must detect type error
method.dynamicNew(1 + loadArgs(args), getCallSiteFlags());
method.store(unaryNode.getSymbol());
@@ -2342,12 +2371,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterNOT(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.rhs();
- load(rhs);
+ load(rhs, Type.BOOLEAN);
final Label trueLabel = new Label("true");
final Label afterLabel = new Label("after");
- method.convert(Type.BOOLEAN);
method.ifne(trueLabel);
method.load(true);
method._goto(afterLabel);
@@ -2361,8 +2389,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterSUB(final UnaryNode unaryNode) {
- load(unaryNode.rhs()).neg().store(unaryNode.getSymbol());
-
+ assert unaryNode.getType().isNumeric();
+ load(unaryNode.rhs(), unaryNode.getType()).neg().store(unaryNode.getSymbol());
return false;
}
@@ -2375,9 +2403,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) {
- assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
- load(lhs);
- load(rhs);
+ loadBinaryOperands(lhs, rhs, type);
method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
method.store(symbol);
}
@@ -2391,8 +2417,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (type.isNumeric()) {
enterNumericAdd(lhs, rhs, type, binaryNode.getSymbol());
} else {
- load(lhs).convert(Type.OBJECT);
- load(rhs).convert(Type.OBJECT);
+ loadBinaryOperands(binaryNode);
method.add();
method.store(binaryNode.getSymbol());
}
@@ -2406,7 +2431,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Label skip = new Label("skip");
- load(lhs).convert(Type.OBJECT).dup().convert(Type.BOOLEAN);
+ load(lhs, Type.OBJECT).dup().convert(Type.BOOLEAN);
if (binaryNode.tokenType() == TokenType.AND) {
method.ifeq(skip);
@@ -2415,7 +2440,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
method.pop();
- load(rhs).convert(Type.OBJECT);
+ load(rhs, Type.OBJECT);
method.label(skip);
method.store(binaryNode.getSymbol());
@@ -2437,13 +2462,16 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (!lhsType.isEquivalentTo(rhsType)) {
//this is OK if scoped, only locals are wrong
- assert !(lhs instanceof IdentNode) || lhs.getSymbol().isScope() : new ASTWriter(binaryNode);
}
new Store<BinaryNode>(binaryNode, lhs) {
@Override
protected void evaluate() {
- load(rhs);
+ if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) {
+ load(rhs, lhsType);
+ } else {
+ load(rhs);
+ }
}
}.store();
@@ -2482,8 +2510,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
protected void evaluate() {
- load(assignNode.lhs(), true).convert(opType);
- load(assignNode.rhs()).convert(opType);
+ loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), opType, true);
op();
method.convert(assignNode.getType());
}
@@ -2654,8 +2681,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
protected abstract void op();
protected void evaluate(final BinaryNode node) {
- load(node.lhs());
- load(node.rhs());
+ loadBinaryOperands(node);
op();
method.store(node.getSymbol());
}
@@ -2737,11 +2763,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Type widest = Type.widest(lhsType, rhsType);
assert widest.isNumeric() || widest.isBoolean() : widest;
- load(lhs);
- method.convert(widest);
- load(rhs);
- method.convert(widest);
-
+ loadBinaryOperands(lhs, rhs, widest);
final Label trueLabel = new Label("trueLabel");
final Label afterLabel = new Label("skip");
@@ -2860,6 +2882,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterSHR(final BinaryNode binaryNode) {
new BinaryArith() {
@Override
+ protected void evaluate(final BinaryNode node) {
+ loadBinaryOperands(node.lhs(), node.rhs(), Type.INT);
+ op();
+ method.store(node.getSymbol());
+ }
+ @Override
protected void op() {
method.shr();
method.convert(Type.LONG).load(JSType.MAX_UINT).and();
@@ -2891,26 +2919,22 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Label falseLabel = new Label("ternary_false");
final Label exitLabel = new Label("ternary_exit");
- Type widest = Type.widest(trueExpr.getType(), falseExpr.getType());
+ Type widest = Type.widest(ternaryNode.getType(), Type.widest(trueExpr.getType(), falseExpr.getType()));
if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
widest = Type.OBJECT;
}
- load(test);
- assert test.getType().isBoolean() : "lhs in ternary must be boolean";
-
+ load(test, Type.BOOLEAN);
// we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17
// will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the
// symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions
- // to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
+ // too early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
// do this property. Then we never need any conversions in CodeGenerator
method.ifeq(falseLabel);
- load(trueExpr);
- method.convert(widest);
+ load(trueExpr, widest);
method._goto(exitLabel);
method.label(falseLabel);
- load(falseExpr);
- method.convert(widest);
+ load(falseExpr, widest);
method.label(exitLabel);
method.store(symbol);
@@ -3042,8 +3066,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final BaseNode baseNode = (BaseNode)target;
final Expression base = baseNode.getBase();
- load(base);
- method.convert(Type.OBJECT);
+ load(base, Type.OBJECT);
depth += Type.OBJECT.getSlots();
if (isSelfModifying()) {
@@ -3062,10 +3085,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
enterBaseNode();
final Expression index = node.getIndex();
- // could be boolean here as well
- load(index);
if (!index.getType().isNumeric()) {
- method.convert(Type.OBJECT);
+ // could be boolean here as well
+ load(index, Type.OBJECT);
+ } else {
+ load(index);
}
depth += index.getType().getSlots();
@@ -3134,8 +3158,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* need to do a conversion on non-equivalent types exists, but is
* very rare. See for example test/script/basic/access-specializer.js
*/
- method.convert(target.getType());
-
target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
protected boolean enterDefault(Node node) {
@@ -3143,24 +3165,17 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
@Override
- public boolean enterUnaryNode(final UnaryNode node) {
- if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
- method.convert(node.rhs().getType());
- }
- return true;
- }
-
- @Override
public boolean enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
assert symbol != null;
if (symbol.isScope()) {
if (isFastScope(symbol)) {
- storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
+ storeFastScopeVar(symbol, CALLSITE_SCOPE | getCallSiteFlags());
} else {
- method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
+ method.dynamicSet(node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
}
} else {
+ method.convert(node.getType());
method.store(symbol);
}
return false;
@@ -3169,7 +3184,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterAccessNode(final AccessNode node) {
- method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
+ method.dynamicSet(node.getProperty().getName(), getCallSiteFlags());
return false;
}
diff --git a/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index be8faab9..6c0a673d 100644
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -162,7 +162,7 @@ enum CompilationPhase {
LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
- return (FunctionNode)fn.accept(new Lower());
+ return (FunctionNode)fn.accept(new Lower(compiler.getCodeInstaller()));
}
@Override
diff --git a/src/jdk/nashorn/internal/codegen/CompileUnit.java b/src/jdk/nashorn/internal/codegen/CompileUnit.java
index 0156716d..73127259 100644
--- a/src/jdk/nashorn/internal/codegen/CompileUnit.java
+++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java
@@ -28,7 +28,7 @@ package jdk.nashorn.internal.codegen;
/**
* Used to track split class compilation.
*/
-public class CompileUnit {
+public class CompileUnit implements Comparable<CompileUnit> {
/** Current class name */
private final String className;
@@ -116,4 +116,9 @@ public class CompileUnit {
public String toString() {
return "[classname=" + className + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
}
+
+ @Override
+ public int compareTo(CompileUnit o) {
+ return className.compareTo(o.className);
+ }
}
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index a31358f6..24173c3e 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -36,8 +36,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
-import jdk.nashorn.internal.ir.TemporarySymbols;
-
import java.io.File;
import java.lang.reflect.Field;
import java.security.AccessController;
@@ -48,18 +46,20 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.TreeSet;
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.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import jdk.nashorn.internal.runtime.CodeInstaller;
@@ -256,8 +256,8 @@ public final class Compiler {
this.sequence = sequence;
this.installer = installer;
this.constantData = new ConstantData();
- this.compileUnits = new HashSet<>();
- this.bytecode = new HashMap<>();
+ this.compileUnits = new TreeSet<>();
+ this.bytecode = new LinkedHashMap<>();
}
private void initCompiler(final FunctionNode functionNode) {
diff --git a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
index 63c1fdb7..15341484 100644
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
@@ -28,49 +28,22 @@ package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.AccessNode;
-import jdk.nashorn.internal.ir.Assignment;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.CallNode;
-import jdk.nashorn.internal.ir.CaseNode;
-import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ExpressionStatement;
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.ReturnNode;
-import jdk.nashorn.internal.ir.RuntimeNode;
-import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TemporarySymbols;
-import jdk.nashorn.internal.ir.TernaryNode;
-import jdk.nashorn.internal.ir.ThrowNode;
-import jdk.nashorn.internal.ir.TypeOverride;
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.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.DebugLogger;
-import jdk.nashorn.internal.runtime.JSType;
/**
* Lower to more primitive operations. After lowering, an AST has symbols and
@@ -97,272 +70,32 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveCallNode(final CallNode callNode) {
- // AccessSpecializer - call return type may change the access for this location
- final Node function = callNode.getFunction();
- if (function instanceof FunctionNode) {
- return setTypeOverride(callNode, ((FunctionNode)function).getReturnType());
- }
- return callNode;
- }
-
- private Node leaveUnary(final UnaryNode unaryNode) {
- return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
- }
-
- @Override
- public Node leaveADD(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- @Override
- public Node leaveBIT_NOT(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- @Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- assert unaryNode.rhs().tokenType() != TokenType.CONVERT : "convert(convert encountered. check its origin and remove it";
- return unaryNode;
- }
-
- @Override
- public Node leaveDECINC(final UnaryNode unaryNode) {
- return specialize(unaryNode).node;
- }
-
- @Override
- public Node leaveNEW(final UnaryNode unaryNode) {
- assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject();
- return unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew());
- }
-
- @Override
- public Node leaveSUB(final UnaryNode unaryNode) {
- return leaveUnary(unaryNode);
- }
-
- /**
- * Add is a special binary, as it works not only on arithmetic, but for
- * strings etc as well.
- */
- @Override
- public Expression leaveADD(final BinaryNode binaryNode) {
- final Expression lhs = binaryNode.lhs();
- final Expression rhs = binaryNode.rhs();
-
- final Type type = binaryNode.getType();
-
- if (type.isObject()) {
- if (!isAddString(binaryNode)) {
- return new RuntimeNode(binaryNode, Request.ADD);
- }
- }
-
- return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type));
- }
-
- @Override
- public Node leaveAND(final BinaryNode binaryNode) {
- return binaryNode;
- }
-
- @Override
- public Node leaveASSIGN(final BinaryNode binaryNode) {
- final SpecializedNode specialized = specialize(binaryNode);
- final BinaryNode specBinaryNode = (BinaryNode)specialized.node;
- Type destType = specialized.type;
- if (destType == null) {
- destType = specBinaryNode.getType();
- }
- // Register assignments to this object in case this is used as constructor
- if (binaryNode.lhs() instanceof AccessNode) {
- AccessNode accessNode = (AccessNode) binaryNode.lhs();
-
- if (accessNode.getBase().getSymbol().isThis()) {
- lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
- }
+ public Node leaveForNode(final ForNode forNode) {
+ if (forNode.isForIn()) {
+ return forNode;
}
- return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
- }
-
- @Override
- public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- @Override
- public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
- return leaveASSIGN(binaryNode);
- }
-
- private boolean symbolIsInteger(final Expression node) {
- final Symbol symbol = node.getSymbol();
- assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
- return true;
- }
- @Override
- public Node leaveBIT_AND(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
+ final Expression init = forNode.getInit();
+ final Expression test = forNode.getTest();
+ final Expression modify = forNode.getModify();
- @Override
- public Node leaveBIT_OR(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
+ assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction();
- @Override
- public Node leaveBIT_XOR(final BinaryNode binaryNode) {
- assert symbolIsInteger(binaryNode);
- return leaveBinary(binaryNode, Type.INT, Type.INT);
+ return forNode.
+ setInit(lc, init == null ? null : discard(init)).
+ setModify(lc, modify == null ? null : discard(modify));
}
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- final BinaryNode newBinaryNode = 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
- return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
+ return binaryNode.setRHS(discard(binaryNode.rhs()));
}
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- 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
- return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
- }
-
- @Override
- public Node leaveDIV(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
-
- @Override
- public Node leaveEQ(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ);
- }
-
- @Override
- public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ_STRICT);
- }
-
- @Override
- public Node leaveGE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GE);
- }
-
- @Override
- public Node leaveGT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GT);
- }
-
- @Override
- public Node leaveLE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LE);
- }
-
- @Override
- public Node leaveLT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LT);
- }
-
- @Override
- public Node leaveMOD(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
- @Override
- public Node leaveMUL(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
- }
-
- @Override
- public Node leaveNE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE);
- }
-
- @Override
- public Node leaveNE_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE_STRICT);
- }
-
- @Override
- public Node leaveOR(final BinaryNode binaryNode) {
- return binaryNode;
- }
-
- @Override
- public Node leaveSAR(final BinaryNode binaryNode) {
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSHL(final BinaryNode binaryNode) {
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSHR(final BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol();
- return leaveBinary(binaryNode, Type.INT, Type.INT);
- }
-
- @Override
- public Node leaveSUB(final BinaryNode binaryNode) {
- return leaveBinaryArith(binaryNode);
+ return binaryNode.setLHS(discard(binaryNode.lhs()));
}
@Override
@@ -372,38 +105,12 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveCatchNode(final CatchNode catchNode) {
- final Expression exceptionCondition = catchNode.getExceptionCondition();
- if (exceptionCondition != null) {
- return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
- }
- return catchNode;
- }
-
- @Override
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
temporarySymbols.reuse();
return expressionStatement.setExpression(discard(expressionStatement.getExpression()));
}
@Override
- public Node leaveForNode(final ForNode forNode) {
- final Expression init = forNode.getInit();
- final Expression test = forNode.getTest();
- final Expression modify = forNode.getModify();
-
- if (forNode.isForIn()) {
- return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
- }
- assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction();
-
- return forNode.
- setInit(lc, init == null ? null : discard(init)).
- setTest(lc, test == null ? null : convert(test, Type.BOOLEAN)).
- setModify(lc, modify == null ? null : discard(modify));
- }
-
- @Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return false;
@@ -430,113 +137,6 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return functionNode.setState(lc, CompilationState.FINALIZED);
}
- @Override
- public Node leaveIfNode(final IfNode ifNode) {
- return ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
- }
-
- @SuppressWarnings("rawtypes")
- @Override
- public boolean enterLiteralNode(final LiteralNode literalNode) {
- if (literalNode instanceof ArrayLiteralNode) {
- final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
- final Expression[] array = arrayLiteralNode.getValue();
- final Type elementType = arrayLiteralNode.getElementType();
-
- for (int i = 0; i < array.length; i++) {
- final Node element = array[i];
- if (element != null) {
- array[i] = convert((Expression)element.accept(this), elementType);
- }
- }
- }
-
- return false;
- }
-
- @Override
- public Node leaveReturnNode(final ReturnNode returnNode) {
- final Expression expr = returnNode.getExpression();
- if (expr != null) {
- return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
- }
- return returnNode;
- }
-
- @Override
- public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
- final List<Expression> args = runtimeNode.getArgs();
- for (final Expression arg : args) {
- assert !arg.getType().isUnknown();
- }
- return runtimeNode;
- }
-
- @Override
- public Node leaveSwitchNode(final SwitchNode switchNode) {
- final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
-
- if (allInteger) {
- return switchNode;
- }
-
- final Expression expression = switchNode.getExpression();
- final List<CaseNode> cases = switchNode.getCases();
- final List<CaseNode> newCases = new ArrayList<>();
-
- for (final CaseNode caseNode : cases) {
- final Expression test = caseNode.getTest();
- newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
- }
-
- return switchNode.
- setExpression(lc, convert(expression, Type.OBJECT)).
- setCases(lc, newCases);
- }
-
- @Override
- public Node leaveTernaryNode(final TernaryNode ternaryNode) {
- return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN));
- }
-
- @Override
- public Node leaveThrowNode(final ThrowNode throwNode) {
- return throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
- }
-
- @Override
- public Node leaveVarNode(final VarNode varNode) {
- final Expression init = varNode.getInit();
- if (init != null) {
- final SpecializedNode specialized = specialize(varNode);
- final VarNode specVarNode = (VarNode)specialized.node;
- Type destType = specialized.type;
- if (destType == null) {
- destType = specVarNode.getName().getType();
- }
- assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type";
- final Expression convertedInit = convert(init, destType);
- temporarySymbols.reuse();
- return specVarNode.setInit(convertedInit);
- }
- temporarySymbols.reuse();
- return varNode;
- }
-
- @Override
- public Node leaveWhileNode(final WhileNode whileNode) {
- final Expression test = whileNode.getTest();
- if (test != null) {
- return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
- }
- return whileNode;
- }
-
- @Override
- public Node leaveWithNode(final WithNode withNode) {
- return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT));
- }
-
private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
if (LOG.isEnabled()) {
if (!symbol.isScope()) {
@@ -583,260 +183,6 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
}
- /**
- * Exit a comparison node and do the appropriate replacements. We need to introduce runtime
- * nodes late for comparisons as types aren't known until the last minute
- *
- * Both compares and adds may turn into runtimes node at this level as when we first bump
- * into the op in Attr, we may type it according to what we know there, which may be wrong later
- *
- * e.g. i (int) < 5 -> normal compare
- * i = object
- * then the post pass that would add the conversion to the 5 needs to
- *
- * @param binaryNode binary node to leave
- * @param request runtime request
- * @return lowered cmp node
- */
- @SuppressWarnings("fallthrough")
- private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
- final Expression lhs = binaryNode.lhs();
- final Expression rhs = binaryNode.rhs();
-
- Type widest = Type.widest(lhs.getType(), rhs.getType());
-
- boolean newRuntimeNode = false, finalized = false;
- switch (request) {
- case EQ_STRICT:
- case NE_STRICT:
- if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
- newRuntimeNode = true;
- widest = Type.OBJECT;
- finalized = true;
- }
- //fallthru
- default:
- if (newRuntimeNode || widest.isObject()) {
- return new RuntimeNode(binaryNode, request).setIsFinal(finalized);
- }
- break;
- }
-
- return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest));
- }
-
- /**
- * Compute the binary arithmetic type given the lhs and an rhs of a binary expression
- * @param lhsType the lhs type
- * @param rhsType the rhs type
- * @return the correct binary type
- */
- private static Type binaryArithType(final Type lhsType, final Type rhsType) {
- if (!Compiler.shouldUseIntegerArithmetic()) {
- return Type.NUMBER;
- }
- return Type.widest(lhsType, rhsType, Type.NUMBER);
- }
-
- private Node leaveBinaryArith(final BinaryNode binaryNode) {
- final Type type = binaryArithType(binaryNode.lhs().getType(), binaryNode.rhs().getType());
- return leaveBinary(binaryNode, type, type);
- }
-
- private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
- Node b = binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
- return b;
- }
-
- /**
- * A symbol (and {@link jdk.nashorn.internal.runtime.Property}) can be tagged as "may be primitive".
- * This is used a hint for dual fields that it is even worth it to try representing this
- * field as something other than java.lang.Object.
- *
- * @param node node in which to tag symbols as primitive
- * @param to which primitive type to use for tagging
- */
- private static void setCanBePrimitive(final Node node, final Type to) {
- final HashSet<Node> exclude = new HashSet<>();
-
- node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- private void setCanBePrimitive(final Symbol symbol) {
- LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol));
- symbol.setCanBePrimitive(to);
- }
-
- @Override
- public boolean enterIdentNode(final IdentNode identNode) {
- if (!exclude.contains(identNode)) {
- setCanBePrimitive(identNode.getSymbol());
- }
- return false;
- }
-
- @Override
- public boolean enterAccessNode(final AccessNode accessNode) {
- setCanBePrimitive(accessNode.getProperty().getSymbol());
- return false;
- }
-
- @Override
- public boolean 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 true;
- }
- });
- }
-
- private static class SpecializedNode {
- final Node node;
- final Type type;
-
- SpecializedNode(Node node, Type type) {
- this.node = node;
- this.type = type;
- }
- }
-
- <T extends Expression> SpecializedNode specialize(final Assignment<T> assignment) {
- final Node node = ((Node)assignment);
- final T lhs = assignment.getAssignmentDest();
- final Expression rhs = assignment.getAssignmentSource();
-
- if (!canHaveCallSiteType(lhs)) {
- return new SpecializedNode(node, null);
- }
-
- final Type to;
- if (node.isSelfModifying()) {
- to = node.getWidestOperationType();
- } else {
- to = rhs.getType();
- }
-
- if (!isSupportedCallSiteType(to)) {
- //meaningless to specialize to boolean or object
- return new SpecializedNode(node, null);
- }
-
- final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
- final Node typePropagatedNode;
- if(newNode instanceof Expression) {
- typePropagatedNode = propagateType((Expression)newNode, to);
- } else if(newNode instanceof VarNode) {
- // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead.
- final VarNode varNode = (VarNode)newNode;
- typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to));
- } else {
- throw new AssertionError();
- }
- return new SpecializedNode(typePropagatedNode, to);
- }
-
-
- /**
- * Is this a node that can have its type overridden. This is true for
- * AccessNodes, IndexNodes and IdentNodes
- *
- * @param node the node to check
- * @return true if node can have a callsite type
- */
- private static boolean canHaveCallSiteType(final Node node) {
- return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType();
- }
-
- /**
- * Is the specialization type supported. Currently we treat booleans as objects
- * and have no special boolean type accessor, thus booleans are ignored.
- * TODO - support booleans? NASHORN-590
- *
- * @param castTo the type to check
- * @return true if call site type is supported
- */
- private static boolean isSupportedCallSiteType(final Type castTo) {
- return castTo.isNumeric(); // don't specializable for boolean
- }
-
- /**
- * Override the type of a node for e.g. access specialization of scope
- * objects. Normally a variable can only get a wider type and narrower type
- * sets are ignored. Not that a variable can still be on object type as
- * per the type analysis, but a specific access may be narrower, e.g. if it
- * is used in an arithmetic op. This overrides a type, regardless of
- * type environment and is used primarily by the access specializer
- *
- * @param node node for which to change type
- * @param to new type
- */
- @SuppressWarnings("unchecked")
- <T extends Expression> 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);
- if (!to.isObject() && from.isObject()) {
- setCanBePrimitive(node, to);
- }
- }
- LOG.info("Type override for lhs in '", node, "' => ", to);
- return ((TypeOverride<T>)node).setType(temporarySymbols, lc, to);
- }
-
- /**
- * Add an explicit conversion. This is needed when attribution has created types
- * that do not mesh into an op type, e.g. a = b, where b is object and a is double
- * at the end of Attr, needs explicit conversion logic.
- *
- * An explicit conversion can be one of the following:
- * + Convert a literal - just replace it with another literal
- * + Convert a scope object - just replace the type of the access, e.g. get()D->get()I
- * + Explicit convert placement, e.g. a = (double)b - all other cases
- *
- * No other part of the world after {@link Attr} may introduce new symbols. This
- * is the only place.
- *
- * @param node node to convert
- * @param to destination type
- * @return conversion node
- */
- private Expression convert(final Expression node, final Type to) {
- assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
- assert node != null : "node is null";
- assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction();
- assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction();
-
- final Type from = node.getType();
-
- if (Type.areEquivalent(from, to)) {
- return node;
- }
-
- if (from.isObject() && to.isObject()) {
- return node;
- }
-
- Expression resultNode = node;
-
- if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
- final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
- if (newNode != null) {
- resultNode = newNode;
- }
- } else {
- if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
- assert node instanceof TypeOverride;
- return setTypeOverride(node, to);
- }
- resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node);
- }
-
- LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
-
- assert !node.isTerminal();
-
- //This is the only place in this file that can create new temporaries
- //FinalizeTypes may not introduce ANY node that is not a conversion.
- return temporarySymbols.ensureSymbol(lc, to, resultNode);
- }
-
private static Expression discard(final Expression node) {
if (node.getSymbol() != null) {
final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
@@ -849,82 +195,5 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return node;
}
- /**
- * Whenever an expression like an addition or an assignment changes type, it
- * may be that case that {@link Attr} created a symbol for an intermediate
- * result of the expression, say for an addition. This also has to be updated
- * if the expression type changes.
- *
- * Assignments use their lhs as node symbol, and in this case we can't modify
- * it. Then {@link CodeGenerator.Store} needs to do an explicit conversion.
- * This is happens very rarely.
- *
- * @param node
- * @param to
- */
- private Expression propagateType(final Expression node, final Type to) {
- Symbol symbol = node.getSymbol();
- if (symbol.isTemp() && symbol.getSymbolType() != to) {
- symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
- LOG.info("Type override for temporary in '", node, "' => ", to);
- }
- return node.setSymbol(lc, symbol);
- }
-
- /**
- * Determine if the outcome of + operator is a string.
- *
- * @param node Node to test.
- * @return true if a string result.
- */
- private boolean isAddString(final Node node) {
- if (node instanceof BinaryNode && node.isTokenType(TokenType.ADD)) {
- final BinaryNode binaryNode = (BinaryNode)node;
- final Node lhs = binaryNode.lhs();
- final Node rhs = binaryNode.rhs();
-
- return isAddString(lhs) || isAddString(rhs);
- }
-
- return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString();
- }
- /**
- * Whenever an explicit conversion is needed and the convertee is a literal, we can
- * just change the literal
- */
- class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
- private final Type type;
-
- LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
- super(parent);
- this.type = type;
- }
-
- @Override
- protected LiteralNode<?> eval() {
- final Object value = ((LiteralNode<?>)parent).getValue();
-
- LiteralNode<?> literalNode = null;
-
- if (type.isString()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
- } else if (type.isBoolean()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value));
- } else if (type.isInteger()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value));
- } else if (type.isLong()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value));
- } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
- literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value));
- }
-
- if (literalNode != null) {
- //inherit literal symbol for attr.
- literalNode = (LiteralNode<?>)literalNode.setSymbol(lc, parent.getSymbol());
- }
-
- return literalNode;
- }
- }
}
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 49dfbb32..59362fa2 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -25,6 +25,8 @@
package jdk.nashorn.internal.codegen;
+import java.util.ArrayList;
+import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
@@ -37,8 +39,10 @@ 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.Statement;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
+import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
@@ -88,12 +92,22 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
@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();
- if (shortCut != null) {
- return new BlockStatement(ifNode.getLineNumber(), shortCut);
+ if (test instanceof LiteralNode.PrimitiveLiteralNode) {
+ final boolean isTrue = ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue();
+ final Block executed = isTrue ? ifNode.getPass() : ifNode.getFail();
+ final Block dropped = isTrue ? ifNode.getFail() : ifNode.getPass();
+ final List<Statement> statements = new ArrayList<>();
+
+ if (executed != null) {
+ statements.addAll(executed.getStatements()); // Get statements form executed branch
}
- return new EmptyNode(ifNode);
+ if (dropped != null) {
+ extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+ }
+ if (statements.isEmpty()) {
+ return new EmptyNode(ifNode);
+ }
+ return BlockStatement.createReplacement(ifNode, ifNode.getFinish(), statements);
}
return ifNode;
}
@@ -101,8 +115,8 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node test = ternaryNode.getTest();
- if (test instanceof LiteralNode) {
- return ((LiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
+ if (test instanceof LiteralNode.PrimitiveLiteralNode) {
+ return ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
}
return ternaryNode;
}
@@ -131,6 +145,17 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
protected abstract LiteralNode<?> eval();
}
+ private static void extractVarNodes(final Block block, final List<Statement> statements) {
+ final LexicalContext lc = new LexicalContext();
+ block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+ @Override
+ public boolean enterVarNode(VarNode varNode) {
+ statements.add(varNode.setInit(null));
+ return false;
+ }
+ });
+ }
+
private static class UnaryNodeConstantEvaluator extends ConstantEvaluator<UnaryNode> {
UnaryNodeConstantEvaluator(final UnaryNode parent) {
super(parent);
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 032d27bc..bf6872fe 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -68,6 +68,7 @@ import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
+import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
@@ -86,10 +87,13 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
private static final DebugLogger LOG = new DebugLogger("lower");
+ // needed only to get unique eval id
+ private final CodeInstaller<?> installer;
+
/**
* Constructor.
*/
- Lower() {
+ Lower(final CodeInstaller<?> installer) {
super(new BlockLexicalContext() {
@Override
@@ -132,6 +136,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
return block.setIsTerminal(this, false);
}
});
+ this.installer = installer;
}
@Override
@@ -529,11 +534,17 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
*/
private String evalLocation(final IdentNode node) {
final Source source = lc.getCurrentFunction().getSource();
+ final int pos = node.position();
+ // Code installer is null when running with --compile-only, use 0 as id in that case
+ final long id = installer == null ? 0 : installer.getUniqueEvalId();
return new StringBuilder().
append(source.getName()).
append('#').
- append(source.getLine(node.position())).
- append("<eval>").
+ append(source.getLine(pos)).
+ append(':').
+ append(source.getColumn(pos)).
+ append("<eval>@").
+ append(id).
toString();
}
diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java
index 2921ea9e..8012adf5 100644
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -134,6 +134,10 @@ public class MapCreator {
flags |= Property.CAN_BE_UNDEFINED;
}
+ if (symbol.isFunctionDeclaration()) {
+ flags |= Property.IS_FUNCTION_DECLARATION;
+ }
+
return flags;
}
diff --git a/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index 8a012ccb..9b6d12aa 100644
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -69,7 +69,6 @@ import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.EnumSet;
import java.util.List;
-
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -1560,7 +1559,7 @@ public class MethodEmitter implements Emitter {
MethodEmitter convert(final Type to) {
final Type type = peekType().convert(method, to);
if (type != null) {
- if (peekType() != to) {
+ if (!peekType().isEquivalentTo(to)) {
debug("convert", peekType(), "->", to);
}
popType();
@@ -1790,15 +1789,14 @@ public class MethodEmitter implements Emitter {
* @param name name of property
* @param flags call site flags
*/
- void dynamicSet(final Type valueType, final String name, final int flags) {
+ void dynamicSet(final String name, final int flags) {
debug("dynamic_set", name, peekType());
- Type type = valueType;
+ Type type = peekType();
if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
type = Type.OBJECT;
convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
}
-
popType(type);
popType(Type.SCOPE);
diff --git a/src/jdk/nashorn/internal/codegen/Namespace.java b/src/jdk/nashorn/internal/codegen/Namespace.java
index 5de2fdf8..72f77a5b 100644
--- a/src/jdk/nashorn/internal/codegen/Namespace.java
+++ b/src/jdk/nashorn/internal/codegen/Namespace.java
@@ -81,7 +81,7 @@ public class Namespace {
final int count = counter + 1;
namespaceDirectory.put(base, count);
- return base + "$" + count;
+ return base + '-' + count;
}
}
diff --git a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
index d30d5645..1339d873 100644
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
@@ -32,7 +32,6 @@ import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.LiteralNode;
@@ -143,7 +142,7 @@ public class SpillObjectCreator extends ObjectCreator {
method.dup();
method.getField(Type.getInternalName(ScriptObject.class), "spill", Type.OBJECT_ARRAY.getDescriptor());
method.load(property.getSlot());
- codegen.load(values.get(i)).convert(OBJECT);
+ codegen.load(values.get(i), OBJECT);
method.arraystore();
}
}
diff --git a/src/jdk/nashorn/internal/codegen/WeighNodes.java b/src/jdk/nashorn/internal/codegen/WeighNodes.java
index 9ecfccd6..f5940488 100644
--- a/src/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -297,11 +297,6 @@ final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- return unaryNodeWeight(unaryNode);
- }
-
- @Override
public Node leaveDECINC(final UnaryNode unaryNode) {
return unaryNodeWeight(unaryNode);
}
diff --git a/src/jdk/nashorn/internal/codegen/types/BooleanType.java b/src/jdk/nashorn/internal/codegen/types/BooleanType.java
index 4331cb55..840b2910 100644
--- a/src/jdk/nashorn/internal/codegen/types/BooleanType.java
+++ b/src/jdk/nashorn/internal/codegen/types/BooleanType.java
@@ -136,8 +136,7 @@ public final class BooleanType extends Type {
invokeStatic(method, JSType.TO_LONG);
} else if (to.isString()) {
invokeStatic(method, VALUE_OF);
- invokeStatic(method, JSType.TO_PRIMITIVE);
- invokeStatic(method, JSType.TO_STRING);
+ invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING);
} else if (to.isObject()) {
invokeStatic(method, VALUE_OF);
} else {
diff --git a/src/jdk/nashorn/internal/codegen/types/ObjectType.java b/src/jdk/nashorn/internal/codegen/types/ObjectType.java
index cb2f876b..1f7a0221 100644
--- a/src/jdk/nashorn/internal/codegen/types/ObjectType.java
+++ b/src/jdk/nashorn/internal/codegen/types/ObjectType.java
@@ -153,8 +153,7 @@ class ObjectType extends Type {
} else if (to.isBoolean()) {
invokeStatic(method, JSType.TO_BOOLEAN);
} else if (to.isString()) {
- invokeStatic(method, JSType.TO_PRIMITIVE);
- invokeStatic(method, JSType.TO_STRING);
+ invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING);
} else {
assert false : "Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString;
}
diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index c1e8bfbb..e7c78953 100644
--- a/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -292,6 +292,16 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
/**
+ * Determines whether this type represents an primitive type according to the ECMAScript specification,
+ * which includes Boolean, Number, and String.
+ *
+ * @return true if a JavaScript primitive type, false otherwise.
+ */
+ public boolean isJSPrimitive() {
+ return !isObject() || isString();
+ }
+
+ /**
* Determines whether a type is the BOOLEAN type
* @return true if BOOLEAN, false otherwise
*/
@@ -441,7 +451,12 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
if (type0.isArray() && type1.isArray()) {
return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
} else if (type0.isArray() != type1.isArray()) {
- return Type.OBJECT; //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
+ //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
+ return Type.OBJECT;
+ } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) {
+ // Object<type=String> and Object<type=ScriptFunction> will produce Object
+ // TODO: maybe find most specific common superclass?
+ return Type.OBJECT;
}
return type0.weight() > type1.weight() ? type0 : type1;
}
diff --git a/src/jdk/nashorn/internal/ir/AccessNode.java b/src/jdk/nashorn/internal/ir/AccessNode.java
index 55b0aa3f..957adf69 100644
--- a/src/jdk/nashorn/internal/ir/AccessNode.java
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -46,12 +45,12 @@ public final class AccessNode extends BaseNode {
* @param property property
*/
public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) {
- super(token, finish, base, false, false);
+ super(token, finish, base, false);
this.property = property.setIsPropertyName();
}
- private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
- super(accessNode, base, isFunction, hasCallSiteType);
+ private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction) {
+ super(accessNode, base, isFunction);
this.property = property;
}
@@ -73,13 +72,6 @@ public final class AccessNode extends BaseNode {
public void toString(final StringBuilder sb) {
final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true);
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
- sb.append('}');
- }
-
if (needsParen) {
sb.append('(');
}
@@ -107,21 +99,14 @@ public final class AccessNode extends BaseNode {
if (this.base == base) {
return this;
}
- return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
+ return new AccessNode(this, base, property, isFunction());
}
private AccessNode setProperty(final IdentNode property) {
if (this.property == property) {
return this;
}
- return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
- }
-
- @Override
- public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- logTypeChange(type);
- final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
- return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
+ return new AccessNode(this, base, property, isFunction());
}
@Override
@@ -129,7 +114,7 @@ public final class AccessNode extends BaseNode {
if (isFunction()) {
return this;
}
- return new AccessNode(this, base, property, true, hasCallSiteType());
+ return new AccessNode(this, base, property, true);
}
}
diff --git a/src/jdk/nashorn/internal/ir/BaseNode.java b/src/jdk/nashorn/internal/ir/BaseNode.java
index f945ef35..96f155d1 100644
--- a/src/jdk/nashorn/internal/ir/BaseNode.java
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java
@@ -25,10 +25,6 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
/**
@@ -38,15 +34,13 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
* @see IndexNode
*/
@Immutable
-public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride<BaseNode> {
+public abstract class BaseNode extends Expression implements FunctionCall {
/** Base Node. */
protected final Expression base;
private final boolean isFunction;
- private final boolean hasCallSiteType;
-
/**
* Constructor
*
@@ -54,13 +48,11 @@ public abstract class BaseNode extends Expression implements FunctionCall, TypeO
* @param finish finish
* @param base base node
* @param isFunction is this a function
- * @param hasCallSiteType does this access have a callsite type
*/
- public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
+ public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) {
super(token, base.getStart(), finish);
this.base = base;
this.isFunction = isFunction;
- this.hasCallSiteType = hasCallSiteType;
}
/**
@@ -68,13 +60,11 @@ public abstract class BaseNode extends Expression implements FunctionCall, TypeO
* @param baseNode node to inherit from
* @param base base
* @param isFunction is this a function
- * @param hasCallSiteType does this access have a callsite type
*/
- protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
+ protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction) {
super(baseNode);
this.base = base;
this.isFunction = isFunction;
- this.hasCallSiteType = hasCallSiteType;
}
/**
@@ -96,26 +86,4 @@ public abstract class BaseNode extends Expression implements FunctionCall, TypeO
*/
public abstract BaseNode setIsFunction();
- @Override
- public boolean canHaveCallSiteType() {
- return true; //carried by the symbol and always the same nodetype==symboltype
- }
-
- /**
- * Does the access have a call site type override?
- * @return true if overridden
- */
- protected boolean hasCallSiteType() {
- return hasCallSiteType;
- }
-
- /**
- * Debug type change
- * @param type new type
- */
- protected final void logTypeChange(final Type type) {
- if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
- }
- }
}
diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java
index 169772d7..0a1d1bfc 100644
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java
@@ -90,6 +90,9 @@ public final class BinaryNode extends Expression implements Assignment<Expressio
return Type.LONG;
case ASSIGN_SAR:
case ASSIGN_SHL:
+ case BIT_AND:
+ case BIT_OR:
+ case BIT_XOR:
case ASSIGN_BIT_AND:
case ASSIGN_BIT_OR:
case ASSIGN_BIT_XOR:
@@ -170,6 +173,42 @@ public final class BinaryNode extends Expression implements Assignment<Expressio
}
@Override
+ public boolean isLocal() {
+ switch (tokenType()) {
+ case SAR:
+ case SHL:
+ case SHR:
+ case BIT_AND:
+ case BIT_OR:
+ case BIT_XOR:
+ case ADD:
+ case DIV:
+ case MOD:
+ case MUL:
+ case SUB:
+ return lhs.isLocal() && lhs.getType().isJSPrimitive()
+ && rhs.isLocal() && rhs.getType().isJSPrimitive();
+ case ASSIGN_ADD:
+ case ASSIGN_BIT_AND:
+ case ASSIGN_BIT_OR:
+ case ASSIGN_BIT_XOR:
+ case ASSIGN_DIV:
+ case ASSIGN_MOD:
+ case ASSIGN_MUL:
+ case ASSIGN_SAR:
+ case ASSIGN_SHL:
+ case ASSIGN_SHR:
+ case ASSIGN_SUB:
+ return lhs instanceof IdentNode && lhs.isLocal() && lhs.getType().isJSPrimitive()
+ && rhs.isLocal() && rhs.getType().isJSPrimitive();
+ case ASSIGN:
+ return lhs instanceof IdentNode && lhs.isLocal() && rhs.isLocal();
+ default:
+ return false;
+ }
+ }
+
+ @Override
public void toString(final StringBuilder sb) {
final TokenType type = tokenType();
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java
index ffaae078..0d38f241 100644
--- a/src/jdk/nashorn/internal/ir/CallNode.java
+++ b/src/jdk/nashorn/internal/ir/CallNode.java
@@ -36,9 +36,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for a function call.
*/
@Immutable
-public final class CallNode extends LexicalContextExpression implements TypeOverride<CallNode> {
-
- private final Type type;
+public final class CallNode extends LexicalContextExpression {
/** Function identifier or function body. */
private final Expression function;
@@ -150,18 +148,16 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
this.function = function;
this.args = args;
this.flags = 0;
- this.type = null;
this.evalArgs = null;
this.lineNumber = lineNumber;
}
- private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final Type type, final EvalArgs evalArgs) {
+ private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final EvalArgs evalArgs) {
super(callNode);
this.lineNumber = callNode.lineNumber;
this.function = function;
this.args = args;
this.flags = flags;
- this.type = type;
this.evalArgs = evalArgs;
}
@@ -175,29 +171,9 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
@Override
public Type getType() {
- if (hasCallSiteType()) {
- return type;
- }
return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT;
}
- @Override
- public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- if (this.type == type) {
- return this;
- }
- return new CallNode(this, function, args, flags, type, evalArgs);
- }
-
- private boolean hasCallSiteType() {
- return this.type != null;
- }
-
- @Override
- public boolean canHaveCallSiteType() {
- return true;
- }
-
/**
* Assist in IR navigation.
*
@@ -212,7 +188,6 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
setFunction((Expression)function.accept(visitor)).
setArgs(Node.accept(visitor, Expression.class, args)).
setFlags(flags).
- setType(null, lc, type).
setEvalArgs(evalArgs == null ?
null :
evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)).
@@ -229,13 +204,6 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
@Override
public void toString(final StringBuilder sb) {
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor());
- sb.append('}');
- }
-
function.toString(sb);
sb.append('(');
@@ -271,7 +239,7 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
if (this.args == args) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -293,7 +261,7 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
if (this.evalArgs == evalArgs) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -321,7 +289,7 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
if (this.function == function) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
/**
@@ -344,6 +312,6 @@ public final class CallNode extends LexicalContextExpression implements TypeOver
if (this.flags == flags) {
return this;
}
- return new CallNode(this, function, args, flags, type, evalArgs);
+ return new CallNode(this, function, args, flags, evalArgs);
}
}
diff --git a/src/jdk/nashorn/internal/ir/Expression.java b/src/jdk/nashorn/internal/ir/Expression.java
index 9006fa8d..f8074fe4 100644
--- a/src/jdk/nashorn/internal/ir/Expression.java
+++ b/src/jdk/nashorn/internal/ir/Expression.java
@@ -96,4 +96,16 @@ public abstract class Expression extends Node {
assert hasType() : this + " has no type";
return symbol.getSymbolType();
}
+
+ /**
+ * Returns {@code true} if this expression depends exclusively on state that is constant
+ * or local to the currently running function and thus inaccessible to other functions.
+ * This implies that a local expression must not call any other functions (neither directly
+ * nor implicitly through a getter, setter, or object-to-primitive type conversion).
+ *
+ * @return true if this expression does not depend on state shared with other functions.
+ */
+ public boolean isLocal() {
+ return false;
+ }
}
diff --git a/src/jdk/nashorn/internal/ir/IdentNode.java b/src/jdk/nashorn/internal/ir/IdentNode.java
index 4b139b25..30e8ed11 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -28,9 +28,7 @@ package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -39,10 +37,11 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for an identifier.
*/
@Immutable
-public final class IdentNode extends Expression 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;
+public final class IdentNode extends Expression implements PropertyKey, FunctionCall {
+ private static final int PROPERTY_NAME = 1 << 0;
+ private static final int INITIALIZED_HERE = 1 << 1;
+ private static final int FUNCTION = 1 << 2;
+ private static final int FUTURESTRICT_NAME = 1 << 3;
/** Identifier. */
private final String name;
@@ -100,19 +99,6 @@ public final class IdentNode extends Expression implements PropertyKey, TypeOver
return callSiteType != null;
}
- @Override
- public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type 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;
- }
- if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
- }
-
- return new IdentNode(this, name, type, flags);
- }
-
/**
* Assist in IR navigation.
*
@@ -152,29 +138,9 @@ public final class IdentNode extends Expression implements PropertyKey, TypeOver
return getName();
}
- /**
- * We can only override type if the symbol lives in the scope, as otherwise
- * it is strongly determined by the local variable already allocated.
- *
- * <p>We also return true if the symbol represents the return value of a function with a
- * non-generic return type as in this case we need to propagate the type instead of
- * converting to object, for example if the symbol is used as the left hand side of an
- * assignment such as in the code below.</p>
- *
- * <pre>
- * try {
- * return 2;
- * } finally {
- * return 3;
- * }
- * }
- * </pre>
- *
- * @return true if can have callsite type
- */
@Override
- public boolean canHaveCallSiteType() {
- return getSymbol() != null && (getSymbol().isScope() || getSymbol().isNonGenericReturn());
+ public boolean isLocal() {
+ return !getSymbol().isScope();
}
/**
@@ -197,6 +163,25 @@ public final class IdentNode extends Expression implements PropertyKey, TypeOver
}
/**
+ * Check if this IdentNode is a future strict name
+ * @return true if this is a future strict name
+ */
+ public boolean isFutureStrictName() {
+ return (flags & FUTURESTRICT_NAME) != 0;
+ }
+
+ /**
+ * Flag this IdentNode as a future strict name
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public IdentNode setIsFutureStrictName() {
+ if (isFutureStrictName()) {
+ return this;
+ }
+ return new IdentNode(this, name, callSiteType, flags | FUTURESTRICT_NAME);
+ }
+
+ /**
* Helper function for local def analysis.
* @return true if IdentNode is initialized on creation
*/
diff --git a/src/jdk/nashorn/internal/ir/IndexNode.java b/src/jdk/nashorn/internal/ir/IndexNode.java
index 2799e9be..83f58ffc 100644
--- a/src/jdk/nashorn/internal/ir/IndexNode.java
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -46,12 +45,12 @@ public final class IndexNode extends BaseNode {
* @param index index for access
*/
public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
- super(token, finish, base, false, false);
+ super(token, finish, base, false);
this.index = index;
}
- private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final boolean hasCallSiteType) {
- super(indexNode, base, isFunction, hasCallSiteType);
+ private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction) {
+ super(indexNode, base, isFunction);
this.index = index;
}
@@ -69,13 +68,6 @@ public final class IndexNode extends BaseNode {
public void toString(final StringBuilder sb) {
final boolean needsParen = tokenType().needsParens(base.tokenType(), true);
- if (hasCallSiteType()) {
- sb.append('{');
- final String desc = getType().getDescriptor();
- sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
- sb.append('}');
- }
-
if (needsParen) {
sb.append('(');
}
@@ -103,7 +95,7 @@ public final class IndexNode extends BaseNode {
if (this.base == base) {
return this;
}
- return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ return new IndexNode(this, base, index, isFunction());
}
/**
@@ -115,7 +107,7 @@ public final class IndexNode extends BaseNode {
if(this.index == index) {
return this;
}
- return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ return new IndexNode(this, base, index, isFunction());
}
@Override
@@ -123,14 +115,7 @@ public final class IndexNode extends BaseNode {
if (isFunction()) {
return this;
}
- return new IndexNode(this, base, index, true, hasCallSiteType());
- }
-
- @Override
- public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- logTypeChange(type);
- final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
- return new IndexNode(newIndexNode, base, index, isFunction(), true);
+ return new IndexNode(this, base, index, true);
}
}
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
index 666be7e3..1b380d38 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -587,11 +587,11 @@ public class LexicalContext {
final FunctionNode fn = (FunctionNode)node;
final Source source = fn.getSource();
String src = source.toString();
- if (src.indexOf(File.pathSeparator) != -1) {
+ if (src.contains(File.pathSeparator)) {
src = src.substring(src.lastIndexOf(File.pathSeparator));
}
src += ' ';
- src += source.getLine(fn.getStart());
+ src += fn.getLineNumber();
sb.append(src);
}
sb.append(' ');
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index b2d9e9fa..8d6823cb 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -28,10 +28,13 @@ package jdk.nashorn.internal.ir;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+
import jdk.nashorn.internal.codegen.CompileUnit;
+import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.parser.Lexer.LexerToken;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
@@ -96,14 +99,6 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return value == null;
}
- /**
- * Check if the literal value is boolean true
- * @return true if literal value is boolean true
- */
- public boolean isTrue() {
- return JSType.toBoolean(value);
- }
-
@Override
public Type getType() {
return Type.typeFor(value.getClass());
@@ -259,8 +254,36 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return new NullLiteralNode(parent.getToken(), parent.getFinish());
}
+ /**
+ * Super class for primitive (side-effect free) literals.
+ *
+ * @param <T> the literal type
+ */
+ public static class PrimitiveLiteralNode<T> extends LiteralNode<T> {
+ private PrimitiveLiteralNode(final long token, final int finish, final T value) {
+ super(token, finish, value);
+ }
+
+ private PrimitiveLiteralNode(final PrimitiveLiteralNode<T> literalNode) {
+ super(literalNode);
+ }
+
+ /**
+ * Check if the literal value is boolean true
+ * @return true if literal value is boolean true
+ */
+ public boolean isTrue() {
+ return JSType.toBoolean(value);
+ }
+
+ @Override
+ public boolean isLocal() {
+ return true;
+ }
+ }
+
@Immutable
- private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
+ private static final class BooleanLiteralNode extends PrimitiveLiteralNode<Boolean> {
private BooleanLiteralNode(final long token, final int finish, final boolean value) {
super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
@@ -312,7 +335,7 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
}
@Immutable
- private static final class NumberLiteralNode extends LiteralNode<Number> {
+ private static final class NumberLiteralNode extends PrimitiveLiteralNode<Number> {
private final Type type = numberGetType(value);
@@ -374,7 +397,7 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return new NumberLiteralNode(parent.getToken(), parent.getFinish(), value);
}
- private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
+ private static class UndefinedLiteralNode extends PrimitiveLiteralNode<Undefined> {
private UndefinedLiteralNode(final long token, final int finish) {
super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
}
@@ -410,7 +433,7 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
}
@Immutable
- private static class StringLiteralNode extends LiteralNode<String> {
+ private static class StringLiteralNode extends PrimitiveLiteralNode<String> {
private StringLiteralNode(final long token, final int finish, final String value) {
super(Token.recast(token, TokenType.STRING), finish, value);
}
@@ -511,18 +534,12 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return object;
} else if (object instanceof LiteralNode) {
return objectAsConstant(((LiteralNode<?>)object).getValue());
- } else if (object instanceof UnaryNode) {
- final UnaryNode unaryNode = (UnaryNode)object;
-
- if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) {
- return objectAsConstant(unaryNode.rhs());
- }
}
return POSTSET_MARKER;
}
- private static final class NullLiteralNode extends LiteralNode<Object> {
+ private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
private NullLiteralNode(final long token, final int finish) {
super(Token.recast(token, TokenType.OBJECT), finish, null);
@@ -767,8 +784,11 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return value;
}
- @Override
- public Type getType() {
+ /**
+ * Get the array element type as Java format, e.g. [I
+ * @return array element type
+ */
+ public ArrayType getArrayType() {
if (elementType.isInteger()) {
return Type.INT_ARRAY;
} else if (elementType.isLong()) {
@@ -780,6 +800,11 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
}
}
+ @Override
+ public Type getType() {
+ return Type.typeFor(NativeArray.class);
+ }
+
/**
* Get the element type of this array literal
* @return element type
diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java
index d100b408..269cb905 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.parser.TokenType;
* IR representation for a runtime call.
*/
@Immutable
-public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode> {
+public class RuntimeNode extends Expression {
/**
* Request enum used for meta-information about the runtime request
@@ -159,6 +159,36 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
}
/**
+ * Derive a runtime node request type for a node
+ * @param node the node
+ * @return request type
+ */
+ public static Request requestFor(final Node node) {
+ assert node.isComparison();
+ switch (node.tokenType()) {
+ case EQ_STRICT:
+ return Request.EQ_STRICT;
+ case NE_STRICT:
+ return Request.NE_STRICT;
+ case EQ:
+ return Request.EQ;
+ case NE:
+ return Request.NE;
+ case LT:
+ return Request.LT;
+ case LE:
+ return Request.LE;
+ case GT:
+ return Request.GT;
+ case GE:
+ return Request.GE;
+ default:
+ assert false;
+ return null;
+ }
+ }
+
+ /**
* Is this an EQ or EQ_STRICT?
*
* @param request a request
@@ -268,9 +298,6 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
/** Call arguments. */
private final List<Expression> args;
- /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
- private final Type callSiteType;
-
/** is final - i.e. may not be removed again, lower in the code pipeline */
private final boolean isFinal;
@@ -287,16 +314,14 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
this.request = request;
this.args = args;
- this.callSiteType = null;
this.isFinal = false;
}
- private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Expression> args) {
+ private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final boolean isFinal, final List<Expression> args) {
super(runtimeNode);
this.request = request;
this.args = args;
- this.callSiteType = callSiteType;
this.isFinal = isFinal;
}
@@ -335,7 +360,6 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
this.request = request;
this.args = args;
- this.callSiteType = null;
this.isFinal = false;
}
@@ -376,7 +400,7 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
if (this.isFinal == isFinal) {
return this;
}
- return new RuntimeNode(this, request, callSiteType, isFinal, args);
+ return new RuntimeNode(this, request, isFinal, args);
}
/**
@@ -384,24 +408,7 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
*/
@Override
public Type getType() {
- return hasCallSiteType() ? callSiteType : request.getReturnType();
- }
-
- @Override
- public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
- if (this.callSiteType == type) {
- return this;
- }
- return new RuntimeNode(this, request, type, isFinal, args);
- }
-
- @Override
- public boolean canHaveCallSiteType() {
- return request == Request.ADD;
- }
-
- private boolean hasCallSiteType() {
- return callSiteType != null;
+ return request.getReturnType();
}
@Override
@@ -450,7 +457,7 @@ public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode>
if (this.args == args) {
return this;
}
- return new RuntimeNode(this, request, callSiteType, isFinal, args);
+ return new RuntimeNode(this, request, isFinal, args);
}
/**
diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index 69e98ac6..2906893f 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -75,6 +75,8 @@ public final class Symbol implements Comparable<Symbol> {
public static final int IS_SPECIALIZED_PARAM = 1 << 13;
/** Is this symbol a shared temporary? */
public static final int IS_SHARED = 1 << 14;
+ /** Is this a function declaration? */
+ public static final int IS_FUNCTION_DECLARATION = 1 << 15;
/** Null or name identifying symbol. */
private final String name;
@@ -360,6 +362,14 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * Check if this symbol is a function declaration
+ * @return true if a function declaration
+ */
+ public boolean isFunctionDeclaration() {
+ return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
+ }
+
+ /**
* Creates an unshared copy of a symbol. The symbol must be currently shared.
* @param newName the name for the new symbol.
* @return a new, unshared symbol.
@@ -396,6 +406,16 @@ public final class Symbol implements Comparable<Symbol> {
/**
+ * Mark this symbol as a function declaration.
+ */
+ public void setIsFunctionDeclaration() {
+ if (!isFunctionDeclaration()) {
+ trace("SET IS FUNCTION DECLARATION");
+ flags |= IS_FUNCTION_DECLARATION;
+ }
+ }
+
+ /**
* Check if this symbol is a variable
* @return true if variable
*/
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index 70e1c726..26c14b76 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -109,6 +109,13 @@ public final class TernaryNode extends Expression {
}
}
+ @Override
+ public boolean isLocal() {
+ return getTest().isLocal()
+ && getTrueExpression().isLocal()
+ && getFalseExpression().isLocal();
+ }
+
/**
* Get the test expression for this ternary expression, i.e. "x" in x ? y : z
* @return the test expression
diff --git a/src/jdk/nashorn/internal/ir/TypeOverride.java b/src/jdk/nashorn/internal/ir/TypeOverride.java
deleted file mode 100644
index 929d0128..00000000
--- a/src/jdk/nashorn/internal/ir/TypeOverride.java
+++ /dev/null
@@ -1,62 +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.codegen.types.Type;
-
-/**
- * A type override makes it possible to change the return type of a node, if we know
- * that the linker can provide it directly. For example, an identity node that is
- * in the scope, can very well look like an object to the compiler of the method it
- * is in, but if someone does (int)x, it make senses to ask for it directly
- * with an int getter instead of loading it as an object and explicitly converting it
- * 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<T extends Node> {
- /**
- * Set the override type
- *
- * @param ts temporary symbols
- * @param lc the current lexical context
- * @param type the type
- * @return a node equivalent to this one except for the requested change.
- */
- public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
-
- /**
- * Returns true if this node can have a callsite override, e.g. all scope ident nodes
- * which lead to dynamic getters can have it, local variable nodes (slots) can't.
- * Call nodes can have it unconditionally and so on
- *
- * @return true if it is possible to assign a type override to this node
- */
- public boolean canHaveCallSiteType();
-
-}
diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index 2de2ca5d..4923d31e 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.parser.TokenType.BIT_NOT;
-import static jdk.nashorn.internal.parser.TokenType.CONVERT;
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
@@ -130,6 +129,26 @@ public final class UnaryNode extends Expression implements Assignment<Expression
}
@Override
+ public boolean isLocal() {
+ switch (tokenType()) {
+ case NEW:
+ return false;
+ case ADD:
+ case SUB:
+ case NOT:
+ case BIT_NOT:
+ return rhs.isLocal() && rhs.getType().isJSPrimitive();
+ case DECPOSTFIX:
+ case DECPREFIX:
+ case INCPOSTFIX:
+ case INCPREFIX:
+ return rhs instanceof IdentNode && rhs.isLocal() && rhs.getType().isJSPrimitive();
+ default:
+ return rhs.isLocal();
+ }
+ }
+
+ @Override
public void toString(final StringBuilder sb) {
toString(sb, new Runnable() {
@Override
@@ -150,19 +169,10 @@ public final class UnaryNode extends Expression implements Assignment<Expression
final TokenType type = tokenType();
final String name = type.getName();
final boolean isPostfix = type == DECPOSTFIX || type == INCPOSTFIX;
- final boolean isConvert = type == CONVERT && getSymbol() != null;
boolean rhsParen = type.needsParens(rhs().tokenType(), false);
- int convertPos = 0;
- if (isConvert) {
- convertPos = sb.length();
- sb.append("(");
- sb.append(getType());
- sb.append(")(");
- }
-
- if (!isPostfix && !isConvert) {
+ if (!isPostfix) {
if (name == null) {
sb.append(type.name());
rhsParen = true;
@@ -186,16 +196,6 @@ public final class UnaryNode extends Expression implements Assignment<Expression
if (isPostfix) {
sb.append(type == DECPOSTFIX ? "--" : "++");
}
-
- if (isConvert) {
- // strip extra cast parenthesis which makes the printout harder to read
- final boolean endsWithParenthesis = sb.charAt(sb.length() - 1) == ')';
- if (!endsWithParenthesis) {
- sb.append(')');
- } else {
- sb.setCharAt(convertPos, ' ');
- }
- }
}
/**
diff --git a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
index 2d4412e7..89269d5f 100644
--- a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
+++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
@@ -25,10 +25,10 @@
package jdk.nashorn.internal.ir.debug;
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryPoolMXBean;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -51,9 +51,9 @@ import java.util.Map;
* switch, it can not detect
* this fact and will report incorrect sizes, as it will presume the default JVM
* behavior.
- *
- * @author Attila Szegedi
*/
+
+@SuppressWarnings("StaticNonFinalUsedInInitialization")
public class ObjectSizeCalculator {
/**
@@ -368,6 +368,29 @@ public class ObjectSizeCalculator {
type.getName());
}
+ // ALERT: java.lang.management is not available in compact 1. We need
+ // to use reflection to soft link test memory statistics.
+
+ static Class<?> managementFactory = null;
+ static Class<?> memoryPoolMXBean = null;
+ static Class<?> memoryUsage = null;
+ static Method getMemoryPoolMXBeans = null;
+ static Method getUsage = null;
+ static Method getMax = null;
+ static {
+ try {
+ managementFactory = Class.forName("java.lang.management.ManagementFactory");
+ memoryPoolMXBean = Class.forName("java.lang.management.MemoryPoolMXBean");
+ memoryUsage = Class.forName("java.lang.management.MemoryUsage");
+
+ getMemoryPoolMXBeans = managementFactory.getMethod("getMemoryPoolMXBeans");
+ getUsage = memoryPoolMXBean.getMethod("getUsage");
+ getMax = memoryUsage.getMethod("getMax");
+ } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+ // Pass thru, asserts when attempting to use.
+ }
+ }
+
/**
* Return the current memory usage
* @return current memory usage derived from system configuration
@@ -409,9 +432,33 @@ public class ObjectSizeCalculator {
strVmVersion.indexOf('.')));
if (vmVersion >= 17) {
long maxMemory = 0;
- for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
- maxMemory += mp.getUsage().getMax();
+
+ /*
+ See ALERT above. The reflection code below duplicates the following
+ sequence, and avoids hard coding of java.lang.management.
+
+ for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
+ maxMemory += mp.getUsage().getMax();
+ }
+ */
+
+ if (getMemoryPoolMXBeans == null) {
+ throw new AssertionError("java.lang.management not available in compact 1");
}
+
+ try {
+ final List<?> memoryPoolMXBeans = (List<?>)getMemoryPoolMXBeans.invoke(managementFactory);
+ for (final Object mp : memoryPoolMXBeans) {
+ final Object usage = getUsage.invoke(mp);
+ final Object max = getMax.invoke(usage);
+ maxMemory += ((Long)max).longValue();
+ }
+ } catch (IllegalAccessException |
+ IllegalArgumentException |
+ InvocationTargetException ex) {
+ throw new AssertionError("java.lang.management not available in compact 1");
+ }
+
if (maxMemory < 30L * 1024 * 1024 * 1024) {
// HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total
// for all memory pools (yes, including code cache).
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 71600395..2b1de7c7 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -51,8 +51,6 @@ public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T
return enterADD(unaryNode);
case BIT_NOT:
return enterBIT_NOT(unaryNode);
- case CONVERT:
- return enterCONVERT(unaryNode);
case DELETE:
return enterDELETE(unaryNode);
case DISCARD:
@@ -84,8 +82,6 @@ public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T
return leaveADD(unaryNode);
case BIT_NOT:
return leaveBIT_NOT(unaryNode);
- case CONVERT:
- return leaveCONVERT(unaryNode);
case DELETE:
return leaveDELETE(unaryNode);
case DISCARD:
@@ -323,26 +319,6 @@ public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T
}
/**
- * Unary enter - callback for entering a conversion
- *
- * @param unaryNode the node
- * @return true if traversal should continue and node children be traversed, false otherwise
- */
- public boolean enterCONVERT(final UnaryNode unaryNode) {
- return enterDefault(unaryNode);
- }
-
- /**
- * Unary leave - callback for leaving a conversion
- *
- * @param unaryNode the node
- * @return processed node, which will replace the original one, or the original node
- */
- public Node leaveCONVERT(final UnaryNode unaryNode) {
- return leaveDefault(unaryNode);
- }
-
- /**
* Unary enter - callback for entering a ++ or -- operator
*
* @param unaryNode the node
diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java
index 161909bb..0a09370a 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -53,19 +53,19 @@ import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
-import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
-import jdk.nashorn.internal.runtime.arrays.ArrayData;
-import jdk.nashorn.internal.runtime.regexp.RegExpResult;
+import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.Scope;
+import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.ScriptingFunctions;
import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.regexp.RegExpResult;
import jdk.nashorn.internal.scripts.JO;
/**
@@ -491,8 +491,8 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
// GlobalObject interface implementation
@Override
- public boolean isOfContext(final Context context) {
- return this.context == context;
+ public boolean isOfContext(final Context ctxt) {
+ return this.context == ctxt;
}
@Override
@@ -1665,9 +1665,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
final ScriptObject stringPrototype = getStringPrototype();
stringPrototype.addOwnProperty("length", Attribute.NON_ENUMERABLE_CONSTANT, 0.0);
- // add Array.prototype.length
+ // set isArray flag on Array.prototype
final ScriptObject arrayPrototype = getArrayPrototype();
- arrayPrototype.addOwnProperty("length", Attribute.NOT_ENUMERABLE|Attribute.NOT_CONFIGURABLE, 0.0);
+ arrayPrototype.setIsArray();
this.DEFAULT_DATE = new NativeDate(Double.NaN, this);
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index 8cb1ded9..67b9f1f1 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -372,9 +372,7 @@ public final class NativeArray extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object isArray(final Object self, final Object arg) {
- return isArray(arg) || (arg == Global.instance().getArrayPrototype())
- || (arg instanceof NativeRegExpExecResult)
- || (arg instanceof JSObject && ((JSObject)arg).isArray());
+ return isArray(arg) || (arg instanceof JSObject && ((JSObject)arg).isArray());
}
/**
@@ -403,6 +401,26 @@ public final class NativeArray extends ScriptObject {
}
}
+ /**
+ * Prototype length getter
+ * @param self self reference
+ * @return the length of the object
+ */
+ @Getter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
+ public static Object getProtoLength(final Object self) {
+ return length(self); // Same as instance getter but we can't make nasgen use the same method for prototype
+ }
+
+ /**
+ * Prototype length setter
+ * @param self self reference
+ * @param length new length property
+ */
+ @Setter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
+ public static void setProtoLength(final Object self, final Object length) {
+ length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype
+ }
+
static long validLength(final Object length, final boolean reject) {
final double doubleLength = JSType.toNumber(length);
if (!Double.isNaN(doubleLength) && JSType.isRepresentableAsLong(doubleLength)) {
@@ -819,8 +837,15 @@ public final class NativeArray extends ScriptObject {
if (bulkable(sobj)) {
sobj.getArray().shiftLeft(1);
} else {
+ boolean hasPrevious = true;
for (long k = 1; k < len; k++) {
- sobj.set(k - 1, sobj.get(k), true);
+ boolean hasCurrent = sobj.has(k);
+ if (hasCurrent) {
+ sobj.set(k - 1, sobj.get(k), true);
+ } else if (hasPrevious) {
+ sobj.delete(k - 1, true);
+ }
+ hasPrevious = hasCurrent;
}
}
sobj.delete(--len, true);
@@ -844,6 +869,10 @@ public final class NativeArray extends ScriptObject {
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object slice(final Object self, final Object start, final Object end) {
final Object obj = Global.toObject(self);
+ if (!(obj instanceof ScriptObject)) {
+ return ScriptRuntime.UNDEFINED;
+ }
+
final ScriptObject sobj = (ScriptObject)obj;
final long len = JSType.toUint32(sobj.getLength());
final long relativeStart = JSType.toLong(start);
@@ -860,9 +889,12 @@ public final class NativeArray extends ScriptObject {
return new NativeArray(sobj.getArray().slice(k, finale));
}
- final NativeArray copy = new NativeArray(0);
+ // Construct array with proper length to have a deleted filter on undefined elements
+ final NativeArray copy = new NativeArray(finale - k);
for (long n = 0; k < finale; n++, k++) {
- copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k));
+ if (sobj.has(k)) {
+ copy.defineOwnProperty(ArrayIndex.getArrayIndex(n), sobj.get(k));
+ }
}
return copy;
@@ -993,19 +1025,42 @@ public final class NativeArray extends ScriptObject {
final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart);
- final NativeArray array = new NativeArray(actualDeleteCount);
+ NativeArray returnValue;
+
+ if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) {
+ try {
+ returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
+
+ // Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements
+ int k = (int) actualStart;
+ for (int i = 0; i < items.length; i++, k++) {
+ sobj.defineOwnProperty(k, items[i]);
+ }
+ } catch (UnsupportedOperationException uoe) {
+ returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len);
+ }
+ } else {
+ returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len);
+ }
+
+ return returnValue;
+ }
+
+ private static NativeArray slowSplice(final ScriptObject sobj, final long start, final long deleteCount, final Object[] items, final long len) {
+
+ final NativeArray array = new NativeArray(deleteCount);
- for (long k = 0; k < actualDeleteCount; k++) {
- final long from = actualStart + k;
+ for (long k = 0; k < deleteCount; k++) {
+ final long from = start + k;
if (sobj.has(from)) {
array.defineOwnProperty(ArrayIndex.getArrayIndex(k), sobj.get(from));
}
}
- if (items.length < actualDeleteCount) {
- for (long k = actualStart; k < (len - actualDeleteCount); k++) {
- final long from = k + actualDeleteCount;
+ if (items.length < deleteCount) {
+ for (long k = start; k < (len - deleteCount); k++) {
+ final long from = k + deleteCount;
final long to = k + items.length;
if (sobj.has(from)) {
@@ -1015,12 +1070,12 @@ public final class NativeArray extends ScriptObject {
}
}
- for (long k = len; k > (len - actualDeleteCount + items.length); k--) {
+ for (long k = len; k > (len - deleteCount + items.length); k--) {
sobj.delete(k - 1, true);
}
- } else if (items.length > actualDeleteCount) {
- for (long k = len - actualDeleteCount; k > actualStart; k--) {
- final long from = k + actualDeleteCount - 1;
+ } else if (items.length > deleteCount) {
+ for (long k = len - deleteCount; k > start; k--) {
+ final long from = k + deleteCount - 1;
final long to = k + items.length - 1;
if (sobj.has(from)) {
@@ -1032,12 +1087,12 @@ public final class NativeArray extends ScriptObject {
}
}
- long k = actualStart;
+ long k = start;
for (int i = 0; i < items.length; i++, k++) {
sobj.set(k, items[i], true);
}
- final long newLength = len - actualDeleteCount + items.length;
+ final long newLength = len - deleteCount + items.length;
sobj.set("length", newLength, true);
return array;
@@ -1108,12 +1163,16 @@ public final class NativeArray extends ScriptObject {
try {
final ScriptObject sobj = (ScriptObject)Global.toObject(self);
final long len = JSType.toUint32(sobj.getLength());
- final long n = JSType.toLong(fromIndex);
+ if (len == 0) {
+ return -1;
+ }
- if (len == 0 || n >= len) {
+ final long n = JSType.toLong(fromIndex);
+ if (n >= len) {
return -1;
}
+
for (long k = Math.max(0, (n < 0) ? (len - Math.abs(n)) : n); k < len; k++) {
if (sobj.has(k)) {
if (ScriptRuntime.EQ_STRICT(sobj.get(k), searchElement)) {
diff --git a/src/jdk/nashorn/internal/objects/NativeError.java b/src/jdk/nashorn/internal/objects/NativeError.java
index dc6aef90..d3e2effe 100644
--- a/src/jdk/nashorn/internal/objects/NativeError.java
+++ b/src/jdk/nashorn/internal/objects/NativeError.java
@@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@@ -37,10 +38,12 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
@@ -133,12 +136,16 @@ public final class NativeError extends ScriptObject {
* @param errorObj the error object
* @return undefined
*/
+ @SuppressWarnings("unused")
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object captureStackTrace(final Object self, final Object errorObj) {
Global.checkObject(errorObj);
final ScriptObject sobj = (ScriptObject)errorObj;
- final ECMAException exp = new ECMAException(sobj, null);
- sobj.set("stack", getScriptStackString(sobj, exp), false);
+ new ECMAException(sobj, null); //constructor has side effects
+ sobj.delete("stack", false);
+ final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
+ final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
+ sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
return UNDEFINED;
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java
index c77002e3..d092cfb6 100644
--- a/src/jdk/nashorn/internal/objects/NativeFunction.java
+++ b/src/jdk/nashorn/internal/objects/NativeFunction.java
@@ -221,6 +221,7 @@ public final class NativeFunction {
final StringBuilder sb = new StringBuilder();
sb.append("(function (");
+ final String funcBody;
if (args.length > 0) {
final StringBuilder paramListBuf = new StringBuilder();
for (int i = 0; i < args.length - 1; i++) {
@@ -230,15 +231,20 @@ public final class NativeFunction {
}
}
+ // now convert function body to a string
+ funcBody = JSType.toString(args[args.length - 1]);
+
final String paramList = paramListBuf.toString();
if (! paramList.isEmpty()) {
checkFunctionParameters(paramList);
sb.append(paramList);
}
+ } else {
+ funcBody = null;
}
+
sb.append(") {\n");
if (args.length > 0) {
- final String funcBody = JSType.toString(args[args.length - 1]);
checkFunctionBody(funcBody);
sb.append(funcBody);
sb.append('\n');
diff --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index 5b89e2ca..668ca8cd 100644
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -629,7 +629,8 @@ public final class NativeJSAdapter extends ScriptObject {
// to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
- adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__),
+ testJSAdaptor(adaptee, null, null, null));
}
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java
index 94e3bef2..c7db39a5 100644
--- a/src/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java
@@ -60,6 +60,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.linker.NashornBeansLinker;
/**
* ECMA 15.2 Object objects
@@ -729,8 +730,7 @@ public final class NativeObject {
final MethodType methodType, final Object source) {
final GuardedInvocation inv;
try {
- inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source),
- Bootstrap.getLinkerServices());
+ inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices());
assert passesGuard(source, inv.getGuard());
} catch(RuntimeException|Error e) {
throw e;
diff --git a/src/jdk/nashorn/internal/objects/NativeString.java b/src/jdk/nashorn/internal/objects/NativeString.java
index 1694b3da..9fd59191 100644
--- a/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk/nashorn/internal/objects/NativeString.java
@@ -505,7 +505,7 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object charAt(final Object self, final Object pos) {
- return charAt(self, JSType.toInteger(pos));
+ return charAtImpl(checkObjectToString(self), JSType.toInteger(pos));
}
/**
@@ -527,7 +527,10 @@ public final class NativeString extends ScriptObject {
*/
@SpecializedFunction
public static String charAt(final Object self, final int pos) {
- final String str = checkObjectToString(self);
+ return charAtImpl(checkObjectToString(self), pos);
+ }
+
+ private static String charAtImpl(final String str, final int pos) {
return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos));
}
@@ -539,7 +542,7 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object charCodeAt(final Object self, final Object pos) {
- return charCodeAt(self, JSType.toInteger(pos));
+ return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos));
}
/**
@@ -561,7 +564,10 @@ public final class NativeString extends ScriptObject {
*/
@SpecializedFunction
public static double charCodeAt(final Object self, final int pos) {
- final String str = checkObjectToString(self);
+ return charCodeAtImpl(checkObjectToString(self), pos);
+ }
+
+ private static double charCodeAtImpl(final String str, final int pos) {
return (pos < 0 || pos >= str.length()) ? Double.NaN : str.charAt(pos);
}
diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index 88421a70..638d18a2 100644
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -25,6 +25,7 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
@@ -255,6 +256,12 @@ public class ScriptFunctionImpl extends ScriptFunction {
return makeFunction(name, methodHandle, null);
}
+ @Override
+ public ScriptFunction makeSynchronizedFunction(final Object sync) {
+ final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
+ return makeFunction(getName(), mh);
+ }
+
/**
* Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we
* can expose it to methods in this package.
diff --git a/src/jdk/nashorn/internal/parser/AbstractParser.java b/src/jdk/nashorn/internal/parser/AbstractParser.java
index 80f7ce07..587ae869 100644
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java
@@ -378,7 +378,7 @@ public abstract class AbstractParser {
next();
// Create IDENT node.
- return new IdentNode(identToken, finish, ident);
+ return new IdentNode(identToken, finish, ident).setIsFutureStrictName();
}
// Get IDENT.
diff --git a/src/jdk/nashorn/internal/parser/Lexer.java b/src/jdk/nashorn/internal/parser/Lexer.java
index 09269c6c..a01705dd 100644
--- a/src/jdk/nashorn/internal/parser/Lexer.java
+++ b/src/jdk/nashorn/internal/parser/Lexer.java
@@ -47,7 +47,6 @@ import static jdk.nashorn.internal.parser.TokenType.XML;
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSErrorType;
-import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options;
@@ -1054,16 +1053,6 @@ public class Lexer extends Scanner {
}
/**
- * Convert string to number.
- *
- * @param valueString String to convert.
- * @return Converted number.
- */
- private static Number valueOf(final String valueString) throws NumberFormatException {
- return JSType.narrowestIntegerRepresentation(Double.valueOf(valueString));
- }
-
- /**
* Scan a number.
*/
protected void scanNumber() {
@@ -1623,7 +1612,7 @@ public class Lexer extends Scanner {
case HEXADECIMAL:
return Lexer.valueOf(source.getString(start + 2, len - 2), 16); // number
case FLOATING:
- return Lexer.valueOf(source.getString(start, len)); // number
+ return Double.valueOf(source.getString(start, len)); // number
case STRING:
return source.getString(start, len); // String
case ESCSTRING:
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index 9663401f..869746cf 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -909,6 +909,10 @@ loop:
default:
break;
}
+
+ if (ident.isFutureStrictName()) {
+ throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
+ }
}
}
@@ -2103,13 +2107,13 @@ loop:
final String ident = (String)expectValue(IDENT);
if (type != COLON) {
- final long getSetToken = token;
+ final long getSetToken = propertyToken;
switch (ident) {
case "get":
final PropertyKey getIdent = propertyName();
final String getterName = getIdent.getPropertyName();
- final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, "get " + NameCodec.encode(getterName));
+ final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
expect(LPAREN);
expect(RPAREN);
functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
@@ -2118,7 +2122,7 @@ loop:
case "set":
final PropertyKey setIdent = propertyName();
final String setterName = setIdent.getPropertyName();
- final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, "set " + NameCodec.encode(setterName));
+ final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
expect(LPAREN);
final IdentNode argIdent = getIdent();
verifyStrictIdent(argIdent, "setter argument");
@@ -2436,7 +2440,7 @@ loop:
// name is null, generate anonymous name
boolean isAnonymous = false;
if (name == null) {
- final String tmpName = "_L" + source.getLine(Token.descPosition(token));
+ final String tmpName = "_L" + functionLine;
name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
isAnonymous = true;
}
diff --git a/src/jdk/nashorn/internal/parser/TokenType.java b/src/jdk/nashorn/internal/parser/TokenType.java
index a976215b..6287a234 100644
--- a/src/jdk/nashorn/internal/parser/TokenType.java
+++ b/src/jdk/nashorn/internal/parser/TokenType.java
@@ -178,7 +178,6 @@ public enum TokenType {
ARRAY (LITERAL, null),
COMMALEFT (IR, null),
- CONVERT (IR, null),
DISCARD (IR, null),
DECPOSTFIX (IR, null),
INCPOSTFIX (IR, null);
diff --git a/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
index be9976e7..28c9630e 100644
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
@@ -68,4 +68,10 @@ public interface CodeInstaller<T> {
* @return unique script id
*/
public long getUniqueScriptId();
+
+ /**
+ * Get next unique eval id
+ * @return unique eval id
+ */
+ public long getUniqueEvalId();
}
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
index afa3657c..18b20a3d 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -48,6 +48,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
}
CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) {
+ assert type != null;
this.type = type;
this.invoker = invoker;
this.constructor = constructor;
@@ -80,7 +81,37 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
@Override
public int compareTo(final CompiledFunction o) {
- return weight() - o.weight();
+ return compareMethodTypes(type(), o.type());
+ }
+
+ private static int compareMethodTypes(final MethodType ownType, final MethodType otherType) {
+ // Comparable interface demands that compareTo() should only return 0 if objects are equal.
+ // Failing to meet this requirement causes same weight functions to replace each other in TreeSet,
+ // so we go some lengths to come up with an ordering between same weight functions,
+ // first falling back to parameter count and then to hash code.
+ if (ownType.equals(otherType)) {
+ return 0;
+ }
+
+ final int diff = weight(ownType) - weight(otherType);
+ if (diff != 0) {
+ return diff;
+ }
+ if (ownType.parameterCount() != otherType.parameterCount()) {
+ return ownType.parameterCount() - otherType.parameterCount();
+ }
+ // We're just interested in not returning 0 here, not correct ordering
+ return ownType.hashCode() - otherType.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof CompiledFunction && type().equals(((CompiledFunction)obj).type());
+ }
+
+ @Override
+ public int hashCode() {
+ return type().hashCode();
}
private int weight() {
@@ -119,14 +150,14 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
* a semantically equivalent linkage can be performed.
*
* @param mt type to check against
- * @return
+ * @return true if types are compatible
*/
boolean typeCompatible(final MethodType mt) {
- final Class<?>[] wantedParams = mt.parameterArray();
- final Class<?>[] existingParams = type().parameterArray();
+ final int wantedParamCount = mt.parameterCount();
+ final int existingParamCount = type.parameterCount();
//if we are not examining a varargs type, the number of parameters must be the same
- if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) {
+ if (wantedParamCount != existingParamCount && !isVarArgsType(mt)) {
return false;
}
@@ -134,10 +165,10 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
//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);
+ final int lastParamIndex = Math.min(wantedParamCount, existingParamCount);
for (int i = 0; i < lastParamIndex; i++) {
- final Type w = Type.typeFor(wantedParams[i]);
- final Type e = Type.typeFor(existingParams[i]);
+ final Type w = Type.typeFor(mt.parameterType(i));
+ final Type e = Type.typeFor(type.parameterType(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.
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
index 1ddc42b5..ba5ae66c 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
@@ -24,6 +24,7 @@
*/
package jdk.nashorn.internal.runtime;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.Iterator;
import java.util.TreeSet;
@@ -35,6 +36,8 @@ import java.util.TreeSet;
@SuppressWarnings("serial")
final class CompiledFunctions extends TreeSet<CompiledFunction> {
+ private CompiledFunction generic;
+
CompiledFunction best(final MethodType type) {
final Iterator<CompiledFunction> iter = iterator();
while (iter.hasNext()) {
@@ -43,13 +46,10 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return next;
}
}
- return mostGeneric();
+ return generic();
}
boolean needsCallee() {
- for (final CompiledFunction inv : this) {
- assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
- }
return ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
}
@@ -57,6 +57,48 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return last();
}
+ CompiledFunction generic() {
+ CompiledFunction gen = this.generic;
+ if (gen == null) {
+ gen = this.generic = makeGeneric(mostGeneric());
+ }
+ return gen;
+ }
+
+ private static CompiledFunction makeGeneric(final CompiledFunction func) {
+ final MethodHandle invoker = composeGenericMethod(func.getInvoker());
+ final MethodHandle constructor = func.hasConstructor() ? composeGenericMethod(func.getConstructor()) : null;
+ return new CompiledFunction(invoker.type(), invoker, constructor);
+ }
+
+ /**
+ * 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.
+ */
+ private static MethodHandle composeGenericMethod(final MethodHandle mh) {
+ final MethodType type = mh.type();
+ final boolean isVarArg = ScriptFunctionData.isVarArg(mh);
+ final int paramCount = isVarArg ? type.parameterCount() - 1 : type.parameterCount();
+
+ MethodType newType = MethodType.genericMethodType(paramCount, isVarArg);
+
+ if (ScriptFunctionData.needsCallee(mh)) {
+ newType = newType.changeParameterType(0, ScriptFunction.class);
+ }
+ return type.equals(newType) ? mh : mh.asType(newType);
+ }
+
/**
* Is the given type even more specific than this entire list? That means
* we have an opportunity for more specific versions of the method
diff --git a/src/jdk/nashorn/internal/runtime/ConsString.java b/src/jdk/nashorn/internal/runtime/ConsString.java
index 9cf51552..8f764f4b 100644
--- a/src/jdk/nashorn/internal/runtime/ConsString.java
+++ b/src/jdk/nashorn/internal/runtime/ConsString.java
@@ -57,10 +57,7 @@ public final class ConsString implements CharSequence {
@Override
public String toString() {
- if (!flat) {
- flatten();
- }
- return (String) left;
+ return (String) flattened();
}
@Override
@@ -70,18 +67,19 @@ public final class ConsString implements CharSequence {
@Override
public char charAt(final int index) {
- if (!flat) {
- flatten();
- }
- return left.charAt(index);
+ return flattened().charAt(index);
}
@Override
public CharSequence subSequence(final int start, final int end) {
+ return flattened().subSequence(start, end);
+ }
+
+ private CharSequence flattened() {
if (!flat) {
flatten();
}
- return left.subSequence(start, end);
+ return left;
}
private void flatten() {
diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java
index 7c69eb52..c9deee35 100644
--- a/src/jdk/nashorn/internal/runtime/Context.java
+++ b/src/jdk/nashorn/internal/runtime/Context.java
@@ -91,6 +91,11 @@ public final class Context {
*/
public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
+ // nashorn load psuedo URL prefixes
+ private static final String LOAD_CLASSPATH = "classpath:";
+ private static final String LOAD_FX = "fx:";
+ private static final String LOAD_NASHORN = "nashorn:";
+
/* Force DebuggerSupport to be loaded. */
static {
DebuggerSupport.FORCELOAD = true;
@@ -134,6 +139,11 @@ public final class Context {
public long getUniqueScriptId() {
return context.getUniqueScriptId();
}
+
+ @Override
+ public long getUniqueEvalId() {
+ return context.getUniqueEvalId();
+ }
}
/** Is Context global debug mode enabled ? */
@@ -233,10 +243,14 @@ public final class Context {
/** Unique id for script. Used only when --loader-per-compile=false */
private final AtomicLong uniqueScriptId;
+ /** Unique id for 'eval' */
+ private final AtomicLong uniqueEvalId;
+
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
- /*package-private*/ ClassLoader getSharedLoader() {
+ /*package-private*/ @SuppressWarnings("static-method")
+ ClassLoader getSharedLoader() {
return sharedLoader;
}
@@ -315,6 +329,7 @@ public final class Context {
this.uniqueScriptId = new AtomicLong();
}
this.errors = errors;
+ this.uniqueEvalId = new AtomicLong();
// if user passed -classpath option, make a class loader with that and set it as
// thread context class loader so that script can access classes from that path.
@@ -501,21 +516,26 @@ public final class Context {
// or a ScriptObject that has "name" and "source" (string valued) properties.
if (src instanceof String) {
final String srcStr = (String)src;
- final File file = new File(srcStr);
- if (srcStr.indexOf(':') != -1) {
- if ((source = loadInternal(srcStr, "nashorn:", "resources/")) == null &&
- (source = loadInternal(srcStr, "fx:", "resources/fx/")) == null) {
- URL url;
- try {
- //check for malformed url. if malformed, it may still be a valid file
- url = new URL(srcStr);
- } catch (final MalformedURLException e) {
- url = file.toURI().toURL();
+ if (srcStr.startsWith(LOAD_CLASSPATH)) {
+ URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
+ source = (url != null)? new Source(url.toString(), url) : null;
+ } else {
+ final File file = new File(srcStr);
+ if (srcStr.indexOf(':') != -1) {
+ if ((source = loadInternal(srcStr, LOAD_NASHORN, "resources/")) == null &&
+ (source = loadInternal(srcStr, LOAD_FX, "resources/fx/")) == null) {
+ URL url;
+ try {
+ //check for malformed url. if malformed, it may still be a valid file
+ url = new URL(srcStr);
+ } catch (final MalformedURLException e) {
+ url = file.toURI().toURL();
+ }
+ source = new Source(url.toString(), url);
}
- source = new Source(url.toString(), url);
+ } else if (file.isFile()) {
+ source = new Source(srcStr, file);
}
- } else if (file.isFile()) {
- source = new Source(srcStr, file);
}
} else if (src instanceof File && ((File)src).isFile()) {
final File file = (File)src;
@@ -610,36 +630,53 @@ public final class Context {
}
/**
+ * Checks that the given Class can be accessed from no permissions context.
+ *
+ * @param clazz Class object
+ * @throw SecurityException if not accessible
+ */
+ public static void checkPackageAccess(final Class<?> clazz) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ Class<?> bottomClazz = clazz;
+ while (bottomClazz.isArray()) {
+ bottomClazz = bottomClazz.getComponentType();
+ }
+ checkPackageAccess(sm, bottomClazz.getName());
+ }
+ }
+
+ /**
* Checks that the given package can be accessed from no permissions context.
*
+ * @param sm current security manager instance
* @param fullName fully qualified package name
* @throw SecurityException if not accessible
*/
- public static void checkPackageAccess(final String fullName) {
+ private static void checkPackageAccess(final SecurityManager sm, final String fullName) {
+ sm.getClass(); // null check
final int index = fullName.lastIndexOf('.');
if (index != -1) {
- final SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- @Override
- public Void run() {
- sm.checkPackageAccess(fullName.substring(0, index));
- return null;
- }
- }, NO_PERMISSIONS_ACC_CTXT);
- }
+ final String pkgName = fullName.substring(0, index);
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ sm.checkPackageAccess(pkgName);
+ return null;
+ }
+ }, NO_PERMISSIONS_ACC_CTXT);
}
}
/**
- * Checks that the given package can be accessed from no permissions context.
+ * Checks that the given Class can be accessed from no permissions context.
*
- * @param fullName fully qualified package name
+ * @param clazz Class object
* @return true if package is accessible, false otherwise
*/
- public static boolean isAccessiblePackage(final String fullName) {
+ private static boolean isAccessiblePackage(final Class<?> clazz) {
try {
- checkPackageAccess(fullName);
+ checkPackageAccess(clazz);
return true;
} catch (final SecurityException se) {
return false;
@@ -653,7 +690,7 @@ public final class Context {
* @return true if Class is accessible, false otherwise
*/
public static boolean isAccessibleClass(final Class<?> clazz) {
- return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz.getName());
+ return Modifier.isPublic(clazz.getModifiers()) && Context.isAccessiblePackage(clazz);
}
/**
@@ -667,8 +704,16 @@ public final class Context {
* @throws ClassNotFoundException if class cannot be resolved
*/
public Class<?> findClass(final String fullName) throws ClassNotFoundException {
+ if (fullName.indexOf('[') != -1 || fullName.indexOf('/') != -1) {
+ // don't allow array class names or internal names.
+ throw new ClassNotFoundException(fullName);
+ }
+
// check package access as soon as possible!
- checkPackageAccess(fullName);
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ checkPackageAccess(sm, fullName);
+ }
// try the script -classpath loader, if that is set
if (classPathLoader != null) {
@@ -803,6 +848,18 @@ public final class Context {
return Context.getContextTrusted();
}
+ private URL getResourceURL(final String resName) {
+ // try the classPathLoader if we have and then
+ // try the appLoader if non-null.
+ if (classPathLoader != null) {
+ return classPathLoader.getResource(resName);
+ } else if (appLoader != null) {
+ return appLoader.getResource(resName);
+ }
+
+ return null;
+ }
+
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
ScriptFunction script = null;
@@ -907,6 +964,10 @@ public final class Context {
}, CREATE_LOADER_ACC_CTXT);
}
+ private long getUniqueEvalId() {
+ return uniqueEvalId.getAndIncrement();
+ }
+
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
diff --git a/src/jdk/nashorn/internal/runtime/DebugLogger.java b/src/jdk/nashorn/internal/runtime/DebugLogger.java
index fa0dbede..e832c861 100644
--- a/src/jdk/nashorn/internal/runtime/DebugLogger.java
+++ b/src/jdk/nashorn/internal/runtime/DebugLogger.java
@@ -65,7 +65,17 @@ public final class DebugLogger {
} else {
this.logger = Logging.getLogger(loggerName);
}
- this.isEnabled = logger.getLevel() != Level.OFF;
+ assert logger != null;
+ this.isEnabled = getLevel() != Level.OFF;
+ }
+
+ /**
+ * Do not currently support chaining this with parent logger. Logger level null
+ * means disabled
+ * @return level
+ */
+ private Level getLevel() {
+ return logger.getLevel() == null ? Level.OFF : logger.getLevel();
}
/**
@@ -126,7 +136,7 @@ public final class DebugLogger {
* @return true if level is above the given one
*/
public boolean levelAbove(final Level level) {
- return logger.getLevel().intValue() > level.intValue();
+ return getLevel().intValue() > level.intValue();
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
index f28ed6ae..c7a410ea 100644
--- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -40,7 +40,7 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
*
* @param name name
* @param arity arity
- * @param list precompiled code
+ * @param functions precompiled code
* @param isStrict strict
* @param isBuiltin builtin
* @param isConstructor constructor
@@ -73,12 +73,13 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
}
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
+ // 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.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor
+ final MethodHandle invoker = MH.insertArguments(mh, 0, false);
+ final MethodHandle constructor = composeConstructor(MH.insertArguments(mh, 0, true));
+ code.add(new CompiledFunction(mh.type(), invoker, constructor));
} else {
code.add(new CompiledFunction(mh.type(), mh));
}
diff --git a/src/jdk/nashorn/internal/runtime/GlobalObject.java b/src/jdk/nashorn/internal/runtime/GlobalObject.java
index 7e01fd6e..3779f3bd 100644
--- a/src/jdk/nashorn/internal/runtime/GlobalObject.java
+++ b/src/jdk/nashorn/internal/runtime/GlobalObject.java
@@ -38,9 +38,10 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName;
public interface GlobalObject {
/**
* Is this global of the given Context?
+ * @param ctxt the context
* @return true if this global belongs to the given Context
*/
- public boolean isOfContext(Context context);
+ public boolean isOfContext(final Context ctxt);
/**
* Does this global belong to a strict Context?
diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index 93f0835b..54130196 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -31,6 +31,8 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
+import java.util.Deque;
+import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -86,6 +88,9 @@ public enum JSType {
/** JavaScript compliant conversion function from Object to number */
public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class);
+ /** JavaScript compliant conversion function from Object to String */
+ public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class);
+
/** JavaScript compliant conversion function from Object to int32 */
public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class);
@@ -104,14 +109,20 @@ public enum JSType {
/** JavaScript compliant conversion function from number to int64 */
public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class);
- /** JavaScript compliant conversion function from Object to String */
- public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class);
-
/** JavaScript compliant conversion function from number to String */
public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class);
- /** JavaScript compliant conversion function from Object to primitive */
- public static final Call TO_PRIMITIVE = staticCall(myLookup, JSType.class, "toPrimitive", Object.class, Object.class);
+ /** Combined call to toPrimitive followed by toString. */
+ public static final Call TO_PRIMITIVE_TO_STRING = staticCall(myLookup, JSType.class, "toPrimitiveToString", String.class, Object.class);
+
+ /** Method handle to convert a JS Object to a Java array. */
+ public static final Call TO_JAVA_ARRAY = staticCall(myLookup, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
+
+ /** Method handle to convert a JS Object to a Java List. */
+ public static final Call TO_JAVA_LIST = staticCall(myLookup, JSType.class, "toJavaList", List.class, Object.class);
+
+ /** Method handle to convert a JS Object to a Java deque. */
+ public static final Call TO_JAVA_DEQUE = staticCall(myLookup, JSType.class, "toJavaDeque", Deque.class, Object.class);
private static final double INT32_LIMIT = 4294967296.0;
@@ -202,26 +213,6 @@ public enum JSType {
}
/**
- * Get the smallest integer representation of a number. Returns an Integer
- * for something that is int representable, and Long for something that
- * is long representable. If the number needs to be a double, this is an
- * identity function
- *
- * @param number number to check
- *
- * @return Number instanceof the narrowest possible integer representation for number
- */
- public static Number narrowestIntegerRepresentation(final double number) {
- if (isRepresentableAsInt(number)) {
- return (int)number;
- } else if (isRepresentableAsLong(number)) {
- return (long)number;
- } else {
- return number;
- }
- }
-
- /**
* Check whether an object is primitive
*
* @param obj an object
@@ -258,12 +249,11 @@ public enum JSType {
* @return the primitive form of the object
*/
public static Object toPrimitive(final Object obj, final Class<?> hint) {
- if (!(obj instanceof ScriptObject)) {
- return obj;
- }
+ return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj;
+ }
- final ScriptObject sobj = (ScriptObject)obj;
- final Object result = sobj.getDefaultValue(hint);
+ private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
+ final Object result = sobj.getDefaultValue(hint);
if (!isPrimitive(result)) {
throw typeError("bad.default.value", result.toString());
@@ -273,6 +263,17 @@ public enum JSType {
}
/**
+ * Combines a hintless toPrimitive and a toString call.
+ *
+ * @param obj an object
+ *
+ * @return the string form of the primitive form of the object
+ */
+ public static String toPrimitiveToString(Object obj) {
+ return toString(toPrimitive(obj));
+ }
+
+ /**
* JavaScript compliant conversion of number to boolean
*
* @param num a number
@@ -476,6 +477,19 @@ public enum JSType {
return toNumberGeneric(obj);
}
+
+ /**
+ * JavaScript compliant conversion of Object to number
+ * See ECMA 9.3 ToNumber
+ *
+ * @param obj an object
+ *
+ * @return a number
+ */
+ public static double toNumber(final ScriptObject obj) {
+ return toNumber(toPrimitive(obj, Number.class));
+ }
+
/**
* Digit representation for a character
*
@@ -872,9 +886,9 @@ public enum JSType {
*/
public static Object toJavaArray(final Object obj, final Class<?> componentType) {
if (obj instanceof ScriptObject) {
- return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType);
+ return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
} else if (obj instanceof JSObject) {
- final ArrayLikeIterator itr = ArrayLikeIterator.arrayLikeIterator(obj);
+ final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
final int len = (int) itr.getLength();
final Object[] res = new Object[len];
int idx = 0;
@@ -882,6 +896,8 @@ public enum JSType {
res[idx++] = itr.next();
}
return convertArray(res, componentType);
+ } else if(obj == null) {
+ return null;
} else {
throw new IllegalArgumentException("not a script object");
}
@@ -895,6 +911,15 @@ public enum JSType {
* @return converted Java array
*/
public static Object convertArray(final Object[] src, final Class<?> componentType) {
+ if(componentType == Object.class) {
+ for(int i = 0; i < src.length; ++i) {
+ final Object e = src[i];
+ if(e instanceof ConsString) {
+ src[i] = e.toString();
+ }
+ }
+ }
+
final int l = src.length;
final Object dst = Array.newInstance(componentType, l);
final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
@@ -911,6 +936,24 @@ public enum JSType {
}
/**
+ * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details.
+ * @param obj the object to convert. Can be any array-like object.
+ * @return a List that is live-backed by the JavaScript object.
+ */
+ public static List<?> toJavaList(final Object obj) {
+ return ListAdapter.create(obj);
+ }
+
+ /**
+ * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details.
+ * @param obj the object to convert. Can be any array-like object.
+ * @return a Deque that is live-backed by the JavaScript object.
+ */
+ public static Deque<?> toJavaDeque(final Object obj) {
+ return ListAdapter.create(obj);
+ }
+
+ /**
* Check if an object is null or undefined
*
* @param obj object to check
@@ -1009,7 +1052,11 @@ public enum JSType {
}
if (obj instanceof ScriptObject) {
- return toNumber(toPrimitive(obj, Number.class));
+ return toNumber((ScriptObject)obj);
+ }
+
+ if (obj instanceof JSObject) {
+ return ((JSObject)obj).toNumber();
}
return Double.NaN;
diff --git a/src/jdk/nashorn/internal/runtime/ListAdapter.java b/src/jdk/nashorn/internal/runtime/ListAdapter.java
index 41d34600..26c22c39 100644
--- a/src/jdk/nashorn/internal/runtime/ListAdapter.java
+++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java
@@ -33,6 +33,7 @@ import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.concurrent.Callable;
import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -119,10 +120,11 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
});
}
+ /** wrapped object */
protected final Object obj;
// allow subclasses only in this package
- ListAdapter(Object obj) {
+ ListAdapter(final Object obj) {
this.obj = obj;
}
@@ -134,7 +136,8 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
*/
public static ListAdapter create(final Object obj) {
if (obj instanceof ScriptObject) {
- return new ScriptObjectListAdapter((ScriptObject)obj);
+ final Object mirror = ScriptObjectMirror.wrap(obj, Context.getGlobal());
+ return new JSObjectListAdapter((JSObject)mirror);
} else if (obj instanceof JSObject) {
return new JSObjectListAdapter((JSObject)obj);
} else {
@@ -143,22 +146,32 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final Object get(int index) {
+ public final Object get(final int index) {
checkRange(index);
return getAt(index);
}
+ /**
+ * Get object at an index
+ * @param index index in list
+ * @return object
+ */
protected abstract Object getAt(final int index);
@Override
- public Object set(int index, Object element) {
+ public Object set(final int index, final Object element) {
checkRange(index);
final Object prevValue = getAt(index);
setAt(index, element);
return prevValue;
}
- protected abstract void setAt(int index, Object element);
+ /**
+ * Set object at an index
+ * @param index index in list
+ * @param element element
+ */
+ protected abstract void setAt(final int index, final Object element);
private void checkRange(int index) {
if(index < 0 || index >= size()) {
@@ -167,18 +180,18 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final void push(Object e) {
+ public final void push(final Object e) {
addFirst(e);
}
@Override
- public final boolean add(Object e) {
+ public final boolean add(final Object e) {
addLast(e);
return true;
}
@Override
- public final void addFirst(Object e) {
+ public final void addFirst(final Object e) {
try {
final InvokeByName unshiftInvoker = getUNSHIFT();
final Object fn = unshiftInvoker.getGetter().invokeExact(obj);
@@ -192,7 +205,7 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final void addLast(Object e) {
+ public final void addLast(final Object e) {
try {
final InvokeByName pushInvoker = getPUSH();
final Object fn = pushInvoker.getGetter().invokeExact(obj);
@@ -206,7 +219,7 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final void add(int index, Object e) {
+ public final void add(final int index, final Object e) {
try {
if(index < 0) {
throw invalidIndex(index);
@@ -225,35 +238,35 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
throw invalidIndex(index);
}
}
- } catch(RuntimeException | Error ex) {
+ } catch(final RuntimeException | Error ex) {
throw ex;
- } catch(Throwable t) {
+ } catch(final Throwable t) {
throw new RuntimeException(t);
}
}
- private static void checkFunction(Object fn, InvokeByName invoke) {
+ private static void checkFunction(final Object fn, final InvokeByName invoke) {
if(!(Bootstrap.isCallable(fn))) {
throw new UnsupportedOperationException("The script object doesn't have a function named " + invoke.getName());
}
}
- private static IndexOutOfBoundsException invalidIndex(int index) {
+ private static IndexOutOfBoundsException invalidIndex(final int index) {
return new IndexOutOfBoundsException(String.valueOf(index));
}
@Override
- public final boolean offer(Object e) {
+ public final boolean offer(final Object e) {
return offerLast(e);
}
@Override
- public final boolean offerFirst(Object e) {
+ public final boolean offerFirst(final Object e) {
addFirst(e);
return true;
}
@Override
- public final boolean offerLast(Object e) {
+ public final boolean offerLast(final Object e) {
addLast(e);
return true;
}
@@ -287,7 +300,7 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final Object remove(int index) {
+ public final Object remove(final int index) {
if(index < 0) {
throw invalidIndex(index);
} else if (index == 0) {
@@ -333,11 +346,11 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- protected final void removeRange(int fromIndex, int toIndex) {
+ protected final void removeRange(final int fromIndex, final int toIndex) {
invokeSpliceRemove(fromIndex, toIndex - fromIndex);
}
- private void invokeSpliceRemove(int fromIndex, int count) {
+ private void invokeSpliceRemove(final int fromIndex, final int count) {
try {
final InvokeByName spliceRemoveInvoker = getSPLICE_REMOVE();
final Object fn = spliceRemoveInvoker.getGetter().invokeExact(obj);
@@ -419,16 +432,16 @@ public abstract class ListAdapter extends AbstractList<Object> implements Random
}
@Override
- public final boolean removeFirstOccurrence(Object o) {
+ public final boolean removeFirstOccurrence(final Object o) {
return removeOccurrence(o, iterator());
}
@Override
- public final boolean removeLastOccurrence(Object o) {
+ public final boolean removeLastOccurrence(final Object o) {
return removeOccurrence(o, descendingIterator());
}
- private static boolean removeOccurrence(Object o, Iterator<Object> it) {
+ private static boolean removeOccurrence(final Object o, final Iterator<Object> it) {
while(it.hasNext()) {
final Object e = it.next();
if(o == null ? e == null : o.equals(e)) {
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index e735ed11..d1dbe2ad 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -56,33 +56,36 @@ public abstract class Property {
public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000;
/** ECMA 8.6.1 - Is this property not writable? */
- public static final int NOT_WRITABLE = 0b0000_0000_0001;
+ public static final int NOT_WRITABLE = 1 << 0;
/** ECMA 8.6.1 - Is this property not enumerable? */
- public static final int NOT_ENUMERABLE = 0b0000_0000_0010;
+ public static final int NOT_ENUMERABLE = 1 << 1;
/** ECMA 8.6.1 - Is this property not configurable? */
- public static final int NOT_CONFIGURABLE = 0b0000_0000_0100;
+ public static final int NOT_CONFIGURABLE = 1 << 2;
- private static final int MODIFY_MASK = 0b0000_0000_1111;
+ private static final int MODIFY_MASK = (NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE);
/** Is this a spill property? See {@link AccessorProperty} */
- public static final int IS_SPILL = 0b0000_0001_0000;
+ public static final int IS_SPILL = 1 << 3;
/** Is this a function parameter? */
- public static final int IS_PARAMETER = 0b0000_0010_0000;
+ public static final int IS_PARAMETER = 1 << 4;
/** Is parameter accessed thru arguments? */
- public static final int HAS_ARGUMENTS = 0b0000_0100_0000;
+ public static final int HAS_ARGUMENTS = 1 << 5;
/** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */
- public static final int IS_ALWAYS_OBJECT = 0b0000_1000_0000;
+ public static final int IS_ALWAYS_OBJECT = 1 << 6;
/** Can this property be primitive? */
- public static final int CAN_BE_PRIMITIVE = 0b0001_0000_0000;
+ public static final int CAN_BE_PRIMITIVE = 1 << 7;
/** Can this property be undefined? */
- public static final int CAN_BE_UNDEFINED = 0b0010_0000_0000;
+ public static final int CAN_BE_UNDEFINED = 1 << 8;
+
+ /* Is this a function declaration property ? */
+ public static final int IS_FUNCTION_DECLARATION = 1 << 9;
/** Property key. */
private final String key;
@@ -522,4 +525,12 @@ public abstract class Property {
public boolean canBeUndefined() {
return (flags & CAN_BE_UNDEFINED) == CAN_BE_UNDEFINED;
}
+
+ /**
+ * Check whether this property represents a function declaration.
+ * @return whether this property is a function declaration or not.
+ */
+ public boolean isFunctionDeclaration() {
+ return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java
index e24364d6..03c4978a 100644
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java
@@ -26,6 +26,8 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import java.lang.invoke.SwitchPoint;
import java.lang.ref.WeakReference;
@@ -50,6 +52,8 @@ import java.util.WeakHashMap;
public final class PropertyMap implements Iterable<Object>, PropertyListener {
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
public static final int NOT_EXTENSIBLE = 0b0000_0001;
+ /** Does this map contain valid array keys? */
+ public static final int CONTAINS_ARRAY_KEYS = 0b0000_0010;
/** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */
private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111;
/** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */
@@ -91,12 +95,16 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
* @param spillLength Number of spill slots used.
+ * @param containsArrayKeys True if properties contain numeric keys
*/
- private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength) {
+ private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) {
this.properties = properties;
this.fieldCount = fieldCount;
this.fieldMaximum = fieldMaximum;
this.spillLength = spillLength;
+ if (containsArrayKeys) {
+ setContainsArrayKeys();
+ }
if (Context.DEBUG) {
count++;
@@ -104,15 +112,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
- * Constructor.
- *
- * @param properties A {@link PropertyHashMap} with initial contents.
- */
- private PropertyMap(final PropertyHashMap properties) {
- this(properties, 0, 0, 0);
- }
-
- /**
* Cloning constructor.
*
* @param propertyMap Existing property map.
@@ -152,12 +151,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
if (Context.DEBUG) {
duplicatedCount++;
}
- return new PropertyMap(this.properties);
+ return new PropertyMap(this.properties, 0, 0, 0, containsArrayKeys());
}
/**
* Public property map allocator.
*
+ * <p>It is the caller's responsibility to make sure that {@code properties} does not contain
+ * properties with keys that are valid array indices.</p>
+ *
* @param properties Collection of initial properties.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
@@ -166,11 +168,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
*/
public static PropertyMap newMap(final Collection<Property> properties, final int fieldCount, final int fieldMaximum, final int spillLength) {
PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
- return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength);
+ return new PropertyMap(newProperties, fieldCount, fieldMaximum, spillLength, false);
}
/**
* Public property map allocator. Used by nasgen generated code.
+ *
+ * <p>It is the caller's responsibility to make sure that {@code properties} does not contain
+ * properties with keys that are valid array indices.</p>
+ *
* @param properties Collection of initial properties.
* @return New {@link PropertyMap}.
*/
@@ -184,7 +190,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New empty {@link PropertyMap}.
*/
public static PropertyMap newMap() {
- return new PropertyMap(EMPTY_HASHMAP);
+ return new PropertyMap(EMPTY_HASHMAP, 0, 0, 0, false);
}
/**
@@ -294,6 +300,9 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
if(!property.isSpill()) {
newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1);
}
+ if (isValidArrayIndex(getArrayIndex(property.getKey()))) {
+ newMap.setContainsArrayKeys();
+ }
newMap.spillLength += property.getSpillCount();
}
@@ -408,6 +417,9 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyMap newMap = new PropertyMap(this, newProperties);
for (final Property property : otherProperties) {
+ if (isValidArrayIndex(getArrayIndex(property.getKey()))) {
+ newMap.setContainsArrayKeys();
+ }
newMap.spillLength += property.getSpillCount();
}
@@ -700,6 +712,22 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
+ * Check if this map contains properties with valid array keys
+ *
+ * @return {@code true} if this map contains properties with valid array keys
+ */
+ public final boolean containsArrayKeys() {
+ return (flags & CONTAINS_ARRAY_KEYS) != 0;
+ }
+
+ /**
+ * Flag this object as having array keys in defined properties
+ */
+ private void setContainsArrayKeys() {
+ flags |= CONTAINS_ARRAY_KEYS;
+ }
+
+ /**
* Check whether a {@link PropertyListener} has been added to this map.
*
* @return {@code true} if {@link PropertyListener} exists
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index a64479a5..e5ca3c9a 100644
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -33,6 +33,7 @@ import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
+import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -52,7 +53,7 @@ import jdk.nashorn.internal.parser.TokenType;
public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/** FunctionNode with the code for this ScriptFunction */
- private volatile FunctionNode functionNode;
+ private FunctionNode functionNode;
/** Source from which FunctionNode was parsed. */
private final Source source;
@@ -64,7 +65,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
private final PropertyMap allocatorMap;
/** Code installer used for all further recompilation/specialization of this ScriptFunction */
- private volatile CodeInstaller<ScriptEnvironment> installer;
+ private CodeInstaller<ScriptEnvironment> installer;
/** Name of class where allocator function resides */
private final String allocatorClassName;
@@ -100,9 +101,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
* @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(),
+ super(functionName(functionNode),
functionNode.getParameters().size(),
functionNode.isStrict(),
false,
@@ -132,13 +131,27 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
if (source != null) {
sb.append(source.getName())
.append(':')
- .append(source.getLine(Token.descPosition(token)))
+ .append(functionNode.getLineNumber())
.append(' ');
}
return sb.toString() + super.toString();
}
+ private static String functionName(final FunctionNode fn) {
+ if (fn.isAnonymous()) {
+ return "";
+ } else {
+ final FunctionNode.Kind kind = fn.getKind();
+ if (kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) {
+ final String name = NameCodec.decode(fn.getIdent().getName());
+ return name.substring(4); // 4 is "get " or "set "
+ } else {
+ return fn.getIdent().getName();
+ }
+ }
+ }
+
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());
@@ -165,7 +178,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
}
@Override
- protected void ensureCodeGenerated() {
+ protected synchronized void ensureCodeGenerated() {
if (!code.isEmpty()) {
return; // nothing to do, we have code, at least some.
}
@@ -323,7 +336,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
}
@Override
- MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
+ synchronized MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
final MethodType runtimeType = runtimeType(callSiteType, args);
assert runtimeType.parameterCount() == callSiteType.parameterCount();
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index 14aab756..ae59855c 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -59,6 +59,9 @@ public abstract class ScriptFunction extends ScriptObject {
/** Method handle for name getter for this ScriptFunction */
public static final MethodHandle G$NAME = findOwnMH("G$name", Object.class, Object.class);
+ /** Method handle used for implementing sync() in mozilla_compat */
+ public static final MethodHandle INVOKE_SYNC = findOwnMH("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
+
/** Method handle for allocate function for this ScriptFunction */
static final MethodHandle ALLOCATE = findOwnMH("allocate", Object.class);
@@ -301,6 +304,14 @@ public abstract class ScriptFunction extends ScriptObject {
public abstract void setPrototype(Object prototype);
/**
+ * Create a function that invokes this function synchronized on {@code sync} or the self object
+ * of the invocation.
+ * @param sync the Object to synchronize on, or undefined
+ * @return synchronized function
+ */
+ public abstract ScriptFunction makeSynchronizedFunction(Object sync);
+
+ /**
* Return the most appropriate invoke handle if there are specializations
* @param type most specific method type to look for invocation with
* @param args args for trampoline invocation
@@ -326,7 +337,7 @@ public abstract class ScriptFunction extends ScriptObject {
* @param self self reference
* @return bound invoke handle
*/
- public final MethodHandle getBoundInvokeHandle(final ScriptObject self) {
+ public final MethodHandle getBoundInvokeHandle(final Object self) {
return MH.bindTo(bindToCalleeIfNeeded(data.getGenericInvoker()), self);
}
@@ -614,6 +625,15 @@ public abstract class ScriptFunction extends ScriptObject {
return result;
}
+ @SuppressWarnings("unused")
+ private static Object invokeSync(final ScriptFunction func, final Object sync, final Object self, final Object... args)
+ throws Throwable {
+ final Object syncObj = sync == UNDEFINED ? self : sync;
+ synchronized (syncObj) {
+ return func.invoke(self, args);
+ }
+ }
+
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 06a12c00..4dbbfba9 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -213,13 +213,13 @@ public abstract class ScriptFunctionData {
*/
public final MethodHandle getGenericInvoker() {
ensureCodeGenerated();
- return composeGenericMethod(code.mostGeneric().getInvoker());
+ return code.generic().getInvoker();
}
final MethodHandle getGenericConstructor() {
ensureCodeGenerated();
- ensureConstructor(code.mostGeneric());
- return composeGenericMethod(code.mostGeneric().getConstructor());
+ ensureConstructor(code.generic());
+ return code.generic().getConstructor();
}
private CompiledFunction getBest(final MethodType callSiteType) {
@@ -267,18 +267,17 @@ public abstract class ScriptFunctionData {
}
/**
- * Compose a constructor given a primordial constructor handle
- *
- * @param ctor primordial constructor handle
- * @param needsCallee do we need to pass a callee
+ * Compose a constructor given a primordial constructor handle.
*
+ * @param ctor primordial constructor handle
* @return the composed constructor
*/
- protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) {
+ protected MethodHandle composeConstructor(final MethodHandle ctor) {
// 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.
+ final boolean needsCallee = needsCallee(ctor);
MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor;
composedCtor = changeReturnTypeToObject(composedCtor);
@@ -472,33 +471,6 @@ public abstract class ScriptFunctionData {
}
/**
- * 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.
@@ -508,10 +480,9 @@ public abstract class ScriptFunctionData {
* @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;
+ final MethodHandle mh = getGenericInvoker();
+ final Object selfObj = convertThisObject(self);
+ final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
if (isVarArg(mh)) {
if (needsCallee(mh)) {
@@ -531,6 +502,12 @@ public abstract class ScriptFunctionData {
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));
+ case 6:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
+ case 7:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
+ case 8:
+ return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
default:
return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
}
@@ -545,15 +522,20 @@ public abstract class ScriptFunctionData {
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));
+ case 5:
+ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
+ case 6:
+ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
+ case 7:
+ return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
default:
return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
}
}
Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable {
- final MethodHandle mh = getGenericConstructor();
-
- final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
+ final MethodHandle mh = getGenericConstructor();
+ final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
if (isVarArg(mh)) {
if (needsCallee(mh)) {
@@ -573,6 +555,12 @@ public abstract class ScriptFunctionData {
return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1));
case 4:
return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2));
+ case 5:
+ return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
+ case 6:
+ return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
+ case 7:
+ return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
default:
return mh.invokeWithArguments(withArguments(fn, paramCount, args));
}
@@ -587,6 +575,12 @@ public abstract class ScriptFunctionData {
return mh.invokeExact(getArg(args, 0), getArg(args, 1));
case 3:
return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2));
+ case 4:
+ return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3));
+ case 5:
+ return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4));
+ case 6:
+ return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5));
default:
return mh.invokeWithArguments(withArguments(null, paramCount, args));
}
@@ -664,20 +658,21 @@ public abstract class ScriptFunctionData {
* @return the adapted handle
*/
private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) {
- return MH.asType(mh, mh.type().changeReturnType(Object.class));
+ final MethodType type = mh.type();
+ return (type.returnType() == Object.class) ? mh : MH.asType(mh, type.changeReturnType(Object.class));
}
private void ensureConstructor(final CompiledFunction inv) {
if (!inv.hasConstructor()) {
- inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker())));
+ inv.setConstructor(composeConstructor(inv.getInvoker()));
}
}
/**
- * Heuristic to figure out if the method handle has a callee argument. If it's type is either
- * {@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
+ * Heuristic to figure out if the method handle has a callee argument. If it's type is
+ * {@code (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 mh the examined method handle
@@ -685,18 +680,8 @@ public abstract class ScriptFunctionData {
* @return true if the method handle expects a callee, false otherwise
*/
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 length > 1 && type.parameterType(1) == ScriptFunction.class;
- }
-
- return type.parameterType(0) == ScriptFunction.class;
+ final MethodType type = mh.type();
+ return (type.parameterCount() > 0 && type.parameterType(0) == ScriptFunction.class);
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/ScriptLoader.java b/src/jdk/nashorn/internal/runtime/ScriptLoader.java
index 736932ea..78185b1c 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java
@@ -52,23 +52,10 @@ final class ScriptLoader extends NashornLoader {
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
checkPackageAccess(name);
- try {
- return super.loadClass(name, resolve);
- } catch (final ClassNotFoundException | SecurityException e) {
- // We'll get ClassNotFoundException for Nashorn 'struct' classes.
- // Also, we'll get SecurityException for jdk.nashorn.internal.*
- // classes. So, load these using to context's 'shared' loader.
- // All these classes start with "jdk.nashorn.internal." prefix.
- try {
- if (name.startsWith(NASHORN_PKG_PREFIX)) {
- return context.getSharedLoader().loadClass(name);
- }
- } catch (final ClassNotFoundException ignored) {
- }
-
- // throw the original exception from here
- throw e;
+ if (name.startsWith(NASHORN_PKG_PREFIX)) {
+ return context.getSharedLoader().loadClass(name);
}
+ return super.loadClass(name, resolve);
}
// package-private and private stuff below this point
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index a4ca6017..c7c82027 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -37,6 +37,8 @@ import static jdk.nashorn.internal.runtime.PropertyDescriptor.SET;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
+import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -131,6 +133,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class);
static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class);
+ static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
@@ -223,14 +226,23 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
for (final Property property : properties) {
final String key = property.getKey();
-
- if (newMap.findProperty(key) == null) {
+ final Property oldProp = newMap.findProperty(key);
+ if (oldProp == null) {
if (property instanceof UserAccessorProperty) {
final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
newMap = newMap.addProperty(prop);
} else {
newMap = newMap.addPropertyBind((AccessorProperty)property, source);
}
+ } else {
+ // See ECMA section 10.5 Declaration Binding Instantiation
+ // step 5 processing each function declaration.
+ if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) {
+ if (oldProp instanceof UserAccessorProperty ||
+ !(oldProp.isWritable() && oldProp.isEnumerable())) {
+ throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+ }
+ }
}
}
@@ -388,7 +400,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return global.newDataDescriptor(getWithProperty(property), configurable, enumerable, writable);
}
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -505,7 +517,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (property == null) {
// promoting an arrayData value to actual property
addOwnProperty(key, propFlags, value);
- removeArraySlot(key);
+ checkIntegerKey(key);
} else {
// Now set the new flags
modifyOwnProperty(property, propFlags);
@@ -591,8 +603,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @param index key for property
* @param value value to define
*/
- protected final void defineOwnProperty(final int index, final Object value) {
- assert ArrayIndex.isValidArrayIndex(index) : "invalid array index";
+ public final void defineOwnProperty(final int index, final Object value) {
+ assert isValidArrayIndex(index) : "invalid array index";
final long longIndex = ArrayIndex.toLongIndex(index);
if (longIndex >= getArray().length()) {
// make array big enough to hold..
@@ -602,9 +614,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private void checkIntegerKey(final String key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
@@ -613,15 +625,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- private void removeArraySlot(final String key) {
- final int index = ArrayIndex.getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- setArray(array.delete(index));
- }
- }
-
/**
* Add a new property to the object.
*
@@ -717,6 +720,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
/**
+ * Low level property API. This is similar to {@link #findProperty(String, boolean)} but returns a
+ * {@code boolean} value instead of a {@link FindProperty} object.
+ * @param key Property key.
+ * @param deep Whether the search should look up proto chain.
+ * @return true if the property was found.
+ */
+ boolean hasProperty(final String key, final boolean deep) {
+ if (getMap().findProperty(key) != null) {
+ return true;
+ }
+
+ if (deep) {
+ final ScriptObject myProto = getProto();
+ if (myProto != null) {
+ return myProto.hasProperty(key, deep);
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Add a new property to the object.
* <p>
* This a more "low level" way that doesn't involve {@link PropertyDescriptor}s
@@ -1178,21 +1203,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* Check if this ScriptObject has array entries. This means that someone has
* set values with numeric keys in the object.
*
- * Note: this can be O(n) up to the array length
- *
* @return true if array entries exists.
*/
public boolean hasArrayEntries() {
- final ArrayData array = getArray();
- final long length = array.length();
-
- for (long i = 0; i < length; i++) {
- if (array.has((int)i)) {
- return true;
- }
- }
-
- return false;
+ return getArray().length() > 0 || getMap().containsArrayKeys();
}
/**
@@ -1708,8 +1722,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- final FindProperty find = findProperty(name, true);
+ if (request.isCallSiteUnstable()) {
+ return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
+ }
+ final FindProperty find = findProperty(name, true);
MethodHandle methodHandle;
if (find == null) {
@@ -1727,10 +1744,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
throw new AssertionError(); // never invoked with any other operation
}
- if (request.isCallSiteUnstable()) {
- return findMegaMorphicGetMethod(desc, name);
- }
-
final Class<?> returnType = desc.getMethodType().returnType();
final Property property = find.getProperty();
methodHandle = find.getGetter(returnType);
@@ -1757,11 +1770,21 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
}
- private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
- final MethodType mhType = desc.getMethodType().insertParameterTypes(1, Object.class);
- final GuardedInvocation inv = findGetIndexMethod(mhType);
+ private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
+ final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
+ final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
+ return new GuardedInvocation(invoker, guard);
+ }
- return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
+ @SuppressWarnings("unused")
+ private Object megamorphicGet(final String key, final boolean isMethod) {
+ final FindProperty find = findProperty(key, true);
+
+ if (find != null) {
+ return getObjectValue(find);
+ }
+
+ return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
}
/**
@@ -1810,7 +1833,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
*/
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- if(request.isCallSiteUnstable()) {
+ if (request.isCallSiteUnstable()) {
return findMegaMorphicSetMethod(desc, name);
}
@@ -2045,6 +2068,26 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return UNDEFINED;
}
+ /**
+ * Get __noSuchMethod__ as a function bound to this object and {@code name} if it is defined.
+ * @param name the method name
+ * @return the bound function, or undefined
+ */
+ private Object getNoSuchMethod(final String name) {
+ final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
+
+ if (find == null) {
+ return invokeNoSuchProperty(name);
+ }
+
+ final Object value = getObjectValue(find);
+ if (! (value instanceof ScriptFunction)) {
+ return UNDEFINED;
+ }
+
+ return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
+ }
+
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
}
@@ -2302,13 +2345,34 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
if (newLength < arrayLength) {
- setArray(getArray().shrink(newLength));
- getArray().setLength(newLength);
+ long actualLength = newLength;
+
+ // Check for numeric keys in property map and delete them or adjust length, depending on whether
+ // they're defined as configurable. See ES5 #15.4.5.2
+ if (getMap().containsArrayKeys()) {
+
+ for (long l = arrayLength - 1; l >= newLength; l--) {
+ final FindProperty find = findProperty(JSType.toString(l), false);
+
+ if (find != null) {
+
+ if (find.getProperty().isConfigurable()) {
+ deleteOwnProperty(find.getProperty());
+ } else {
+ actualLength = l + 1;
+ break;
+ }
+ }
+ }
+ }
+
+ setArray(getArray().shrink(actualLength));
+ getArray().setLength(actualLength);
}
}
private int getInt(final int index, final String key) {
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
final FindProperty find = object.findProperty(key, false, false, this);
@@ -2339,7 +2403,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public int getInt(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2351,7 +2415,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public int getInt(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2363,7 +2427,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public int getInt(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2385,7 +2449,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private long getLong(final int index, final String key) {
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
final FindProperty find = object.findProperty(key, false, false, this);
@@ -2416,7 +2480,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public long getLong(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2428,7 +2492,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public long getLong(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2440,7 +2504,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public long getLong(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2462,7 +2526,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private double getDouble(final int index, final String key) {
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
final FindProperty find = object.findProperty(key, false, false, this);
@@ -2493,7 +2557,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public double getDouble(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2505,7 +2569,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public double getDouble(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2517,7 +2581,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public double getDouble(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2539,7 +2603,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private Object get(final int index, final String key) {
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject object = this; ; ) {
final FindProperty find = object.findProperty(key, false, false, this);
@@ -2570,7 +2634,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public Object get(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2582,7 +2646,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public Object get(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2594,7 +2658,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public Object get(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -2626,7 +2690,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
final long oldLength = getArray().length();
final long longIndex = index & JSType.MAX_UINT;
- if (!getArray().has(index)) {
+ if (getMap().containsArrayKeys()) {
final String key = JSType.toString(longIndex);
final FindProperty find = findProperty(key, true);
@@ -2710,9 +2774,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public void set(final Object key, final int value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2722,14 +2786,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(key, JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final Object key, final long value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2739,14 +2804,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(key, JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final Object key, final double value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2756,14 +2822,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(key, JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final Object key, final Object value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2773,17 +2840,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- final String propName = JSType.toString(key);
- final FindProperty find = findProperty(propName, true);
-
- setObject(find, strict, propName, value);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, value);
}
@Override
public void set(final double key, final int value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2793,14 +2858,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final double key, final long value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2810,14 +2876,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final double key, final double value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2827,14 +2894,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final double key, final Object value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2844,14 +2912,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), value, strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, value);
}
@Override
public void set(final long key, final int value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2861,14 +2930,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final long key, final long value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2878,14 +2948,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final long key, final double value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2895,14 +2966,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final long key, final Object value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2912,14 +2984,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), value, strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, value);
}
@Override
public void set(final int key, final int value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2929,14 +3002,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final int key, final long value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2946,14 +3020,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final int key, final double value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2963,14 +3038,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), JSType.toObject(value), strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, JSType.toObject(value));
}
@Override
public void set(final int key, final Object value, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
setArray(getArray().set(index, value, strict));
} else {
@@ -2980,14 +3056,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return;
}
- set(JSType.toObject(key), value, strict);
+ final String propName = JSType.toString(key);
+ setObject(findProperty(propName, true), strict, propName, value);
}
@Override
public boolean has(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject self = this; self != null; self = self.getProto()) {
if (self.getArray().has(index)) {
return true;
@@ -2995,16 +3072,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- final FindProperty find = findProperty(JSType.toString(key), true);
-
- return find != null;
+ return hasProperty(JSType.toString(key), true);
}
@Override
public boolean has(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject self = this; self != null; self = self.getProto()) {
if (self.getArray().has(index)) {
return true;
@@ -3012,16 +3087,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- final FindProperty find = findProperty(JSType.toString(key), true);
-
- return find != null;
+ return hasProperty(JSType.toString(key), true);
}
@Override
public boolean has(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject self = this; self != null; self = self.getProto()) {
if (self.getArray().has(index)) {
return true;
@@ -3029,16 +3102,14 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- final FindProperty find = findProperty(JSType.toString(key), true);
-
- return find != null;
+ return hasProperty(JSType.toString(key), true);
}
@Override
public boolean has(final int key) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
- if (ArrayIndex.isValidArrayIndex(index)) {
+ if (isValidArrayIndex(index)) {
for (ScriptObject self = this; self != null; self = self.getProto()) {
if (self.getArray().has(index)) {
return true;
@@ -3046,66 +3117,32 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- final FindProperty find = findProperty(JSType.toString(key), true);
-
- return find != null;
+ return hasProperty(JSType.toString(key), true);
}
@Override
public boolean hasOwnProperty(final Object key) {
- final int index = ArrayIndex.getArrayIndex(key);
-
- if (getArray().has(index)) {
- return true;
- }
-
- final FindProperty find = findProperty(JSType.toString(key), false);
-
- return find != null;
+ return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
}
@Override
public boolean hasOwnProperty(final int key) {
- final int index = ArrayIndex.getArrayIndex(key);
-
- if (getArray().has(index)) {
- return true;
- }
-
- final FindProperty find = findProperty(JSType.toString(key), false);
-
- return find != null;
+ return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
}
@Override
public boolean hasOwnProperty(final long key) {
- final int index = ArrayIndex.getArrayIndex(key);
-
- if (getArray().has(index)) {
- return true;
- }
-
- final FindProperty find = findProperty(JSType.toString(key), false);
-
- return find != null;
+ return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
}
@Override
public boolean hasOwnProperty(final double key) {
- final int index = ArrayIndex.getArrayIndex(key);
-
- if (getArray().has(index)) {
- return true;
- }
-
- final FindProperty find = findProperty(JSType.toString(key), false);
-
- return find != null;
+ return getArray().has(getArrayIndex(key)) || hasProperty(JSType.toString(key), false);
}
@Override
public boolean delete(final int key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -3121,7 +3158,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public boolean delete(final long key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -3137,7 +3174,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public boolean delete(final double key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
@@ -3153,7 +3190,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@Override
public boolean delete(final Object key, final boolean strict) {
- final int index = ArrayIndex.getArrayIndex(key);
+ final int index = getArrayIndex(key);
final ArrayData array = getArray();
if (array.has(index)) {
diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
index c9b40512..d9705676 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
@@ -47,6 +47,7 @@ import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.ir.debug.JSONWriter;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -258,6 +259,11 @@ public final class ScriptRuntime {
return ((Map<?,?>)obj).keySet().iterator();
}
+ final Object wrapped = Global.instance().wrapAsObject(obj);
+ if (wrapped instanceof ScriptObject) {
+ return ((ScriptObject)wrapped).propertyIterator();
+ }
+
return Collections.emptyIterator();
}
@@ -336,6 +342,11 @@ public final class ScriptRuntime {
return ((Iterable<?>)obj).iterator();
}
+ final Object wrapped = Global.instance().wrapAsObject(obj);
+ if (wrapped instanceof ScriptObject) {
+ return ((ScriptObject)wrapped).valueIterator();
+ }
+
return Collections.emptyIterator();
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
index 6bd0479f..8a03533e 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
@@ -190,7 +190,7 @@ public final class ScriptingFunctions {
char buffer[] = new char[1024];
try (final InputStreamReader inputStream = new InputStreamReader(process.getErrorStream())) {
for (int length; (length = inputStream.read(buffer, 0, buffer.length)) != -1; ) {
- outBuffer.append(buffer, 0, length);
+ errBuffer.append(buffer, 0, length);
}
} catch (IOException ex) {
exception[1] = ex;
diff --git a/src/jdk/nashorn/internal/runtime/Source.java b/src/jdk/nashorn/internal/runtime/Source.java
index 9273e7a8..0455a86c 100644
--- a/src/jdk/nashorn/internal/runtime/Source.java
+++ b/src/jdk/nashorn/internal/runtime/Source.java
@@ -272,6 +272,10 @@ public final class Source {
/**
* Return line number of character position.
+ *
+ * <p>This method can be expensive for large sources as it iterates through
+ * all characters up to {@code position}.</p>
+ *
* @param position Position of character in source content.
* @return Line number.
*/
diff --git a/src/jdk/nashorn/internal/runtime/WithObject.java b/src/jdk/nashorn/internal/runtime/WithObject.java
index 7dc8307c..6e03dc60 100644
--- a/src/jdk/nashorn/internal/runtime/WithObject.java
+++ b/src/jdk/nashorn/internal/runtime/WithObject.java
@@ -316,6 +316,10 @@ public final class WithObject extends ScriptObject implements Scope {
return expression;
}
+ /**
+ * Get the parent scope for this {@code WithObject}
+ * @return the parent scope
+ */
public ScriptObject getParentScope() {
return getProto();
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index ca4adb62..5c0c0476 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -461,7 +461,23 @@ public abstract class ArrayData {
*/
public abstract ArrayData slice(long from, long to);
- private static Class<?> widestType(final Object... items) {
+ /**
+ * Fast splice operation. This just modifies the array according to the number of
+ * elements added and deleted but does not insert the added elements. Throws
+ * {@code UnsupportedOperationException} if fast splice operation is not supported
+ * for this class or arguments.
+ *
+ * @param start start index of splice operation
+ * @param removed number of removed elements
+ * @param added number of added elements
+ * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments.
+ */
+ public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ static Class<?> widestType(final Object... items) {
assert items.length > 0;
Class<?> widest = Integer.class;
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
index add39912..07ddda2d 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
@@ -269,4 +269,32 @@ final class IntArrayData extends ArrayData {
return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
+
+ @Override
+ public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
+ final long oldLength = length();
+ final long newLength = oldLength - removed + added;
+ if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
+ throw new UnsupportedOperationException();
+ }
+ final ArrayData returnValue = (removed == 0) ?
+ EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+
+ if (newLength != oldLength) {
+ final int[] newArray;
+
+ if (newLength > array.length) {
+ newArray = new int[ArrayData.nextSize((int)newLength)];
+ System.arraycopy(array, 0, newArray, 0, start);
+ } else {
+ newArray = array;
+ }
+
+ System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
+ array = newArray;
+ setLength(newLength);
+ }
+
+ return returnValue;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java
index 92a80029..a6b6bb9a 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java
@@ -77,4 +77,4 @@ class JavaArrayIterator extends ArrayLikeIterator<Object> {
public void remove() {
throw new UnsupportedOperationException("remove");
}
-} \ No newline at end of file
+}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
index 59a63155..4bb96aae 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
@@ -92,7 +92,7 @@ final class LongArrayData extends ArrayData {
@Override
public ArrayData convert(final Class<?> type) {
- if (type == Long.class) {
+ if (type == Integer.class || type == Long.class) {
return this;
}
final int length = (int) length();
@@ -238,4 +238,32 @@ final class LongArrayData extends ArrayData {
final long newLength = to - start;
return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
+
+ @Override
+ public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
+ final long oldLength = length();
+ final long newLength = oldLength - removed + added;
+ if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
+ throw new UnsupportedOperationException();
+ }
+ final ArrayData returnValue = (removed == 0) ?
+ EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+
+ if (newLength != oldLength) {
+ final long[] newArray;
+
+ if (newLength > array.length) {
+ newArray = new long[ArrayData.nextSize((int)newLength)];
+ System.arraycopy(array, 0, newArray, 0, start);
+ } else {
+ newArray = array;
+ }
+
+ System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
+ array = newArray;
+ setLength(newLength);
+ }
+
+ return returnValue;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
index 2ecf9d74..8254db63 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
@@ -218,4 +218,32 @@ final class NumberArrayData extends ArrayData {
final long newLength = to - start;
return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
+
+ @Override
+ public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
+ final long oldLength = length();
+ final long newLength = oldLength - removed + added;
+ if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
+ throw new UnsupportedOperationException();
+ }
+ final ArrayData returnValue = (removed == 0) ?
+ EMPTY_ARRAY : new NumberArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+
+ if (newLength != oldLength) {
+ final double[] newArray;
+
+ if (newLength > array.length) {
+ newArray = new double[ArrayData.nextSize((int)newLength)];
+ System.arraycopy(array, 0, newArray, 0, start);
+ } else {
+ newArray = array;
+ }
+
+ System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
+ array = newArray;
+ setLength(newLength);
+ }
+
+ return returnValue;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
index 136e6437..a9a1b5b2 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
@@ -206,4 +206,32 @@ final class ObjectArrayData extends ArrayData {
final long newLength = to - start;
return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
+
+ @Override
+ public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
+ final long oldLength = length();
+ final long newLength = oldLength - removed + added;
+ if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
+ throw new UnsupportedOperationException();
+ }
+ final ArrayData returnValue = (removed == 0) ?
+ EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+
+ if (newLength != oldLength) {
+ final Object[] newArray;
+
+ if (newLength > array.length) {
+ newArray = new Object[ArrayData.nextSize((int)newLength)];
+ System.arraycopy(array, 0, newArray, 0, start);
+ } else {
+ newArray = array;
+ }
+
+ System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
+ array = newArray;
+ setLength(newLength);
+ }
+
+ return returnValue;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java
index dcb37cfd..b90bae68 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java
@@ -55,4 +55,4 @@ final class ReverseJavaArrayIterator extends JavaArrayIterator {
protected long bumpIndex() {
return index--;
}
-} \ No newline at end of file
+}
diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index f725817a..0d5f68a1 100644
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -63,7 +63,7 @@ public final class Bootstrap {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
- factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
+ factory.setFallbackLinkers(new NashornBeansLinker(), new NashornBottomLinker());
factory.setSyncOnRelink(true);
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
if (relinkThreshold > -1) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
index ccd497d7..77c1618b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
@@ -72,7 +72,7 @@ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
// Delegate to BeansLinker
- final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
+ final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass),
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
if(inv == null) {
return null;
diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index 45451a8b..f0d45317 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -25,25 +25,28 @@
package jdk.nashorn.internal.runtime.linker;
-import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.HashMap;
+import java.util.Map;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
-import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.JSType;
/**
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
* as ScriptObjects from other Nashorn contexts.
*/
-final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
+final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory {
@Override
public boolean canLinkType(final Class<?> type) {
return canLinkTypeStatic(type);
@@ -75,6 +78,22 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
return Bootstrap.asType(inv, linkerServices, desc);
}
+ @Override
+ public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
+ final boolean sourceIsAlwaysJSObject = JSObject.class.isAssignableFrom(sourceType);
+ if(!sourceIsAlwaysJSObject && !sourceType.isAssignableFrom(JSObject.class)) {
+ return null;
+ }
+
+ final MethodHandle converter = CONVERTERS.get(targetType);
+ if(converter == null) {
+ return null;
+ }
+
+ return new GuardedInvocation(converter, sourceIsAlwaysJSObject ? null : IS_JSOBJECT_GUARD).asType(MethodType.methodType(targetType, sourceType));
+ }
+
+
private static GuardedInvocation lookup(final CallSiteDescriptor desc) {
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
final int c = desc.getNameTokenCount();
@@ -87,9 +106,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
case "setElem":
return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
case "call":
- return findCallMethod(desc, operator);
- case "callMethod":
- return findCallMethodMethod(desc, operator);
+ return findCallMethod(desc);
case "new":
return findNewMethod(desc);
default:
@@ -115,14 +132,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
return new GuardedInvocation(JSOBJECTLINKER_PUT, null, IS_JSOBJECT_GUARD);
}
- private static GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final String operator) {
- final String methodName = desc.getNameToken(2);
- MethodHandle func = MH.insertArguments(JSOBJECT_CALLMEMBER, 1, methodName);
- func = MH.asCollector(func, Object[].class, desc.getMethodType().parameterCount() - 1);
- return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
- }
-
- private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final String operator) {
+ private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
final MethodHandle func = MH.asCollector(JSOBJECT_CALL, Object[].class, desc.getMethodType().parameterCount() - 2);
return new GuardedInvocation(func, null, IS_JSOBJECT_GUARD);
}
@@ -140,7 +150,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
@SuppressWarnings("unused")
private static Object get(final Object jsobj, final Object key) {
if (key instanceof Integer) {
- return ((JSObject)jsobj).getSlot((int)(Integer)key);
+ return ((JSObject)jsobj).getSlot((Integer)key);
} else if (key instanceof Number) {
final int index = getIndex((Number)key);
if (index > -1) {
@@ -155,7 +165,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
@SuppressWarnings("unused")
private static void put(final Object jsobj, final Object key, final Object value) {
if (key instanceof Integer) {
- ((JSObject)jsobj).setSlot((int)(Integer)key, value);
+ ((JSObject)jsobj).setSlot((Integer)key, value);
} else if (key instanceof Number) {
((JSObject)jsobj).setSlot(getIndex((Number)key), value);
} else if (key instanceof String) {
@@ -163,6 +173,25 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
}
}
+ @SuppressWarnings("unused")
+ private static int toInt32(final JSObject obj) {
+ return JSType.toInt32(toNumber(obj));
+ }
+
+ @SuppressWarnings("unused")
+ private static long toInt64(final JSObject obj) {
+ return JSType.toInt64(toNumber(obj));
+ }
+
+ private static double toNumber(final JSObject obj) {
+ return obj == null ? 0 : obj.toNumber();
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean toBoolean(final JSObject obj) {
+ return obj != null;
+ }
+
private static int getIndex(final Number n) {
final double value = n.doubleValue();
return JSType.isRepresentableAsInt(value) ? (int)value : -1;
@@ -178,27 +207,31 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
// method handles of JSObject class
private static final MethodHandle JSOBJECT_GETMEMBER = findJSObjectMH("getMember", Object.class, String.class);
private static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH("setMember", Void.TYPE, String.class, Object.class);
- private static final MethodHandle JSOBJECT_CALLMEMBER = findJSObjectMH("callMember", Object.class, String.class, Object[].class);
private static final MethodHandle JSOBJECT_CALL = findJSObjectMH("call", Object.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_NEW = findJSObjectMH("newObject", Object.class, Object[].class);
+ private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
+ static {
+ CONVERTERS.put(boolean.class, findOwnMH("toBoolean", boolean.class, JSObject.class));
+ CONVERTERS.put(int.class, findOwnMH("toInt32", int.class, JSObject.class));
+ CONVERTERS.put(long.class, findOwnMH("toInt64", long.class, JSObject.class));
+ CONVERTERS.put(double.class, findOwnMH("toNumber", double.class, JSObject.class));
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
- final Class<?> own = JSObjectLinker.class;
- final MethodType mt = MH.type(rtype, types);
- try {
- return MH.findStatic(MethodHandles.lookup(), own, name, mt);
- } catch (final MethodHandleFactory.LookupException e) {
- return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
- }
+ return findMH(name, JSObjectLinker.class, rtype, types);
}
private static MethodHandle findJSObjectMH(final String name, final Class<?> rtype, final Class<?>... types) {
- final Class<?> own = JSObject.class;
+ return findMH(name, JSObject.class, rtype, types);
+ }
+
+ private static MethodHandle findMH(final String name, final Class<?> target, final Class<?> rtype, final Class<?>... types) {
final MethodType mt = MH.type(rtype, types);
try {
- return MH.findVirtual(MethodHandles.publicLookup(), own, name, mt);
+ return MH.findStatic(MethodHandles.lookup(), target, name, mt);
} catch (final MethodHandleFactory.LookupException e) {
- return MH.findVirtual(MethodHandles.lookup(), own, name, mt);
+ return MH.findVirtual(MethodHandles.lookup(), target, name, mt);
}
}
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
index 8ebdc810..5b8d4cfe 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
@@ -93,7 +93,7 @@ import sun.reflect.CallerSensitive;
* its last argument preceded by original constructor arguments. This constructor will use the passed function as the
* implementation for all abstract methods. For consistency, any concrete methods sharing the single abstract method
* name will also be overridden by the function. When methods on the adapter instance are invoked, the ScriptFunction is
- * invoked with {@code null} as its "this".
+ * invoked with global or UNDEFINED as its "this" depending whether the function is non-strict or not.
* </li>
* <li>
* If the adapter being generated can have class-level overrides, constructors taking same arguments as the superclass
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
index 5130f3d6..b221d000 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
@@ -109,7 +109,7 @@ public final class JavaAdapterFactory {
if (sm != null) {
for (Class<?> type : types) {
// check for restricted package access
- Context.checkPackageAccess(type.getName());
+ Context.checkPackageAccess(type);
}
}
return getAdapterInfo(types).getAdapterClassFor(classOverrides);
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java
index 6614304f..06ae1b11 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java
@@ -29,6 +29,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -53,8 +54,8 @@ public final class JavaAdapterServices {
* @return the appropriately adapted method handle for invoking the script function.
*/
public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type) {
- // JS "this" will be null for SAMs
- return adaptHandle(fn.getBoundInvokeHandle(null), type);
+ // JS "this" will be global object or undefined depending on if 'fn' is strict or not
+ return adaptHandle(fn.getBoundInvokeHandle(fn.isStrict()? ScriptRuntime.UNDEFINED : Context.getGlobal()), type);
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
index f035071b..984d0f41 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java
@@ -25,9 +25,9 @@
package jdk.nashorn.internal.runtime.linker;
+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.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -211,6 +211,20 @@ final class JavaArgumentConverters {
return null;
} else if (obj instanceof Long) {
return (Long) obj;
+ } else if (obj instanceof Integer) {
+ return ((Integer)obj).longValue();
+ } else if (obj instanceof Double) {
+ final Double d = (Double)obj;
+ if(Double.isInfinite(d.doubleValue())) {
+ return 0L;
+ }
+ return d.longValue();
+ } else if (obj instanceof Float) {
+ final Float f = (Float)obj;
+ if(Float.isInfinite(f.floatValue())) {
+ return 0L;
+ }
+ return f.longValue();
} else if (obj instanceof Number) {
return ((Number)obj).longValue();
} else if (obj instanceof String || obj instanceof ConsString) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
index 8e40805a..c42af1d8 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
@@ -100,8 +100,9 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
type.changeParameterType(0, adapterClass), 0);
// Delegate to BeansLinker
- final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
- linkRequest.replaceArguments(newDescriptor, args), linkerServices);
+ final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation(
+ BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args),
+ linkerServices);
final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
if(guardedInv == null) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
new file mode 100644
index 00000000..e2db2b11
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
@@ -0,0 +1,127 @@
+/*
+ * 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 java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import jdk.internal.dynalink.beans.BeansLinker;
+import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.GuardingDynamicLinker;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.support.Lookup;
+import jdk.nashorn.internal.runtime.ConsString;
+
+/**
+ * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
+ * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
+ * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
+ * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
+ * the target method handle parameter signature is {@code Object}.
+ */
+public class NashornBeansLinker implements GuardingDynamicLinker {
+ private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
+
+ private final BeansLinker beansLinker = new BeansLinker();
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
+ }
+
+ /**
+ * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special
+ * conversions that this class does.
+ * @param delegateLinker the linker to which the actual work is delegated to.
+ * @param linkRequest the delegated link request
+ * @param linkerServices the original link services that will be augmented with special conversions
+ * @return the guarded invocation from the delegate, possibly augmented with special conversions
+ * @throws Exception if the delegate throws an exception
+ */
+ public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
+ }
+
+ @SuppressWarnings("unused")
+ private static Object exportArgument(final Object arg) {
+ return arg instanceof ConsString ? arg.toString() : arg;
+ }
+
+ private static class NashornBeansLinkerServices implements LinkerServices {
+ private final LinkerServices linkerServices;
+
+ NashornBeansLinkerServices(final LinkerServices linkerServices) {
+ this.linkerServices = linkerServices;
+ }
+
+ @Override
+ public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
+ final MethodHandle typed = linkerServices.asType(handle, fromType);
+
+ final MethodType handleType = handle.type();
+ final int paramCount = handleType.parameterCount();
+ assert fromType.parameterCount() == handleType.parameterCount();
+
+ MethodHandle[] filters = null;
+ for(int i = 0; i < paramCount; ++i) {
+ if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
+ if(filters == null) {
+ filters = new MethodHandle[paramCount];
+ }
+ filters[i] = EXPORT_ARGUMENT;
+ }
+ }
+
+ return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+ }
+
+ private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
+ return handleType == Object.class && fromType == Object.class;
+ }
+
+ @Override
+ public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
+ return linkerServices.getTypeConverter(sourceType, targetType);
+ }
+
+ @Override
+ public boolean canConvert(final Class<?> from, final Class<?> to) {
+ return linkerServices.canConvert(from, to);
+ }
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
+ return linkerServices.getGuardedInvocation(linkRequest);
+ }
+
+ @Override
+ public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
+ return linkerServices.compareConversion(sourceType, targetType1, targetType2);
+ }
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
index 6dbcbdd3..c94df15b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
@@ -33,14 +33,18 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.HashMap;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
+import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
@@ -50,7 +54,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* setters for Java objects that couldn't be linked by any other linker, and throw appropriate ECMAScript errors for
* attempts to invoke arbitrary Java objects as functions or constructors.
*/
-final class NashornBottomLinker implements GuardingDynamicLinker {
+final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeConverterFactory {
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
@@ -129,6 +133,29 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
throw new AssertionError("unknown call type " + desc);
}
+ @Override
+ public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
+ final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType);
+ return gi == null ? null : gi.asType(MH.type(targetType, sourceType));
+ }
+
+ /**
+ * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType(Class, Class)} that doesn't
+ * care about adapting the method signature; that's done by the invoking method. Returns conversion from Object to String/number/boolean (JS primitive types).
+ * @param sourceType the source type
+ * @param targetType the target type
+ * @return a guarded invocation that converts from the source type to the target type.
+ * @throws Exception if something goes wrong
+ */
+ private static GuardedInvocation convertToTypeNoCast(final Class<?> sourceType, final Class<?> targetType) throws Exception {
+ final MethodHandle mh = CONVERTERS.get(targetType);
+ if (mh != null) {
+ return new GuardedInvocation(mh, null);
+ }
+
+ return null;
+ }
+
private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
return Bootstrap.asType(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc);
}
@@ -161,6 +188,15 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
throw new AssertionError("unknown call type " + desc);
}
+ private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
+ static {
+ CONVERTERS.put(boolean.class, JSType.TO_BOOLEAN.methodHandle());
+ CONVERTERS.put(double.class, JSType.TO_NUMBER.methodHandle());
+ CONVERTERS.put(int.class, JSType.TO_INTEGER.methodHandle());
+ CONVERTERS.put(long.class, JSType.TO_LONG.methodHandle());
+ CONVERTERS.put(String.class, JSType.TO_STRING.methodHandle());
+ }
+
private static String getArgument(final LinkRequest linkRequest) {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
if (desc.getNameTokenCount() > 2) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
index 3a23b141..27e4573f 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
@@ -30,6 +30,10 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Modifier;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import javax.script.Bindings;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.ConversionComparator;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -38,6 +42,12 @@ import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.ScriptUtils;
+import jdk.nashorn.internal.objects.NativeArray;
+import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Undefined;
@@ -47,6 +57,13 @@ import jdk.nashorn.internal.runtime.Undefined;
* includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
*/
final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
+ private static final ClassValue<MethodHandle> ARRAY_CONVERTERS = new ClassValue<MethodHandle>() {
+ @Override
+ protected MethodHandle computeValue(Class<?> type) {
+ return createArrayConverter(type);
+ }
+ };
+
/**
* Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
*/
@@ -103,6 +120,17 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
if (mh != null) {
return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : IS_NASHORN_OR_UNDEFINED_TYPE);
}
+
+ final GuardedInvocation arrayConverter = getArrayConverter(sourceType, targetType);
+ if(arrayConverter != null) {
+ return arrayConverter;
+ }
+
+ final GuardedInvocation mirrorConverter = getMirrorConverter(sourceType, targetType);
+ if(mirrorConverter != null) {
+ return mirrorConverter;
+ }
+
return getSamTypeConverter(sourceType, targetType);
}
@@ -129,6 +157,53 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return null;
}
+ /**
+ * Returns a guarded invocation that converts from a source type that is NativeArray to a Java array or List or
+ * Deque type.
+ * @param sourceType the source type (presumably NativeArray a superclass of it)
+ * @param targetType the target type (presumably an array type, or List or Deque)
+ * @return a guarded invocation that converts from the source type to the target type. null is returned if
+ * either the source type is neither NativeArray, nor a superclass of it, or if the target type is not an array
+ * type, List, or Deque.
+ */
+ private static GuardedInvocation getArrayConverter(final Class<?> sourceType, final Class<?> targetType) {
+ final boolean isSourceTypeNativeArray = sourceType == NativeArray.class;
+ // If source type is more generic than ScriptFunction class, we'll need to use a guard
+ final boolean isSourceTypeGeneric = !isSourceTypeNativeArray && sourceType.isAssignableFrom(NativeArray.class);
+
+ if (isSourceTypeNativeArray || isSourceTypeGeneric) {
+ final MethodHandle guard = isSourceTypeGeneric ? IS_NATIVE_ARRAY : null;
+ if(targetType.isArray()) {
+ return new GuardedInvocation(ARRAY_CONVERTERS.get(targetType), guard);
+ }
+ if(targetType == List.class) {
+ return new GuardedInvocation(JSType.TO_JAVA_LIST.methodHandle(), guard);
+ }
+ if(targetType == Deque.class) {
+ return new GuardedInvocation(JSType.TO_JAVA_DEQUE.methodHandle(), guard);
+ }
+ }
+ return null;
+ }
+
+ private static MethodHandle createArrayConverter(final Class<?> type) {
+ assert type.isArray();
+ final MethodHandle converter = MH.insertArguments(JSType.TO_JAVA_ARRAY.methodHandle(), 1, type.getComponentType());
+ return MH.asType(converter, converter.type().changeReturnType(type));
+ }
+
+ private static GuardedInvocation getMirrorConverter(Class<?> sourceType, Class<?> targetType) {
+ // Could've also used (targetType.isAssignableFrom(ScriptObjectMirror.class) && targetType != Object.class) but
+ // it's probably better to explicitly spell out the supported target types
+ if (targetType == Map.class || targetType == Bindings.class || targetType == JSObject.class || targetType == ScriptObjectMirror.class) {
+ if(ScriptObject.class.isAssignableFrom(sourceType)) {
+ return new GuardedInvocation(CREATE_MIRROR, null);
+ }
+ return new GuardedInvocation(CREATE_MIRROR, IS_SCRIPT_OBJECT);
+ }
+ return null;
+ }
+
private static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
return isAbstractClass(clazz) && !ScriptObject.class.isAssignableFrom(clazz) &&
JavaAdapterFactory.isAutoConvertibleFromFunction(clazz);
@@ -148,7 +223,26 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
@Override
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
+ if(sourceType == NativeArray.class) {
+ // Prefer lists, as they're less costly to create than arrays.
+ if(isList(targetType1)) {
+ if(!isList(targetType2)) {
+ return Comparison.TYPE_1_BETTER;
+ }
+ } else if(isList(targetType2)) {
+ return Comparison.TYPE_2_BETTER;
+ }
+ // Then prefer arrays
+ if(targetType1.isArray()) {
+ if(!targetType2.isArray()) {
+ return Comparison.TYPE_1_BETTER;
+ }
+ } else if(targetType2.isArray()) {
+ return Comparison.TYPE_2_BETTER;
+ }
+ }
if(ScriptObject.class.isAssignableFrom(sourceType)) {
+ // Prefer interfaces
if(targetType1.isInterface()) {
if(!targetType2.isInterface()) {
return Comparison.TYPE_1_BETTER;
@@ -160,16 +254,27 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return Comparison.INDETERMINATE;
}
+ private static boolean isList(Class<?> clazz) {
+ return clazz == List.class || clazz == Deque.class;
+ }
+
+ private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class));
private static final MethodHandle IS_SCRIPT_FUNCTION = Guards.isInstance(ScriptFunction.class, MH.type(Boolean.TYPE, Object.class));
+ private static final MethodHandle IS_NATIVE_ARRAY = Guards.isOfClass(NativeArray.class, MH.type(Boolean.TYPE, Object.class));
- private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined",
- Boolean.TYPE, Object.class);
+ private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", Boolean.TYPE, Object.class);
+ private static final MethodHandle CREATE_MIRROR = findOwnMH("createMirror", Object.class, Object.class);
@SuppressWarnings("unused")
private static boolean isNashornTypeOrUndefined(final Object obj) {
return obj instanceof ScriptObject || obj instanceof Undefined;
}
+ @SuppressWarnings("unused")
+ private static Object createMirror(final Object obj) {
+ return ScriptUtils.wrap(obj);
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), NashornLinker.class, name, MH.type(rtype, types));
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
index 9c9f5283..72ed9766 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
@@ -70,7 +70,7 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
// We intercept "new" on StaticClass instances to provide additional capabilities
if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
// make sure new is on accessible Class
- Context.checkPackageAccess(receiverClass.getName());
+ Context.checkPackageAccess(receiverClass);
// Is the class abstract? (This includes interfaces.)
if (NashornLinker.isAbstractClass(receiverClass)) {
@@ -93,7 +93,7 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
private static GuardedInvocation delegate(LinkerServices linkerServices, final LinkRequest request) throws Exception {
- return staticClassLinker.getGuardedInvocation(request, linkerServices);
+ return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices);
}
private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class<?> receiverClass) {
diff --git a/src/jdk/nashorn/internal/runtime/resources/fx/base.js b/src/jdk/nashorn/internal/runtime/resources/fx/base.js
index b0bfc3fb..382eabb2 100644
--- a/src/jdk/nashorn/internal/runtime/resources/fx/base.js
+++ b/src/jdk/nashorn/internal/runtime/resources/fx/base.js
@@ -33,7 +33,6 @@ var JFX_SWING_CLASSES = [];
var JFX_SWT_CLASSES = [];
function LOAD_FX_CLASSES(clsList) {
-
for each (var cls in clsList) {
// Ex. Stage = Java.type("javafx.stage.Stage");
this[cls[cls.length - 1]] = Java.type(cls.join("."));
@@ -146,3 +145,5 @@ function LOAD_FX_CLASSES(clsList) {
}
}
})();
+
+LOAD_FX_CLASSES(JFX_BASE_CLASSES);
diff --git a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
index 6b934ad4..85e2161c 100644
--- a/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
+++ b/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js
@@ -41,7 +41,12 @@ Object.defineProperty(this, "JavaAdapter", {
}
});
+
// importPackage
+// avoid unnecessary chaining of __noSuchProperty__ again
+// in case user loads this script more than once.
+if (typeof importPackage == 'undefined') {
+
Object.defineProperty(this, "importPackage", {
configurable: true, enumerable: false, writable: true,
value: (function() {
@@ -91,6 +96,19 @@ Object.defineProperty(this, "importPackage", {
})()
});
+}
+
+// sync
+Object.defineProperty(this, "sync", {
+ configurable: true, enumerable: false, writable: true,
+ value: function(func, syncobj) {
+ if (arguments.length < 1 || arguments.length > 2 ) {
+ throw "sync(function [,object]) parameter count mismatch";
+ }
+ return Packages.jdk.nashorn.api.scripting.ScriptUtils.makeSynchronizedFunction(func, syncobj);
+ }
+});
+
// Object.prototype.__defineGetter__
Object.defineProperty(Object.prototype, "__defineGetter__", {
configurable: true, enumerable: false, writable: true,
@@ -344,13 +362,16 @@ Object.defineProperty(String.prototype, "sup", {
// Rhino: global.importClass
Object.defineProperty(this, "importClass", {
configurable: true, enumerable: false, writable: true,
- value: function(clazz) {
- if (Java.isType(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");
+ value: function() {
+ for (var arg in arguments) {
+ var clazz = arguments[arg];
+ if (Java.isType(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/overview.html b/src/overview.html
index 5418854f..e242a5b9 100644
--- a/src/overview.html
+++ b/src/overview.html
@@ -108,6 +108,6 @@ identity and doesn't carry i.e. static members. Again, see the link for {@code N
<h2>Other non-standard built-in objects</h2>
In addition to {@code Java}, Nashorn also exposes some other non-standard built-in objects:
<a href="jdk/nashorn/internal/objects/NativeJSAdapter.html">{@code JSAdapter}</a>,
-<a href="jdk/nashorn/internal/objects/NativeJavaImporter.html">{@code JavaImporter},
+<a href="jdk/nashorn/internal/objects/NativeJavaImporter.html">{@code JavaImporter}</a>,
<a href="jdk/nashorn/internal/runtime/NativeJavaPackage.html">{@code Packages}.</a>
</body>
diff --git a/test/examples/array-micro.js b/test/examples/array-micro.js
index 075e78d8..9bb898f6 100644
--- a/test/examples/array-micro.js
+++ b/test/examples/array-micro.js
@@ -90,6 +90,24 @@ bench("set", function() {
array[6] = 6;
});
+bench("push", function() {
+ var arr = [1, 2, 3];
+ arr.push(4);
+ arr.push(5);
+ arr.push(6);
+});
+
+bench("pop", function() {
+ var arr = [1, 2, 3];
+ arr.pop();
+ arr.pop();
+ arr.pop();
+});
+
+bench("splice", function() {
+ [1, 2, 3].splice(0, 2, 5, 6, 7);
+});
+
var all = function(e) { return true; };
var none = function(e) { return false; };
diff --git a/test/script/assert.js b/test/script/assert.js
index 25bc2599..3656f86c 100644
--- a/test/script/assert.js
+++ b/test/script/assert.js
@@ -61,3 +61,22 @@ Object.defineProperty(this, "fail", {
}
}
});
+
+Object.defineProperty(this, "printError", {
+ configuable: true,
+ enumerable: false,
+ writable: true,
+ value: function (e) {
+ var msg = e.message;
+ var str = e.name + ':';
+ if (e.lineNumber > 0) {
+ str += e.lineNumber + ':';
+ }
+ if (e.columnNumber > 0) {
+ str += e.columnNumber + ':';
+ }
+ str += msg.substring(msg.indexOf(' ') + 1);
+ print(str);
+ }
+});
+
diff --git a/test/script/basic/JDK-8015355.js b/test/script/basic/JDK-8015355.js
index bc39d8d9..aa1a39de 100644
--- a/test/script/basic/JDK-8015355.js
+++ b/test/script/basic/JDK-8015355.js
@@ -28,10 +28,6 @@
* @run
*/
-function fail(msg) {
- print(msg);
-}
-
function check(callback) {
try {
callback();
diff --git a/test/script/basic/JDK-8019508.js b/test/script/basic/JDK-8019508.js
index d23035c6..88ecbec3 100644
--- a/test/script/basic/JDK-8019508.js
+++ b/test/script/basic/JDK-8019508.js
@@ -36,7 +36,7 @@ function checkObjLiteral(str) {
if (! (e instanceof SyntaxError)) {
fail("expected SyntaxError, got " + e);
}
- print(e.message.replace(/\\/g, '/'));
+ printError(e);
}
}
diff --git a/test/script/basic/JDK-8019508.js.EXPECTED b/test/script/basic/JDK-8019508.js.EXPECTED
index d5f81409..a3d883f0 100644
--- a/test/script/basic/JDK-8019508.js.EXPECTED
+++ b/test/script/basic/JDK-8019508.js.EXPECTED
@@ -1,12 +1,12 @@
-test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({,})
^
-test/script/basic/JDK-8019508.js#33<eval>:1:2 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({, a:2 })
^
-test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected property id but found ,
+SyntaxError:33:Expected property id but found ,
({a:3,,})
^
-test/script/basic/JDK-8019508.js#33<eval>:1:6 Expected comma but found ident
+SyntaxError:33:Expected comma but found ident
({a:3 b:2}
^
diff --git a/test/script/basic/JDK-8019553.js b/test/script/basic/JDK-8019553.js
index d7546187..bec3a528 100644
--- a/test/script/basic/JDK-8019553.js
+++ b/test/script/basic/JDK-8019553.js
@@ -33,7 +33,7 @@ function check(str) {
eval(str);
fail("SyntaxError expected for: " + str);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
}
diff --git a/test/script/basic/JDK-8019553.js.EXPECTED b/test/script/basic/JDK-8019553.js.EXPECTED
index 78d22bea..38e52866 100644
--- a/test/script/basic/JDK-8019553.js.EXPECTED
+++ b/test/script/basic/JDK-8019553.js.EXPECTED
@@ -1,12 +1,12 @@
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found +
+SyntaxError:33:Expected l-value but found +
++ +3
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
+SyntaxError:33:Expected l-value but found -
++ -7
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found +
+SyntaxError:33:Expected l-value but found +
-- +2
^
-SyntaxError: test/script/basic/JDK-8019553.js#33<eval>:1:3 Expected l-value but found -
+SyntaxError:33:Expected l-value but found -
-- -8
^
diff --git a/test/script/basic/JDK-8019791.js b/test/script/basic/JDK-8019791.js
index 75e92819..ad32ce3c 100644
--- a/test/script/basic/JDK-8019791.js
+++ b/test/script/basic/JDK-8019791.js
@@ -33,7 +33,7 @@ try {
eval('"" ~ ""');
print("FAILED: SyntaxError expected for: \"\" ~ \"\"");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
// Used to crash instead of SyntaxError
@@ -41,7 +41,7 @@ try {
eval("function() { if (1~0) return 0; return 1 }");
print("FAILED: SyntaxError expected for: if (1~0) ");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
// The following are valid, but used to crash
diff --git a/test/script/basic/JDK-8019791.js.EXPECTED b/test/script/basic/JDK-8019791.js.EXPECTED
index 5aec5909..b214b2c6 100644
--- a/test/script/basic/JDK-8019791.js.EXPECTED
+++ b/test/script/basic/JDK-8019791.js.EXPECTED
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/JDK-8019791.js#33<eval>:1:3 Expected ; but found ~
+SyntaxError:33:Expected ; but found ~
"" ~ ""
^
-SyntaxError: test/script/basic/JDK-8019791.js#41<eval>:1:18 Expected ) but found ~
+SyntaxError:41:Expected ) but found ~
function() { if (1~0) return 0; return 1 }
^
diff --git a/test/script/basic/JDK-8019805.js b/test/script/basic/JDK-8019805.js
index 70371fb8..7e3e25b5 100644
--- a/test/script/basic/JDK-8019805.js
+++ b/test/script/basic/JDK-8019805.js
@@ -32,5 +32,5 @@ try {
eval("for each(var v=0;false;);");
print("FAILED: for each(var v=0; false;); should have thrown error");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
diff --git a/test/script/basic/JDK-8019805.js.EXPECTED b/test/script/basic/JDK-8019805.js.EXPECTED
index 154c3326..76d335e4 100644
--- a/test/script/basic/JDK-8019805.js.EXPECTED
+++ b/test/script/basic/JDK-8019805.js.EXPECTED
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/JDK-8019805.js#32<eval>:1:16 for each can only be used with for..in
+SyntaxError:32:for each can only be used with for..in
for each(var v=0;false;);
^
diff --git a/test/script/basic/JDK-8023026.js b/test/script/basic/JDK-8023026.js
index 9080ec8c..0a6f0272 100644
--- a/test/script/basic/JDK-8023026.js
+++ b/test/script/basic/JDK-8023026.js
@@ -48,7 +48,7 @@ function checkIterations(obj) {
function(x) x*x));
}
-var array = new (Java.type("[I"))(4);
+var array = new (Java.type("int[]"))(4);
for (var i in array) {
array[i] = i;
}
diff --git a/test/script/basic/JDK-8024847.js b/test/script/basic/JDK-8024847.js
index 4a671ecd..2ead01fd 100644
--- a/test/script/basic/JDK-8024847.js
+++ b/test/script/basic/JDK-8024847.js
@@ -100,3 +100,9 @@ var obj = new JSObject() {
var jlist = Java.to(obj, java.util.List);
print(jlist instanceof java.util.List);
print(jlist);
+
+var obj = new JSObject() {
+ toNumber: function() { return 42; }
+};
+
+print(32 + obj);
diff --git a/test/script/basic/JDK-8024847.js.EXPECTED b/test/script/basic/JDK-8024847.js.EXPECTED
index 015183a0..16bff3e2 100644
--- a/test/script/basic/JDK-8024847.js.EXPECTED
+++ b/test/script/basic/JDK-8024847.js.EXPECTED
@@ -10,3 +10,4 @@ true
[hello, world]
true
[nashorn, js]
+74
diff --git a/test/script/basic/JDK-8025213.js b/test/script/basic/JDK-8025213.js
new file mode 100644
index 00000000..062a389e
--- /dev/null
+++ b/test/script/basic/JDK-8025213.js
@@ -0,0 +1,39 @@
+/*
+ * 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-8025213: Assignment marks variable as defined too early
+ *
+ * @test
+ * @run
+ */
+
+function test() {
+ if (String("")) {
+ var foo = 42;
+ }
+ foo = foo + 1;
+ print(foo);
+}
+
+test();
diff --git a/test/script/basic/JDK-8025213.js.EXPECTED b/test/script/basic/JDK-8025213.js.EXPECTED
new file mode 100644
index 00000000..736991a1
--- /dev/null
+++ b/test/script/basic/JDK-8025213.js.EXPECTED
@@ -0,0 +1 @@
+NaN
diff --git a/test/script/basic/JDK-8025488.js b/test/script/basic/JDK-8025488.js
new file mode 100644
index 00000000..8229b9fa
--- /dev/null
+++ b/test/script/basic/JDK-8025488.js
@@ -0,0 +1,43 @@
+/*
+ * 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-8025488: Error.captureStackTrace should not format error stack
+ *
+ * @test
+ * @run
+ */
+
+
+function MyError () {
+ Error.call(this);
+ Error.captureStackTrace(this);
+ this.arr = {};
+};
+
+MyError.prototype.toString = function() {
+ return this.arr.toString();
+}
+
+var e = new MyError();
+print(e.stack.replace(/\\/g, '/'));
diff --git a/test/script/basic/JDK-8025488.js.EXPECTED b/test/script/basic/JDK-8025488.js.EXPECTED
new file mode 100644
index 00000000..40b244a9
--- /dev/null
+++ b/test/script/basic/JDK-8025488.js.EXPECTED
@@ -0,0 +1,3 @@
+[object Object]
+ at MyError (test/script/basic/JDK-8025488.js:34)
+ at <program> (test/script/basic/JDK-8025488.js:42)
diff --git a/test/script/basic/JDK-8025515.js b/test/script/basic/JDK-8025515.js
new file mode 100644
index 00000000..f3d7cee4
--- /dev/null
+++ b/test/script/basic/JDK-8025515.js
@@ -0,0 +1,58 @@
+/*
+ * 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-8025515: Performance issues with Source.getLine()
+ *
+ * @test
+ * @run
+ */
+
+// Make sure synthetic names of anonymous functions have correct line numbers
+
+function testMethodName(f, expected) {
+ try {
+ f();
+ fail("expected error");
+ } catch (e) {
+ var stack = e.getStackTrace();
+ if (stack[0].methodName !== expected) {
+ fail("got " + stack[0].methodName + ", expected " + expected);
+ }
+ }
+}
+
+testMethodName(function() {
+ return a.b.c;
+}, "_L45");
+
+testMethodName(function() { throw new Error() }, "_L49");
+
+var f = (function() {
+ return function() { a.b.c; };
+})();
+testMethodName(f, "_L51$_L52");
+
+testMethodName((function() {
+ return function() { return a.b.c; };
+})(), "_L56$_L57");
diff --git a/test/script/basic/JDK-8025520.js b/test/script/basic/JDK-8025520.js
new file mode 100644
index 00000000..773a30ab
--- /dev/null
+++ b/test/script/basic/JDK-8025520.js
@@ -0,0 +1,50 @@
+/*
+ * 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-8025520: Array.prototype.slice should only copy defined elements
+ *
+ * @test
+ * @run
+ */
+
+var s = Array.prototype.slice.call({length: 6, 3: 1}, 2, 5);
+
+if (s.length != 3) {
+ fail("s.length != 3");
+}
+if (0 in s) {
+ fail("0 in s");
+}
+if (s.hasOwnProperty(0)) {
+ fail("s.hasOwnProperty(0)");
+}
+if (s[1] !== 1) {
+ fail("s[1] !== 1");
+}
+if (2 in s) {
+ fail("2 in s");
+}
+if (s.hasOwnProperty(2)) {
+ fail("s.hasOwnProperty(2)");
+}
diff --git a/test/script/basic/JDK-8025589.js b/test/script/basic/JDK-8025589.js
new file mode 100644
index 00000000..a74261c1
--- /dev/null
+++ b/test/script/basic/JDK-8025589.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-8025589: Array.prototype.shift should only copy defined elements in generic mode
+ *
+ * @test
+ * @run
+ */
+
+var s = {length: 4, 2: 1};
+Array.prototype.shift.call(s);
+
+if (s.length != 3) {
+ fail("s.length != 3");
+}
+if (0 in s) {
+ fail("0 in s");
+}
+if (s.hasOwnProperty(0)) {
+ fail("s.hasOwnProperty(0)");
+}
+if (s[1] !== 1) {
+ fail("s[1] !== 1");
+}
+if (2 in s) {
+ fail("2 in s");
+}
+if (s.hasOwnProperty(2)) {
+ fail("s.hasOwnProperty(2)");
+}
diff --git a/test/script/basic/JDK-8026008.js b/test/script/basic/JDK-8026008.js
new file mode 100644
index 00000000..20c1d5f0
--- /dev/null
+++ b/test/script/basic/JDK-8026008.js
@@ -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.
+ *
+ * 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-8026008: Constant folding removes var statement
+ *
+ * @test
+ * @run
+ */
+
+if (false) {
+ var x1 = 10;
+ if (false) {
+ var x2;
+ }
+} else {
+ print(x1, x2);
+}
+
+if (undefined) {
+ var z1;
+ if (null) {
+ var z2;
+ }
+}
+
+print(z1, z2);
+
+if (1) {
+ print(y1, y2);
+} else if (0) {
+ var y1 = 1;
+} else {
+ var y2 = 2
+}
diff --git a/test/script/basic/JDK-8026008.js.EXPECTED b/test/script/basic/JDK-8026008.js.EXPECTED
new file mode 100644
index 00000000..6bbb6d93
--- /dev/null
+++ b/test/script/basic/JDK-8026008.js.EXPECTED
@@ -0,0 +1,3 @@
+undefined undefined
+undefined undefined
+undefined undefined
diff --git a/test/script/basic/JDK-8026016.js b/test/script/basic/JDK-8026016.js
new file mode 100644
index 00000000..43f268d8
--- /dev/null
+++ b/test/script/basic/JDK-8026016.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-8026016: too many relinks dominate avatar.js http benchmark
+ *
+ * @test
+ * @run
+ */
+
+function accessMegamorphic() {
+ for (var i = 0; i < 26; i++) {
+ var o = {};
+ o[String.fromCharCode(i + 97)] = 1;
+ o._;
+ }
+}
+
+function invokeMegamorphic() {
+ for (var i = 0; i < 26; i++) {
+ var o = {};
+ o[String.fromCharCode(i + 97)] = 1;
+ try {
+ o._(i);
+ } catch (e) {
+ print(e);
+ }
+ }
+}
+
+Object.prototype.__noSuchProperty__ = function() {
+ print("no such property", Array.prototype.slice.call(arguments));
+};
+
+invokeMegamorphic();
+accessMegamorphic();
+
+Object.prototype.__noSuchMethod__ = function() {
+ print("no such method", Array.prototype.slice.call(arguments));
+};
+
+invokeMegamorphic();
+accessMegamorphic();
+
+Object.prototype.__noSuchMethod__ = "nofunction";
+
+invokeMegamorphic();
+accessMegamorphic();
diff --git a/test/script/basic/JDK-8026016.js.EXPECTED b/test/script/basic/JDK-8026016.js.EXPECTED
new file mode 100644
index 00000000..a2d23834
--- /dev/null
+++ b/test/script/basic/JDK-8026016.js.EXPECTED
@@ -0,0 +1,182 @@
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+TypeError: Cannot call undefined
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such method _,0
+no such method _,1
+no such method _,2
+no such method _,3
+no such method _,4
+no such method _,5
+no such method _,6
+no such method _,7
+no such method _,8
+no such method _,9
+no such method _,10
+no such method _,11
+no such method _,12
+no such method _,13
+no such method _,14
+no such method _,15
+no such method _,16
+no such method _,17
+no such method _,18
+no such method _,19
+no such method _,20
+no such method _,21
+no such method _,22
+no such method _,23
+no such method _,24
+no such method _,25
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+TypeError: Cannot call undefined
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
diff --git a/test/script/basic/JDK-8026033.js b/test/script/basic/JDK-8026033.js
new file mode 100644
index 00000000..4a5d8594
--- /dev/null
+++ b/test/script/basic/JDK-8026033.js
@@ -0,0 +1,39 @@
+/*
+ * 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-8026033: Switch should load expression even when there are no cases in it
+ *
+ * @test
+ * @run
+ */
+
+try {
+ (function() { switch(x) {} })();
+ fail("Should have thrown ReferenceError");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("ReferenceError expected, got " + e);
+ }
+ print(e);
+}
diff --git a/test/script/basic/JDK-8026033.js.EXPECTED b/test/script/basic/JDK-8026033.js.EXPECTED
new file mode 100644
index 00000000..c007ed7b
--- /dev/null
+++ b/test/script/basic/JDK-8026033.js.EXPECTED
@@ -0,0 +1 @@
+ReferenceError: "x" is not defined
diff --git a/test/script/basic/JDK-8026042.js b/test/script/basic/JDK-8026042.js
new file mode 100644
index 00000000..a853626f
--- /dev/null
+++ b/test/script/basic/JDK-8026042.js
@@ -0,0 +1,43 @@
+/*
+ * 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-8026042: FoldConstants need to guard against ArrayLiteralNode
+ *
+ * @test
+ * @run
+ */
+
+try {
+ if ([a]) {
+ print("fail");
+ }
+} catch (e) {
+ print(e);
+}
+
+try {
+ [a] ? print(1) : print(2);
+} catch (e) {
+ print(e);
+}
diff --git a/test/script/basic/JDK-8026042.js.EXPECTED b/test/script/basic/JDK-8026042.js.EXPECTED
new file mode 100644
index 00000000..aae23d09
--- /dev/null
+++ b/test/script/basic/JDK-8026042.js.EXPECTED
@@ -0,0 +1,2 @@
+ReferenceError: "a" is not defined
+ReferenceError: "a" is not defined
diff --git a/test/script/basic/JDK-8026048.js b/test/script/basic/JDK-8026048.js
new file mode 100644
index 00000000..33789fea
--- /dev/null
+++ b/test/script/basic/JDK-8026048.js
@@ -0,0 +1,37 @@
+/*
+ * 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-8026048: Function constructor should convert arguments to String before performing any syntax checks
+ *
+ * @test
+ * @run
+ */
+
+try {
+ Function("-", {toString:function(){throw "err"}})
+} catch (e) {
+ if (e !== "err") {
+ fail("err xpected, got " + e);
+ }
+}
diff --git a/test/script/basic/JDK-8026112.js b/test/script/basic/JDK-8026112.js
new file mode 100644
index 00000000..0e869f70
--- /dev/null
+++ b/test/script/basic/JDK-8026112.js
@@ -0,0 +1,31 @@
+/*
+ * 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-8026112: Function("with(x ? 1e81 : (x2.constructor = 0.1)){}") throws AssertionError: double is not compatible with object
+ *
+ * @test
+ * @run
+ */
+
+Function("with(x ? 1e81 : (x2.constructor = 0.1)){}")
diff --git a/test/script/basic/JDK-8026125.js b/test/script/basic/JDK-8026125.js
new file mode 100644
index 00000000..bb3a43d8
--- /dev/null
+++ b/test/script/basic/JDK-8026125.js
@@ -0,0 +1,32 @@
+/*
+ * 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-8026125: Array.prototype.slice.call(Java.type("java.util.HashMap")) throws ClassCastException: jdk.internal.dynalink.beans.StaticClass cannot be cast to jdk.nashorn.internal.runtime.ScriptObject
+ *
+ * @test
+ * @run
+ */
+
+Array.prototype.splice.call(Java.type("java.util.HashMap"))
+Array.prototype.slice.call(Java.type("java.util.HashMap"))
diff --git a/test/script/basic/JDK-8026137.js b/test/script/basic/JDK-8026137.js
new file mode 100644
index 00000000..4a19643f
--- /dev/null
+++ b/test/script/basic/JDK-8026137.js
@@ -0,0 +1,44 @@
+/*
+ * 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-8026137: Binary evaluation order in JavaScript is load load
+ * convert convert, not load convert load convert.
+ *
+ * @test
+ * @run
+ */
+
+try {
+ (function f() { Object.defineProperty({},"x",{get: function(){return {valueOf:function(){throw 0}}}}).x - Object.defineProperty({},"x",{get: function(){throw 1}}).x })()
+}
+catch (e) {
+ print(e);
+}
+
+try {
+ ({valueOf: function(){throw 0}}) - ({valueOf: function(){throw 1}} - 1)
+} catch (e) {
+ print(e);
+}
+
diff --git a/test/script/basic/JDK-8026137.js.EXPECTED b/test/script/basic/JDK-8026137.js.EXPECTED
new file mode 100644
index 00000000..6ed281c7
--- /dev/null
+++ b/test/script/basic/JDK-8026137.js.EXPECTED
@@ -0,0 +1,2 @@
+1
+1
diff --git a/test/script/basic/JDK-8026161.js b/test/script/basic/JDK-8026161.js
new file mode 100644
index 00000000..49f888b7
--- /dev/null
+++ b/test/script/basic/JDK-8026161.js
@@ -0,0 +1,32 @@
+/*
+ * 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-8026161: Don't narrow floating-point literals in the lexer
+ *
+ * @test
+ * @run
+ */
+
+print(new java.awt.Color(1, 1, 1)) // creates Color[r=1,g=1,b=1]
+print(new java.awt.Color(1.0, 1.0, 1.0)) // Color[r=255,g=255,b=255]
diff --git a/test/script/basic/JDK-8026161.js.EXPECTED b/test/script/basic/JDK-8026161.js.EXPECTED
new file mode 100644
index 00000000..c7b00b08
--- /dev/null
+++ b/test/script/basic/JDK-8026161.js.EXPECTED
@@ -0,0 +1,2 @@
+java.awt.Color[r=1,g=1,b=1]
+java.awt.Color[r=255,g=255,b=255]
diff --git a/test/script/basic/JDK-8026162.js b/test/script/basic/JDK-8026162.js
new file mode 100644
index 00000000..ccd6ee71
--- /dev/null
+++ b/test/script/basic/JDK-8026162.js
@@ -0,0 +1,48 @@
+/*
+ * 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-8026162: "this" in SAM adapter functions is wrong
+ *
+ * @test
+ * @run
+ */
+
+var global = this;
+
+new java.lang.Runnable(
+ function func() {
+ if (this !== global) {
+ fail("Expected 'this' to be global instance");
+ }
+ }
+).run();
+
+new java.lang.Runnable(
+ function func() {
+ 'use strict';
+ if (typeof this != 'undefined') {
+ fail("Expected 'undefined' to be global instance");
+ }
+ }
+).run();
diff --git a/test/script/basic/JDK-8026167.js b/test/script/basic/JDK-8026167.js
new file mode 100644
index 00000000..4959e62a
--- /dev/null
+++ b/test/script/basic/JDK-8026167.js
@@ -0,0 +1,50 @@
+/*
+ * 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-8026167: Class cache/reuse of 'eval' scripts results in ClassCastException in some cases.
+ *
+ * @test
+ * @run
+ */
+
+var m = new javax.script.ScriptEngineManager();
+var e = m.getEngineByName('js');
+
+// leave the whitespace - need both eval("e") at same column for this test!
+
+e.eval('function f(e) { eval("e") } f()');
+e.eval('function f() { var e = 33; eval("e") } f()');
+
+function f() {
+ Function.call.call(function x() { eval("x") }); eval("x")
+}
+
+try {
+ f();
+ fail("Should have thrown ReferenceError");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("ReferenceError expected but got " + e);
+ }
+}
diff --git a/test/script/basic/JDK-8026248.js b/test/script/basic/JDK-8026248.js
new file mode 100644
index 00000000..e54d3383
--- /dev/null
+++ b/test/script/basic/JDK-8026248.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-8026248: importClass has to be a varargs function
+ *
+ * @test
+ * @run
+ */
+
+load('nashorn:mozilla_compat.js')
+
+importClass(java.io.File, java.io.InputStream)
+
+print(File)
+print(InputStream)
+
+importClass(java.util.Map, java.util.HashMap, java.io.PrintStream)
+
+print(HashMap)
+print(Map)
+print(PrintStream)
+
+importClass.call(this, java.util.Collections, java.util.List);
+print(Collections)
+print(List)
+
+importClass.apply(this, [ java.util.Queue, java.math.BigInteger, java.math.BigDecimal ]);
+print(Queue)
+print(BigInteger)
+print(BigDecimal)
diff --git a/test/script/basic/JDK-8026248.js.EXPECTED b/test/script/basic/JDK-8026248.js.EXPECTED
new file mode 100644
index 00000000..361b8e17
--- /dev/null
+++ b/test/script/basic/JDK-8026248.js.EXPECTED
@@ -0,0 +1,10 @@
+[JavaClass java.io.File]
+[JavaClass java.io.InputStream]
+[JavaClass java.util.HashMap]
+[JavaClass java.util.Map]
+[JavaClass java.io.PrintStream]
+[JavaClass java.util.Collections]
+[JavaClass java.util.List]
+[JavaClass java.util.Queue]
+[JavaClass java.math.BigInteger]
+[JavaClass java.math.BigDecimal]
diff --git a/test/script/basic/JDK-8026264.js b/test/script/basic/JDK-8026264.js
new file mode 100644
index 00000000..b4de01d2
--- /dev/null
+++ b/test/script/basic/JDK-8026264.js
@@ -0,0 +1,54 @@
+/*
+ * 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-8026264: Getter, setter function name mangling issues
+ *
+ * @test
+ * @run
+ */
+
+var obj = {
+ get ":"(){},
+ set ":"(x){},
+ get ""(){},
+ set ""(x){}
+};
+
+var desc = Object.getOwnPropertyDescriptor(obj, ":");
+if (desc.get.name != ':') {
+ fail("getter name is expected to be ':' got " + desc.get.name);
+}
+
+if (desc.set.name != ':') {
+ fail("setter name is expected to be ':' got " + desc.set.name);
+}
+
+desc = Object.getOwnPropertyDescriptor(obj, "");
+if (desc.get.name != '') {
+ fail("getter name is expected to be '' got " + desc.get.name);
+}
+
+if (desc.set.name != '') {
+ fail("setter name is expected to be '' got " + desc.set.name);
+}
diff --git a/test/script/basic/JDK-8026292.js b/test/script/basic/JDK-8026292.js
new file mode 100644
index 00000000..740895f2
--- /dev/null
+++ b/test/script/basic/JDK-8026292.js
@@ -0,0 +1,65 @@
+/*
+ * 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-8026292: Megamorphic setter fails with boolean value
+ *
+ * @test
+ * @run
+ */
+
+function megamorphic(o) {
+ o.w = true;
+ if (!o.w)
+ throw new Error();
+}
+
+// Calls below must exceed megamorphic callsite threshhold
+for (var i = 0; i < 10; i++) {
+ megamorphic({a: 1});
+ megamorphic({b: 1});
+ megamorphic({c: 1});
+ megamorphic({d: 1});
+ megamorphic({e: 1});
+ megamorphic({f: 1});
+ megamorphic({g: 1});
+ megamorphic({h: 1});
+ megamorphic({i: 1});
+ megamorphic({j: 1});
+ megamorphic({k: 1});
+ megamorphic({l: 1});
+ megamorphic({m: 1});
+ megamorphic({n: 1});
+ megamorphic({o: 1});
+ megamorphic({p: 1});
+ megamorphic({q: 1});
+ megamorphic({r: 1});
+ megamorphic({s: 1});
+ megamorphic({t: 1});
+ megamorphic({u: 1});
+ megamorphic({v: 1});
+ megamorphic({w: 1});
+ megamorphic({x: 1});
+ megamorphic({y: 1});
+ megamorphic({z: 1});
+}
diff --git a/test/script/basic/JDK-8026302.js b/test/script/basic/JDK-8026302.js
new file mode 100644
index 00000000..786cc118
--- /dev/null
+++ b/test/script/basic/JDK-8026302.js
@@ -0,0 +1,48 @@
+/*
+ * 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-8026302: source representation of getter and setter methods is wrong
+ *
+ * @test
+ * @run
+ */
+
+var obj = {
+ get "foo"() {},
+ set "foo"(x) {},
+ get bar() {},
+ set bar(x) {},
+ get ":"() {},
+ set ":"(x) {},
+ get 12() {},
+ set 12(x) {},
+ get 1.8e-8() {},
+ set 1.8e-8(x) {}
+}
+
+for (var prop in obj) {
+ var desc = Object.getOwnPropertyDescriptor(obj, prop);
+ print(desc.get);
+ print(desc.set);
+}
diff --git a/test/script/basic/JDK-8026302.js.EXPECTED b/test/script/basic/JDK-8026302.js.EXPECTED
new file mode 100644
index 00000000..232edc00
--- /dev/null
+++ b/test/script/basic/JDK-8026302.js.EXPECTED
@@ -0,0 +1,10 @@
+get "foo"() {}
+set "foo"(x) {}
+get bar() {}
+set bar(x) {}
+get ":"() {}
+set ":"(x) {}
+get 12() {}
+set 12(x) {}
+get 1.8e-8() {}
+set 1.8e-8(x) {}
diff --git a/test/script/basic/JDK-8026317.js b/test/script/basic/JDK-8026317.js
new file mode 100644
index 00000000..57bea9cb
--- /dev/null
+++ b/test/script/basic/JDK-8026317.js
@@ -0,0 +1,63 @@
+/*
+ * 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-8026317: $ in the function name results in wrong function being invoked
+ *
+ * @test
+ * @run
+ */
+
+function case1() {
+ function g() {
+ return 0
+ }
+ function g() {
+ return 1
+ }
+ function g$1() {
+ return 2
+ }
+
+ return g$1()
+}
+
+print(case1());
+
+function case2() {
+ function g() {
+ return 0
+ }
+
+ var h = function g() {
+ return 1
+ }
+
+ function g$1() {
+ return 2
+ }
+
+ return h()
+}
+
+print(case2());
diff --git a/test/script/basic/JDK-8026317.js.EXPECTED b/test/script/basic/JDK-8026317.js.EXPECTED
new file mode 100644
index 00000000..5f1d0ece
--- /dev/null
+++ b/test/script/basic/JDK-8026317.js.EXPECTED
@@ -0,0 +1,2 @@
+2
+1
diff --git a/test/script/basic/JDK-8026367.js b/test/script/basic/JDK-8026367.js
new file mode 100644
index 00000000..c5e12358
--- /dev/null
+++ b/test/script/basic/JDK-8026367.js
@@ -0,0 +1,61 @@
+/*
+ * 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-8026367: Add a sync keyword to mozilla_compat
+ *
+ * @test
+ * @run
+ */
+
+if (typeof sync === "undefined") {
+ load("nashorn:mozilla_compat.js");
+}
+
+var obj = {
+ count: 0,
+ // Sync called with one argument will synchronize on this-object of invocation
+ inc: sync(function(d) {
+ this.count += d;
+ }),
+ // Pass explicit object to synchronize on as second argument
+ dec: sync(function(d) {
+ this.count -= d;
+ }, obj)
+};
+
+var t1 = new java.lang.Thread(function() {
+ for (var i = 0; i < 100000; i++) obj.inc(1);
+});
+var t2 = new java.lang.Thread(function() {
+ for (var i = 0; i < 100000; i++) obj.dec(1);
+});
+
+t1.start();
+t2.start();
+t1.join();
+t2.join();
+
+if (obj.count !== 0) {
+ throw new Error("Expected count == 0, got " + obj.count);
+}
diff --git a/test/script/basic/JDK-8026692.js b/test/script/basic/JDK-8026692.js
new file mode 100644
index 00000000..f9f0f38c
--- /dev/null
+++ b/test/script/basic/JDK-8026692.js
@@ -0,0 +1,32 @@
+/*
+ * 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-8026692: eval() throws NullPointerException with --compile-only
+ *
+ * @test
+ * @option --compile-only
+ * @run
+ */
+
+eval("");
diff --git a/test/script/basic/JDK-8026693.js b/test/script/basic/JDK-8026693.js
new file mode 100644
index 00000000..fd1dd5fa
--- /dev/null
+++ b/test/script/basic/JDK-8026693.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.
+ */
+
+/**
+ * JDK-8026693: getType() called on DISCARD node
+ *
+ * @test
+ * @run
+ */
+
+function f() {
+ if(x, y) z;
+}
diff --git a/test/script/basic/JDK-8026701.js b/test/script/basic/JDK-8026701.js
new file mode 100644
index 00000000..90a1739c
--- /dev/null
+++ b/test/script/basic/JDK-8026701.js
@@ -0,0 +1,72 @@
+/*
+ * 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-8026701: Array.prototype.splice is slow on dense arrays
+ *
+ * @test
+ * @run
+ */
+
+function testSplice(arr, e1, e2, e3) {
+ try {
+ print(arr);
+ print(arr.splice(3, 0, e1, e2, e3));
+ print(arr);
+ print(arr.splice(2, 3));
+ print(arr);
+ print(arr.splice(2, 3, arr[2], arr[3], arr[4]));
+ print(arr);
+ print(arr.splice(20, 10));
+ print(arr);
+ print(arr.splice(arr.length, 0, e1, e2, e3));
+ print(arr);
+ print(arr.splice(0, 2, arr[0], arr[1], arr[2], arr[3]));
+ print(arr);
+ } catch (error) {
+ print(error);
+ }
+}
+
+function convert(array, type) {
+ return (typeof Java === "undefined") ? array : Java.from(Java.to(array, type));
+}
+
+// run some splice tests on all dense array implementations
+testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2, -3);
+testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2, -3);
+testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, -2, -3);
+testSplice(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], -1, -2, -3);
+
+// test array conversion during splice
+testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, "-2", "-3");
+testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2.5, -3.5);
+testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, "-2", "-3");
+testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2.5, -3.5);
+testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, "-2", "-3");
+
+// test combination with defined elements
+testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13}), -1, -2, -3);
+testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false}), -1, -2, -3);
+testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, configurable: false}), -1, -2, -3);
+testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false, configurable: false}), -1, -2, -3);
diff --git a/test/script/basic/JDK-8026701.js.EXPECTED b/test/script/basic/JDK-8026701.js.EXPECTED
new file mode 100644
index 00000000..b70bbe25
--- /dev/null
+++ b/test/script/basic/JDK-8026701.js.EXPECTED
@@ -0,0 +1,147 @@
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10
+3,-1,-2.5
+1,2,-3.5,4,5,6,7,8,9,10
+-3.5,4,5
+1,2,-3.5,4,5,6,7,8,9,10
+
+1,2,-3.5,4,5,6,7,8,9,10
+
+1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
+1,2
+1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10
+3,-1,-2.5
+1,2,-3.5,4,5,6,7,8,9,10
+-3.5,4,5
+1,2,-3.5,4,5,6,7,8,9,10
+
+1,2,-3.5,4,5,6,7,8,9,10
+
+1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
+1,2
+1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
+1,2,3,4,5,6,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,6,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,6,7,8,9,10
+-3,4,5
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10
+
+1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
+1,2,3,4,5,13,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,13,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,13,7,8,9,10
+-3,4,5
+1,2,-3,4,5,13,7,8,9,10
+
+1,2,-3,4,5,13,7,8,9,10
+
+1,2,-3,4,5,13,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3
+1,2,3,4,5,13,7,8,9,10
+TypeError: "5" is not a writable property of [object Array]
+1,2,3,4,5,13,7,8,9,10
+
+1,2,3,-1,-2,-3,4,5,13,7,8,9,10
+3,-1,-2
+1,2,-3,4,5,13,7,8,9,10
+-3,4,5
+1,2,-3,4,5,13,7,8,9,10
+
+1,2,-3,4,5,13,7,8,9,10
+
+1,2,-3,4,5,13,7,8,9,10,-1,-2,-3
+1,2
+1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3
+1,2,3,4,5,13,7,8,9,10
+TypeError: "5" is not a writable property of [object Array]
diff --git a/test/script/basic/JDK-8026805.js b/test/script/basic/JDK-8026805.js
new file mode 100644
index 00000000..0133a0b6
--- /dev/null
+++ b/test/script/basic/JDK-8026805.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-8026805: Array.prototype.length doesn't work as expected
+ *
+ * @test
+ * @run
+ */
+
+if (Array.prototype.length !== 0) {
+ throw new Error("Initial length not 0");
+}
+
+Array.prototype[3] = 1;
+
+if (Array.prototype.length !== 4) {
+ throw new Error("length not updated to 4");
+}
+
+Array.prototype.length = 0;
+
+if (Array.prototype.length !== 0) {
+ throw new Error("length not reset to 0");
+}
+
+if (3 in Array.prototype) {
+ throw new Error("array element not deleted");
+}
diff --git a/test/script/basic/JDK-8026858.js b/test/script/basic/JDK-8026858.js
new file mode 100644
index 00000000..92562ac1
--- /dev/null
+++ b/test/script/basic/JDK-8026858.js
@@ -0,0 +1,66 @@
+/*
+ * 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-8026858: Array length does not handle defined properties correctly
+ *
+ * @test
+ * @run
+ */
+
+var arr = [];
+
+Object.defineProperty(arr, "3", {value: 1 /* configurable: false */});
+
+if (arr[3] != 1) {
+ throw new Error("arr[3] not defined");
+}
+
+if (arr.length !== 4) {
+ throw new Error("Array length not updated to 4");
+}
+
+Object.defineProperty(arr, "5", {value: 1, configurable: true});
+
+if (arr[5] != 1) {
+ throw new Error("arr[5] not defined");
+}
+
+if (arr.length !== 6) {
+ throw new Error("Array length not updated to 4");
+}
+
+arr.length = 0;
+
+if (5 in arr) {
+ throw new Error("configurable element was not deleted");
+}
+
+if (arr[3] != 1) {
+ throw new Error("non-configurable element was deleted");
+}
+
+if (arr.length !== 4) {
+ throw new Error("Array length not set");
+}
+
diff --git a/test/script/basic/JDK-8026955.js b/test/script/basic/JDK-8026955.js
new file mode 100644
index 00000000..a54e3d96
--- /dev/null
+++ b/test/script/basic/JDK-8026955.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-8026955: for-in should convert primitive values to object
+ *
+ * @test
+ * @run
+ */
+
+Object.prototype[4] = "world";
+String.prototype[3] = "hello";
+Number.prototype[3] = "hello";
+Boolean.prototype[3] = "hello";
+
+function testForIn(x) {
+ for (var i in x) {
+ print(i, x[i]);
+ }
+ for each (var i in x) {
+ print(i);
+ }
+}
+
+testForIn("abc");
+testForIn(false);
+testForIn(3);
+testForIn(null);
+testForIn();
+testForIn(String.prototype);
+
diff --git a/test/script/basic/JDK-8026955.js.EXPECTED b/test/script/basic/JDK-8026955.js.EXPECTED
new file mode 100644
index 00000000..3852d5ab
--- /dev/null
+++ b/test/script/basic/JDK-8026955.js.EXPECTED
@@ -0,0 +1,22 @@
+0 a
+1 b
+2 c
+3 hello
+4 world
+a
+b
+c
+hello
+world
+3 hello
+4 world
+hello
+world
+3 hello
+4 world
+hello
+world
+3 hello
+4 world
+hello
+world
diff --git a/test/script/basic/JDK-8027016.js b/test/script/basic/JDK-8027016.js
new file mode 100644
index 00000000..f84050fb
--- /dev/null
+++ b/test/script/basic/JDK-8027016.js
@@ -0,0 +1,42 @@
+/*
+ * 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-8027016: Array.prototype.indexOf should return -1 when array is of length zero
+ *
+ * @test
+ * @run
+ */
+
+var res = [].indexOf(null, {valueOf:function(){throw "not reached"}});
+if (res != -1) {
+ fail("expected -1 on indexOf on empty array");
+}
+
+// add index beyond length check as well
+
+res = [].indexOf(null, 1);
+if (res != -1) {
+ fail("expected -1 on indexOf on empty array");
+}
+
diff --git a/test/script/basic/JDK-8027024.js b/test/script/basic/JDK-8027024.js
new file mode 100644
index 00000000..890c6917
--- /dev/null
+++ b/test/script/basic/JDK-8027024.js
@@ -0,0 +1,58 @@
+/*
+ * 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-8027024: String.prototype.charAt and charCodeAt do not evaluate 'self' and 'pos' arguments in right order
+ *
+ * @test
+ * @run
+ */
+
+
+String.prototype.charAt.call(
+ {
+ toString: function() {
+ print("charAt.self.toString");
+ }
+ },
+
+ {
+ valueOf: function() {
+ print("charAt.pos.valueOf");
+ }
+ }
+);
+
+String.prototype.charCodeAt.call(
+ {
+ toString: function() {
+ print("charCodeAt.self.toString");
+ }
+ },
+
+ {
+ valueOf: function() {
+ print("charCodeAt.pos.valueOf");
+ }
+ }
+);
diff --git a/test/script/basic/JDK-8027024.js.EXPECTED b/test/script/basic/JDK-8027024.js.EXPECTED
new file mode 100644
index 00000000..9793e73a
--- /dev/null
+++ b/test/script/basic/JDK-8027024.js.EXPECTED
@@ -0,0 +1,4 @@
+charAt.self.toString
+charAt.pos.valueOf
+charCodeAt.self.toString
+charCodeAt.pos.valueOf
diff --git a/test/script/basic/JDK-8027042.js b/test/script/basic/JDK-8027042.js
new file mode 100644
index 00000000..eea6373b
--- /dev/null
+++ b/test/script/basic/JDK-8027042.js
@@ -0,0 +1,58 @@
+/*
+ * 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-8027042: Evaluation order for binary operators can be improved
+ *
+ * @test
+ * @run
+ */
+
+// var with getter side effect
+Object.defineProperty(this, "a", { get: function() {print("get a"); return 1; }});
+
+// var with both getter and conversion side effect
+Object.defineProperty(this, "b", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }});
+
+(function() {
+ // var with toPrimitive conversion side effect
+ var c = {valueOf: function() { print("conv c"); return 100; }};
+
+ print(b + (c + a));
+ print(b + (c + b));
+ print(b + (a + b));
+ print(b + (b + c));
+ print(b + (b + c));
+ print(b + (c + (a - b)));
+ print(b + (c + (c - b)));
+ print(b + (c + (b - c)));
+ print(b + (b + (a ? 2 : 3)));
+ print(b + (b + (b ? 2 : 3)));
+ print(b + (b + (c ? 2 : 3)));
+ print(b + ((-c) + (-a)));
+ print(b + ((-c) + (-b)));
+ print(b + ((-c) + (-c)));
+ try { print(b + new a); } catch (e) {}
+ try { print(b + new b); } catch (e) {}
+ try { print(b + new c); } catch (e) {}
+})();
diff --git a/test/script/basic/JDK-8027042.js.EXPECTED b/test/script/basic/JDK-8027042.js.EXPECTED
new file mode 100644
index 00000000..25b34e61
--- /dev/null
+++ b/test/script/basic/JDK-8027042.js.EXPECTED
@@ -0,0 +1,88 @@
+get b
+get a
+conv c
+conv b
+111
+get b
+get b
+conv c
+conv b
+conv b
+120
+get b
+get a
+get b
+conv b
+conv b
+21
+get b
+get b
+conv b
+conv c
+conv b
+120
+get b
+get b
+conv b
+conv c
+conv b
+120
+get b
+get a
+get b
+conv b
+conv c
+conv b
+101
+get b
+get b
+conv c
+conv b
+conv c
+conv b
+200
+get b
+get b
+conv b
+conv c
+conv c
+conv b
+20
+get b
+get b
+get a
+conv b
+conv b
+22
+get b
+get b
+get b
+conv b
+conv b
+22
+get b
+get b
+conv b
+conv b
+22
+get b
+conv c
+get a
+conv b
+-91
+get b
+conv c
+get b
+conv b
+conv b
+-100
+get b
+conv c
+conv c
+conv b
+-190
+get b
+get a
+get b
+get b
+get b
diff --git a/test/script/basic/JDK-8027236.js b/test/script/basic/JDK-8027236.js
new file mode 100644
index 00000000..02f9e8d8
--- /dev/null
+++ b/test/script/basic/JDK-8027236.js
@@ -0,0 +1,37 @@
+/*
+ * 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-8027236: Ensure ScriptObject and ConsString aren't visible to Java
+ *
+ * @test
+ * @run
+ */
+
+// Check that ConsString is flattened
+var m = new java.util.HashMap()
+var x = "f"
+x += "oo"
+m.put(x, "bar")
+print(m.get("foo"))
+// Note: many more tests are run by the JavaExportImportTest TestNG class.
diff --git a/test/script/basic/JDK-8027236.js.EXPECTED b/test/script/basic/JDK-8027236.js.EXPECTED
new file mode 100644
index 00000000..5716ca59
--- /dev/null
+++ b/test/script/basic/JDK-8027236.js.EXPECTED
@@ -0,0 +1 @@
+bar
diff --git a/test/script/basic/JDK-8027562.js b/test/script/basic/JDK-8027562.js
new file mode 100644
index 00000000..950584b4
--- /dev/null
+++ b/test/script/basic/JDK-8027562.js
@@ -0,0 +1,39 @@
+/*
+ * 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-8027562: eval should load second and subsequent arguments for side effect
+ *
+ * @test
+ * @run
+ */
+
+try {
+ eval("", x);
+ fail("should have thrown ReferenceError for 'x'");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("Expected ReferenceError, got " + e);
+ }
+ print(e);
+}
diff --git a/test/script/basic/JDK-8027562.js.EXPECTED b/test/script/basic/JDK-8027562.js.EXPECTED
new file mode 100644
index 00000000..c007ed7b
--- /dev/null
+++ b/test/script/basic/JDK-8027562.js.EXPECTED
@@ -0,0 +1 @@
+ReferenceError: "x" is not defined
diff --git a/test/script/basic/JDK-8027700.js b/test/script/basic/JDK-8027700.js
new file mode 100644
index 00000000..4c5445d8
--- /dev/null
+++ b/test/script/basic/JDK-8027700.js
@@ -0,0 +1,54 @@
+/*
+ * 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-8027700: function redeclaration checks missing for declaration binding instantiation
+ *
+ * @test
+ * @run
+ */
+
+Object.defineProperty(this,"x", {
+ value:0,
+ writable:true,
+ enumerable:false
+})
+
+try {
+ eval("function x() {}");
+ fail("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected but got " + e);
+ }
+}
+
+Object.defineProperty(this, "foo", { value:0 })
+try {
+ eval("function foo() {}");
+ fail("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected but got " + e);
+ }
+}
diff --git a/test/script/basic/JDK-8027753.js b/test/script/basic/JDK-8027753.js
new file mode 100644
index 00000000..2af0baad
--- /dev/null
+++ b/test/script/basic/JDK-8027753.js
@@ -0,0 +1,50 @@
+/*
+ * 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-8027753: Support ScriptObject to JSObject, ScriptObjectMirror, Map, Bindings auto-conversion as well as explicit wrap, unwrap
+ *
+ * @test
+ * @run
+ */
+
+var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils");
+var ScriptObjectMirror = Java.type("jdk.nashorn.api.scripting.ScriptObjectMirror");
+
+var obj = { foo: 34, bar: 'hello' };
+
+var wrapped = ScriptUtils.wrap(obj);
+if (! (wrapped instanceof ScriptObjectMirror)) {
+ fail("ScriptUtils.wrap does not return a ScriptObjectMirror");
+}
+
+print("wrapped.foo = " + wrapped.foo);
+print("wrapped.bar = " + wrapped.bar);
+
+var unwrapped = ScriptUtils.unwrap(wrapped);
+if (! (unwrapped instanceof Object)) {
+ fail("ScriptUtils.unwrap does not return a ScriptObject");
+}
+
+// same object unwrapped?
+print(unwrapped === obj);
diff --git a/test/script/basic/JDK-8027753.js.EXPECTED b/test/script/basic/JDK-8027753.js.EXPECTED
new file mode 100644
index 00000000..30a8779e
--- /dev/null
+++ b/test/script/basic/JDK-8027753.js.EXPECTED
@@ -0,0 +1,3 @@
+wrapped.foo = 34
+wrapped.bar = hello
+true
diff --git a/test/script/basic/JDK-8027828.js b/test/script/basic/JDK-8027828.js
new file mode 100644
index 00000000..ab60938b
--- /dev/null
+++ b/test/script/basic/JDK-8027828.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-8027828: ClassCastException when converting return value of a Java method to boolean
+ *
+ * @test
+ * @run
+ */
+
+var x = new java.util.HashMap()
+x.put('test', new java.io.File('test'))
+if (x.get("test")) {
+ print('Found!')
+}
diff --git a/test/script/basic/JDK-8027828.js.EXPECTED b/test/script/basic/JDK-8027828.js.EXPECTED
new file mode 100644
index 00000000..7a8c9edc
--- /dev/null
+++ b/test/script/basic/JDK-8027828.js.EXPECTED
@@ -0,0 +1 @@
+Found!
diff --git a/test/script/basic/JDK-8028020.js b/test/script/basic/JDK-8028020.js
new file mode 100644
index 00000000..4dfa0cad
--- /dev/null
+++ b/test/script/basic/JDK-8028020.js
@@ -0,0 +1,40 @@
+/*
+ * 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-8028020: Function parameter as last expression in comma in return value causes bad type calculation
+ *
+ * @test
+ * @run
+ */
+
+function f(x) {
+ return 1, x
+}
+
+function g(x, y) {
+ return x, y
+}
+
+print(f("'1, x' works."))
+print(g(42, "'x, y' works too."))
diff --git a/test/script/basic/JDK-8028020.js.EXPECTED b/test/script/basic/JDK-8028020.js.EXPECTED
new file mode 100644
index 00000000..816a21ce
--- /dev/null
+++ b/test/script/basic/JDK-8028020.js.EXPECTED
@@ -0,0 +1,2 @@
+'1, x' works.
+'x, y' works too.
diff --git a/test/script/basic/NASHORN-100.js b/test/script/basic/NASHORN-100.js
index fdea1cf0..df81284d 100644
--- a/test/script/basic/NASHORN-100.js
+++ b/test/script/basic/NASHORN-100.js
@@ -35,5 +35,5 @@ try {
if (! (e instanceof SyntaxError)) {
fail("#2 expected SyntaxError got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
diff --git a/test/script/basic/NASHORN-100.js.EXPECTED b/test/script/basic/NASHORN-100.js.EXPECTED
index d183bb33..e9c5a253 100644
--- a/test/script/basic/NASHORN-100.js.EXPECTED
+++ b/test/script/basic/NASHORN-100.js.EXPECTED
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/NASHORN-100.js#32<eval>:1:0 Invalid return statement
+SyntaxError:32:Invalid return statement
return;
^
diff --git a/test/script/basic/NASHORN-293.js b/test/script/basic/NASHORN-293.js
index cd83ec46..013714b8 100644
--- a/test/script/basic/NASHORN-293.js
+++ b/test/script/basic/NASHORN-293.js
@@ -40,15 +40,13 @@ for (var i = 0; i < 3; i++) {
try {
eval(src);
} catch (e) {
- var location = e.fileName ? e.fileName.slice(-9) : "unknown source";
- print(e.name, "@", location);
+ printError(e);
}
}
for (var i = 0; i < 3; i++) {
try {
eval(src);
} catch (e) {
- var location = e.fileName ? e.fileName.slice(-9) : "unknown source";
- print(e.name, "@", location);
+ printError(e);
}
}
diff --git a/test/script/basic/NASHORN-293.js.EXPECTED b/test/script/basic/NASHORN-293.js.EXPECTED
index 68278106..90fe5f08 100644
--- a/test/script/basic/NASHORN-293.js.EXPECTED
+++ b/test/script/basic/NASHORN-293.js.EXPECTED
@@ -1,9 +1,9 @@
hello
hello
hello
-TypeError @ #41<eval>
-TypeError @ #41<eval>
-TypeError @ #41<eval>
-TypeError @ #49<eval>
-TypeError @ #49<eval>
-TypeError @ #49<eval>
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
+TypeError:1:read property "foo" from undefined
diff --git a/test/script/basic/NASHORN-397.js b/test/script/basic/NASHORN-397.js
index e9484bc0..63e7b3ac 100644
--- a/test/script/basic/NASHORN-397.js
+++ b/test/script/basic/NASHORN-397.js
@@ -35,11 +35,8 @@ if (typeof (5).x !== 'number') {
fail("typeof(5).x is not 'number'");
}
-// It is function because PrintStream implements Closeable, which is
-// marked with @FunctionalInterface. Yes, this means calling a stream
-// like "stream()" closes it.
-if (typeof (java.lang.System.out) != 'function') {
- fail("typeof java.lang.System.out is not 'object'");
+if (typeof (java.net.Proxy.NO_PROXY) != 'object') {
+ fail("typeof java.net.Proxy.NO_PROXY is not 'object'");
}
if (typeof (java.lang.Math.PI) != 'number') {
diff --git a/test/script/basic/NASHORN-40.js b/test/script/basic/NASHORN-40.js
index f031730b..34331ef2 100644
--- a/test/script/basic/NASHORN-40.js
+++ b/test/script/basic/NASHORN-40.js
@@ -31,11 +31,11 @@
try {
eval("print(.foo)");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval(".bar = 3423;");
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
diff --git a/test/script/basic/NASHORN-40.js.EXPECTED b/test/script/basic/NASHORN-40.js.EXPECTED
index 0e03cab3..94f15980 100644
--- a/test/script/basic/NASHORN-40.js.EXPECTED
+++ b/test/script/basic/NASHORN-40.js.EXPECTED
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/NASHORN-40.js#32<eval>:1:6 Expected an operand but found .
+SyntaxError:32:Expected an operand but found .
print(.foo)
^
-SyntaxError: test/script/basic/NASHORN-40.js#38<eval>:1:0 Expected an operand but found .
+SyntaxError:38:Expected an operand but found .
.bar = 3423;
^
diff --git a/test/script/basic/NASHORN-51.js b/test/script/basic/NASHORN-51.js
index bc41d79b..45d00e9e 100644
--- a/test/script/basic/NASHORN-51.js
+++ b/test/script/basic/NASHORN-51.js
@@ -35,28 +35,28 @@ for (i in literals) {
eval(literals[i] + "++");
print("ERROR!! post increment : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval(literals[i] + "--");
print("ERROR!! post decrement : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval("++" + literals[i]);
print("ERROR!! pre increment : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
eval("--" + literals[i]);
print("ERROR!! pre decrement : " + literals[i]);
} catch (e) {
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
}
diff --git a/test/script/basic/NASHORN-51.js.EXPECTED b/test/script/basic/NASHORN-51.js.EXPECTED
index 9479f7e1..52013856 100644
--- a/test/script/basic/NASHORN-51.js.EXPECTED
+++ b/test/script/basic/NASHORN-51.js.EXPECTED
@@ -1,72 +1,72 @@
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
1++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
1--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++1
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--1
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
0++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
0--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++0
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--0
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
3.14++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
3.14--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++3.14
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--3.14
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
true++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
true--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++true
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--true
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
false++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
false--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++false
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--false
^
-ReferenceError: test/script/basic/NASHORN-51.js#35<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:35:Invalid left hand side for assignment
null++
^
-ReferenceError: test/script/basic/NASHORN-51.js#42<eval>:1:0 Invalid left hand side for assignment
+ReferenceError:42:Invalid left hand side for assignment
null--
^
-ReferenceError: test/script/basic/NASHORN-51.js#49<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:49:Invalid left hand side for assignment
++null
^
-ReferenceError: test/script/basic/NASHORN-51.js#56<eval>:1:2 Invalid left hand side for assignment
+ReferenceError:56:Invalid left hand side for assignment
--null
^
diff --git a/test/script/basic/NASHORN-98.js b/test/script/basic/NASHORN-98.js
index 3e50cf56..9e341e0c 100644
--- a/test/script/basic/NASHORN-98.js
+++ b/test/script/basic/NASHORN-98.js
@@ -34,7 +34,7 @@ try {
if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
try {
@@ -43,5 +43,5 @@ try {
if (! (e instanceof SyntaxError)) {
fail("syntax error expected here got " + e);
}
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
diff --git a/test/script/basic/NASHORN-98.js.EXPECTED b/test/script/basic/NASHORN-98.js.EXPECTED
index 93a89364..a43935bf 100644
--- a/test/script/basic/NASHORN-98.js.EXPECTED
+++ b/test/script/basic/NASHORN-98.js.EXPECTED
@@ -1,6 +1,6 @@
-SyntaxError: test/script/basic/NASHORN-98.js#32<eval>:1:13 Expected comma but found decimal
+SyntaxError:32:Expected comma but found decimal
var x = [ 23 34 ]
^
-SyntaxError: test/script/basic/NASHORN-98.js#41<eval>:1:18 Expected comma but found ident
+SyntaxError:41:Expected comma but found ident
var x = { foo: 33 bar: 'hello' }
^
diff --git a/test/script/basic/convert.js b/test/script/basic/convert.js
new file mode 100644
index 00000000..8d11d122
--- /dev/null
+++ b/test/script/basic/convert.js
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/**
+ * Tests for convert method of ScriptUtils.
+ *
+ * @test
+ * @run
+ */
+
+var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils");
+obj = { valueOf: function() { print("hello"); return 43.3; } };
+
+// object to double
+print(ScriptUtils.convert(obj, java.lang.Number.class));
+
+// array to List
+var arr = [3, 44, 23, 33];
+var list = ScriptUtils.convert(arr, java.util.List.class);
+print(list instanceof java.util.List)
+print(list);
+
+// object to Map
+obj = { foo: 333, bar: 'hello'};
+var map = ScriptUtils.convert(obj, java.util.Map.class);
+print(map instanceof java.util.Map);
+for (m in map) {
+ print(m + " " + map[m]);
+}
+
+// object to String
+obj = { toString: function() { print("in toString"); return "foo" } };
+print(ScriptUtils.convert(obj, java.lang.String.class));
+
+// array to Java array
+var jarr = ScriptUtils.convert(arr, Java.type("int[]"));
+print(jarr instanceof Java.type("int[]"));
+for (i in jarr) {
+ print(jarr[i]);
+}
+
diff --git a/test/script/basic/convert.js.EXPECTED b/test/script/basic/convert.js.EXPECTED
new file mode 100644
index 00000000..e83faebd
--- /dev/null
+++ b/test/script/basic/convert.js.EXPECTED
@@ -0,0 +1,14 @@
+hello
+43.3
+true
+[3, 44, 23, 33]
+true
+foo 333
+bar hello
+in toString
+foo
+true
+3
+44
+23
+33
diff --git a/test/script/basic/eval.js b/test/script/basic/eval.js
index bd63068c..3d66c028 100644
--- a/test/script/basic/eval.js
+++ b/test/script/basic/eval.js
@@ -69,5 +69,5 @@ try {
eval("print('hello)");
} catch (e) {
print("is syntax error? " + (e instanceof SyntaxError));
- print(e.toString().replace(/\\/g, '/'));
+ printError(e);
}
diff --git a/test/script/basic/eval.js.EXPECTED b/test/script/basic/eval.js.EXPECTED
index 3ab2f3da..7fe97ef6 100644
--- a/test/script/basic/eval.js.EXPECTED
+++ b/test/script/basic/eval.js.EXPECTED
@@ -10,6 +10,6 @@ eval.length 1
100
3300
is syntax error? true
-SyntaxError: test/script/basic/eval.js#69<eval>:1:13 Missing close quote
+SyntaxError:69:Missing close quote
print('hello)
^
diff --git a/test/script/basic/objects.js.EXPECTED b/test/script/basic/objects.js.EXPECTED
index a6bedc09..d59daa87 100644
--- a/test/script/basic/objects.js.EXPECTED
+++ b/test/script/basic/objects.js.EXPECTED
@@ -29,18 +29,18 @@ abc is writable? undefined
abc is configurable? true
abc is enumerable? true
abc's value = undefined
-abc's get = abc() { return "abc"; }
+abc's get = get abc() { return "abc"; }
abc's set = undefined
xyz is writable? undefined
xyz is configurable? true
xyz is enumerable? true
xyz's value = undefined
xyz's get = undefined
-xyz's set = xyz(val) { print(val); }
+xyz's set = set xyz(val) { print(val); }
hey is writable? undefined
hey is configurable? true
hey is enumerable? true
hey's value = undefined
-hey's get = hey() { return "hey"; }
-hey's set = hey(val) { print(val); }
+hey's get = get hey() { return "hey"; }
+hey's set = set hey(val) { print(val); }
undefined
diff --git a/test/script/error/JDK-8026039.js b/test/script/error/JDK-8026039.js
new file mode 100644
index 00000000..f37d9bdd
--- /dev/null
+++ b/test/script/error/JDK-8026039.js
@@ -0,0 +1,32 @@
+/*
+ * 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-8026039: future strict names are allowed as function name and argument name of a strict function
+ *
+ * @test/compile-error
+ */
+
+function public() {"use strict"}
+
+function f(public) {"use strict"}
diff --git a/test/script/error/JDK-8026039.js.EXPECTED b/test/script/error/JDK-8026039.js.EXPECTED
new file mode 100644
index 00000000..cde398f3
--- /dev/null
+++ b/test/script/error/JDK-8026039.js.EXPECTED
@@ -0,0 +1,9 @@
+test/script/error/JDK-8026039.js:30:9 "public" cannot be used as function name in strict mode
+function public() {"use strict"}
+ ^
+test/script/error/JDK-8026039.js:32:11 Expected ident but found public
+function f(public) {"use strict"}
+ ^
+test/script/error/JDK-8026039.js:33:0 Expected } but found eof
+
+^
diff --git a/test/script/jfx.js b/test/script/jfx.js
new file mode 100644
index 00000000..5962b5d0
--- /dev/null
+++ b/test/script/jfx.js
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * Base library for JavaFX canvas run by Nashorn testing.
+ * @subtest
+ *
+ *
+ */
+
+var System = Java.type("java.lang.System");
+var AWTImage = Java.type("org.jemmy.image.AWTImage");
+var PNGDecoder = Java.type("org.jemmy.image.PNGDecoder");
+var JemmyFxRoot = Java.type("org.jemmy.fx.Root");
+var AWTRobotCapturer = Java.type("org.jemmy.image.AWTRobotCapturer");
+var ByWindowType = Java.type("org.jemmy.fx.ByWindowType");
+var Scene = Java.type("javafx.scene.Scene");
+var Stage = Java.type("javafx.stage.Stage");
+var File = Java.type("java.io.File");
+var OSInfo = Java.type("sun.awt.OSInfo");
+var OSType = Java.type("sun.awt.OSInfo.OSType");
+var StringBuffer = Java.type("java.lang.StringBuffer");
+var Paint = Java.type("javafx.scene.paint.Paint");
+var Color = Java.type("javafx.scene.paint.Color");
+var Image = Java.type("javafx.scene.image.Image");
+var Canvas = Java.type("javafx.scene.canvas.Canvas");
+var BorderPane = Java.type("javafx.scene.layout.BorderPane");
+var StackPane = Java.type("javafx.scene.layout.StackPane");
+var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap");
+var Platform = Java.type("javafx.application.Platform");
+var Runnable = Java.type("java.lang.Runnable");
+var RunnableExtend = Java.extend(Runnable);
+var AnimationTimer = Java.type("javafx.animation.AnimationTimer");
+var AnimationTimerExtend = Java.extend(AnimationTimer);
+var Timer = Java.type("java.util.Timer");
+var TimerTask = Java.type("java.util.TimerTask");
+
+var TESTNAME = "test";
+var fsep = System.getProperty("file.separator");
+
+function checkImageAndExit() {
+ var raceTimer = new Timer(true);
+ var timerTask = new TimerTask() {
+ run: function run() {
+ var tmpdir = System.getProperty("java.io.tmpdir");
+ var timenow = (new Date()).getTime();
+ var scrShotTmp = tmpdir + fsep + "screenshot" + timenow +".png";
+ var goldenImageDir = __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden";
+ makeScreenShot(scrShotTmp);
+ var dupImg = isDuplicateImages(scrShotTmp, goldenImageDir);
+ (new File(scrShotTmp)).delete();
+ if (!dupImg) System.err.println("ERROR: screenshot does not match the golden image");
+ exit(0);
+ }
+ };
+ raceTimer.schedule(timerTask, 100);
+}
+
+function makeScreenShot(shootToImg) {
+ JemmyFxRoot.ROOT.getEnvironment().setImageCapturer(new AWTRobotCapturer());
+ var wrap = JemmyFxRoot.ROOT.lookup(new ByWindowType($STAGE.class)).lookup(Scene.class).wrap(0);
+ var imageJemmy = wrap.getScreenImage();
+ imageJemmy.save(shootToImg);
+}
+
+function isDuplicateImages(screenShot, goldenDir) {
+ var f1 = new File(screenShot);
+ var f2;
+ var sb = new StringBuffer(goldenDir);
+ if (OSInfo.getOSType() == OSType.WINDOWS) {
+ f2 = new File(sb.append(fsep + "windows.png").toString());
+ } else if (OSInfo.getOSType() == OSType.LINUX) {
+ f2 = new File(sb.append(fsep + "linux.png").toString());
+ } else if (OSInfo.getOSType() == OSType.MACOSX) {
+ f2 = new File(sb.append(fsep + "macosx.png").toString());
+ }
+ if (f1.exists() && f2.exists()) {
+ var image1 = new AWTImage(PNGDecoder.decode(f1.getAbsolutePath()));
+ var image2 = new AWTImage(PNGDecoder.decode(f2.getAbsolutePath()));
+ return image1.compareTo(image2) == null ? true : false;
+ }
+ return false;
+}
diff --git a/test/script/jfx/flyingimage.js b/test/script/jfx/flyingimage.js
new file mode 100644
index 00000000..844a0fc3
--- /dev/null
+++ b/test/script/jfx/flyingimage.js
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * Testing JavaFX canvas run by Nashorn.
+ *
+ * @test/nocompare
+ * @run
+ * @fork
+ */
+
+TESTNAME = "flyingimage";
+
+var WIDTH = 800;
+var HEIGHT = 600;
+var canvas = new Canvas(WIDTH, HEIGHT);
+function fileToURL(file) {
+ return new File(file).toURI().toURL().toExternalForm();
+}
+var imageUrl = fileToURL(__DIR__ + "flyingimage/flyingimage.png");
+var img = new Image(imageUrl);
+var isFrameRendered = false;
+function renderFrame() {
+ var t = frame;
+ var gc = canvas.graphicsContext2D;
+ gc.setFill(Color.web("#cccccc"));
+ gc.fillRect(0, 0, WIDTH, HEIGHT);
+ gc.setStroke(Color.web("#000000"));
+ gc.setLineWidth(1);
+ gc.strokeRect(5, 5, WIDTH - 10, HEIGHT - 10);
+ var c = 200;
+ var msc= 0.5 * HEIGHT / img.height;
+ var sp0 = 0.003;
+ for (var h = 0; h < c; h++) {
+ gc.setTransform(1, 0, 0, 1, 0, 0);
+ var yh = h / (c - 1);
+ gc.translate((0.5 + Math.sin(t * sp0 + h * 0.1) / 3) * WIDTH, 25 + (HEIGHT * 3 / 4 - 40) * (yh * yh));
+ var sc = 30 / img.height + msc * yh * yh;
+ gc.rotate(90 * Math.sin(t * sp0 + h * 0.1 + Math.PI));
+ gc.scale(sc, sc);
+ gc.drawImage(img, -img.width / 2, -img.height / 2);
+ }
+ gc.setTransform(1, 0, 0, 1, 0, 0);
+ isFrameRendered = true;
+}
+var stack = new StackPane();
+var pane = new BorderPane();
+pane.setCenter(canvas);
+stack.getChildren().add(pane);
+$STAGE.scene = new Scene(stack);
+var frame = 0;
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 200) {
+ renderFrame();
+ frame++;
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
+
diff --git a/test/script/jfx/flyingimage/flyingimage.png b/test/script/jfx/flyingimage/flyingimage.png
new file mode 100644
index 00000000..afc44dd3
--- /dev/null
+++ b/test/script/jfx/flyingimage/flyingimage.png
Binary files differ
diff --git a/test/script/jfx/flyingimage/golden/linux.png b/test/script/jfx/flyingimage/golden/linux.png
new file mode 100644
index 00000000..4a668a6d
--- /dev/null
+++ b/test/script/jfx/flyingimage/golden/linux.png
Binary files differ
diff --git a/test/script/jfx/flyingimage/golden/macosx.png b/test/script/jfx/flyingimage/golden/macosx.png
new file mode 100644
index 00000000..ba72fe68
--- /dev/null
+++ b/test/script/jfx/flyingimage/golden/macosx.png
Binary files differ
diff --git a/test/script/jfx/flyingimage/golden/windows.png b/test/script/jfx/flyingimage/golden/windows.png
new file mode 100644
index 00000000..e47ae4df
--- /dev/null
+++ b/test/script/jfx/flyingimage/golden/windows.png
Binary files differ
diff --git a/test/script/jfx/kaleidoscope.js b/test/script/jfx/kaleidoscope.js
new file mode 100644
index 00000000..4430ff01
--- /dev/null
+++ b/test/script/jfx/kaleidoscope.js
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * Testing JavaFX canvas run by Nashorn.
+ *
+ * @test/nocompare
+ * @run
+ * @fork
+ */
+
+TESTNAME = "kaleidoscope";
+
+var WIDTH = 800;
+var HEIGHT = 600;
+var canvas = new Canvas(WIDTH, HEIGHT);
+var context = canvas.graphicsContext2D;
+
+var x,y;
+var p_x,p_y;
+var a=0;
+var b=0;
+var angle=Math.PI/180*8;
+var color=0;
+var limit1=Math.PI*1.5;
+var limit2=Math.PI*1.79;
+var c=new Array(6);
+var d=new Array(6);
+var r,e;
+var fade;
+var prv_x,prv_y,prv_x2,prv_y2;
+var isFrameRendered = false;
+
+function renderFrame() {
+ if (!isFrameRendered) {
+ a=0.2*angle;
+ b=0.7*angle;
+ r=0;
+ fade=32;
+ for(var i=0;i<6;i++)
+ {
+ c[i]=1.0/(i+1)/2;
+ d[i]=1.0/(i+1)/2;
+ }
+ radius=Math.round((WIDTH+HEIGHT)/8);
+ e=radius*0.2;
+ p_x=Math.round(WIDTH/2);
+ p_y=Math.round(HEIGHT/2);
+ x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]);
+ y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]);
+ isFrameRendered = true;
+ }
+ anim();
+}
+
+function anim() {
+ var a1=Math.cos(a*2);
+ var a2=Math.cos(a*4);
+ var a3=Math.cos(a);
+ var a4=Math.sin(a);
+ if(b>limit1&&b<limit2) {
+ r+=radius*0.02*a1;
+ prv_x=x;
+ prv_y=y;
+ x=prv_x2+r*a3;
+ y=prv_y2+r*a4;
+ } else {
+ prv_x=x;
+ prv_y=y;
+ prv_x2=x;
+ prv_y2=y;
+ x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]);
+ y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]);
+ }
+ var c3=16*Math.cos(a*10);
+ var c1=Math.floor(56*Math.cos(a*angle*4)+c3);
+ var c2=Math.floor(56*Math.sin(a*angle*4)-c3);
+ context.lineCap=StrokeLineCap.ROUND;
+ context.setStroke(Paint.valueOf('rgba('+(192+c1)+','+(192+c2)+','+(192-c1)+','+(0.01-0.005*-a1)+')'));
+ context.lineWidth=e*1.4+e*0.8*a3;
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ context.lineWidth=e+e*0.8*a3;
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ context.setStroke(Paint.valueOf('rgba('+(192+c1)+','+(192+c2)+','+(192-c1)+','+(0.06-0.03*-a1)+')'));
+ context.lineWidth=e*0.6+e*0.35*a3;
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ context.setStroke(Paint.valueOf('rgba(0,0,0,0.06)'));
+ context.lineWidth=e*0.4+e*0.225*a3;
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ context.setStroke(Paint.valueOf('rgba('+(192+c1)+','+(192+c2)+','+(192-c1)+','+(0.1-0.075*-a1)+')'));
+ context.lineWidth=e*0.2+e*0.1*a3;
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ context.setStroke(Paint.valueOf('rgba(255,255,255,0.4)'));
+ context.lineWidth=e*(0.1-0.05*-a2);
+ draw_line(p_x,p_y,prv_x,prv_y,x,y);
+ a+=angle*Math.cos(b);
+ b+=angle*0.1;
+}
+
+function draw_line(x,y,x1,y1,x2,y2) {
+ context.beginPath();
+ context.moveTo(x+x1,y+y1);
+ context.lineTo(x+x2,y+y2);
+ context.moveTo(x-x1,y+y1);
+ context.lineTo(x-x2,y+y2);
+ context.moveTo(x-x1,y-y1);
+ context.lineTo(x-x2,y-y2);
+ context.moveTo(x+x1,y-y1);
+ context.lineTo(x+x2,y-y2);
+ context.moveTo(x+y1,y+x1);
+ context.lineTo(x+y2,y+x2);
+ context.moveTo(x-y1,y+x1);
+ context.lineTo(x-y2,y+x2);
+ context.moveTo(x-y1,y-x1);
+ context.lineTo(x-y2,y-x2);
+ context.moveTo(x+y1,y-x1);
+ context.lineTo(x+y2,y-x2);
+ context.moveTo(x,y+x2);
+ context.lineTo(x,y+x1);
+ context.moveTo(x,y-x2);
+ context.lineTo(x,y-x1);
+ context.moveTo(x+x2,y);
+ context.lineTo(x+x1,y);
+ context.moveTo(x-x2,y);
+ context.lineTo(x-x1,y);
+ context.stroke();
+ context.closePath();
+}
+
+var stack = new StackPane();
+var pane = new BorderPane();
+pane.setCenter(canvas);
+stack.getChildren().add(pane);
+$STAGE.scene = new Scene(stack);
+var frame = 0;
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 800) {
+ renderFrame();
+ frame++;
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
diff --git a/test/script/jfx/kaleidoscope/golden/linux.png b/test/script/jfx/kaleidoscope/golden/linux.png
new file mode 100644
index 00000000..4d7e81ad
--- /dev/null
+++ b/test/script/jfx/kaleidoscope/golden/linux.png
Binary files differ
diff --git a/test/script/jfx/kaleidoscope/golden/macosx.png b/test/script/jfx/kaleidoscope/golden/macosx.png
new file mode 100644
index 00000000..64d9499b
--- /dev/null
+++ b/test/script/jfx/kaleidoscope/golden/macosx.png
Binary files differ
diff --git a/test/script/jfx/kaleidoscope/golden/windows.png b/test/script/jfx/kaleidoscope/golden/windows.png
new file mode 100644
index 00000000..4d7e81ad
--- /dev/null
+++ b/test/script/jfx/kaleidoscope/golden/windows.png
Binary files differ
diff --git a/test/script/jfx/spread.js b/test/script/jfx/spread.js
new file mode 100644
index 00000000..4a8f38ce
--- /dev/null
+++ b/test/script/jfx/spread.js
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * Testing JavaFX canvas run by Nashorn.
+ *
+ * @test/nocompare
+ * @run
+ * @fork
+ */
+
+TESTNAME = "spread";
+
+var WIDTH = 800;
+var HEIGHT = 600;
+var canvas = new Canvas(WIDTH, HEIGHT);
+var context = canvas.graphicsContext2D;
+
+/* "Spread" tech demo of canvas by Tom Theisen
+ *
+ * This will animate a sequence of branch structures in a canvas element.
+ * Each frame, a new direction is calculated, similar to the last frame.
+ */
+
+var start_width = 20; // starting width of each branch
+var frame_time = 30; // milliseconds per frame
+var straighten_factor = 0.95; // value from 0 to 1, factor applied to direction_offset every frame
+var curviness = 0.2; // amount of random direction change each frame
+
+var color_speed = 0.03; // speed at which colors change when cycling is enabled
+var branch_shrink = 0.95; // factor by which branches shrink every frame
+var min_width = 1; // minimum WIDTH for branch, after which they are discontinued
+var branch_opacity = 0.4; // opacity of lines drawn
+var branch_count = 3; // branch count per tree
+var branch_bud_size = 0.5; // ratio of original branch size at which branch will split
+var branch_bud_angle = 1; // angle offset for split branch;
+
+var paper; // reference to graphics context
+var branches = Object(); // linked list of active branches
+var color_styles = []; // pre-computed list of colors as styles. format: (r,g,b,a)
+var direction_offset = 0; // current direction offset in radians. this is applied to all branches.
+var frame = 0; // frame counter
+var timespent = 0; // total time spent so far, used to calculate average frame render duration
+var frameratespan; // html span element for updating performance number
+
+// preferences object, contains an attribute for each user setting
+var prefs = {
+ wrap: true, // causes branches reaching edge of viewable area to appear on opposite side
+ fade: false, // fade existing graphics on each frame
+ cycle: true, // gradually change colors each frame
+ new_branch_frames: 20 // number of frames elapsed between each auto-generated tree
+};
+
+// create tree at the specified position with number of branches
+function create_tree(branches, start_width, position, branch_count) {
+ var angle_offset = Math.PI * 2 / branch_count;
+ for (var i = 0; i < branch_count; ++i) {
+ branch_add(branches, new Branch(position, angle_offset * i, start_width));
+ }
+}
+
+// add branch to collection
+function branch_add(branches, branch) {
+ branch.next = branches.next;
+ branches.next = branch;
+}
+
+// get the coordinates for the position of a new tree
+// use the center of the canvas
+function get_new_tree_center(width, height) {
+ return {
+ x: 0.5 * width,
+ y: 0.5 * height
+ };
+}
+
+// Branch constructor
+// position has x and y properties
+// direction is in radians
+function Branch(position, direction, width) {
+ this.x = position.x;
+ this.y = position.y;
+ this.width = width;
+ this.original_width = width;
+ this.direction = direction;
+}
+
+// update position, direction and width of a particular branch
+function branch_update(branches, branch, paper) {
+ paper.beginPath();
+ paper.lineWidth = branch.width;
+ paper.moveTo(branch.x, branch.y);
+
+ branch.width *= branch_shrink;
+ branch.direction += direction_offset;
+ branch.x += Math.cos(branch.direction) * branch.width;
+ branch.y += Math.sin(branch.direction) * branch.width;
+
+ paper.lineTo(branch.x, branch.y);
+ paper.stroke();
+
+ if (prefs.wrap) wrap_branch(branch, WIDTH, HEIGHT);
+
+ if (branch.width < branch.original_width * branch_bud_size) {
+ branch.original_width *= branch_bud_size;
+ branch_add(branches, new Branch(branch, branch.direction + 1, branch.original_width));
+ }
+}
+
+function draw_frame() {
+ if (prefs.fade) {
+ paper.fillRect(0, 0, WIDTH, HEIGHT);
+ }
+
+ if (prefs.cycle) {
+ paper.setStroke(Paint.valueOf(color_styles[frame % color_styles.length]));
+ }
+
+ if (frame++ % prefs.new_branch_frames == 0) {
+ create_tree(branches, start_width, get_new_tree_center(WIDTH, HEIGHT), branch_count);
+ }
+
+ direction_offset += (0.35 + (frame % 200) * 0.0015) * curviness - curviness / 2;
+ direction_offset *= straighten_factor;
+
+ var branch = branches;
+ var prev_branch = branches;
+ while (branch = branch.next) {
+ branch_update(branches, branch, paper);
+
+ if (branch.width < min_width) {
+ // remove branch from list
+ prev_branch.next = branch.next;
+ }
+
+ prev_branch = branch;
+ }
+}
+
+// constrain branch position to visible area by "wrapping" from edge to edge
+function wrap_branch(branch, WIDTH, HEIGHT) {
+ branch.x = positive_mod(branch.x, WIDTH);
+ branch.y = positive_mod(branch.y, HEIGHT);
+}
+
+// for a < 0, b > 0, javascript returns a negative number for a % b
+// this is a variant of the % operator that adds b to the result in this case
+function positive_mod(a, b) {
+ // ECMA 262 11.5.3: Applying the % Operator
+ // remainder operator does not convert operands to integers,
+ // although negative results are possible
+
+ return ((a % b) + b) % b;
+}
+
+// pre-compute color styles that will be used for color cycling
+function populate_colors(color_speed, color_styles, branch_opacity) {
+ // used in calculation of RGB values
+ var two_thirds_pi = Math.PI * 2 / 3;
+ var four_thirds_pi = Math.PI * 4 / 3;
+ var two_pi = Math.PI * 2;
+
+ // hue does represent hue, but not in the conventional HSL scheme
+ for(var hue = 0; hue < two_pi; hue += color_speed) {
+ var r = Math.floor(Math.sin(hue) * 128 + 128);
+ var g = Math.floor(Math.sin(hue + two_thirds_pi) * 128 + 128);
+ var b = Math.floor(Math.sin(hue + four_thirds_pi) * 128 + 128);
+ color = "rgba(" + [r, g, b, branch_opacity].join() + ")";
+
+ color_styles.push(color);
+ }
+}
+
+// apply initial settings to canvas object
+function setup_canvas() {
+ paper = canvas.graphicsContext2D;
+ paper.setFill(Paint.valueOf('rgb(0, 0, 0)'));
+ paper.fillRect(0, 0, WIDTH, HEIGHT);
+ paper.setFill(Paint.valueOf("rgba(0, 0, 0, 0.005)"));
+ paper.setStroke(Paint.valueOf("rgba(128, 128, 64, " + String(branch_opacity) + ")"));
+}
+
+populate_colors(color_speed, color_styles, branch_opacity);
+setup_canvas();
+
+var stack = new StackPane();
+var pane = new BorderPane();
+pane.setCenter(canvas);
+stack.getChildren().add(pane);
+$STAGE.scene = new Scene(stack);
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 200) {
+ draw_frame();
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
+
diff --git a/test/script/jfx/spread/golden/linux.png b/test/script/jfx/spread/golden/linux.png
new file mode 100644
index 00000000..fc535a47
--- /dev/null
+++ b/test/script/jfx/spread/golden/linux.png
Binary files differ
diff --git a/test/script/jfx/spread/golden/macosx.png b/test/script/jfx/spread/golden/macosx.png
new file mode 100644
index 00000000..c2881623
--- /dev/null
+++ b/test/script/jfx/spread/golden/macosx.png
Binary files differ
diff --git a/test/script/jfx/spread/golden/windows.png b/test/script/jfx/spread/golden/windows.png
new file mode 100644
index 00000000..fc535a47
--- /dev/null
+++ b/test/script/jfx/spread/golden/windows.png
Binary files differ
diff --git a/test/script/sandbox/arrayclass.js b/test/script/sandbox/arrayclass.js
new file mode 100644
index 00000000..c29c86bd
--- /dev/null
+++ b/test/script/sandbox/arrayclass.js
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/**
+ * Try to access array class of a sensitive class like Unsafe.
+ *
+ * @test
+ * @security
+ * @run
+ */
+
+try {
+ var unsafeArr = Java.type("[Lsun.misc.Unsafe;");
+ fail("No Exception for [Lsun.misc.Unsafe;");
+} catch (e) {
+ print(e);
+}
diff --git a/test/script/sandbox/arrayclass.js.EXPECTED b/test/script/sandbox/arrayclass.js.EXPECTED
new file mode 100644
index 00000000..d66d77f0
--- /dev/null
+++ b/test/script/sandbox/arrayclass.js.EXPECTED
@@ -0,0 +1 @@
+java.lang.ClassNotFoundException: [Lsun.misc.Unsafe;
diff --git a/test/script/sandbox/loadcompat.js b/test/script/sandbox/loadcompat.js
index e99f67f2..f0338df7 100644
--- a/test/script/sandbox/loadcompat.js
+++ b/test/script/sandbox/loadcompat.js
@@ -48,3 +48,7 @@ if (typeof JavaAdapter != 'function') {
if (typeof importPackage != 'function') {
fail("importPackage function is missing in compatibility script");
}
+
+if (typeof sync != 'function') {
+ fail("sync function is missing in compatibility script");
+}
diff --git a/test/script/trusted/JDK-8025629.js b/test/script/trusted/JDK-8025629.js
new file mode 100644
index 00000000..7dda8465
--- /dev/null
+++ b/test/script/trusted/JDK-8025629.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.
+ */
+
+/**
+ * JDK-8025629: load function should support a way to load scripts from classpath
+ *
+ * @test
+ * @run
+ */
+
+load("classpath:jdk/nashorn/internal/runtime/resources/load_test.js")
+
+Assert.assertEquals(loadedFunc("hello"), "HELLO");
diff --git a/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java b/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java
new file mode 100644
index 00000000..4a1d8d5d
--- /dev/null
+++ b/test/src/jdk/nashorn/api/javaaccess/ArrayConversionTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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.javaaccess;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.testng.TestNG;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ArrayConversionTest {
+ private static ScriptEngine e = null;
+
+ public static void main(final String[] args) {
+ TestNG.main(args);
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws ScriptException {
+ e = new ScriptEngineManager().getEngineByName("nashorn");
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ e = null;
+ }
+
+ @Test
+ public void testIntArrays() throws ScriptException {
+ runTest("assertNullIntArray", "null");
+ runTest("assertEmptyIntArray", "[]");
+ runTest("assertSingle42IntArray", "[42]");
+ runTest("assertSingle42IntArray", "['42']");
+ runTest("assertIntArrayConversions", "[false, true, NaN, Infinity, -Infinity, 0.4, 0.6, null, undefined, [], {}, [1], [1, 2]]");
+ }
+
+ @Test
+ public void testIntIntArrays() throws ScriptException {
+ runTest("assertNullIntIntArray", "null");
+ runTest("assertEmptyIntIntArray", "[]");
+ runTest("assertSingleEmptyIntIntArray", "[[]]");
+ runTest("assertSingleNullIntIntArray", "[null]");
+ runTest("assertLargeIntIntArray", "[[false], [1], [2, 3], [4, 5, 6], ['7', {valueOf: function() { return 8 }}]]");
+ }
+
+ @Test
+ public void testObjectObjectArrays() throws ScriptException {
+ runTest("assertLargeObjectObjectArray", "[[false], [1], ['foo', 42.3], [{x: 17}]]");
+ }
+
+ @Test
+ public void testBooleanArrays() throws ScriptException {
+ runTest("assertBooleanArrayConversions", "[false, true, '', 'false', 0, 1, 0.4, 0.6, {}, [], [false], [true], NaN, Infinity, null, undefined]");
+ }
+
+ @Test
+ public void testArrayAmbiguity() throws ScriptException {
+ runTest("x", "'abc'");
+ runTest("x", "['foo', 'bar']");
+ }
+
+ @Test
+ public void testListArrays() throws ScriptException {
+ runTest("assertListArray", "[['foo', 'bar'], ['apple', 'orange']]");
+ }
+
+ @Test
+ public void testVarArgs() throws ScriptException {
+ // Sole NativeArray in vararg position becomes vararg array itself
+ runTest("assertVarArg_42_17", "[42, 17]");
+ // NativeArray in vararg position becomes an argument if there are more arguments
+ runTest("assertVarArg_array_17", "[42], 18");
+ // Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't
+ runTest("assertVarArg_function", "function() { return 'Hello' }");
+ }
+
+ private static void runTest(final String testMethodName, final String argument) throws ScriptException {
+ e.eval("Java.type('" + ArrayConversionTest.class.getName() + "')." + testMethodName + "(" + argument + ")");
+ }
+
+ public static void assertNullIntArray(int[] array) {
+ assertNull(array);
+ }
+
+ public static void assertNullIntIntArray(int[][] array) {
+ assertNull(array);
+ }
+
+ public static void assertEmptyIntArray(int[] array) {
+ assertEquals(0, array.length);
+ }
+
+ public static void assertSingle42IntArray(int[] array) {
+ assertEquals(1, array.length);
+ assertEquals(42, array[0]);
+ }
+
+
+ public static void assertIntArrayConversions(int[] array) {
+ assertEquals(13, array.length);
+ assertEquals(0, array[0]); // false
+ assertEquals(1, array[1]); // true
+ assertEquals(0, array[2]); // NaN
+ assertEquals(0, array[3]); // Infinity
+ assertEquals(0, array[4]); // -Infinity
+ assertEquals(0, array[5]); // 0.4
+ assertEquals(0, array[6]); // 0.6 - floor, not round
+ assertEquals(0, array[7]); // null
+ assertEquals(0, array[8]); // undefined
+ assertEquals(0, array[9]); // []
+ assertEquals(0, array[10]); // {}
+ assertEquals(1, array[11]); // [1]
+ assertEquals(0, array[12]); // [1, 2]
+ }
+
+ public static void assertEmptyIntIntArray(int[][] array) {
+ assertEquals(0, array.length);
+ }
+
+ public static void assertSingleEmptyIntIntArray(int[][] array) {
+ assertEquals(1, array.length);
+ assertTrue(Arrays.equals(new int[0], array[0]));
+ }
+
+ public static void assertSingleNullIntIntArray(int[][] array) {
+ assertEquals(1, array.length);
+ assertNull(null, array[0]);
+ }
+
+ public static void assertLargeIntIntArray(int[][] array) {
+ assertEquals(5, array.length);
+ assertTrue(Arrays.equals(new int[] { 0 }, array[0]));
+ assertTrue(Arrays.equals(new int[] { 1 }, array[1]));
+ assertTrue(Arrays.equals(new int[] { 2, 3 }, array[2]));
+ assertTrue(Arrays.equals(new int[] { 4, 5, 6 }, array[3]));
+ assertTrue(Arrays.equals(new int[] { 7, 8 }, array[4]));
+ }
+
+ public static void assertLargeObjectObjectArray(Object[][] array) throws ScriptException {
+ assertEquals(4, array.length);
+ assertTrue(Arrays.equals(new Object[] { Boolean.FALSE }, array[0]));
+ assertTrue(Arrays.equals(new Object[] { 1 }, array[1]));
+ assertTrue(Arrays.equals(new Object[] { "foo", 42.3d }, array[2]));
+ assertEquals(1, array[3].length);
+ e.getBindings(ScriptContext.ENGINE_SCOPE).put("obj", array[3][0]);
+ assertEquals(17, e.eval("obj.x"));
+ }
+
+ public static void assertBooleanArrayConversions(boolean[] array) {
+ assertEquals(16, array.length);
+ assertFalse(array[0]); // false
+ assertTrue(array[1]); // true
+ assertFalse(array[2]); // ''
+ assertTrue(array[3]); // 'false' (yep, every non-empty string converts to true)
+ assertFalse(array[4]); // 0
+ assertTrue(array[5]); // 1
+ assertTrue(array[6]); // 0.4
+ assertTrue(array[7]); // 0.6
+ assertTrue(array[8]); // {}
+ assertTrue(array[9]); // []
+ assertTrue(array[10]); // [false]
+ assertTrue(array[11]); // [true]
+ assertFalse(array[12]); // NaN
+ assertTrue(array[13]); // Infinity
+ assertFalse(array[14]); // null
+ assertFalse(array[15]); // undefined
+ }
+
+ public static void assertListArray(List<?>[] array) {
+ assertEquals(2, array.length);
+ assertEquals(Arrays.asList("foo", "bar"), array[0]);
+ assertEquals(Arrays.asList("apple", "orange"), array[1]);
+ }
+
+ public static void assertVarArg_42_17(Object... args) throws ScriptException {
+ assertEquals(2, args.length);
+ assertEquals(42, ((Number)args[0]).intValue());
+ assertEquals(17, ((Number)args[1]).intValue());
+ }
+
+ public static void assertVarArg_array_17(Object... args) throws ScriptException {
+ assertEquals(2, args.length);
+ e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]);
+ assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42"));
+ assertEquals(18, ((Number)args[1]).intValue());
+ }
+
+ public static void assertVarArg_function(Object... args) throws ScriptException {
+ assertEquals(1, args.length);
+ e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]);
+ assertEquals("Hello", e.eval("fn()"));
+ }
+
+
+
+ public static void x(String y) {
+ assertEquals("abc", y);
+ }
+ public static void x(String[] y) {
+ assertTrue(Arrays.equals(new String[] { "foo", "bar"}, y));
+ }
+}
diff --git a/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java
new file mode 100644
index 00000000..1eadfb77
--- /dev/null
+++ b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.javaaccess;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.JSObject;
+import org.testng.TestNG;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ConsStringTest {
+ private static ScriptEngine e = null;
+
+ public static void main(final String[] args) {
+ TestNG.main(args);
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws ScriptException {
+ e = new ScriptEngineManager().getEngineByName("nashorn");
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ e = null;
+ }
+
+ @Test
+ public void testConsStringFlattening() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final Map<Object, Object> m = new HashMap<>();
+ b.put("m", m);
+ e.eval("var x = 'f'; x += 'oo'; var y = 'b'; y += 'ar'; m.put(x, y)");
+ assertEquals("bar", m.get("foo"));
+ }
+
+ @Test
+ public void testConsStringFromMirror() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final Map<Object, Object> m = new HashMap<>();
+ e.eval("var x = 'f'; x += 'oo'; var obj = {x: x};");
+ assertEquals("foo", ((JSObject)b.get("obj")).getMember("x"));
+ }
+
+ @Test
+ public void testArrayConsString() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final ArrayHolder h = new ArrayHolder();
+ b.put("h", h);
+ e.eval("var x = 'f'; x += 'oo'; h.array = [x];");
+ assertEquals(1, h.array.length);
+ assertEquals("foo", h.array[0]);
+ }
+
+
+ public static class ArrayHolder {
+ private Object[] array;
+
+ public void setArray(Object[] array) {
+ this.array = array;
+ }
+
+ public Object[] getArray() {
+ return array;
+ }
+ }
+}
diff --git a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java
index 14207b7d..4be66b81 100644
--- a/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java
+++ b/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java
@@ -412,7 +412,7 @@ public class MethodAccessTest {
@Test
public void accessMethodMixedWithEllipsis() throws ScriptException {
- assertArrayEquals(new Object[] { "Hello", 10, true, -100500, 80 }, (Object[])e.eval("o.methodMixedWithEllipsis('Hello', 10, true, -100500,80.0);"));
+ assertArrayEquals(new Object[] { "Hello", 10, true, -100500, 80d }, (Object[])e.eval("o.methodMixedWithEllipsis('Hello', 10, true, -100500,80.0);"));
assertArrayEquals(new Object[] { "Nashorn", 15 }, (Object[])e.eval("o.methodMixedWithEllipsis('Nashorn',15);"));
}
@@ -431,8 +431,8 @@ public class MethodAccessTest {
@Test
public void accessMethodDoubleVSintOverloaded() throws ScriptException {
- assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(0.0);"));
- assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(1000.0);"));
+ assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(0.0);"));
+ assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(1000.0);"));
assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(0.01);"));
assertEquals("double", e.eval("o.overloadedMethodDoubleVSint(100.02);"));
assertEquals("int", e.eval("o.overloadedMethodDoubleVSint(0);"));
diff --git a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
index acb57164..a574e6f6 100644
--- a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
+++ b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java
@@ -46,7 +46,7 @@ import org.testng.annotations.Test;
* JSObject implementations.
*/
public class PluggableJSObjectTest {
- public static class MapWrapperObject extends JSObject {
+ public static class MapWrapperObject extends AbstractJSObject {
private final HashMap<String, Object> map = new LinkedHashMap<>();
public HashMap<String, Object> getMap() {
@@ -109,7 +109,7 @@ public class PluggableJSObjectTest {
}
}
- public static class BufferObject extends JSObject {
+ public static class BufferObject extends AbstractJSObject {
private final IntBuffer buf;
public BufferObject(int size) {
@@ -170,7 +170,7 @@ public class PluggableJSObjectTest {
}
}
- public static class Adder extends JSObject {
+ public static class Adder extends AbstractJSObject {
@Override
public Object call(Object thiz, Object... args) {
double res = 0.0;
@@ -202,7 +202,7 @@ public class PluggableJSObjectTest {
}
}
- public static class Factory extends JSObject {
+ public static class Factory extends AbstractJSObject {
@Override
public Object newObject(Object... args) {
return new HashMap<Object, Object>();
diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
index 99207de0..55aacb34 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
@@ -523,6 +523,18 @@ public class ScriptEngineTest {
assertEquals(sw.toString(), println("34 true hello"));
}
+ @Test
+ public void scriptObjectAutoConversionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ e.eval("obj = { foo: 'hello' }");
+ e.put("Window", e.eval("Packages.jdk.nashorn.api.scripting.Window"));
+ assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
+ assertEquals(e.eval("Window.funcScriptObjectMirror(obj)"), "hello");
+ assertEquals(e.eval("Window.funcMap(obj)"), "hello");
+ assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
+ }
+
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
// Returns String that would be the result of calling PrintWriter.println
diff --git a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
index c7b40c63..544f4ea7 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
@@ -26,6 +26,7 @@
package jdk.nashorn.api.scripting;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@@ -129,7 +130,7 @@ public class ScriptObjectMirrorTest {
final ScriptEngine e = m.getEngineByName("nashorn");
try {
e.eval("var obj = { '1': 'world', func: function() { return this.bar; }, bar: 'hello' }");
- JSObject obj = (JSObject) e.get("obj");
+ ScriptObjectMirror obj = (ScriptObjectMirror) e.get("obj");
// try basic get on existing properties
if (!obj.getMember("bar").equals("hello")) {
@@ -227,4 +228,28 @@ public class ScriptObjectMirrorTest {
final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject();
assertTrue(newObj instanceof ScriptObjectMirror);
}
+
+ @Test
+ public void conversionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptObjectMirror arr = (ScriptObjectMirror)e.eval("[33, 45, 23]");
+ final int[] intArr = arr.to(int[].class);
+ assertEquals(intArr[0], 33);
+ assertEquals(intArr[1], 45);
+ assertEquals(intArr[2], 23);
+
+ final List<?> list = arr.to(List.class);
+ assertEquals(list.get(0), 33);
+ assertEquals(list.get(1), 45);
+ assertEquals(list.get(2), 23);
+
+ ScriptObjectMirror obj = (ScriptObjectMirror)e.eval(
+ "({ valueOf: function() { return 42 } })");
+ assertEquals(Double.valueOf(42.0), obj.to(Double.class));
+
+ obj = (ScriptObjectMirror)e.eval(
+ "({ toString: function() { return 'foo' } })");
+ assertEquals("foo", obj.to(String.class));
+ }
}
diff --git a/test/src/jdk/nashorn/api/scripting/Window.java b/test/src/jdk/nashorn/api/scripting/Window.java
index bde23941..510c5dae 100644
--- a/test/src/jdk/nashorn/api/scripting/Window.java
+++ b/test/src/jdk/nashorn/api/scripting/Window.java
@@ -25,6 +25,9 @@
package jdk.nashorn.api.scripting;
+import java.util.Map;
+import javax.script.Bindings;
+
public class Window {
private String location = "http://localhost:8080/window";
@@ -63,4 +66,20 @@ public class Window {
System.out.println("window.setTimeout: " + delay + ", code: " + code);
return 0;
}
+
+ public static Object funcJSObject(final JSObject jsobj) {
+ return jsobj.getMember("foo");
+ }
+
+ public static Object funcScriptObjectMirror(final ScriptObjectMirror sobj) {
+ return sobj.get("foo");
+ }
+
+ public static Object funcMap(final Map<?,?> map) {
+ return map.get("foo");
+ }
+
+ public static Object funcBindings(final Bindings bindings) {
+ return bindings.get("foo");
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java b/test/src/jdk/nashorn/internal/runtime/resources/load_test.js
index 4fe2dc40..21672d61 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java
+++ b/test/src/jdk/nashorn/internal/runtime/resources/load_test.js
@@ -23,32 +23,6 @@
* questions.
*/
-package jdk.nashorn.internal.runtime;
-
-/**
- * A ListAdapter that can wrap a ScriptObject.
- */
-public final class ScriptObjectListAdapter extends ListAdapter {
- /**
- * Creates a new list wrapper for the specified ScriptObject.
- * @param obj script the object to wrap
- */
- public ScriptObjectListAdapter(final ScriptObject obj) {
- super(obj);
- }
-
- @Override
- public int size() {
- return JSType.toInt32(((ScriptObject)obj).getLength());
- }
-
- @Override
- protected Object getAt(int index) {
- return ((ScriptObject)obj).get(index);
- }
-
- @Override
- protected void setAt(int index, Object element) {
- ((ScriptObject)obj).set(index, element, false);
- }
+function loadedFunc(arg) {
+ return arg.toUpperCase();
}