aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkizune <none@none>2013-12-03 14:13:15 +0400
committerkizune <none@none>2013-12-03 14:13:15 +0400
commitb854ad3e03504bf7f5a58443e1a8bd76067d95da (patch)
tree370037c9ea2b910022e52a9e376222039490efde
parent93b0287291715332b671452d26b9c5686835f517 (diff)
parent2e0213826b841d0c3ab9302a0c99217161c4fb81 (diff)
downloadnashorn-b854ad3e03504bf7f5a58443e1a8bd76067d95da.tar.gz
Merge
-rw-r--r--.hgtags4
-rw-r--r--make/build.xml7
-rw-r--r--make/project.properties2
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptObjectMirror.java40
-rw-r--r--src/jdk/nashorn/api/scripting/ScriptUtils.java100
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java10
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java37
-rw-r--r--src/jdk/nashorn/internal/codegen/MapCreator.java4
-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/Symbol.java20
-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.java8
-rw-r--r--src/jdk/nashorn/internal/objects/NativeObject.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunctions.java50
-rw-r--r--src/jdk/nashorn/internal/runtime/ConsString.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java14
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java31
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java105
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java13
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptingFunctions.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java5
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java127
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java38
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornLinker.java39
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java2
-rw-r--r--test/script/basic/JDK-8015355.js4
-rw-r--r--test/script/basic/JDK-8027042.js58
-rw-r--r--test/script/basic/JDK-8027042.js.EXPECTED88
-rw-r--r--test/script/basic/JDK-8027236.js37
-rw-r--r--test/script/basic/JDK-8027236.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8027562.js39
-rw-r--r--test/script/basic/JDK-8027562.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8027700.js54
-rw-r--r--test/script/basic/JDK-8027753.js50
-rw-r--r--test/script/basic/JDK-8027753.js.EXPECTED3
-rw-r--r--test/script/basic/JDK-8027828.js35
-rw-r--r--test/script/basic/JDK-8027828.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8028020.js40
-rw-r--r--test/script/basic/JDK-8028020.js.EXPECTED2
-rw-r--r--test/script/basic/convert.js61
-rw-r--r--test/script/basic/convert.js.EXPECTED14
-rw-r--r--test/script/jfx.js37
-rw-r--r--test/script/jfx/flyingimage.js33
-rw-r--r--test/script/jfx/flyingimage/flyingimage.pngbin439 -> 1278 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/linux.pngbin14754 -> 68179 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/macosx.pngbin12298 -> 68361 bytes
-rw-r--r--test/script/jfx/flyingimage/golden/windows.pngbin9849 -> 68588 bytes
-rw-r--r--test/script/jfx/kaleidoscope.js59
-rw-r--r--test/script/jfx/kaleidoscope/golden/linux.pngbin185802 -> 192428 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/macosx.pngbin202995 -> 202987 bytes
-rw-r--r--test/script/jfx/kaleidoscope/golden/windows.pngbin202946 -> 192428 bytes
-rw-r--r--test/script/jfx/spread.js222
-rw-r--r--test/script/jfx/spread/golden/linux.pngbin0 -> 201159 bytes
-rw-r--r--test/script/jfx/spread/golden/macosx.pngbin0 -> 199251 bytes
-rw-r--r--test/script/jfx/spread/golden/windows.pngbin0 -> 201159 bytes
-rw-r--r--test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java99
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java12
-rw-r--r--test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java25
-rw-r--r--test/src/jdk/nashorn/api/scripting/Window.java19
68 files changed, 1641 insertions, 205 deletions
diff --git a/.hgtags b/.hgtags
index 130f85dd..3fe1fdb0 100644
--- a/.hgtags
+++ b/.hgtags
@@ -224,3 +224,7 @@ d49a8c2173f5f90c9a39cc4af8e03cfa8f35ee4c jdk8-b110
6a4fdb3bb4e34af4c5bb8db467bb01e13b1a7e31 jdk8-b112
676cd7bf5e092356f7ee2116c8cf88cdc12377c7 jdk8-b113
79f7b79bf97b71c9b5c9b103dbdef5f269eeb86d jdk8-b114
+f0d3ac2474ee755b1180ec71bcdfa190845b17eb jdk8-b115
+0fb1a427fbf6e04c77cebbbf99b6631c664ed793 jdk8-b116
+1db3d4e4d18913e853d7bebf86816e87fda00a71 jdk8-b117
+8d014b039b44c23fa520ce20c2c27f7aa91441e9 jdk8-b118
diff --git a/make/build.xml b/make/build.xml
index c90cdd6f..7d1f42ae 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -372,6 +372,12 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" {
<copy file="${file.reference.jfxrt.jar}" todir="dist"/>
+ <condition property="jfx.prism.order" value="-Dprism.order=j2d" else=" ">
+ <not>
+ <os family="mac"/>
+ </not>
+ </condition>
+
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
<jvmarg line="${ext.class.path}"/>
@@ -380,6 +386,7 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" {
<propertyref prefix="testjfx-test-sys-prop."/>
<mapper from="testjfx-test-sys-prop.*" to="*" type="glob"/>
</propertyset>
+ <sysproperty key="test.fork.jvm.options" value="${testjfx-test-sys-prop.test.fork.jvm.options} ${jfx.prism.order}"/>
<classpath>
<pathelement path="${testjfx.run.test.classpath}"/>
</classpath>
diff --git a/make/project.properties b/make/project.properties
index 33c94780..c3ffca4e 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -230,7 +230,7 @@ testjfx.run.test.classpath=\
${file.reference.jemmyawtinput.jar}${path.separator}\
${file.reference.testng.jar}${path.separator}\
${nashorn.internal.tests.jar}${path.separator}\
- ${nashorn.api.tests.jar}
+ ${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}
diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index ee287a2e..911f1663 100644
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -41,6 +41,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.script.Bindings;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
@@ -594,14 +595,35 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
/**
- * Make a script object mirror on given object if needed.
+ * Utilitity to convert this script object to the given type.
*
- * @param obj object to be wrapped
- * @param homeGlobal global to which this object belongs
- * @return wrapped object
+ * @param type destination type to convert to
+ * @return converted object
+ */
+ public <T> T to(final Class<T> type) {
+ return inGlobal(new Callable<T>() {
+ @Override
+ public T call() {
+ return type.cast(ScriptUtils.convert(sobj, type));
+ }
+ });
+ }
+
+ /**
+ * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+ *
+ * @param obj object to be wrapped/converted
+ * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+ * @return wrapped/converted object
*/
- public static Object wrap(final Object obj, final ScriptObject homeGlobal) {
- return (obj instanceof ScriptObject && homeGlobal != null) ? new ScriptObjectMirror((ScriptObject)obj, homeGlobal) : obj;
+ public static Object wrap(final Object obj, final Object homeGlobal) {
+ if(obj instanceof ScriptObject) {
+ return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj;
+ }
+ if(obj instanceof ConsString) {
+ return obj.toString();
+ }
+ return obj;
}
/**
@@ -611,7 +633,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @param homeGlobal global to which this object belongs
* @return unwrapped object
*/
- public static Object unwrap(final Object obj, final ScriptObject homeGlobal) {
+ public static Object unwrap(final Object obj, final Object homeGlobal) {
if (obj instanceof ScriptObjectMirror) {
final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
return (mirror.global == homeGlobal)? mirror.sobj : obj;
@@ -627,7 +649,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @param homeGlobal global to which this object belongs
* @return wrapped array
*/
- public static Object[] wrapArray(final Object[] args, final ScriptObject homeGlobal) {
+ public static Object[] wrapArray(final Object[] args, final Object homeGlobal) {
if (args == null || args.length == 0) {
return args;
}
@@ -648,7 +670,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @param homeGlobal global to which this object belongs
* @return unwrapped array
*/
- public static Object[] unwrapArray(final Object[] args, final ScriptObject homeGlobal) {
+ public static Object[] unwrapArray(final Object[] args, final Object homeGlobal) {
if (args == null || args.length == 0) {
return args;
}
diff --git a/src/jdk/nashorn/api/scripting/ScriptUtils.java b/src/jdk/nashorn/api/scripting/ScriptUtils.java
index 48045e1f..29d03db4 100644
--- a/src/jdk/nashorn/api/scripting/ScriptUtils.java
+++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java
@@ -25,11 +25,17 @@
package jdk.nashorn.api.scripting;
+import java.lang.invoke.MethodHandle;
+import jdk.internal.dynalink.beans.StaticClass;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
+import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
- * Utilities that are to be called from script code
+ * Utilities that are to be called from script code.
*/
public final class ScriptUtils {
private ScriptUtils() {}
@@ -71,4 +77,96 @@ public final class ScriptUtils {
return func.makeSynchronizedFunction(sync);
}
+ /**
+ * Make a script object mirror on given object if needed.
+ *
+ * @param obj object to be wrapped
+ * @return wrapped object
+ */
+ public static Object wrap(final Object obj) {
+ if (obj instanceof ScriptObject) {
+ return ScriptObjectMirror.wrap(obj, Context.getGlobal());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Unwrap a script object mirror if needed.
+ *
+ * @param obj object to be unwrapped
+ * @return unwrapped object
+ */
+ public static Object unwrap(final Object obj) {
+ if (obj instanceof ScriptObjectMirror) {
+ return ScriptObjectMirror.unwrap(obj, Context.getGlobal());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Wrap an array of object to script object mirrors if needed.
+ *
+ * @param args array to be unwrapped
+ * @return wrapped array
+ */
+ public static Object[] wrapArray(final Object[] args) {
+ if (args == null || args.length == 0) {
+ return args;
+ }
+
+ return ScriptObjectMirror.wrapArray(args, Context.getGlobal());
+ }
+
+ /**
+ * Unwrap an array of script object mirrors if needed.
+ *
+ * @param args array to be unwrapped
+ * @return unwrapped array
+ */
+ public static Object[] unwrapArray(final Object[] args) {
+ if (args == null || args.length == 0) {
+ return args;
+ }
+
+ return ScriptObjectMirror.unwrapArray(args, Context.getGlobal());
+ }
+
+ /**
+ * Convert the given object to the given type.
+ *
+ * @param obj object to be converted
+ * @param type destination type to convert to
+ * @return converted object
+ */
+ public static Object convert(final Object obj, final Object type) {
+ if (obj == null) {
+ return null;
+ }
+
+ final Class<?> clazz;
+ if (type instanceof Class) {
+ clazz = (Class<?>)type;
+ } else if (type instanceof StaticClass) {
+ clazz = ((StaticClass)type).getRepresentedClass();
+ } else {
+ throw new IllegalArgumentException("type expected");
+ }
+
+ final LinkerServices linker = Bootstrap.getLinkerServices();
+ final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz);
+ if (converter == null) {
+ // no supported conversion!
+ throw new UnsupportedOperationException("conversion not supported");
+ }
+
+ try {
+ return converter.invoke(obj);
+ } catch (final RuntimeException | Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
}
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 5415a06d..f1ced8ad 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -271,6 +271,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
functionNode.addDeclaredSymbol(symbol);
if (varNode.isFunctionDeclaration()) {
newType(symbol, FunctionNode.FUNCTION_TYPE);
+ symbol.setIsFunctionDeclaration();
}
return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
}
@@ -1264,12 +1265,17 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
- return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode));
+ return leaveComma(binaryNode, binaryNode.rhs());
}
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
- return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode));
+ return leaveComma(binaryNode, binaryNode.lhs());
+ }
+
+ private Node leaveComma(final BinaryNode commaNode, final Expression effectiveExpr) {
+ ensureTypeNotUnknown(effectiveExpr);
+ return end(ensureSymbol(effectiveExpr.getType(), commaNode));
}
@Override
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 7dd12de1..f5c1fb87 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;
@@ -415,6 +412,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method;
}
+ assert !type.isUnknown();
+
/*
* The load may be of type IdentNode, e.g. "x", AccessNode, e.g. "x.y"
* or IndexNode e.g. "x[y]". Both AccessNodes and IndexNodes are
@@ -709,6 +708,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());
diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java
index 2921ea9e..8012adf5 100644
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -134,6 +134,10 @@ public class MapCreator {
flags |= Property.CAN_BE_UNDEFINED;
}
+ if (symbol.isFunctionDeclaration()) {
+ flags |= Property.IS_FUNCTION_DECLARATION;
+ }
+
return flags;
}
diff --git a/src/jdk/nashorn/internal/codegen/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/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index 69e98ac6..2906893f 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -75,6 +75,8 @@ public final class Symbol implements Comparable<Symbol> {
public static final int IS_SPECIALIZED_PARAM = 1 << 13;
/** Is this symbol a shared temporary? */
public static final int IS_SHARED = 1 << 14;
+ /** Is this a function declaration? */
+ public static final int IS_FUNCTION_DECLARATION = 1 << 15;
/** Null or name identifying symbol. */
private final String name;
@@ -360,6 +362,14 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * Check if this symbol is a function declaration
+ * @return true if a function declaration
+ */
+ public boolean isFunctionDeclaration() {
+ return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
+ }
+
+ /**
* Creates an unshared copy of a symbol. The symbol must be currently shared.
* @param newName the name for the new symbol.
* @return a new, unshared symbol.
@@ -396,6 +406,16 @@ public final class Symbol implements Comparable<Symbol> {
/**
+ * Mark this symbol as a function declaration.
+ */
+ public void setIsFunctionDeclaration() {
+ if (!isFunctionDeclaration()) {
+ trace("SET IS FUNCTION DECLARATION");
+ flags |= IS_FUNCTION_DECLARATION;
+ }
+ }
+
+ /**
* Check if this symbol is a variable
* @return true if variable
*/
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index 70e1c726..26c14b76 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -109,6 +109,13 @@ public final class TernaryNode extends Expression {
}
}
+ @Override
+ public boolean isLocal() {
+ return getTest().isLocal()
+ && getTrueExpression().isLocal()
+ && getFalseExpression().isLocal();
+ }
+
/**
* Get the test expression for this ternary expression, i.e. "x" in x ? y : z
* @return the test expression
diff --git a/src/jdk/nashorn/internal/ir/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 a0df10b0..0a09370a 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -53,19 +53,19 @@ import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
-import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
-import jdk.nashorn.internal.runtime.arrays.ArrayData;
-import jdk.nashorn.internal.runtime.regexp.RegExpResult;
+import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.Scope;
+import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.ScriptingFunctions;
import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.regexp.RegExpResult;
import jdk.nashorn.internal.scripts.JO;
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java
index 94e3bef2..c7db39a5 100644
--- a/src/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java
@@ -60,6 +60,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
+import jdk.nashorn.internal.runtime.linker.NashornBeansLinker;
/**
* ECMA 15.2 Object objects
@@ -729,8 +730,7 @@ public final class NativeObject {
final MethodType methodType, final Object source) {
final GuardedInvocation inv;
try {
- inv = linker.getGuardedInvocation(createLinkRequest(operation, methodType, source),
- Bootstrap.getLinkerServices());
+ inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices());
assert passesGuard(source, inv.getGuard());
} catch(RuntimeException|Error e) {
throw e;
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
index 1ddc42b5..ba5ae66c 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
@@ -24,6 +24,7 @@
*/
package jdk.nashorn.internal.runtime;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.Iterator;
import java.util.TreeSet;
@@ -35,6 +36,8 @@ import java.util.TreeSet;
@SuppressWarnings("serial")
final class CompiledFunctions extends TreeSet<CompiledFunction> {
+ private CompiledFunction generic;
+
CompiledFunction best(final MethodType type) {
final Iterator<CompiledFunction> iter = iterator();
while (iter.hasNext()) {
@@ -43,13 +46,10 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return next;
}
}
- return mostGeneric();
+ return generic();
}
boolean needsCallee() {
- for (final CompiledFunction inv : this) {
- assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
- }
return ScriptFunctionData.needsCallee(mostGeneric().getInvoker());
}
@@ -57,6 +57,48 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return last();
}
+ CompiledFunction generic() {
+ CompiledFunction gen = this.generic;
+ if (gen == null) {
+ gen = this.generic = makeGeneric(mostGeneric());
+ }
+ return gen;
+ }
+
+ private static CompiledFunction makeGeneric(final CompiledFunction func) {
+ final MethodHandle invoker = composeGenericMethod(func.getInvoker());
+ final MethodHandle constructor = func.hasConstructor() ? composeGenericMethod(func.getConstructor()) : null;
+ return new CompiledFunction(invoker.type(), invoker, constructor);
+ }
+
+ /**
+ * Takes a method handle, and returns a potentially different method handle that can be used in
+ * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}.
+ * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
+ * {@code Object} as well, except for the following ones:
+ * <ul>
+ * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
+ * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
+ * (callee) as an argument.</li>
+ * </ul>
+ *
+ * @param mh the original method handle
+ *
+ * @return the new handle, conforming to the rules above.
+ */
+ private static MethodHandle composeGenericMethod(final MethodHandle mh) {
+ final MethodType type = mh.type();
+ final boolean isVarArg = ScriptFunctionData.isVarArg(mh);
+ final int paramCount = isVarArg ? type.parameterCount() - 1 : type.parameterCount();
+
+ MethodType newType = MethodType.genericMethodType(paramCount, isVarArg);
+
+ if (ScriptFunctionData.needsCallee(mh)) {
+ newType = newType.changeParameterType(0, ScriptFunction.class);
+ }
+ return type.equals(newType) ? mh : mh.asType(newType);
+ }
+
/**
* Is the given type even more specific than this entire list? That means
* we have an opportunity for more specific versions of the method
diff --git a/src/jdk/nashorn/internal/runtime/ConsString.java b/src/jdk/nashorn/internal/runtime/ConsString.java
index 9cf51552..8f764f4b 100644
--- a/src/jdk/nashorn/internal/runtime/ConsString.java
+++ b/src/jdk/nashorn/internal/runtime/ConsString.java
@@ -57,10 +57,7 @@ public final class ConsString implements CharSequence {
@Override
public String toString() {
- if (!flat) {
- flatten();
- }
- return (String) left;
+ return (String) flattened();
}
@Override
@@ -70,18 +67,19 @@ public final class ConsString implements CharSequence {
@Override
public char charAt(final int index) {
- if (!flat) {
- flatten();
- }
- return left.charAt(index);
+ return flattened().charAt(index);
}
@Override
public CharSequence subSequence(final int start, final int end) {
+ return flattened().subSequence(start, end);
+ }
+
+ private CharSequence flattened() {
if (!flat) {
flatten();
}
- return left.subSequence(start, end);
+ return left;
}
private void flatten() {
diff --git a/src/jdk/nashorn/internal/runtime/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 e1b91302..54130196 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -88,6 +88,9 @@ public enum JSType {
/** JavaScript compliant conversion function from Object to number */
public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class);
+ /** JavaScript compliant conversion function from Object to String */
+ public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class);
+
/** JavaScript compliant conversion function from Object to int32 */
public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class);
@@ -883,7 +886,7 @@ public enum JSType {
*/
public static Object toJavaArray(final Object obj, final Class<?> componentType) {
if (obj instanceof ScriptObject) {
- return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType);
+ return ((ScriptObject)obj).getArray().asArrayOfType(componentType);
} else if (obj instanceof JSObject) {
final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj);
final int len = (int) itr.getLength();
@@ -908,6 +911,15 @@ public enum JSType {
* @return converted Java array
*/
public static Object convertArray(final Object[] src, final Class<?> componentType) {
+ if(componentType == Object.class) {
+ for(int i = 0; i < src.length; ++i) {
+ final Object e = src[i];
+ if(e instanceof ConsString) {
+ src[i] = e.toString();
+ }
+ }
+ }
+
final int l = src.length;
final Object dst = Array.newInstance(componentType, l);
final MethodHandle converter = Bootstrap.getLinkerServices().getTypeConverter(Object.class, componentType);
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index e735ed11..d1dbe2ad 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -56,33 +56,36 @@ public abstract class Property {
public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000;
/** ECMA 8.6.1 - Is this property not writable? */
- public static final int NOT_WRITABLE = 0b0000_0000_0001;
+ public static final int NOT_WRITABLE = 1 << 0;
/** ECMA 8.6.1 - Is this property not enumerable? */
- public static final int NOT_ENUMERABLE = 0b0000_0000_0010;
+ public static final int NOT_ENUMERABLE = 1 << 1;
/** ECMA 8.6.1 - Is this property not configurable? */
- public static final int NOT_CONFIGURABLE = 0b0000_0000_0100;
+ public static final int NOT_CONFIGURABLE = 1 << 2;
- private static final int MODIFY_MASK = 0b0000_0000_1111;
+ private static final int MODIFY_MASK = (NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE);
/** Is this a spill property? See {@link AccessorProperty} */
- public static final int IS_SPILL = 0b0000_0001_0000;
+ public static final int IS_SPILL = 1 << 3;
/** Is this a function parameter? */
- public static final int IS_PARAMETER = 0b0000_0010_0000;
+ public static final int IS_PARAMETER = 1 << 4;
/** Is parameter accessed thru arguments? */
- public static final int HAS_ARGUMENTS = 0b0000_0100_0000;
+ public static final int HAS_ARGUMENTS = 1 << 5;
/** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */
- public static final int IS_ALWAYS_OBJECT = 0b0000_1000_0000;
+ public static final int IS_ALWAYS_OBJECT = 1 << 6;
/** Can this property be primitive? */
- public static final int CAN_BE_PRIMITIVE = 0b0001_0000_0000;
+ public static final int CAN_BE_PRIMITIVE = 1 << 7;
/** Can this property be undefined? */
- public static final int CAN_BE_UNDEFINED = 0b0010_0000_0000;
+ public static final int CAN_BE_UNDEFINED = 1 << 8;
+
+ /* Is this a function declaration property ? */
+ public static final int IS_FUNCTION_DECLARATION = 1 << 9;
/** Property key. */
private final String key;
@@ -522,4 +525,12 @@ public abstract class Property {
public boolean canBeUndefined() {
return (flags & CAN_BE_UNDEFINED) == CAN_BE_UNDEFINED;
}
+
+ /**
+ * Check whether this property represents a function declaration.
+ * @return whether this property is a function declaration or not.
+ */
+ public boolean isFunctionDeclaration() {
+ return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/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/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 5d1fbcd6..c7c82027 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -226,14 +226,23 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
for (final Property property : properties) {
final String key = property.getKey();
-
- if (newMap.findProperty(key) == null) {
+ final Property oldProp = newMap.findProperty(key);
+ if (oldProp == null) {
if (property instanceof UserAccessorProperty) {
final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
newMap = newMap.addProperty(prop);
} else {
newMap = newMap.addPropertyBind((AccessorProperty)property, source);
}
+ } else {
+ // See ECMA section 10.5 Declaration Binding Instantiation
+ // step 5 processing each function declaration.
+ if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) {
+ if (oldProp instanceof UserAccessorProperty ||
+ !(oldProp.isWritable() && oldProp.isEnumerable())) {
+ throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this));
+ }
+ }
}
}
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/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index f725817a..0d5f68a1 100644
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -63,7 +63,7 @@ public final class Bootstrap {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
- factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
+ factory.setFallbackLinkers(new NashornBeansLinker(), new NashornBottomLinker());
factory.setSyncOnRelink(true);
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
if (relinkThreshold > -1) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
index ccd497d7..77c1618b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
@@ -72,7 +72,7 @@ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
// Delegate to BeansLinker
- final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
+ final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass),
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
if(inv == null) {
return null;
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
index 8e40805a..c42af1d8 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
@@ -100,8 +100,9 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
type.changeParameterType(0, adapterClass), 0);
// Delegate to BeansLinker
- final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
- linkRequest.replaceArguments(newDescriptor, args), linkerServices);
+ final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation(
+ BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args),
+ linkerServices);
final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
if(guardedInv == null) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
new file mode 100644
index 00000000..e2db2b11
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime.linker;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import jdk.internal.dynalink.beans.BeansLinker;
+import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.GuardingDynamicLinker;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.support.Lookup;
+import jdk.nashorn.internal.runtime.ConsString;
+
+/**
+ * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
+ * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
+ * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
+ * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
+ * the target method handle parameter signature is {@code Object}.
+ */
+public class NashornBeansLinker implements GuardingDynamicLinker {
+ private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
+
+ private final BeansLinker beansLinker = new BeansLinker();
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
+ }
+
+ /**
+ * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special
+ * conversions that this class does.
+ * @param delegateLinker the linker to which the actual work is delegated to.
+ * @param linkRequest the delegated link request
+ * @param linkerServices the original link services that will be augmented with special conversions
+ * @return the guarded invocation from the delegate, possibly augmented with special conversions
+ * @throws Exception if the delegate throws an exception
+ */
+ public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
+ }
+
+ @SuppressWarnings("unused")
+ private static Object exportArgument(final Object arg) {
+ return arg instanceof ConsString ? arg.toString() : arg;
+ }
+
+ private static class NashornBeansLinkerServices implements LinkerServices {
+ private final LinkerServices linkerServices;
+
+ NashornBeansLinkerServices(final LinkerServices linkerServices) {
+ this.linkerServices = linkerServices;
+ }
+
+ @Override
+ public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
+ final MethodHandle typed = linkerServices.asType(handle, fromType);
+
+ final MethodType handleType = handle.type();
+ final int paramCount = handleType.parameterCount();
+ assert fromType.parameterCount() == handleType.parameterCount();
+
+ MethodHandle[] filters = null;
+ for(int i = 0; i < paramCount; ++i) {
+ if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
+ if(filters == null) {
+ filters = new MethodHandle[paramCount];
+ }
+ filters[i] = EXPORT_ARGUMENT;
+ }
+ }
+
+ return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
+ }
+
+ private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
+ return handleType == Object.class && fromType == Object.class;
+ }
+
+ @Override
+ public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
+ return linkerServices.getTypeConverter(sourceType, targetType);
+ }
+
+ @Override
+ public boolean canConvert(final Class<?> from, final Class<?> to) {
+ return linkerServices.canConvert(from, to);
+ }
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
+ return linkerServices.getGuardedInvocation(linkRequest);
+ }
+
+ @Override
+ public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
+ return linkerServices.compareConversion(sourceType, targetType1, targetType2);
+ }
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
index 6dbcbdd3..c94df15b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
@@ -33,14 +33,18 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.HashMap;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
+import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
@@ -50,7 +54,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* setters for Java objects that couldn't be linked by any other linker, and throw appropriate ECMAScript errors for
* attempts to invoke arbitrary Java objects as functions or constructors.
*/
-final class NashornBottomLinker implements GuardingDynamicLinker {
+final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeConverterFactory {
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
@@ -129,6 +133,29 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
throw new AssertionError("unknown call type " + desc);
}
+ @Override
+ public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
+ final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType);
+ return gi == null ? null : gi.asType(MH.type(targetType, sourceType));
+ }
+
+ /**
+ * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType(Class, Class)} that doesn't
+ * care about adapting the method signature; that's done by the invoking method. Returns conversion from Object to String/number/boolean (JS primitive types).
+ * @param sourceType the source type
+ * @param targetType the target type
+ * @return a guarded invocation that converts from the source type to the target type.
+ * @throws Exception if something goes wrong
+ */
+ private static GuardedInvocation convertToTypeNoCast(final Class<?> sourceType, final Class<?> targetType) throws Exception {
+ final MethodHandle mh = CONVERTERS.get(targetType);
+ if (mh != null) {
+ return new GuardedInvocation(mh, null);
+ }
+
+ return null;
+ }
+
private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
return Bootstrap.asType(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc);
}
@@ -161,6 +188,15 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
throw new AssertionError("unknown call type " + desc);
}
+ private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
+ static {
+ CONVERTERS.put(boolean.class, JSType.TO_BOOLEAN.methodHandle());
+ CONVERTERS.put(double.class, JSType.TO_NUMBER.methodHandle());
+ CONVERTERS.put(int.class, JSType.TO_INTEGER.methodHandle());
+ CONVERTERS.put(long.class, JSType.TO_LONG.methodHandle());
+ CONVERTERS.put(String.class, JSType.TO_STRING.methodHandle());
+ }
+
private static String getArgument(final LinkRequest linkRequest) {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
if (desc.getNameTokenCount() > 2) {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
index a760c604..27e4573f 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
@@ -32,6 +32,8 @@ import java.lang.invoke.MethodHandles;
import java.lang.reflect.Modifier;
import java.util.Deque;
import java.util.List;
+import java.util.Map;
+import javax.script.Bindings;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.ConversionComparator;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -40,7 +42,11 @@ import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.objects.NativeArray;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -115,9 +121,14 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : IS_NASHORN_OR_UNDEFINED_TYPE);
}
- GuardedInvocation inv = getArrayConverter(sourceType, targetType);
- if(inv != null) {
- return inv;
+ final GuardedInvocation arrayConverter = getArrayConverter(sourceType, targetType);
+ if(arrayConverter != null) {
+ return arrayConverter;
+ }
+
+ final GuardedInvocation mirrorConverter = getMirrorConverter(sourceType, targetType);
+ if(mirrorConverter != null) {
+ return mirrorConverter;
}
return getSamTypeConverter(sourceType, targetType);
@@ -181,6 +192,18 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return MH.asType(converter, converter.type().changeReturnType(type));
}
+ private static GuardedInvocation getMirrorConverter(Class<?> sourceType, Class<?> targetType) {
+ // Could've also used (targetType.isAssignableFrom(ScriptObjectMirror.class) && targetType != Object.class) but
+ // it's probably better to explicitly spell out the supported target types
+ if (targetType == Map.class || targetType == Bindings.class || targetType == JSObject.class || targetType == ScriptObjectMirror.class) {
+ if(ScriptObject.class.isAssignableFrom(sourceType)) {
+ return new GuardedInvocation(CREATE_MIRROR, null);
+ }
+ return new GuardedInvocation(CREATE_MIRROR, IS_SCRIPT_OBJECT);
+ }
+ return null;
+ }
+
private static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
return isAbstractClass(clazz) && !ScriptObject.class.isAssignableFrom(clazz) &&
JavaAdapterFactory.isAutoConvertibleFromFunction(clazz);
@@ -235,17 +258,23 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return clazz == List.class || clazz == Deque.class;
}
+ private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class));
private static final MethodHandle IS_SCRIPT_FUNCTION = Guards.isInstance(ScriptFunction.class, MH.type(Boolean.TYPE, Object.class));
private static final MethodHandle IS_NATIVE_ARRAY = Guards.isOfClass(NativeArray.class, MH.type(Boolean.TYPE, Object.class));
- private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined",
- Boolean.TYPE, Object.class);
+ private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", Boolean.TYPE, Object.class);
+ private static final MethodHandle CREATE_MIRROR = findOwnMH("createMirror", Object.class, Object.class);
@SuppressWarnings("unused")
private static boolean isNashornTypeOrUndefined(final Object obj) {
return obj instanceof ScriptObject || obj instanceof Undefined;
}
+ @SuppressWarnings("unused")
+ private static Object createMirror(final Object obj) {
+ return ScriptUtils.wrap(obj);
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), NashornLinker.class, name, MH.type(rtype, types));
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
index ce60d790..72ed9766 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
@@ -93,7 +93,7 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
private static GuardedInvocation delegate(LinkerServices linkerServices, final LinkRequest request) throws Exception {
- return staticClassLinker.getGuardedInvocation(request, linkerServices);
+ return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices);
}
private static GuardedInvocation checkNullConstructor(final GuardedInvocation ctorInvocation, final Class<?> receiverClass) {
diff --git a/test/script/basic/JDK-8015355.js b/test/script/basic/JDK-8015355.js
index bc39d8d9..aa1a39de 100644
--- a/test/script/basic/JDK-8015355.js
+++ b/test/script/basic/JDK-8015355.js
@@ -28,10 +28,6 @@
* @run
*/
-function fail(msg) {
- print(msg);
-}
-
function check(callback) {
try {
callback();
diff --git a/test/script/basic/JDK-8027042.js b/test/script/basic/JDK-8027042.js
new file mode 100644
index 00000000..eea6373b
--- /dev/null
+++ b/test/script/basic/JDK-8027042.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027042: Evaluation order for binary operators can be improved
+ *
+ * @test
+ * @run
+ */
+
+// var with getter side effect
+Object.defineProperty(this, "a", { get: function() {print("get a"); return 1; }});
+
+// var with both getter and conversion side effect
+Object.defineProperty(this, "b", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }});
+
+(function() {
+ // var with toPrimitive conversion side effect
+ var c = {valueOf: function() { print("conv c"); return 100; }};
+
+ print(b + (c + a));
+ print(b + (c + b));
+ print(b + (a + b));
+ print(b + (b + c));
+ print(b + (b + c));
+ print(b + (c + (a - b)));
+ print(b + (c + (c - b)));
+ print(b + (c + (b - c)));
+ print(b + (b + (a ? 2 : 3)));
+ print(b + (b + (b ? 2 : 3)));
+ print(b + (b + (c ? 2 : 3)));
+ print(b + ((-c) + (-a)));
+ print(b + ((-c) + (-b)));
+ print(b + ((-c) + (-c)));
+ try { print(b + new a); } catch (e) {}
+ try { print(b + new b); } catch (e) {}
+ try { print(b + new c); } catch (e) {}
+})();
diff --git a/test/script/basic/JDK-8027042.js.EXPECTED b/test/script/basic/JDK-8027042.js.EXPECTED
new file mode 100644
index 00000000..25b34e61
--- /dev/null
+++ b/test/script/basic/JDK-8027042.js.EXPECTED
@@ -0,0 +1,88 @@
+get b
+get a
+conv c
+conv b
+111
+get b
+get b
+conv c
+conv b
+conv b
+120
+get b
+get a
+get b
+conv b
+conv b
+21
+get b
+get b
+conv b
+conv c
+conv b
+120
+get b
+get b
+conv b
+conv c
+conv b
+120
+get b
+get a
+get b
+conv b
+conv c
+conv b
+101
+get b
+get b
+conv c
+conv b
+conv c
+conv b
+200
+get b
+get b
+conv b
+conv c
+conv c
+conv b
+20
+get b
+get b
+get a
+conv b
+conv b
+22
+get b
+get b
+get b
+conv b
+conv b
+22
+get b
+get b
+conv b
+conv b
+22
+get b
+conv c
+get a
+conv b
+-91
+get b
+conv c
+get b
+conv b
+conv b
+-100
+get b
+conv c
+conv c
+conv b
+-190
+get b
+get a
+get b
+get b
+get b
diff --git a/test/script/basic/JDK-8027236.js b/test/script/basic/JDK-8027236.js
new file mode 100644
index 00000000..02f9e8d8
--- /dev/null
+++ b/test/script/basic/JDK-8027236.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027236: Ensure ScriptObject and ConsString aren't visible to Java
+ *
+ * @test
+ * @run
+ */
+
+// Check that ConsString is flattened
+var m = new java.util.HashMap()
+var x = "f"
+x += "oo"
+m.put(x, "bar")
+print(m.get("foo"))
+// Note: many more tests are run by the JavaExportImportTest TestNG class.
diff --git a/test/script/basic/JDK-8027236.js.EXPECTED b/test/script/basic/JDK-8027236.js.EXPECTED
new file mode 100644
index 00000000..5716ca59
--- /dev/null
+++ b/test/script/basic/JDK-8027236.js.EXPECTED
@@ -0,0 +1 @@
+bar
diff --git a/test/script/basic/JDK-8027562.js b/test/script/basic/JDK-8027562.js
new file mode 100644
index 00000000..950584b4
--- /dev/null
+++ b/test/script/basic/JDK-8027562.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027562: eval should load second and subsequent arguments for side effect
+ *
+ * @test
+ * @run
+ */
+
+try {
+ eval("", x);
+ fail("should have thrown ReferenceError for 'x'");
+} catch (e) {
+ if (! (e instanceof ReferenceError)) {
+ fail("Expected ReferenceError, got " + e);
+ }
+ print(e);
+}
diff --git a/test/script/basic/JDK-8027562.js.EXPECTED b/test/script/basic/JDK-8027562.js.EXPECTED
new file mode 100644
index 00000000..c007ed7b
--- /dev/null
+++ b/test/script/basic/JDK-8027562.js.EXPECTED
@@ -0,0 +1 @@
+ReferenceError: "x" is not defined
diff --git a/test/script/basic/JDK-8027700.js b/test/script/basic/JDK-8027700.js
new file mode 100644
index 00000000..4c5445d8
--- /dev/null
+++ b/test/script/basic/JDK-8027700.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027700: function redeclaration checks missing for declaration binding instantiation
+ *
+ * @test
+ * @run
+ */
+
+Object.defineProperty(this,"x", {
+ value:0,
+ writable:true,
+ enumerable:false
+})
+
+try {
+ eval("function x() {}");
+ fail("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected but got " + e);
+ }
+}
+
+Object.defineProperty(this, "foo", { value:0 })
+try {
+ eval("function foo() {}");
+ fail("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ fail("TypeError expected but got " + e);
+ }
+}
diff --git a/test/script/basic/JDK-8027753.js b/test/script/basic/JDK-8027753.js
new file mode 100644
index 00000000..2af0baad
--- /dev/null
+++ b/test/script/basic/JDK-8027753.js
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027753: Support ScriptObject to JSObject, ScriptObjectMirror, Map, Bindings auto-conversion as well as explicit wrap, unwrap
+ *
+ * @test
+ * @run
+ */
+
+var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils");
+var ScriptObjectMirror = Java.type("jdk.nashorn.api.scripting.ScriptObjectMirror");
+
+var obj = { foo: 34, bar: 'hello' };
+
+var wrapped = ScriptUtils.wrap(obj);
+if (! (wrapped instanceof ScriptObjectMirror)) {
+ fail("ScriptUtils.wrap does not return a ScriptObjectMirror");
+}
+
+print("wrapped.foo = " + wrapped.foo);
+print("wrapped.bar = " + wrapped.bar);
+
+var unwrapped = ScriptUtils.unwrap(wrapped);
+if (! (unwrapped instanceof Object)) {
+ fail("ScriptUtils.unwrap does not return a ScriptObject");
+}
+
+// same object unwrapped?
+print(unwrapped === obj);
diff --git a/test/script/basic/JDK-8027753.js.EXPECTED b/test/script/basic/JDK-8027753.js.EXPECTED
new file mode 100644
index 00000000..30a8779e
--- /dev/null
+++ b/test/script/basic/JDK-8027753.js.EXPECTED
@@ -0,0 +1,3 @@
+wrapped.foo = 34
+wrapped.bar = hello
+true
diff --git a/test/script/basic/JDK-8027828.js b/test/script/basic/JDK-8027828.js
new file mode 100644
index 00000000..ab60938b
--- /dev/null
+++ b/test/script/basic/JDK-8027828.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8027828: ClassCastException when converting return value of a Java method to boolean
+ *
+ * @test
+ * @run
+ */
+
+var x = new java.util.HashMap()
+x.put('test', new java.io.File('test'))
+if (x.get("test")) {
+ print('Found!')
+}
diff --git a/test/script/basic/JDK-8027828.js.EXPECTED b/test/script/basic/JDK-8027828.js.EXPECTED
new file mode 100644
index 00000000..7a8c9edc
--- /dev/null
+++ b/test/script/basic/JDK-8027828.js.EXPECTED
@@ -0,0 +1 @@
+Found!
diff --git a/test/script/basic/JDK-8028020.js b/test/script/basic/JDK-8028020.js
new file mode 100644
index 00000000..4dfa0cad
--- /dev/null
+++ b/test/script/basic/JDK-8028020.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8028020: Function parameter as last expression in comma in return value causes bad type calculation
+ *
+ * @test
+ * @run
+ */
+
+function f(x) {
+ return 1, x
+}
+
+function g(x, y) {
+ return x, y
+}
+
+print(f("'1, x' works."))
+print(g(42, "'x, y' works too."))
diff --git a/test/script/basic/JDK-8028020.js.EXPECTED b/test/script/basic/JDK-8028020.js.EXPECTED
new file mode 100644
index 00000000..816a21ce
--- /dev/null
+++ b/test/script/basic/JDK-8028020.js.EXPECTED
@@ -0,0 +1,2 @@
+'1, x' works.
+'x, y' works too.
diff --git a/test/script/basic/convert.js b/test/script/basic/convert.js
new file mode 100644
index 00000000..8d11d122
--- /dev/null
+++ b/test/script/basic/convert.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests for convert method of ScriptUtils.
+ *
+ * @test
+ * @run
+ */
+
+var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils");
+obj = { valueOf: function() { print("hello"); return 43.3; } };
+
+// object to double
+print(ScriptUtils.convert(obj, java.lang.Number.class));
+
+// array to List
+var arr = [3, 44, 23, 33];
+var list = ScriptUtils.convert(arr, java.util.List.class);
+print(list instanceof java.util.List)
+print(list);
+
+// object to Map
+obj = { foo: 333, bar: 'hello'};
+var map = ScriptUtils.convert(obj, java.util.Map.class);
+print(map instanceof java.util.Map);
+for (m in map) {
+ print(m + " " + map[m]);
+}
+
+// object to String
+obj = { toString: function() { print("in toString"); return "foo" } };
+print(ScriptUtils.convert(obj, java.lang.String.class));
+
+// array to Java array
+var jarr = ScriptUtils.convert(arr, Java.type("int[]"));
+print(jarr instanceof Java.type("int[]"));
+for (i in jarr) {
+ print(jarr[i]);
+}
+
diff --git a/test/script/basic/convert.js.EXPECTED b/test/script/basic/convert.js.EXPECTED
new file mode 100644
index 00000000..e83faebd
--- /dev/null
+++ b/test/script/basic/convert.js.EXPECTED
@@ -0,0 +1,14 @@
+hello
+43.3
+true
+[3, 44, 23, 33]
+true
+foo 333
+bar hello
+in toString
+foo
+true
+3
+44
+23
+33
diff --git a/test/script/jfx.js b/test/script/jfx.js
index 26f97873..5962b5d0 100644
--- a/test/script/jfx.js
+++ b/test/script/jfx.js
@@ -37,13 +37,24 @@ 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 Paint = Java.type("javafx.scene.paint.Paint");
+var Color = Java.type("javafx.scene.paint.Color");
+var Image = Java.type("javafx.scene.image.Image");
+var Canvas = Java.type("javafx.scene.canvas.Canvas");
+var BorderPane = Java.type("javafx.scene.layout.BorderPane");
+var StackPane = Java.type("javafx.scene.layout.StackPane");
+var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap");
+var Platform = Java.type("javafx.application.Platform");
+var Runnable = Java.type("java.lang.Runnable");
+var RunnableExtend = Java.extend(Runnable);
+var AnimationTimer = Java.type("javafx.animation.AnimationTimer");
+var AnimationTimerExtend = Java.extend(AnimationTimer);
+var Timer = Java.type("java.util.Timer");
+var TimerTask = Java.type("java.util.TimerTask");
-var WAIT = 2000;
var TESTNAME = "test";
var fsep = System.getProperty("file.separator");
@@ -53,14 +64,16 @@ function checkImageAndExit() {
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");
+ var scrShotTmp = tmpdir + fsep + "screenshot" + timenow +".png";
+ var goldenImageDir = __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden";
+ makeScreenShot(scrShotTmp);
+ var dupImg = isDuplicateImages(scrShotTmp, goldenImageDir);
+ (new File(scrShotTmp)).delete();
+ if (!dupImg) System.err.println("ERROR: screenshot does not match the golden image");
exit(0);
}
};
- raceTimer.schedule(timerTask, WAIT);
+ raceTimer.schedule(timerTask, 100);
}
function makeScreenShot(shootToImg) {
@@ -70,10 +83,10 @@ function makeScreenShot(shootToImg) {
imageJemmy.save(shootToImg);
}
-function isDuplicateImages(file1, file2) {
- var f1 = new File(file1);
+function isDuplicateImages(screenShot, goldenDir) {
+ var f1 = new File(screenShot);
var f2;
- var sb = new StringBuffer(file2);
+ var sb = new StringBuffer(goldenDir);
if (OSInfo.getOSType() == OSType.WINDOWS) {
f2 = new File(sb.append(fsep + "windows.png").toString());
} else if (OSInfo.getOSType() == OSType.LINUX) {
@@ -81,8 +94,6 @@ function isDuplicateImages(file1, file2) {
} 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()));
diff --git a/test/script/jfx/flyingimage.js b/test/script/jfx/flyingimage.js
index 4cf3f7fc..844a0fc3 100644
--- a/test/script/jfx/flyingimage.js
+++ b/test/script/jfx/flyingimage.js
@@ -31,15 +31,6 @@
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);
@@ -48,10 +39,9 @@ function fileToURL(file) {
}
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 t = frame;
var gc = canvas.graphicsContext2D;
gc.setFill(Color.web("#cccccc"));
gc.fillRect(0, 0, WIDTH, HEIGHT);
@@ -61,7 +51,7 @@ function renderFrame() {
var c = 200;
var msc= 0.5 * HEIGHT / img.height;
var sp0 = 0.003;
- for (var h = 0; h < c; h++, t++) {
+ for (var h = 0; h < c; h++) {
gc.setTransform(1, 0, 0, 1, 0, 0);
var yh = h / (c - 1);
gc.translate((0.5 + Math.sin(t * sp0 + h * 0.1) / 3) * WIDTH, 25 + (HEIGHT * 3 / 4 - 40) * (yh * yh));
@@ -69,15 +59,26 @@ function renderFrame() {
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();
+var frame = 0;
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 200) {
+ renderFrame();
+ frame++;
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
+
diff --git a/test/script/jfx/flyingimage/flyingimage.png b/test/script/jfx/flyingimage/flyingimage.png
index ecd98a14..afc44dd3 100644
--- a/test/script/jfx/flyingimage/flyingimage.png
+++ 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
index 4f678853..4a668a6d 100644
--- a/test/script/jfx/flyingimage/golden/linux.png
+++ 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
index cb153219..ba72fe68 100644
--- a/test/script/jfx/flyingimage/golden/macosx.png
+++ 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
index e3897148..e47ae4df 100644
--- a/test/script/jfx/flyingimage/golden/windows.png
+++ 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
index a932c517..4430ff01 100644
--- a/test/script/jfx/kaleidoscope.js
+++ b/test/script/jfx/kaleidoscope.js
@@ -30,13 +30,6 @@
*/
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;
@@ -56,26 +49,28 @@ var d=new Array(6);
var r,e;
var fade;
var prv_x,prv_y,prv_x2,prv_y2;
+var isFrameRendered = false;
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();
+ if (!isFrameRendered) {
+ a=0.2*angle;
+ b=0.7*angle;
+ r=0;
+ fade=32;
+ for(var i=0;i<6;i++)
+ {
+ c[i]=1.0/(i+1)/2;
+ d[i]=1.0/(i+1)/2;
+ }
+ radius=Math.round((WIDTH+HEIGHT)/8);
+ e=radius*0.2;
+ p_x=Math.round(WIDTH/2);
+ p_y=Math.round(HEIGHT/2);
+ x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]);
+ y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]);
+ isFrameRendered = true;
}
+ anim();
}
function anim() {
@@ -154,9 +149,19 @@ function draw_line(x,y,x1,y1,x2,y2) {
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
+var frame = 0;
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 800) {
+ renderFrame();
+ frame++;
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
diff --git a/test/script/jfx/kaleidoscope/golden/linux.png b/test/script/jfx/kaleidoscope/golden/linux.png
index ccc92fe9..4d7e81ad 100644
--- a/test/script/jfx/kaleidoscope/golden/linux.png
+++ 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
index 1adeb1e4..64d9499b 100644
--- a/test/script/jfx/kaleidoscope/golden/macosx.png
+++ 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
index 84ee37c0..4d7e81ad 100644
--- a/test/script/jfx/kaleidoscope/golden/windows.png
+++ b/test/script/jfx/kaleidoscope/golden/windows.png
Binary files differ
diff --git a/test/script/jfx/spread.js b/test/script/jfx/spread.js
new file mode 100644
index 00000000..4a8f38ce
--- /dev/null
+++ b/test/script/jfx/spread.js
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Testing JavaFX canvas run by Nashorn.
+ *
+ * @test/nocompare
+ * @run
+ * @fork
+ */
+
+TESTNAME = "spread";
+
+var WIDTH = 800;
+var HEIGHT = 600;
+var canvas = new Canvas(WIDTH, HEIGHT);
+var context = canvas.graphicsContext2D;
+
+/* "Spread" tech demo of canvas by Tom Theisen
+ *
+ * This will animate a sequence of branch structures in a canvas element.
+ * Each frame, a new direction is calculated, similar to the last frame.
+ */
+
+var start_width = 20; // starting width of each branch
+var frame_time = 30; // milliseconds per frame
+var straighten_factor = 0.95; // value from 0 to 1, factor applied to direction_offset every frame
+var curviness = 0.2; // amount of random direction change each frame
+
+var color_speed = 0.03; // speed at which colors change when cycling is enabled
+var branch_shrink = 0.95; // factor by which branches shrink every frame
+var min_width = 1; // minimum WIDTH for branch, after which they are discontinued
+var branch_opacity = 0.4; // opacity of lines drawn
+var branch_count = 3; // branch count per tree
+var branch_bud_size = 0.5; // ratio of original branch size at which branch will split
+var branch_bud_angle = 1; // angle offset for split branch;
+
+var paper; // reference to graphics context
+var branches = Object(); // linked list of active branches
+var color_styles = []; // pre-computed list of colors as styles. format: (r,g,b,a)
+var direction_offset = 0; // current direction offset in radians. this is applied to all branches.
+var frame = 0; // frame counter
+var timespent = 0; // total time spent so far, used to calculate average frame render duration
+var frameratespan; // html span element for updating performance number
+
+// preferences object, contains an attribute for each user setting
+var prefs = {
+ wrap: true, // causes branches reaching edge of viewable area to appear on opposite side
+ fade: false, // fade existing graphics on each frame
+ cycle: true, // gradually change colors each frame
+ new_branch_frames: 20 // number of frames elapsed between each auto-generated tree
+};
+
+// create tree at the specified position with number of branches
+function create_tree(branches, start_width, position, branch_count) {
+ var angle_offset = Math.PI * 2 / branch_count;
+ for (var i = 0; i < branch_count; ++i) {
+ branch_add(branches, new Branch(position, angle_offset * i, start_width));
+ }
+}
+
+// add branch to collection
+function branch_add(branches, branch) {
+ branch.next = branches.next;
+ branches.next = branch;
+}
+
+// get the coordinates for the position of a new tree
+// use the center of the canvas
+function get_new_tree_center(width, height) {
+ return {
+ x: 0.5 * width,
+ y: 0.5 * height
+ };
+}
+
+// Branch constructor
+// position has x and y properties
+// direction is in radians
+function Branch(position, direction, width) {
+ this.x = position.x;
+ this.y = position.y;
+ this.width = width;
+ this.original_width = width;
+ this.direction = direction;
+}
+
+// update position, direction and width of a particular branch
+function branch_update(branches, branch, paper) {
+ paper.beginPath();
+ paper.lineWidth = branch.width;
+ paper.moveTo(branch.x, branch.y);
+
+ branch.width *= branch_shrink;
+ branch.direction += direction_offset;
+ branch.x += Math.cos(branch.direction) * branch.width;
+ branch.y += Math.sin(branch.direction) * branch.width;
+
+ paper.lineTo(branch.x, branch.y);
+ paper.stroke();
+
+ if (prefs.wrap) wrap_branch(branch, WIDTH, HEIGHT);
+
+ if (branch.width < branch.original_width * branch_bud_size) {
+ branch.original_width *= branch_bud_size;
+ branch_add(branches, new Branch(branch, branch.direction + 1, branch.original_width));
+ }
+}
+
+function draw_frame() {
+ if (prefs.fade) {
+ paper.fillRect(0, 0, WIDTH, HEIGHT);
+ }
+
+ if (prefs.cycle) {
+ paper.setStroke(Paint.valueOf(color_styles[frame % color_styles.length]));
+ }
+
+ if (frame++ % prefs.new_branch_frames == 0) {
+ create_tree(branches, start_width, get_new_tree_center(WIDTH, HEIGHT), branch_count);
+ }
+
+ direction_offset += (0.35 + (frame % 200) * 0.0015) * curviness - curviness / 2;
+ direction_offset *= straighten_factor;
+
+ var branch = branches;
+ var prev_branch = branches;
+ while (branch = branch.next) {
+ branch_update(branches, branch, paper);
+
+ if (branch.width < min_width) {
+ // remove branch from list
+ prev_branch.next = branch.next;
+ }
+
+ prev_branch = branch;
+ }
+}
+
+// constrain branch position to visible area by "wrapping" from edge to edge
+function wrap_branch(branch, WIDTH, HEIGHT) {
+ branch.x = positive_mod(branch.x, WIDTH);
+ branch.y = positive_mod(branch.y, HEIGHT);
+}
+
+// for a < 0, b > 0, javascript returns a negative number for a % b
+// this is a variant of the % operator that adds b to the result in this case
+function positive_mod(a, b) {
+ // ECMA 262 11.5.3: Applying the % Operator
+ // remainder operator does not convert operands to integers,
+ // although negative results are possible
+
+ return ((a % b) + b) % b;
+}
+
+// pre-compute color styles that will be used for color cycling
+function populate_colors(color_speed, color_styles, branch_opacity) {
+ // used in calculation of RGB values
+ var two_thirds_pi = Math.PI * 2 / 3;
+ var four_thirds_pi = Math.PI * 4 / 3;
+ var two_pi = Math.PI * 2;
+
+ // hue does represent hue, but not in the conventional HSL scheme
+ for(var hue = 0; hue < two_pi; hue += color_speed) {
+ var r = Math.floor(Math.sin(hue) * 128 + 128);
+ var g = Math.floor(Math.sin(hue + two_thirds_pi) * 128 + 128);
+ var b = Math.floor(Math.sin(hue + four_thirds_pi) * 128 + 128);
+ color = "rgba(" + [r, g, b, branch_opacity].join() + ")";
+
+ color_styles.push(color);
+ }
+}
+
+// apply initial settings to canvas object
+function setup_canvas() {
+ paper = canvas.graphicsContext2D;
+ paper.setFill(Paint.valueOf('rgb(0, 0, 0)'));
+ paper.fillRect(0, 0, WIDTH, HEIGHT);
+ paper.setFill(Paint.valueOf("rgba(0, 0, 0, 0.005)"));
+ paper.setStroke(Paint.valueOf("rgba(128, 128, 64, " + String(branch_opacity) + ")"));
+}
+
+populate_colors(color_speed, color_styles, branch_opacity);
+setup_canvas();
+
+var stack = new StackPane();
+var pane = new BorderPane();
+pane.setCenter(canvas);
+stack.getChildren().add(pane);
+$STAGE.scene = new Scene(stack);
+var timer = new AnimationTimerExtend() {
+ handle: function handle(now) {
+ if (frame < 200) {
+ draw_frame();
+ } else {
+ checkImageAndExit();
+ timer.stop();
+ }
+ }
+};
+timer.start();
+
diff --git a/test/script/jfx/spread/golden/linux.png b/test/script/jfx/spread/golden/linux.png
new file mode 100644
index 00000000..fc535a47
--- /dev/null
+++ b/test/script/jfx/spread/golden/linux.png
Binary files differ
diff --git a/test/script/jfx/spread/golden/macosx.png b/test/script/jfx/spread/golden/macosx.png
new file mode 100644
index 00000000..c2881623
--- /dev/null
+++ b/test/script/jfx/spread/golden/macosx.png
Binary files differ
diff --git a/test/script/jfx/spread/golden/windows.png b/test/script/jfx/spread/golden/windows.png
new file mode 100644
index 00000000..fc535a47
--- /dev/null
+++ b/test/script/jfx/spread/golden/windows.png
Binary files differ
diff --git a/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java
new file mode 100644
index 00000000..1eadfb77
--- /dev/null
+++ b/test/src/jdk/nashorn/api/javaaccess/ConsStringTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api.javaaccess;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.JSObject;
+import org.testng.TestNG;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class ConsStringTest {
+ private static ScriptEngine e = null;
+
+ public static void main(final String[] args) {
+ TestNG.main(args);
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws ScriptException {
+ e = new ScriptEngineManager().getEngineByName("nashorn");
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ e = null;
+ }
+
+ @Test
+ public void testConsStringFlattening() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final Map<Object, Object> m = new HashMap<>();
+ b.put("m", m);
+ e.eval("var x = 'f'; x += 'oo'; var y = 'b'; y += 'ar'; m.put(x, y)");
+ assertEquals("bar", m.get("foo"));
+ }
+
+ @Test
+ public void testConsStringFromMirror() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final Map<Object, Object> m = new HashMap<>();
+ e.eval("var x = 'f'; x += 'oo'; var obj = {x: x};");
+ assertEquals("foo", ((JSObject)b.get("obj")).getMember("x"));
+ }
+
+ @Test
+ public void testArrayConsString() throws ScriptException {
+ final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
+ final ArrayHolder h = new ArrayHolder();
+ b.put("h", h);
+ e.eval("var x = 'f'; x += 'oo'; h.array = [x];");
+ assertEquals(1, h.array.length);
+ assertEquals("foo", h.array[0]);
+ }
+
+
+ public static class ArrayHolder {
+ private Object[] array;
+
+ public void setArray(Object[] array) {
+ this.array = array;
+ }
+
+ public Object[] getArray() {
+ return array;
+ }
+ }
+}
diff --git a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
index 99207de0..55aacb34 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java
@@ -523,6 +523,18 @@ public class ScriptEngineTest {
assertEquals(sw.toString(), println("34 true hello"));
}
+ @Test
+ public void scriptObjectAutoConversionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ e.eval("obj = { foo: 'hello' }");
+ e.put("Window", e.eval("Packages.jdk.nashorn.api.scripting.Window"));
+ assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
+ assertEquals(e.eval("Window.funcScriptObjectMirror(obj)"), "hello");
+ assertEquals(e.eval("Window.funcMap(obj)"), "hello");
+ assertEquals(e.eval("Window.funcJSObject(obj)"), "hello");
+ }
+
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
// Returns String that would be the result of calling PrintWriter.println
diff --git a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
index 6c35ee40..544f4ea7 100644
--- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
+++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java
@@ -26,6 +26,7 @@
package jdk.nashorn.api.scripting;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
@@ -227,4 +228,28 @@ public class ScriptObjectMirrorTest {
final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject();
assertTrue(newObj instanceof ScriptObjectMirror);
}
+
+ @Test
+ public void conversionTest() throws ScriptException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final ScriptObjectMirror arr = (ScriptObjectMirror)e.eval("[33, 45, 23]");
+ final int[] intArr = arr.to(int[].class);
+ assertEquals(intArr[0], 33);
+ assertEquals(intArr[1], 45);
+ assertEquals(intArr[2], 23);
+
+ final List<?> list = arr.to(List.class);
+ assertEquals(list.get(0), 33);
+ assertEquals(list.get(1), 45);
+ assertEquals(list.get(2), 23);
+
+ ScriptObjectMirror obj = (ScriptObjectMirror)e.eval(
+ "({ valueOf: function() { return 42 } })");
+ assertEquals(Double.valueOf(42.0), obj.to(Double.class));
+
+ obj = (ScriptObjectMirror)e.eval(
+ "({ toString: function() { return 'foo' } })");
+ assertEquals("foo", obj.to(String.class));
+ }
}
diff --git a/test/src/jdk/nashorn/api/scripting/Window.java b/test/src/jdk/nashorn/api/scripting/Window.java
index bde23941..510c5dae 100644
--- a/test/src/jdk/nashorn/api/scripting/Window.java
+++ b/test/src/jdk/nashorn/api/scripting/Window.java
@@ -25,6 +25,9 @@
package jdk.nashorn.api.scripting;
+import java.util.Map;
+import javax.script.Bindings;
+
public class Window {
private String location = "http://localhost:8080/window";
@@ -63,4 +66,20 @@ public class Window {
System.out.println("window.setTimeout: " + delay + ", code: " + code);
return 0;
}
+
+ public static Object funcJSObject(final JSObject jsobj) {
+ return jsobj.getMember("foo");
+ }
+
+ public static Object funcScriptObjectMirror(final ScriptObjectMirror sobj) {
+ return sobj.get("foo");
+ }
+
+ public static Object funcMap(final Map<?,?> map) {
+ return map.get("foo");
+ }
+
+ public static Object funcBindings(final Bindings bindings) {
+ return bindings.get("foo");
+ }
}