aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlana <none@none>2013-10-31 16:47:09 -0700
committerlana <none@none>2013-10-31 16:47:09 -0700
commit667799c17e14bcd6303ad32c6fd9e654d52af7b0 (patch)
tree2430a17ae2f4d87c7455da370dc91d3dd3c7b1c1
parent7f430652c2ec0109c36963c26b6407ad9ae75a6c (diff)
parentbfd238be9c055093ae8ff41fad0a32ae7f183acf (diff)
-rw-r--r--make/build.xml35
-rw-r--r--make/project.properties27
-rw-r--r--src/jdk/nashorn/api/scripting/AbstractJSObject.java254
-rw-r--r--src/jdk/nashorn/api/scripting/JSObject.java104
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptObjectMirror.java13
-rw-r--r--src/jdk/nashorn/internal/codegen/BranchOptimizer.java9
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java61
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java4
-rw-r--r--src/jdk/nashorn/internal/codegen/SpillObjectCreator.java3
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java12
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java39
-rw-r--r--src/jdk/nashorn/internal/ir/Expression.java12
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java5
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java5
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java20
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java59
-rw-r--r--src/jdk/nashorn/internal/objects/Global.java4
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java79
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJSAdapter.java3
-rw-r--r--src/jdk/nashorn/internal/objects/NativeString.java14
-rw-r--r--src/jdk/nashorn/internal/parser/Lexer.java13
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunctions.java50
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java48
-rw-r--r--src/jdk/nashorn/internal/runtime/ListAdapter.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java54
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java105
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptLoader.java20
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java53
-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/arrays/ArrayData.java18
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java28
-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/linker/JSObjectLinker.java85
-rw-r--r--src/overview.html2
-rw-r--r--test/examples/array-micro.js18
-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-8026161.js32
-rw-r--r--test/script/basic/JDK-8026161.js.EXPECTED2
-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.js (renamed from src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java)55
-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-8027562.js39
-rw-r--r--test/script/basic/JDK-8027562.js.EXPECTED1
-rw-r--r--test/script/basic/NASHORN-397.js7
-rw-r--r--test/script/jfx.js92
-rw-r--r--test/script/jfx/flyingimage.js83
-rw-r--r--test/script/jfx/flyingimage/flyingimage.pngbin0 -> 439 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/linux.pngbin0 -> 14754 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/macosx.pngbin0 -> 12298 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/windows.pngbin0 -> 9849 bytes
-rw-r--r--test/script/jfx/kaleidoscope.js162
-rw-r--r--test/script/jfx/kaleidoscope/golden/linux.pngbin0 -> 185802 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/macosx.pngbin0 -> 202995 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/windows.pngbin0 -> 202946 bytes
-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/ScriptObjectMirrorTest.java2
71 files changed, 2096 insertions, 383 deletions
diff --git a/make/build.xml b/make/build.xml
index 01410947..c90cdd6f 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">
@@ -351,6 +361,31 @@ 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"/>
+
+ <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>
+ <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/project.properties b/make/project.properties
index 2ad619be..33c94780 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}:\
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 a2d761b4..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(final Object thiz, final 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(final 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(final 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(final String name, final 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(final 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(final 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(final String name) {
- return false;
- }
+ public boolean hasMember(final String name);
/**
* Does this object have a indexed property?
@@ -118,18 +93,14 @@ public abstract class JSObject {
* @param slot index to check
* @return true if this object has a slot
*/
- public boolean hasSlot(final 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(final String name) {
- //empty
- }
+ public void removeMember(final String name);
/**
* Set a named member in this JavaScript object
@@ -137,9 +108,7 @@ public abstract class JSObject {
* @param name name of the member
* @param value value of the member
*/
- public void setMember(final String name, final Object value) {
- //empty
- }
+ public void setMember(final String name, final Object value);
/**
* Set an indexed member in this JavaScript object
@@ -147,9 +116,7 @@ public abstract class JSObject {
* @param index index of the member slot
* @param value value of the member
*/
- public void setSlot(final int index, final Object value) {
- //empty
- }
+ public void setSlot(final int index, final Object value);
// property and value iteration
@@ -158,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
@@ -181,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.
@@ -191,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/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index 3a27d23e..ee287a2e 100644
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -43,6 +43,7 @@ import java.util.concurrent.Callable;
import javax.script.Bindings;
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 +51,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 +162,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();
@@ -705,4 +705,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/internal/codegen/BranchOptimizer.java b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
index bf01de0f..ad9bdb07 100644
--- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
+++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
@@ -72,8 +72,7 @@ final class BranchOptimizer {
}
// convert to boolean
- codegen.load(unaryNode);
- method.convert(Type.BOOLEAN);
+ codegen.load(unaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
@@ -146,8 +145,7 @@ final class BranchOptimizer {
break;
}
- codegen.load(binaryNode);
- method.convert(Type.BOOLEAN);
+ codegen.load(binaryNode, Type.BOOLEAN);
if (state) {
method.ifne(label);
} else {
@@ -169,8 +167,7 @@ final class BranchOptimizer {
}
}
- codegen.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 e7093572..206433db 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -359,8 +359,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return load(node, node.hasType() ? node.getType() : null, false);
}
- private static boolean safeLiteral(final Expression rhs) {
- return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode);
+ // 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) {
@@ -374,25 +377,19 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// 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 is not an object, or RIGHT is a constant literal, then we can do the
+ // 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.
- final Type lhsType = lhs.getType();
- if (lhsType.isObject() && !safeLiteral(rhs)) {
- // Can't reorder. Load and convert separately.
- load(lhs, lhsType, baseAlreadyOnStack);
- load(rhs, rhs.getType(), false);
- // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op
- if (!lhsType.isEquivalentTo(type)) {
- method.swap();
- method.convert(type);
- method.swap();
- }
- method.convert(type);
- } else {
+ 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;
@@ -402,7 +399,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false);
}
- private MethodEmitter load(final Expression node, final Type type) {
+ MethodEmitter load(final Expression node, final Type type) {
return load(node, type, false);
}
@@ -432,7 +429,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@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(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
@@ -442,7 +439,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@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(type, getCallSiteFlags(), indexNode.isFunction());
@@ -632,11 +629,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++;
}
@@ -707,6 +706,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
// load evaluated code
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());
@@ -1277,7 +1282,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();
}
@@ -1719,7 +1724,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
for (final Expression arg : args) {
- load(arg).convert(Type.OBJECT);
+ load(arg, Type.OBJECT);
}
method.invokestatic(
@@ -2105,7 +2110,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;
}
@@ -2352,7 +2357,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());
@@ -2383,7 +2388,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterSUB(final UnaryNode unaryNode) {
assert unaryNode.getType().isNumeric();
- load(unaryNode.rhs()).convert(unaryNode.getType()).neg().store(unaryNode.getSymbol());
+ load(unaryNode.rhs(), unaryNode.getType()).neg().store(unaryNode.getSymbol());
return false;
}
@@ -2424,7 +2429,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);
@@ -2433,7 +2438,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());
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 82e9890c..bf6872fe 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -88,12 +88,12 @@ 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;
+ private final CodeInstaller<?> installer;
/**
* Constructor.
*/
- Lower(final CodeInstaller installer) {
+ Lower(final CodeInstaller<?> installer) {
super(new BlockLexicalContext() {
@Override
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/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index 2fa2c315..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
*/
@@ -443,7 +453,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
} else if (type0.isArray() != type1.isArray()) {
//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() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) {
+ } 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;
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/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 631153b8..30e8ed11 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -138,6 +138,11 @@ public final class IdentNode extends Expression implements PropertyKey, Function
return getName();
}
+ @Override
+ public boolean isLocal() {
+ return !getSymbol().isScope();
+ }
+
/**
* Check if this IdentNode is a property name
* @return true if this is a property name
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index fcdf55c1..8d6823cb 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -275,6 +275,11 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
public boolean isTrue() {
return JSType.toBoolean(value);
}
+
+ @Override
+ public boolean isLocal() {
+ return true;
+ }
}
@Immutable
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/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index 3857dd39..4923d31e 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -129,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
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/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java
index f2fd08a5..a0df10b0 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -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 37b6355b..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)) {
@@ -1007,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;
- for (long k = 0; k < actualDeleteCount; k++) {
- final long from = actualStart + k;
+ 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 < 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)) {
@@ -1029,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)) {
@@ -1046,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;
@@ -1122,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/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/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/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/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/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/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index 774295a1..e1b91302 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -210,26 +210,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
@@ -266,12 +246,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());
@@ -495,6 +474,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
*
@@ -1048,7 +1040,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 44302462..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;
@@ -135,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 {
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/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index 04c3ae8d..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, ScriptFunction, ...)} or {@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
+ * 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) == ScriptFunction.class) {
- return true;
- }
-
- return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == 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 42c8fb4a..78185b1c 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptLoader.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptLoader.java
@@ -52,24 +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) {
- //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 59b50eb0..5d1fbcd6 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -508,7 +508,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);
@@ -594,7 +594,7 @@ 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) {
+ 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()) {
@@ -616,15 +616,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
}
- private void removeArraySlot(final String key) {
- final int index = getArrayIndex(key);
- final ArrayData array = getArray();
-
- if (array.has(index)) {
- setArray(array.delete(index));
- }
- }
-
/**
* Add a new property to the object.
*
@@ -1203,21 +1194,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();
}
/**
@@ -2356,8 +2336,29 @@ 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);
}
}
@@ -2680,7 +2681,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);
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/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/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/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index f9491dec..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);
}
@@ -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/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/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-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-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/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java b/test/script/basic/JDK-8026955.js
index 4fe2dc40..a54e3d96 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObjectListAdapter.java
+++ b/test/script/basic/JDK-8026955.js
@@ -1,54 +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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
+ * 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.
*/
-package jdk.nashorn.internal.runtime;
-
/**
- * A ListAdapter that can wrap a ScriptObject.
+ * JDK-8026955: for-in should convert primitive values to object
+ *
+ * @test
+ * @run
*/
-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());
- }
+Object.prototype[4] = "world";
+String.prototype[3] = "hello";
+Number.prototype[3] = "hello";
+Boolean.prototype[3] = "hello";
- @Override
- protected Object getAt(int index) {
- return ((ScriptObject)obj).get(index);
+function testForIn(x) {
+ for (var i in x) {
+ print(i, x[i]);
}
-
- @Override
- protected void setAt(int index, Object element) {
- ((ScriptObject)obj).set(index, element, false);
+ 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-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/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/jfx.js b/test/script/jfx.js
new file mode 100644
index 00000000..26f97873
--- /dev/null
+++ b/test/script/jfx.js
@@ -0,0 +1,92 @@
+/*
+ * 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 Timer = Java.type("java.util.Timer");
+var TimerTask = Java.type("java.util.TimerTask");
+var OSInfo = Java.type("sun.awt.OSInfo");
+var OSType = Java.type("sun.awt.OSInfo.OSType");
+var StringBuffer = Java.type("java.lang.StringBuffer");
+
+var WAIT = 2000;
+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();
+ makeScreenShot(tmpdir + fsep + "screenshot" + timenow +".png");
+ var dupImg = isDuplicateImages(tmpdir + fsep + "screenshot" + timenow +".png", __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden");
+ (new File(mpdir + fsep + "screenshot" + timenow +".png")).delete();
+ if (!dupImg) System.err.println("ERROR: screenshot does not match golden image");
+ exit(0);
+ }
+ };
+ raceTimer.schedule(timerTask, WAIT);
+}
+
+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(file1, file2) {
+ var f1 = new File(file1);
+ var f2;
+ var sb = new StringBuffer(file2);
+ 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());
+ }
+ print(f1.getAbsolutePath());
+ print(f2.getAbsolutePath());
+ 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..4cf3f7fc
--- /dev/null
+++ b/test/script/jfx/flyingimage.js
@@ -0,0 +1,83 @@
+/*
+ * 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 Image = Java.type("javafx.scene.image.Image");
+var Color = Java.type("javafx.scene.paint.Color");
+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 Font = Java.type("javafx.scene.text.Font");
+var FontSmoothingType = Java.type("javafx.scene.text.FontSmoothingType");
+var Text = Java.type("javafx.scene.text.Text");
+
+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 font = new Font("Arial", 16);
+var t = 0;
+var isFrameRendered = false;
+function renderFrame() {
+ 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++, t++) {
+ 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);
+renderFrame();
+checkImageAndExit();
diff --git a/test/script/jfx/flyingimage/flyingimage.png b/test/script/jfx/flyingimage/flyingimage.png
new file mode 100644
index 00000000..ecd98a14
--- /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..4f678853
--- /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..cb153219
--- /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..e3897148
--- /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..a932c517
--- /dev/null
+++ b/test/script/jfx/kaleidoscope.js
@@ -0,0 +1,162 @@
+/*
+ * 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";
+WAIT = 4000;
+
+var Paint = Java.type("javafx.scene.paint.Paint");
+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 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;
+
+function renderFrame() {
+ 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]);
+ for (i = 0; i < 800; i++) {
+ 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);
+renderFrame();
+checkImageAndExit(); \ No newline at end of file
diff --git a/test/script/jfx/kaleidoscope/golden/linux.png b/test/script/jfx/kaleidoscope/golden/linux.png
new file mode 100644
index 00000000..ccc92fe9
--- /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..1adeb1e4
--- /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..84ee37c0
--- /dev/null
+++ b/test/script/jfx/kaleidoscope/golden/windows.png
Binary files differ
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/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
index c7b40c63..6c35ee40 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
@@ -129,7 +129,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")) {