aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrobm <none@none>2017-01-04 19:44:40 +0000
committerrobm <none@none>2017-01-04 19:44:40 +0000
commitb825ce88a014b466ad3a6f4c3812be1e00b77d03 (patch)
treea8097065b66f98bd17c37d6c36e09a7b91c54896
parentfb152de042bfc2020c9377fb3b4fa9846152e9b1 (diff)
parent9102bbfc23f2288eccfed2dc67a404a21fe4a27b (diff)
downloadjdk8u_nashorn-b825ce88a014b466ad3a6f4c3812be1e00b77d03.tar.gz
Merge
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java77
-rw-r--r--src/jdk/nashorn/internal/ir/debug/PrintVisitor.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java22
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornLinker.java14
-rw-r--r--test/script/basic/JDK-8170594.js45
-rw-r--r--test/script/basic/JDK-8171849.js47
-rw-r--r--test/script/basic/es6/JDK-8168373.js44
-rw-r--r--test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java38
-rw-r--r--test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java74
10 files changed, 329 insertions, 36 deletions
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index b2a31646..6b9b731f 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -4016,7 +4016,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
void loadStack() {
assert assignNode.getWidestOperandType() == Type.INT;
if (isRhsZero(binaryNode)) {
- loadExpressionAsType(binaryNode.lhs(), Type.INT);
+ loadExpression(binaryNode.lhs(), TypeBounds.INT, true);
} else {
loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.INT, true, false);
method.shr();
diff --git a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index 310a0875..63bafa71 100644
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -33,6 +33,7 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
@@ -122,9 +123,9 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
private final List<JumpOrigin> origins = new LinkedList<>();
private Map<Symbol, LvarType> types = Collections.emptyMap();
- void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
+ void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) {
origins.add(new JumpOrigin(originNode, originTypes));
- this.types = getUnionTypes(this.types, originTypes);
+ this.types = calc.getUnionTypes(this.types, originTypes);
}
}
private enum LvarType {
@@ -185,12 +186,15 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
}
@SuppressWarnings("unchecked")
- private static IdentityHashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
- return (IdentityHashMap<Symbol, LvarType>)((IdentityHashMap<?,?>)map).clone();
+ private static HashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
+ return (HashMap<Symbol, LvarType>)((HashMap<?,?>)map).clone();
}
private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType,
final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) {
+ if (invalidatedSymbols.contains(symbol)) {
+ return next;
+ }
final LvarType targetType = joinLvarTypes.get(symbol);
assert targetType != null;
if(targetType == branchLvarType) {
@@ -208,7 +212,7 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
}
- private static Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
+ private Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
if(types1 == types2 || types1.isEmpty()) {
return types2;
} else if(types2.isEmpty()) {
@@ -261,6 +265,11 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
final LvarType type2 = types2.get(symbol);
union.put(symbol, widestLvarType(type1, type2));
}
+ // If the two sets of symbols differ, there's a good chance that some of
+ // symbols only appearing in one of the sets are lexically invalidated,
+ // so we remove them from further consideration.
+ // This is not strictly necessary, just a working set size optimization.
+ union.keySet().removeAll(invalidatedSymbols);
return union;
}
@@ -359,8 +368,6 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
return LvarType.OBJECT;
}
- // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
- // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
}
private final Compiler compiler;
@@ -368,7 +375,10 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
// Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
// allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
// value.
- private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+ private Map<Symbol, LvarType> localVariableTypes = Collections.emptyMap();
+ // Set of symbols whose lexical scope has already ended.
+ private final Set<Symbol> invalidatedSymbols = new HashSet<>();
+
// Stack for evaluated expression types.
private final Deque<LvarType> typeStack = new ArrayDeque<>();
@@ -464,9 +474,19 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
@Override
public boolean enterBlock(final Block block) {
+ boolean cloned = false;
for(final Symbol symbol: block.getSymbols()) {
- if(symbol.isBytecodeLocal() && getLocalVariableTypeOrNull(symbol) == null) {
- setType(symbol, LvarType.UNDEFINED);
+ if(symbol.isBytecodeLocal()) {
+ if (getLocalVariableTypeOrNull(symbol) == null) {
+ if (!cloned) {
+ cloneOrNewLocalVariableTypes();
+ cloned = true;
+ }
+ localVariableTypes.put(symbol, LvarType.UNDEFINED);
+ }
+ // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
+ // make sure all symbols lexically scoped by the block become valid again.
+ invalidatedSymbols.remove(symbol);
}
}
return true;
@@ -1046,15 +1066,11 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
// throw an exception.
reachable = true;
catchBody.accept(this);
- final Symbol exceptionSymbol = exception.getSymbol();
if(reachable) {
- localVariableTypes = cloneMap(localVariableTypes);
- localVariableTypes.remove(exceptionSymbol);
jumpToLabel(catchBody, endLabel);
canExit = true;
}
- localVariableTypes = cloneMap(afterConditionTypes);
- localVariableTypes.remove(exceptionSymbol);
+ localVariableTypes = afterConditionTypes;
}
// NOTE: if we had one or more conditional catch blocks with no unconditional catch block following them, then
// there will be an unconditional rethrow, so the join point can never be reached from the last
@@ -1204,7 +1220,7 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
}
private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) {
- getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types);
+ getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this);
}
@Override
@@ -1226,16 +1242,18 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
boolean cloned = false;
for(final Symbol symbol: block.getSymbols()) {
- // Undefine the symbol outside the block
- if(localVariableTypes.containsKey(symbol)) {
- if(!cloned) {
- localVariableTypes = cloneMap(localVariableTypes);
- cloned = true;
+ if(symbol.hasSlot()) {
+ // Invalidate the symbol when its defining block ends
+ if (symbol.isBytecodeLocal()) {
+ if(localVariableTypes.containsKey(symbol)) {
+ if(!cloned) {
+ localVariableTypes = cloneMap(localVariableTypes);
+ cloned = true;
+ }
+ }
+ invalidateSymbol(symbol);
}
- localVariableTypes.remove(symbol);
- }
- if(symbol.hasSlot()) {
final SymbolConversions conversions = symbolConversions.get(symbol);
if(conversions != null) {
// Potentially make some currently dead types live if they're needed as a source of a type
@@ -1605,10 +1623,19 @@ final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
}
assert symbol.hasSlot();
assert !symbol.isGlobal();
- localVariableTypes = localVariableTypes.isEmpty() ? new IdentityHashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+ cloneOrNewLocalVariableTypes();
localVariableTypes.put(symbol, type);
}
+ private void cloneOrNewLocalVariableTypes() {
+ localVariableTypes = localVariableTypes.isEmpty() ? new HashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+ }
+
+ private void invalidateSymbol(final Symbol symbol) {
+ localVariableTypes.remove(symbol);
+ invalidatedSymbols.add(symbol);
+ }
+
/**
* Set a flag in the symbol marking it as needing to be able to store a value of a particular type. Every symbol for
* a local variable will be assigned between 1 and 6 local variable slots for storing all types it is known to need
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index bb8d61a5..fccad153 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -397,7 +397,7 @@ public final class PrintVisitor extends SimpleNodeVisitor {
@Override
public boolean enterVarNode(final VarNode varNode) {
- sb.append("var ");
+ sb.append(varNode.isConst() ? "const " : varNode.isLet() ? "let " : "var ");
varNode.getName().toString(sb, printTypes);
printLocalVariableConversion(varNode.getName());
final Node init = varNode.getInit();
diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index e8e493b3..7eb23a9b 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -39,9 +39,13 @@ import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.objects.Global;
/**
* A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
@@ -141,9 +145,9 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
}
private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) {
- MethodHandle mh = JSOBJECT_CALL;
+ MethodHandle mh = NashornCallSiteDescriptor.isScope(desc)? JSOBJECT_SCOPE_CALL : JSOBJECT_CALL;
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
- mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, JSOBJECT_CALL);
+ mh = MH.insertArguments(JSOBJECT_CALL_TO_APPLY, 0, mh);
}
final MethodType type = desc.getMethodType();
mh = type.parameterType(type.parameterCount() - 1) == Object[].class ?
@@ -214,6 +218,19 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
}
}
+ // This is used when a JSObject is called as scope call to do undefined -> Global this translation.
+ @SuppressWarnings("unused")
+ private static Object jsObjectScopeCall(final JSObject jsObj, final Object thiz, final Object[] args) {
+ final Object modifiedThiz;
+ if (thiz == ScriptRuntime.UNDEFINED && !jsObj.isStrictFunction()) {
+ final Global global = Context.getGlobal();
+ modifiedThiz = ScriptObjectMirror.wrap(global, global);
+ } else {
+ modifiedThiz = thiz;
+ }
+ return jsObj.call(modifiedThiz, args);
+ }
+
private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
// method handles of the current class
@@ -225,6 +242,7 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
private static final MethodHandle JSOBJECT_GETMEMBER = findJSObjectMH_V("getMember", Object.class, String.class);
private static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class);
private static final MethodHandle JSOBJECT_CALL = findJSObjectMH_V("call", Object.class, Object.class, Object[].class);
+ private static final MethodHandle JSOBJECT_SCOPE_CALL = findOwnMH_S("jsObjectScopeCall", Object.class, JSObject.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
private static final MethodHandle JSOBJECT_NEW = findJSObjectMH_V("newObject", Object.class, Object[].class);
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
index ddcbae1f..b8e01ffd 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
@@ -251,15 +251,15 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
@Override
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
if(sourceType == NativeArray.class) {
- // Prefer lists, as they're less costly to create than arrays.
- if(isList(targetType1)) {
- if(!isList(targetType2)) {
+ // Prefer those types we can convert to with just a wrapper (cheaper than Java array creation).
+ if(isArrayPreferredTarget(targetType1)) {
+ if(!isArrayPreferredTarget(targetType2)) {
return Comparison.TYPE_1_BETTER;
}
- } else if(isList(targetType2)) {
+ } else if(isArrayPreferredTarget(targetType2)) {
return Comparison.TYPE_2_BETTER;
}
- // Then prefer arrays
+ // Then prefer Java arrays
if(targetType1.isArray()) {
if(!targetType2.isArray()) {
return Comparison.TYPE_1_BETTER;
@@ -281,8 +281,8 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
return Comparison.INDETERMINATE;
}
- private static boolean isList(final Class<?> clazz) {
- return clazz == List.class || clazz == Deque.class;
+ private static boolean isArrayPreferredTarget(final Class<?> clazz) {
+ return clazz == List.class || clazz == Collection.class || clazz == Queue.class || clazz == Deque.class;
}
private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class));
diff --git a/test/script/basic/JDK-8170594.js b/test/script/basic/JDK-8170594.js
new file mode 100644
index 00000000..6365500a
--- /dev/null
+++ b/test/script/basic/JDK-8170594.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 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-8170594: >>>=0 generates invalid bytecode for BaseNode LHS
+ *
+ * @test
+ * @run
+ */
+
+var obj1 = {x: "100"};
+(function (o, p) {
+ if (p) {
+ o.x >>>= 0;
+ }
+})(obj1, true)
+Assert.assertTrue(obj1.x === 100)
+
+var obj2 = ["100"];
+(function (o, p) {
+ if (p) {
+ o[0] >>>= 0;
+ }
+})(obj2, true)
+Assert.assertTrue(obj2[0] === 100)
diff --git a/test/script/basic/JDK-8171849.js b/test/script/basic/JDK-8171849.js
new file mode 100644
index 00000000..febc97ce
--- /dev/null
+++ b/test/script/basic/JDK-8171849.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 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-8171849: Collection and Queue conversions not prioritized for Arrays
+ *
+ * @test
+ * @run
+ */
+
+var acp = new (Java.type("jdk.nashorn.test.models.ArrayConversionPreferences"))
+
+var a = [1, "", {}]
+
+Assert.assertTrue(acp.testCollectionOverMap(a))
+Assert.assertTrue(acp.testCollectionOverArray(a))
+Assert.assertTrue(acp.testListOverMap(a))
+Assert.assertTrue(acp.testListOverArray(a))
+Assert.assertTrue(acp.testListOverCollection(a))
+Assert.assertTrue(acp.testQueueOverMap(a))
+Assert.assertTrue(acp.testQueueOverArray(a))
+Assert.assertTrue(acp.testQueueOverCollection(a))
+Assert.assertTrue(acp.testDequeOverMap(a))
+Assert.assertTrue(acp.testDequeOverArray(a))
+Assert.assertTrue(acp.testDequeOverCollection(a))
+Assert.assertTrue(acp.testDequeOverQueue(a))
+Assert.assertTrue(acp.testArrayOverMap(a))
diff --git a/test/script/basic/es6/JDK-8168373.js b/test/script/basic/es6/JDK-8168373.js
new file mode 100644
index 00000000..af26e735
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168373.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 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-8168373: don't emit conversions for symbols outside their lexical scope
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function p() { return false } // "predicate"
+function r(x) { return x } // "read"
+
+(function() {
+ try { // Try creates control flow edges from assignments into catch blocks.
+ // Lexically scoped, never read int variable (undefined at catch block) but still with a cf edge into catch block.
+ // Since it's never read, it's not written either (Nashorn optimizes some dead writes).
+ let x = 0;
+ if (p()) { throw {}; } // We need `p()` so this block doesn't get optimized away, for possibility of a `throw`
+ x = 0.0; // change the type of x to double
+ r(x); // read x otherwise it's optimized away
+ } catch (e) {} // under the bug, "throw" will try to widen unwritten int x to double for here and cause a verifier error
+})()
diff --git a/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
index f9c78fc7..7656dc6b 100644
--- a/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
+++ b/test/src/jdk/nashorn/api/scripting/test/ScriptObjectMirrorTest.java
@@ -41,6 +41,7 @@ import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.testng.annotations.Test;
@@ -386,4 +387,41 @@ public class ScriptObjectMirrorTest {
assertTrue(func.isFunction());
assertEquals(func.call(e.eval("this"), "hello"), "hello world");
}
+
+ // @bug 8170565: JSObject call() is passed undefined for the argument 'thiz'
+ @Test
+ public void jsObjectThisTest() throws Exception {
+ final ScriptEngineManager engineManager = new ScriptEngineManager();
+ final ScriptEngine e = engineManager.getEngineByName("nashorn");
+ e.put("func", new AbstractJSObject() {
+ @Override
+ public boolean isFunction() { return true; }
+
+ @Override
+ public Object call(Object thiz, Object...args) {
+ return thiz;
+ }
+ });
+
+ assertTrue((boolean)e.eval("func() === this"));
+
+ // check that there is no blind undefined->Global translation!
+ assertTrue((boolean)e.eval("typeof(Function.prototype.call.call(func, undefined)) == 'undefined'"));
+
+ // make sure that strict functions don't get translated this for scope calls!
+ e.put("sfunc", new AbstractJSObject() {
+ @Override
+ public boolean isFunction() { return true; }
+
+ @Override
+ public boolean isStrictFunction() { return true; }
+
+ @Override
+ public Object call(Object thiz, Object...args) {
+ return thiz;
+ }
+ });
+
+ assertTrue((boolean)e.eval("typeof sfunc() == 'undefined'"));
+ }
}
diff --git a/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java b/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java
new file mode 100644
index 00000000..a88f3c37
--- /dev/null
+++ b/test/src/jdk/nashorn/test/models/ArrayConversionPreferences.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+public class ArrayConversionPreferences {
+ public boolean testCollectionOverMap(final Collection x) { return true; }
+ public boolean testCollectionOverMap(final Map x) { return false; }
+
+ public boolean testCollectionOverArray(final Collection x) { return true; }
+ public boolean testCollectionOverArray(final Object[] x) { return false; }
+
+ public boolean testListOverMap(final List x) { return true; }
+ public boolean testListOverMap(final Map x) { return false; }
+
+ public boolean testListOverArray(final List x) { return true; }
+ public boolean testListOverArray(final Object[] x) { return false; }
+
+ public boolean testListOverCollection(final List x) { return true; }
+ public boolean testListOverCollection(final Collection x) { return false; }
+
+ public boolean testQueueOverMap(final Queue x) { return true; }
+ public boolean testQueueOverMap(final Map x) { return false; }
+
+ public boolean testQueueOverArray(final Queue x) { return true; }
+ public boolean testQueueOverArray(final Object[] x) { return false; }
+
+ public boolean testQueueOverCollection(final Queue x) { return true; }
+ public boolean testQueueOverCollection(final Collection x) { return false; }
+
+ public boolean testDequeOverMap(final Deque x) { return true; }
+ public boolean testDequeOverMap(final Map x) { return false; }
+
+ public boolean testDequeOverArray(final Deque x) { return true; }
+ public boolean testDequeOverArray(final Object[] x) { return false; }
+
+ public boolean testDequeOverCollection(final Deque x) { return true; }
+ public boolean testDequeOverCollection(final Collection x) { return false; }
+
+ public boolean testDequeOverQueue(final Deque x) { return true; }
+ public boolean testDequeOverQueue(final Queue x) { return false; }
+
+ public boolean testArrayOverMap(final Object[] x) { return true; }
+ public boolean testArrayOverMap(final Map x) { return false; }
+}
+