aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorasaha <none@none>2014-12-12 14:58:31 -0800
committerasaha <none@none>2014-12-12 14:58:31 -0800
commit25350777b70f7a2757ab33c19eb4b1f26901126c (patch)
tree98c2069aab01c95a54d790313b4e31e966f8c270
parentf4460d5a8a36724e1f6dd91cc4641c6a53f81bca (diff)
parent23f869e575e7cb252f2695ceb3c59475595f86b6 (diff)
-rw-r--r--.hgtags2
-rw-r--r--src/jdk/nashorn/internal/codegen/AssignSymbols.java36
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java7
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/MapCreator.java4
-rw-r--r--src/jdk/nashorn/internal/ir/ForNode.java24
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java14
-rw-r--r--src/jdk/nashorn/internal/ir/LoopNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/VarNode.java19
-rw-r--r--src/jdk/nashorn/internal/ir/WhileNode.java5
-rw-r--r--src/jdk/nashorn/internal/objects/Global.java188
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDataView.java20
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFunction.java9
-rw-r--r--src/jdk/nashorn/internal/objects/NativeObject.java3
-rw-r--r--src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java5
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java58
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeStore.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java8
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java142
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayData.java15
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java59
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundCallable.java96
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java132
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java57
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java91
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Messages.properties4
-rw-r--r--test/script/basic/JDK-8049407-big-endian.js33
-rw-r--r--test/script/basic/JDK-8049407-big-endian.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8049407-payload.js37
-rw-r--r--test/script/basic/JDK-8049407.js33
-rw-r--r--test/script/basic/JDK-8049407.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8051778.js83
-rw-r--r--test/script/basic/JDK-8051778.js.EXPECTED10
-rw-r--r--test/script/basic/NASHORN-377-big-endian.js33
-rw-r--r--test/script/basic/NASHORN-377-big-endian.js.EXPECTED34
-rw-r--r--test/script/basic/NASHORN-377-payload.js226
-rw-r--r--test/script/basic/NASHORN-377.js199
-rw-r--r--test/script/basic/compile-octane-normal.js4
-rw-r--r--test/script/basic/compile-octane-splitter.js4
-rw-r--r--test/script/basic/compile-octane.js2
-rw-r--r--test/script/basic/es6/const-empty.js2
-rw-r--r--test/script/basic/es6/const-redeclare-extra.js2
-rw-r--r--test/script/basic/es6/const-redeclare-extra.js.EXPECTED12
-rw-r--r--test/script/basic/es6/const-redeclare.js2
-rw-r--r--test/script/basic/es6/for-let.js37
-rw-r--r--test/script/basic/es6/for-let.js.EXPECTED22
-rw-r--r--test/script/basic/es6/let-const-statement-context.js49
-rw-r--r--test/script/basic/es6/let-const-statement-context.js.EXPECTED30
-rw-r--r--test/script/basic/es6/let-const-switch.js45
-rw-r--r--test/script/basic/es6/let-const-switch.js.EXPECTED12
-rw-r--r--test/script/basic/es6/let-load.js18
-rw-r--r--test/script/basic/es6/let-load.js.EXPECTED5
-rw-r--r--test/script/basic/es6/let-redeclare-extra.js2
-rw-r--r--test/script/basic/es6/let-redeclare-extra.js.EXPECTED10
-rw-r--r--test/script/basic/es6/let-redeclare.js2
-rw-r--r--test/script/basic/es6/let_const_closure.js.EXPECTED6
-rw-r--r--test/script/basic/es6/let_const_reuse.js2
-rw-r--r--test/script/basic/es6/lexical-toplevel-def.js34
-rw-r--r--test/script/basic/es6/lexical-toplevel-print.js51
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js31
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js30
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js31
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js30
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js31
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js31
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare.js78
-rw-r--r--test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED100
-rw-r--r--test/script/basic/es6/lexical-toplevel.js35
-rw-r--r--test/script/basic/es6/lexical-toplevel.js.EXPECTED32
-rw-r--r--test/script/nosecurity/JDK-8050964.js1
-rw-r--r--test/script/nosecurity/JDK-8055034.js2
-rw-r--r--test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java212
-rw-r--r--test/src/jdk/nashorn/internal/test/framework/TestFinder.java7
77 files changed, 2183 insertions, 571 deletions
diff --git a/.hgtags b/.hgtags
index 0bbc5b88..847ccb13 100644
--- a/.hgtags
+++ b/.hgtags
@@ -350,4 +350,6 @@ d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13
7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14
fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15
e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16
+88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17
+653739706172ae94e999731a3a9f10f8ce11ffca jdk8u40-b18
05a3614ed5276e5db2a73cce918be04b1a2922fb jdk8u45-b00
diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java
index 88fd89bb..6eb89a16 100644
--- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -189,7 +189,7 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
* @param body the body of the FunctionNode we are entering
*/
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
- // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
+ // This visitor will assign symbol to all declared variables.
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
protected boolean enterDefault(final Node node) {
@@ -200,16 +200,17 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
@Override
public Node leaveVarNode(final VarNode varNode) {
- if (varNode.isStatement()) {
- final IdentNode ident = varNode.getName();
- final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
- final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
- if (varNode.isFunctionDeclaration()) {
- symbol.setIsFunctionDeclaration();
- }
- return varNode.setName(ident.setSymbol(symbol));
+ final IdentNode ident = varNode.getName();
+ final boolean blockScoped = varNode.isBlockScoped();
+ if (blockScoped && lc.inUnprotectedSwitchContext()) {
+ throwUnprotectedSwitchError(varNode);
+ }
+ final Block block = blockScoped ? lc.getCurrentBlock() : body;
+ final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
+ if (varNode.isFunctionDeclaration()) {
+ symbol.setIsFunctionDeclaration();
}
- return varNode;
+ return varNode.setName(ident.setSymbol(symbol));
}
});
}
@@ -356,6 +357,10 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
} else {
symbol.setHasBeenDeclared();
+ // Set scope flag on top-level block scoped symbols
+ if (function.isProgram() && function.getBody() == block) {
+ symbol.setIsScope();
+ }
}
} else if ((flags & IS_INTERNAL) != 0) {
// Always create a new definition.
@@ -540,7 +545,7 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
final int flags;
if (varNode.isAnonymousFunctionDeclaration()) {
flags = IS_INTERNAL;
- } else if (lc.getCurrentFunction().isProgram()) {
+ } else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
flags = IS_SCOPE;
} else {
flags = 0;
@@ -1044,6 +1049,15 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
return !(units == null || units.isEmpty());
}
+ private void throwUnprotectedSwitchError(final VarNode varNode) {
+ // Block scoped declarations in switch statements without explicit blocks should be declared
+ // in a common block that contains all the case clauses. We cannot support this without a
+ // fundamental rewrite of how switch statements are handled (case nodes contain blocks and are
+ // directly contained by switch node). As a temporary solution we throw a reference error here.
+ final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const");
+ throwParserException(msg, varNode);
+ }
+
private void throwParserException(final String message, final Node origin) {
if (origin == null) {
throw new ParserException(message);
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 6e84dd89..1bf3b382 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -3264,6 +3264,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
emitContinueLabel(continueLabel, liveLocalsOnContinue);
}
+ if (loopNode.hasPerIterationScope() && lc.getParentBlock().needsScope()) {
+ // ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here.
+ method.loadCompilerConstant(SCOPE);
+ method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class));
+ method.storeCompilerConstant(SCOPE);
+ }
+
if(method.isReachable()) {
if(modify != null) {
lineNumber(loopNode);
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index 724c6f1e..b52d3984 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -525,7 +525,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Lo
if (isAlwaysTrue(test)) {
//turn it into a for node without a test.
- final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, ForNode.IS_FOR).accept(this);
+ final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this);
lc.replace(whileNode, forNode);
return forNode;
}
diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java
index 3ba3f630..1bec86fc 100644
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -152,6 +152,10 @@ public class MapCreator<T> {
flags |= Property.NOT_WRITABLE;
}
+ if (symbol.isBlockScoped()) {
+ flags |= Property.IS_LEXICAL_BINDING;
+ }
+
// Mark symbol as needing declaration. Access before declaration will throw a ReferenceError.
if (symbol.isBlockScoped() && symbol.isScope()) {
flags |= Property.NEEDS_DECLARATION;
diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java
index 2847947c..ef6f11db 100644
--- a/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/src/jdk/nashorn/internal/ir/ForNode.java
@@ -45,14 +45,14 @@ public final class ForNode extends LoopNode {
/** Iterator symbol. */
private Symbol iterator;
- /** Is this a normal for loop? */
- public static final int IS_FOR = 1 << 0;
-
/** Is this a normal for in loop? */
- public static final int IS_FOR_IN = 1 << 1;
+ public static final int IS_FOR_IN = 1 << 0;
/** Is this a normal for each in loop? */
- public static final int IS_FOR_EACH = 1 << 2;
+ public static final int IS_FOR_EACH = 1 << 1;
+
+ /** Does this loop need a per-iteration scope because its init contain a LET declaration? */
+ public static final int PER_ITERATION_SCOPE = 1 << 2;
private final int flags;
@@ -273,4 +273,18 @@ public final class ForNode extends LoopNode {
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
}
+
+ @Override
+ public boolean hasPerIterationScope() {
+ return (flags & PER_ITERATION_SCOPE) != 0;
+ }
+
+ /**
+ * Set the per-iteration-scope flag on this node.
+ * @param lc lexical context
+ * @return the node with flag set
+ */
+ public ForNode setPerIterationScope(final LexicalContext lc) {
+ return setFlags(lc, flags | PER_ITERATION_SCOPE);
+ }
}
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
index 2b59a07c..487d6aeb 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -597,6 +597,20 @@ public class LexicalContext {
throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't");
}
+ /**
+ * Checks whether the current context is inside a switch statement without explicit blocks (curly braces).
+ * @return true if in unprotected switch statement
+ */
+ public boolean inUnprotectedSwitchContext() {
+ for (int i = sp; i > 0; i--) {
+ final LexicalContextNode next = stack[i];
+ if (next instanceof Block) {
+ return stack[i - 1] instanceof SwitchNode;
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
diff --git a/src/jdk/nashorn/internal/ir/LoopNode.java b/src/jdk/nashorn/internal/ir/LoopNode.java
index e6436ad9..5991a32a 100644
--- a/src/jdk/nashorn/internal/ir/LoopNode.java
+++ b/src/jdk/nashorn/internal/ir/LoopNode.java
@@ -176,4 +176,10 @@ public abstract class LoopNode extends BreakableStatement {
* @return new loop node if changed otherwise the same
*/
public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
+
+ /**
+ * Does this loop have a LET declaration and hence require a per-iteration scope?
+ * @return true if a per-iteration scope is required.
+ */
+ public abstract boolean hasPerIterationScope();
}
diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java
index 44d7d4c7..1cee8cb5 100644
--- a/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/src/jdk/nashorn/internal/ir/VarNode.java
@@ -45,19 +45,16 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
/** Is this a var statement (as opposed to a "var" in a for loop statement) */
private final int flags;
- /** Flag that determines if this function node is a statement */
- public static final int IS_STATEMENT = 1 << 0;
-
/** Flag for ES6 LET declaration */
- public static final int IS_LET = 1 << 1;
+ public static final int IS_LET = 1 << 0;
/** Flag for ES6 CONST declaration */
- public static final int IS_CONST = 1 << 2;
+ public static final int IS_CONST = 1 << 1;
/** Flag that determines if this is the last function declaration in a function
* This is used to micro optimize the placement of return value assignments for
* a program node */
- public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
+ public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 2;
/**
* Constructor
@@ -69,7 +66,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param init init node or null if just a declaration
*/
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) {
- this(lineNumber, token, finish, name, init, IS_STATEMENT);
+ this(lineNumber, token, finish, name, init, 0);
}
private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) {
@@ -260,14 +257,6 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
}
/**
- * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
- * @return true if this is a var statement (as opposed to a var initializer in a for loop).
- */
- public boolean isStatement() {
- return (flags & IS_STATEMENT) != 0;
- }
-
- /**
* Returns true if this is a function declaration.
* @return true if this is a function declaration.
*/
diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java
index 9a0981fb..7e60fee0 100644
--- a/src/jdk/nashorn/internal/ir/WhileNode.java
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java
@@ -148,4 +148,9 @@ public final class WhileNode extends LoopNode {
}
return test == null;
}
+
+ @Override
+ public boolean hasPerIterationScope() {
+ return false;
+ }
}
diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java
index 6a978627..bb3e13d2 100644
--- a/src/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk/nashorn/internal/objects/Global.java
@@ -34,6 +34,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -44,6 +45,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
+import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.ClassFilter;
@@ -54,6 +56,8 @@ import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.GlobalConstants;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
@@ -69,6 +73,7 @@ import jdk.nashorn.internal.runtime.Specialization;
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.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.regexp.RegExpResult;
import jdk.nashorn.internal.scripts.JO;
@@ -410,13 +415,14 @@ public final class Global extends ScriptObject implements Scope {
// Used to store the last RegExp result to support deprecated RegExp constructor properties
private RegExpResult lastRegExpResult;
- private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class);
- private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class);
- private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class);
- private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class);
- private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class);
- private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
- private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class);
+ private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class);
+ private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class);
+ private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class);
+ private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class);
+ private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class);
+ private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
+ private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class);
+ private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class);
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -429,6 +435,12 @@ public final class Global extends ScriptObject implements Scope {
// current ScriptEngine associated - can be null.
private ScriptEngine engine;
+ // ES6 global lexical scope.
+ private final LexicalScope lexicalScope;
+
+ // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope.
+ private SwitchPoint lexicalScopeSwitchPoint;
+
/**
* Set the current script context
* @param scontext script context
@@ -466,6 +478,7 @@ public final class Global extends ScriptObject implements Scope {
super(checkAndGetMap(context));
this.context = context;
this.setIsScope();
+ this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null;
}
/**
@@ -1694,6 +1707,133 @@ public final class Global extends ScriptObject implements Scope {
splitState = state;
}
+ /**
+ * Return the ES6 global scope for lexically declared bindings.
+ * @return the ES6 lexical global scope.
+ */
+ public final ScriptObject getLexicalScope() {
+ assert context.getEnv()._es6;
+ return lexicalScope;
+ }
+
+ @Override
+ public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) {
+ PropertyMap ownMap = getMap();
+ LexicalScope lexicalScope = null;
+ PropertyMap lexicalMap = null;
+ boolean hasLexicalDefinitions = false;
+
+ if (context.getEnv()._es6) {
+ lexicalScope = (LexicalScope) getLexicalScope();
+ lexicalMap = lexicalScope.getMap();
+
+ for (final jdk.nashorn.internal.runtime.Property property : properties) {
+ if (property.isLexicalBinding()) {
+ hasLexicalDefinitions = true;
+ }
+ // ES6 15.1.8 steps 6. and 7.
+ final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey());
+ if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) {
+ throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+ }
+ final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey());
+ if (lexicalProperty != null && !property.isConfigurable()) {
+ throw ECMAErrors.syntaxError("redeclare.variable", property.getKey());
+ }
+ }
+ }
+
+ for (final jdk.nashorn.internal.runtime.Property property : properties) {
+ if (property.isLexicalBinding()) {
+ assert lexicalScope != null;
+ lexicalMap = lexicalScope.addBoundProperty(lexicalMap, source, property);
+
+ if (ownMap.findProperty(property.getKey()) != null) {
+ // If property exists in the global object invalidate any global constant call sites.
+ invalidateGlobalConstant(property.getKey());
+ }
+ } else {
+ ownMap = addBoundProperty(ownMap, source, property);
+ }
+ }
+
+ setMap(ownMap);
+
+ if (hasLexicalDefinitions) {
+ lexicalScope.setMap(lexicalMap);
+ invalidateLexicalSwitchPoint();
+ }
+ }
+
+ @Override
+ public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
+
+ if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
+ if (lexicalScope.hasOwnProperty(name)) {
+ return lexicalScope.findGetMethod(desc, request, operator);
+ }
+ }
+
+ final GuardedInvocation invocation = super.findGetMethod(desc, request, operator);
+
+ // We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
+ // because those are invalidated per-key in the addBoundProperties method above.
+ // We therefor check if the invocation does already have a switchpoint and the property is non-inherited,
+ // assuming this only applies to global constants. If other non-inherited properties will
+ // start using switchpoints some time in the future we'll have to revisit this.
+ if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) {
+ return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
+ }
+
+ return invocation;
+ }
+
+ @Override
+ public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
+
+ if (lexicalScope != null && isScope) {
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ if (lexicalScope.hasOwnProperty(name)) {
+ return lexicalScope.findSetMethod(desc, request);
+ }
+ }
+
+ final GuardedInvocation invocation = super.findSetMethod(desc, request);
+
+ if (isScope && context.getEnv()._es6) {
+ return invocation.addSwitchPoint(getLexicalScopeSwitchPoint());
+ }
+
+ return invocation;
+ }
+
+ private synchronized SwitchPoint getLexicalScopeSwitchPoint() {
+ SwitchPoint switchPoint = lexicalScopeSwitchPoint;
+ if (switchPoint == null || switchPoint.hasBeenInvalidated()) {
+ switchPoint = lexicalScopeSwitchPoint = new SwitchPoint();
+ }
+ return switchPoint;
+ }
+
+ private synchronized void invalidateLexicalSwitchPoint() {
+ if (lexicalScopeSwitchPoint != null) {
+ context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update");
+ SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint });
+ }
+ }
+
+
+ @SuppressWarnings("unused")
+ private static Object lexicalScopeFilter(final Object self) {
+ if (self instanceof Global) {
+ return ((Global) self).getLexicalScope();
+ }
+ return self;
+ }
+
private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
final T func = initConstructor(name, clazz);
tagBuiltinProperties(name, func);
@@ -1739,7 +1879,7 @@ public final class Global extends ScriptObject implements Scope {
this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE);
this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN);
this.load = ScriptFunctionImpl.makeFunction("load", LOAD);
- this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOADWITHNEWGLOBAL);
+ this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL);
this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT);
this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT);
@@ -2205,4 +2345,36 @@ public final class Global extends ScriptObject implements Scope {
protected boolean isGlobal() {
return true;
}
+
+ /**
+ * A class representing the ES6 global lexical scope.
+ */
+ private static class LexicalScope extends ScriptObject {
+
+ LexicalScope(final ScriptObject proto) {
+ super(proto, PropertyMap.newMap());
+ }
+
+ @Override
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ return filterInvocation(super.findGetMethod(desc, request, operator));
+ }
+
+ @Override
+ protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ return filterInvocation(super.findSetMethod(desc, request));
+ }
+
+ @Override
+ protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) {
+ // We override this method just to make it callable by Global
+ return super.addBoundProperty(propMap, source, property);
+ }
+
+ private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) {
+ final MethodType type = invocation.getInvocation().type();
+ return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER);
+ }
+ }
+
}
diff --git a/src/jdk/nashorn/internal/objects/NativeDataView.java b/src/jdk/nashorn/internal/objects/NativeDataView.java
index fb502771..14c11f69 100644
--- a/src/jdk/nashorn/internal/objects/NativeDataView.java
+++ b/src/jdk/nashorn/internal/objects/NativeDataView.java
@@ -105,10 +105,10 @@ public class NativeDataView extends ScriptObject {
private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) {
super(Global.instance().getDataViewPrototype(), $nasgenmap$);
- this.buffer = arrBuf;
+ this.buffer = arrBuf;
this.byteOffset = offset;
this.byteLength = length;
- this.buf = buf;
+ this.buf = buf;
}
/**
@@ -135,14 +135,14 @@ public class NativeDataView extends ScriptObject {
throw typeError("not.an.arraybuffer.in.dataview");
}
- final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0];
+ final NativeArrayBuffer arrBuf = (NativeArrayBuffer)args[0];
switch (args.length) {
- case 1:
- return new NativeDataView(arrBuf);
- case 2:
- return new NativeDataView(arrBuf, JSType.toInt32(args[1]));
- default:
- return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2]));
+ case 1:
+ return new NativeDataView(arrBuf);
+ case 2:
+ return new NativeDataView(arrBuf, JSType.toInt32(args[1]));
+ default:
+ return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2]));
}
}
@@ -995,7 +995,7 @@ public class NativeDataView extends ScriptObject {
private static NativeDataView checkSelf(final Object self) {
if (!(self instanceof NativeDataView)) {
- throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self));
+ throw typeError("not.an.arraybuffer.in.dataview", ScriptRuntime.safeToString(self));
}
return (NativeDataView)self;
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java
index c4a79a56..bd2f2dd9 100644
--- a/src/jdk/nashorn/internal/objects/NativeFunction.java
+++ b/src/jdk/nashorn/internal/objects/NativeFunction.java
@@ -48,6 +48,7 @@ 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.linker.Bootstrap;
/**
* ECMA 15.3 Function Objects
@@ -204,11 +205,7 @@ public final class NativeFunction {
* @return function with bound arguments
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
- public static ScriptFunction bind(final Object self, final Object... args) {
- if (!(self instanceof ScriptFunction)) {
- throw typeError("not.a.function", ScriptRuntime.safeToString(self));
- }
-
+ public static Object bind(final Object self, final Object... args) {
final Object thiz = (args.length == 0) ? UNDEFINED : args[0];
Object[] arguments;
@@ -219,7 +216,7 @@ public final class NativeFunction {
arguments = ScriptRuntime.EMPTY_ARRAY;
}
- return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments);
+ return Bootstrap.bindCallable(self, thiz, arguments);
}
/**
diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java
index 7a1375d3..c086442d 100644
--- a/src/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java
@@ -28,6 +28,7 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -804,7 +805,7 @@ public final class NativeObject {
// name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
// constant for any given method name and object's class.)
return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
- Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
+ Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class);
} catch(RuntimeException|Error e) {
throw e;
} catch(final Throwable t) {
diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index 36e7716b..f147234b 100644
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -30,7 +30,6 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
-
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
@@ -237,13 +236,13 @@ public class ScriptFunctionImpl extends ScriptFunction {
/**
* Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we
- * can expose it to methods in this package.
+ * can expose it.
* @param self the self to bind to this function. Can be null (in which case, null is bound as this).
* @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
* @return a function with the specified self and parameters bound.
*/
@Override
- protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
+ public ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
return super.makeBoundFunction(self, args);
}
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index 3162e184..9c6f974d 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -559,7 +559,7 @@ loop:
// Set up new block. Captures first token.
Block newBlock = newBlock();
try {
- statement();
+ statement(false, false, true);
} finally {
newBlock = restoreBlock(newBlock);
}
@@ -707,20 +707,9 @@ loop:
FunctionNode.Kind.SCRIPT,
functionLine);
- // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
- final int startLine = start;
- Block outer = useBlockScope() ? newBlock() : null;
functionDeclarations = new ArrayList<>();
-
- try {
- sourceElements(allowPropertyFunction);
- addFunctionDeclarations(script);
- } finally {
- if (outer != null) {
- outer = restoreBlock(outer);
- appendStatement(new BlockStatement(startLine, outer));
- }
- }
+ sourceElements(allowPropertyFunction);
+ addFunctionDeclarations(script);
functionDeclarations = null;
expect(EOF);
@@ -783,7 +772,7 @@ loop:
try {
// Get the next element.
- statement(true, allowPropertyFunction);
+ statement(true, allowPropertyFunction, false);
allowPropertyFunction = false;
// check for directive prologues
@@ -873,13 +862,15 @@ loop:
* Parse any of the basic statement types.
*/
private void statement() {
- statement(false, false);
+ statement(false, false, false);
}
/**
* @param topLevel does this statement occur at the "top level" of a script or a function?
+ * @param allowPropertyFunction allow property "get" and "set" functions?
+ * @param singleStatement are we in a single statement context?
*/
- private void statement(final boolean topLevel, final boolean allowPropertyFunction) {
+ private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
if (type == FUNCTION) {
// As per spec (ECMA section 12), function declarations as arbitrary statement
// is not "portable". Implementation can issue a warning or disallow the same.
@@ -943,6 +934,9 @@ loop:
break;
default:
if (useBlockScope() && (type == LET || type == CONST)) {
+ if (singleStatement) {
+ throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
+ }
variableStatement(type, true);
break;
}
@@ -1068,7 +1062,7 @@ loop:
next();
final List<VarNode> vars = new ArrayList<>();
- int varFlags = VarNode.IS_STATEMENT;
+ int varFlags = 0;
if (varType == LET) {
varFlags |= VarNode.IS_LET;
} else if (varType == CONST) {
@@ -1221,7 +1215,7 @@ loop:
Block outer = useBlockScope() ? newBlock() : null;
// Create FOR node, capturing FOR token.
- ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
+ ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0);
lc.push(forNode);
try {
@@ -1241,19 +1235,22 @@ loop:
switch (type) {
case VAR:
- // Var statements captured in for outer block.
+ // Var declaration captured in for outer block.
vars = variableStatement(type, false);
break;
case SEMICOLON:
break;
default:
if (useBlockScope() && (type == LET || type == CONST)) {
- // LET/CONST captured in container block created above.
+ if (type == LET) {
+ forNode = forNode.setPerIterationScope(lc);
+ }
+ // LET/CONST declaration captured in container block created above.
vars = variableStatement(type, false);
break;
}
if (env._const_as_var && type == CONST) {
- // Var statements captured in for outer block.
+ // Var declaration captured in for outer block.
vars = variableStatement(TokenType.VAR, false);
break;
}
@@ -1334,11 +1331,12 @@ loop:
appendStatement(forNode);
} finally {
lc.pop(forNode);
- if (outer != null) {
- outer.setFinish(forNode.getFinish());
- outer = restoreBlock(outer);
- appendStatement(new BlockStatement(startLine, outer));
- }
+ }
+
+ if (outer != null) {
+ outer.setFinish(forNode.getFinish());
+ outer = restoreBlock(outer);
+ appendStatement(new BlockStatement(startLine, outer));
}
}
@@ -2710,11 +2708,7 @@ loop:
}
if (isStatement) {
- int varFlags = VarNode.IS_STATEMENT;
- if (!topLevel && useBlockScope()) {
- // mark ES6 block functions as lexically scoped
- varFlags |= VarNode.IS_LET;
- }
+ final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
if (topLevel) {
functionDeclarations.add(varNode);
diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java
index 0e85beeb..4e745ff4 100644
--- a/src/jdk/nashorn/internal/runtime/CodeStore.java
+++ b/src/jdk/nashorn/internal/runtime/CodeStore.java
@@ -82,10 +82,9 @@ public abstract class CodeStore implements Loggable {
* Returns a new code store instance.
*
* @param context the current context
- * @return The instance
- * @throws IOException If an error occurs
+ * @return The instance, or null if code store could not be created
*/
- public static CodeStore newCodeStore(final Context context) throws IOException {
+ public static CodeStore newCodeStore(final Context context) {
final Class<CodeStore> baseClass = CodeStore.class;
try {
// security check first
@@ -103,9 +102,14 @@ public abstract class CodeStore implements Loggable {
} catch (final AccessControlException e) {
context.getLogger(CodeStore.class).warning("failed to load code store provider ", e);
}
- final CodeStore store = new DirectoryCodeStore(context);
- store.initLogger(context);
- return store;
+ try {
+ final CodeStore store = new DirectoryCodeStore(context);
+ store.initLogger(context);
+ return store;
+ } catch (final IOException e) {
+ context.getLogger(CodeStore.class).warning("failed to create cache directory ", e);
+ return null;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java
index 86369ab7..9e851998 100644
--- a/src/jdk/nashorn/internal/runtime/Context.java
+++ b/src/jdk/nashorn/internal/runtime/Context.java
@@ -509,11 +509,7 @@ public final class Context {
}
if (env._persistent_cache) {
- try {
- codeStore = newCodeStore(this);
- } catch (final IOException e) {
- throw new RuntimeException("Error initializing code cache", e);
- }
+ codeStore = newCodeStore(this);
}
// print version info if asked.
@@ -1200,7 +1196,7 @@ public final class Context {
FunctionNode functionNode = null;
// We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation
// just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData.
- final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
+ final boolean useCodeStore = codeStore != null && !env._parse_only && !env._optimistic_types;
final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
if (useCodeStore) {
diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index 75395ea4..7e54b1e2 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -714,6 +714,9 @@ public enum JSType {
* @return a number
*/
public static double toNumber(final Object obj) {
+ if (obj instanceof Double) {
+ return (Double)obj;
+ }
if (obj instanceof Number) {
return ((Number)obj).doubleValue();
}
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index 41baa642..4225c251 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -84,14 +84,17 @@ public abstract class Property implements Serializable {
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
/** Is this a builtin property, e.g. Function.prototype.apply */
- public static final int IS_BUILTIN = 1 << 7;
+ public static final int IS_BUILTIN = 1 << 7;
/** Is this property bound to a receiver? This means get/set operations will be delegated to
* a statically defined object instead of the object passed as callsite parameter. */
- public static final int IS_BOUND = 1 << 7;
+ public static final int IS_BOUND = 1 << 8;
/** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
- public static final int NEEDS_DECLARATION = 1 << 8;
+ public static final int NEEDS_DECLARATION = 1 << 9;
+
+ /** Is this property an ES6 lexical binding? */
+ public static final int IS_LEXICAL_BINDING = 1 << 10;
/** Property key. */
private final String key;
@@ -714,4 +717,12 @@ public abstract class Property implements Serializable {
public boolean isFunctionDeclaration() {
return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
}
+
+ /**
+ * Is this a property defined by ES6 let or const?
+ * @return true if this property represents a lexical binding.
+ */
+ public boolean isLexicalBinding() {
+ return (flags & IS_LEXICAL_BINDING) == IS_LEXICAL_BINDING;
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 89246241..3f605910 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -46,6 +46,8 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag;
import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
import java.lang.invoke.MethodHandle;
@@ -98,7 +100,7 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards;
* </ul>
*/
-public abstract class ScriptObject implements PropertyAccess {
+public abstract class ScriptObject implements PropertyAccess, Cloneable {
/** __proto__ special property name inside object literals. ES6 draft. */
public static final String PROTO_PROPERTY_NAME = "__proto__";
@@ -304,29 +306,44 @@ public abstract class ScriptObject implements PropertyAccess {
PropertyMap newMap = this.getMap();
for (final Property property : properties) {
- final String key = property.getKey();
- final Property oldProp = newMap.findProperty(key);
- if (oldProp == null) {
- if (property instanceof UserAccessorProperty) {
- // Note: we copy accessor functions to this object which is semantically different from binding.
- final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
- newMap = newMap.addPropertyNoHistory(prop);
- } else {
- newMap = newMap.addPropertyBind((AccessorProperty)property, source);
- }
+ newMap = addBoundProperty(newMap, source, property);
+ }
+
+ this.setMap(newMap);
+ }
+
+ /**
+ * Add a bound property from {@code source}, using the interim property map {@code propMap}, and return the
+ * new interim property map.
+ *
+ * @param propMap the property map
+ * @param source the source object
+ * @param property the property to be added
+ * @return the new property map
+ */
+ protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property) {
+ PropertyMap newMap = propMap;
+ final String key = property.getKey();
+ final Property oldProp = newMap.findProperty(key);
+ if (oldProp == null) {
+ if (property instanceof UserAccessorProperty) {
+ // Note: we copy accessor functions to this object which is semantically different from binding.
+ final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
+ newMap = newMap.addPropertyNoHistory(prop);
} 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));
- }
+ 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));
}
}
}
-
- this.setMap(newMap);
+ return newMap;
}
/**
@@ -510,7 +527,11 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
- private void invalidateGlobalConstant(final String key) {
+ /**
+ * Invalidate any existing global constant method handles that may exist for {@code key}.
+ * @param key the property name
+ */
+ protected void invalidateGlobalConstant(final String key) {
final GlobalConstants globalConstants = getGlobalConstants();
if (globalConstants != null) {
globalConstants.delete(key);
@@ -2183,6 +2204,9 @@ public abstract class ScriptObject implements PropertyAccess {
if (find != null) {
if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
+ if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) {
+ throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode.
+ }
// Existing, non-writable property
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
}
@@ -3084,7 +3108,7 @@ public abstract class ScriptObject implements PropertyAccess {
private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) {
if (longIndex >= oldLength) {
if (!isExtensible()) {
- if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
+ if (isStrictFlag(callSiteFlags)) {
throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this));
}
return true;
@@ -3108,7 +3132,7 @@ public abstract class ScriptObject implements PropertyAccess {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
- final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
+ final boolean strict = isStrictFlag(callSiteFlags);
setArray(getArray().set(index, value, strict));
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
}
@@ -3118,7 +3142,7 @@ public abstract class ScriptObject implements PropertyAccess {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
- final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
+ final boolean strict = isStrictFlag(callSiteFlags);
setArray(getArray().set(index, value, strict));
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
}
@@ -3128,7 +3152,7 @@ public abstract class ScriptObject implements PropertyAccess {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
- final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
+ final boolean strict = isStrictFlag(callSiteFlags);
setArray(getArray().set(index, value, strict));
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
}
@@ -3138,7 +3162,7 @@ public abstract class ScriptObject implements PropertyAccess {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
- final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags);
+ final boolean strict = isStrictFlag(callSiteFlags);
setArray(getArray().set(index, value, strict));
doesNotHaveEnsureDelete(longIndex, oldLength, strict);
}
@@ -3159,7 +3183,7 @@ public abstract class ScriptObject implements PropertyAccess {
invalidateGlobalConstant(key);
if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
- final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
+ final boolean isScope = isScopeFlag(callSiteFlags);
// If the start object of the find is not this object it means the property was found inside a
// 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
// to the 'with' object.
@@ -3180,16 +3204,19 @@ public abstract class ScriptObject implements PropertyAccess {
if (f != null) {
if (!f.getProperty().isWritable()) {
- if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
+ if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) {
+ throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode.
+ }
+ if (isStrictFlag(callSiteFlags)) {
throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
}
return;
}
- f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags));
+ f.setValue(value, isStrictFlag(callSiteFlags));
} else if (!isExtensible()) {
- if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
+ if (isStrictFlag(callSiteFlags)) {
throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
}
} else {
@@ -3216,7 +3243,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3236,7 +3263,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3256,7 +3283,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3276,7 +3303,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3295,7 +3322,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3314,7 +3341,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3333,7 +3360,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3352,7 +3379,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3371,7 +3398,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3390,7 +3417,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3409,7 +3436,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3428,7 +3455,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3446,7 +3473,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
final ArrayData data = getArray();
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3464,7 +3491,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3483,7 +3510,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3502,7 +3529,7 @@ public abstract class ScriptObject implements PropertyAccess {
if (isValidArrayIndex(index)) {
final ArrayData data = getArray();
if (data.has(index)) {
- setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ setArray(data.set(index, value, isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3667,6 +3694,29 @@ public abstract class ScriptObject implements PropertyAccess {
}
/**
+ * Return a shallow copy of this ScriptObject.
+ * @return a shallow copy.
+ */
+ public final ScriptObject copy() {
+ try {
+ return clone();
+ } catch (final CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected ScriptObject clone() throws CloneNotSupportedException {
+ final ScriptObject clone = (ScriptObject) super.clone();
+ if (objectSpill != null) {
+ clone.objectSpill = objectSpill.clone();
+ clone.primitiveSpill = primitiveSpill.clone();
+ }
+ clone.arrayData = arrayData.copy();
+ return clone;
+ }
+
+ /**
* Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object.
*
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index b018596f..f0a8c7a2 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -61,9 +61,9 @@ public abstract class ArrayData {
/**
* Length of the array data. Not necessarily length of the wrapped array.
* This is private to ensure that no one in a subclass is able to touch the length
- * without going through {@link setLength}. This is used to implement
+ * without going through {@link #setLength}. This is used to implement
* {@link LengthNotWritableFilter}s, ensuring that there are no ways past
- * a {@link setLength} function replaced by a nop
+ * a {@link #setLength} function replaced by a nop
*/
private long length;
@@ -79,11 +79,7 @@ public abstract class ArrayData {
*/
private static class UntouchedArrayData extends ContinuousArrayData {
private UntouchedArrayData() {
- this(0);
- }
-
- private UntouchedArrayData(final int length) {
- super(length);
+ super(0);
}
private ArrayData toRealArrayData() {
@@ -100,7 +96,8 @@ public abstract class ArrayData {
@Override
public ContinuousArrayData copy() {
- return new UntouchedArrayData((int)length());
+ assert length() == 0;
+ return this;
}
@Override
@@ -246,7 +243,7 @@ public abstract class ArrayData {
public Class<?> getBoxedElementType() {
return Integer.class;
}
- };
+ }
/**
* Constructor
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java
index 244739b3..ff4c13e2 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java
@@ -25,11 +25,7 @@
package jdk.nashorn.internal.runtime.arrays;
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
-import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -98,17 +94,7 @@ public abstract class IteratorAction<T> {
* @return result of apply
*/
public final T apply() {
- final boolean strict;
- if (callbackfn instanceof ScriptFunction) {
- strict = ((ScriptFunction)callbackfn).isStrict();
- } else if (callbackfn instanceof JSObject &&
- ((JSObject)callbackfn).isFunction()) {
- strict = ((JSObject)callbackfn).isStrictFunction();
- } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) {
- strict = false;
- } else {
- throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn));
- }
+ final boolean strict = Bootstrap.isStrictCallable(callbackfn);
// for non-strict callback, need to translate undefined thisArg to be global object
thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg;
diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index 8c270fb8..749c4728 100644
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
@@ -50,6 +51,8 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.RuntimeCallSite;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
+import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
import jdk.nashorn.internal.runtime.ScriptFunction;
@@ -94,7 +97,7 @@ public final class Bootstrap {
new NashornLinker(),
new NashornPrimitiveLinker(),
new NashornStaticClassLinker(),
- new BoundDynamicMethodLinker(),
+ new BoundCallableLinker(),
new JavaSuperAdapterLinker(),
new JSObjectLinker(nashornBeansLinker),
new BrowserJSObjectLinker(nashornBeansLinker),
@@ -136,19 +139,47 @@ public final class Bootstrap {
}
return obj instanceof ScriptFunction ||
- ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) ||
- isDynamicMethod(obj) ||
+ isJSObjectFunction(obj) ||
+ BeansLinker.isDynamicMethod(obj) ||
+ obj instanceof BoundCallable ||
isFunctionalInterfaceObject(obj) ||
obj instanceof StaticClass;
}
/**
+ * Returns true if the given object is a strict callable
+ * @param callable the callable object to be checked for strictness
+ * @return true if the obj is a strict callable, false if it is a non-strict callable.
+ * @throws ECMAException with {@code TypeError} if the object is not a callable.
+ */
+ public static boolean isStrictCallable(final Object callable) {
+ if (callable instanceof ScriptFunction) {
+ return ((ScriptFunction)callable).isStrict();
+ } else if (isJSObjectFunction(callable)) {
+ return ((JSObject)callable).isStrictFunction();
+ } else if (callable instanceof BoundCallable) {
+ return isStrictCallable(((BoundCallable)callable).getCallable());
+ } else if (BeansLinker.isDynamicMethod(callable) || callable instanceof StaticClass) {
+ return false;
+ }
+ throw notFunction(callable);
+ }
+
+ private static ECMAException notFunction(final Object obj) {
+ return typeError("not.a.function", ScriptRuntime.safeToString(obj));
+ }
+
+ private static boolean isJSObjectFunction(final Object obj) {
+ return obj instanceof JSObject && ((JSObject)obj).isFunction();
+ }
+
+ /**
* Returns if the given object is a dynalink Dynamic method
* @param obj object to be checked
* @return true if the obj is a dynamic method
*/
public static boolean isDynamicMethod(final Object obj) {
- return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj);
+ return BeansLinker.isDynamicMethod(obj instanceof BoundCallable ? ((BoundCallable)obj).getCallable() : obj);
}
/**
@@ -370,14 +401,22 @@ public final class Bootstrap {
}
/**
- * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with
- * {@code BeansLinker} to a receiver.
- * @param dynamicMethod the dynamic method to bind
+ * Binds any object Nashorn can use as a [[Callable]] to a receiver and optionally arguments.
+ * @param callable the callable to bind
* @param boundThis the bound "this" value.
- * @return a bound dynamic method.
+ * @param boundArgs the bound arguments. Can be either null or empty array to signify no arguments are bound.
+ * @return a bound callable.
+ * @throws ECMAException with {@code TypeError} if the object is not a callable.
*/
- public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- return new BoundDynamicMethod(dynamicMethod, boundThis);
+ public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) {
+ if (callable instanceof ScriptFunctionImpl) {
+ return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs);
+ } else if (callable instanceof BoundCallable) {
+ return ((BoundCallable)callable).bind(boundArgs);
+ } else if (isCallable(callable)) {
+ return new BoundCallable(callable, boundThis, boundArgs);
+ }
+ throw notFunction(callable);
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java
new file mode 100644
index 00000000..a0eee0de
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util.Arrays;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ * Represents a Nashorn callable bound to a receiver and optionally arguments. Note that objects of this class
+ * are just the tuples of a callable and a bound this and arguments, without any behavior. All the behavior is
+ * defined in the {@code BoundCallableLinker}.
+ */
+public final class BoundCallable {
+ private final Object callable;
+ private final Object boundThis;
+ private final Object[] boundArgs;
+
+ BoundCallable(final Object callable, final Object boundThis, final Object[] boundArgs) {
+ this.callable = callable;
+ this.boundThis = boundThis;
+ this.boundArgs = isEmptyArray(boundArgs) ? ScriptRuntime.EMPTY_ARRAY : boundArgs.clone();
+ }
+
+ private BoundCallable(final BoundCallable original, final Object[] extraBoundArgs) {
+ this.callable = original.callable;
+ this.boundThis = original.boundThis;
+ this.boundArgs = original.concatenateBoundArgs(extraBoundArgs);
+ }
+
+ Object getCallable() {
+ return callable;
+ }
+
+ Object getBoundThis() {
+ return boundThis;
+ }
+
+ Object[] getBoundArgs() {
+ return boundArgs;
+ }
+
+ BoundCallable bind(final Object[] extraBoundArgs) {
+ if (isEmptyArray(extraBoundArgs)) {
+ return this;
+ }
+ return new BoundCallable(this, extraBoundArgs);
+ }
+
+ private Object[] concatenateBoundArgs(final Object[] extraBoundArgs) {
+ if (boundArgs.length == 0) {
+ return extraBoundArgs.clone();
+ }
+ final int origBoundArgsLen = boundArgs.length;
+ final int extraBoundArgsLen = extraBoundArgs.length;
+ final Object[] newBoundArgs = new Object[origBoundArgsLen + extraBoundArgsLen];
+ System.arraycopy(boundArgs, 0, newBoundArgs, 0, origBoundArgsLen);
+ System.arraycopy(extraBoundArgs, 0, newBoundArgs, origBoundArgsLen, extraBoundArgsLen);
+ return newBoundArgs;
+ }
+
+ private static boolean isEmptyArray(final Object[] a) {
+ return a == null || a.length == 0;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder b = new StringBuilder(callable.toString()).append(" on ").append(boundThis);
+ if (boundArgs.length != 0) {
+ b.append(" with ").append(Arrays.toString(boundArgs));
+ }
+ return b.toString();
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java
new file mode 100644
index 00000000..d52063bf
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java
@@ -0,0 +1,132 @@
+/*
+ * 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 java.util.Arrays;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
+import jdk.internal.dynalink.support.Guards;
+
+/**
+ * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either
+ * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding.
+ */
+final class BoundCallableLinker implements TypeBasedGuardingDynamicLinker {
+ @Override
+ public boolean canLinkType(final Class<?> type) {
+ return type == BoundCallable.class;
+ }
+
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
+ final Object objBoundCallable = linkRequest.getReceiver();
+ if(!(objBoundCallable instanceof BoundCallable)) {
+ return null;
+ }
+
+ final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
+ if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) {
+ return null;
+ }
+ final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR);
+ // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form
+ // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter.
+ final boolean isCall;
+ if ("new".equals(operation)) {
+ isCall = false;
+ } else if ("call".equals(operation)) {
+ isCall = true;
+ } else {
+ // Only dyn:call and dyn:new are supported.
+ return null;
+ }
+ final BoundCallable boundCallable = (BoundCallable)objBoundCallable;
+ final Object callable = boundCallable.getCallable();
+ final Object boundThis = boundCallable.getBoundThis();
+
+ // We need to ask the linker services for a delegate invocation on the target callable.
+
+ // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating
+ final Object[] args = linkRequest.getArguments();
+ final Object[] boundArgs = boundCallable.getBoundArgs();
+ final int argsLen = args.length;
+ final int boundArgsLen = boundArgs.length;
+ final Object[] newArgs = new Object[argsLen + boundArgsLen];
+ newArgs[0] = callable;
+ final int firstArgIndex;
+ if (isCall) {
+ newArgs[1] = boundThis;
+ firstArgIndex = 2;
+ } else {
+ firstArgIndex = 1;
+ }
+ System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen);
+ System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex);
+
+ // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...)
+ // call site type when delegating to underlying linker (for dyn:new, there's no this).
+ final MethodType type = descriptor.getMethodType();
+ // Use R(T0, ...) => R(callable.class, ...)
+ MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
+ if (isCall) {
+ // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
+ newMethodType = newMethodType.changeParameterType(1, boundThis.getClass());
+ }
+ // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
+ for(int i = boundArgs.length; i-- > 0;) {
+ newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass());
+ }
+ final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType);
+
+ // Delegate to target's linker
+ final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs));
+ if(inv == null) {
+ return null;
+ }
+
+ // Bind (callable[, boundThis], boundArgs) to the delegate handle
+ final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0,
+ Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length));
+ final Class<?> p0Type = type.parameterType(0);
+ final MethodHandle droppingHandle;
+ if (isCall) {
+ // Ignore incoming boundCallable and this
+ droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
+ } else {
+ // Ignore incoming boundCallable
+ droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type);
+ }
+ // Identity guard on boundCallable object
+ final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable);
+ return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java
deleted file mode 100644
index 9008547f..00000000
--- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.linker;
-
-import java.util.Objects;
-import jdk.internal.dynalink.beans.BeansLinker;
-
-/**
- * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of
- * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}.
- */
-final class BoundDynamicMethod {
- private final Object dynamicMethod;
- private final Object boundThis;
-
- BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- assert BeansLinker.isDynamicMethod(dynamicMethod);
- this.dynamicMethod = dynamicMethod;
- this.boundThis = boundThis;
- }
-
- Object getDynamicMethod() {
- return dynamicMethod;
- }
-
- Object getBoundThis() {
- return boundThis;
- }
-
- @Override
- public String toString() {
- return dynamicMethod.toString() + " on " + Objects.toString(boundThis);
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
deleted file mode 100644
index 67e29835..00000000
--- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.linker;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import jdk.internal.dynalink.CallSiteDescriptor;
-import jdk.internal.dynalink.beans.BeansLinker;
-import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
-import jdk.internal.dynalink.support.Guards;
-
-/**
- * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method
- * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding.
- */
-final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
- @Override
- public boolean canLinkType(final Class<?> type) {
- return type == BoundDynamicMethod.class;
- }
-
- @Override
- public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
- final Object objBoundDynamicMethod = linkRequest.getReceiver();
- if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) {
- return null;
- }
-
- final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod;
- final Object dynamicMethod = boundDynamicMethod.getDynamicMethod();
- final Object boundThis = boundDynamicMethod.getBoundThis();
-
- // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to
- // BeansLinker
- final Object[] args = linkRequest.getArguments();
- args[0] = dynamicMethod;
- args[1] = boundThis;
-
- // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to
- // BeansLinker.
- final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
- final MethodType type = descriptor.getMethodType();
- final Class<?> dynamicMethodClass = dynamicMethod.getClass();
- final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
- type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
-
- // Delegate to BeansLinker
- final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass),
- linkRequest.replaceArguments(newDescriptor, args), linkerServices);
- if(inv == null) {
- return null;
- }
-
- // Bind (dynamicMethod, boundThis) to the handle
- final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis);
- final Class<?> p0Type = type.parameterType(0);
- // Ignore incoming (boundDynamicMethod, this)
- final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1));
- // Identity guard on boundDynamicMethod object
- final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod);
-
- return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type)));
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
index 5fc93cb4..9aeefd72 100644
--- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
@@ -165,7 +165,7 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
*/
@SuppressWarnings("unused")
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
- return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis);
+ return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null);
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties
index 3a161c8d..119277df 100644
--- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -82,7 +82,7 @@ type.error.not.a.constructor={0} is not a constructor function
type.error.not.a.file={0} is not a File
type.error.not.a.numeric.array={0} is not a numeric array
type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer
-type.error.not.an.arraybuffer.in.dataview=First arg to DataView constructor must be an ArrayBuffer
+type.error.not.an.arraybuffer.in.dataview=First argument to DataView constructor must be an ArrayBuffer
type.error.no.reflection.with.classfilter=Java reflection not supported when class filter is present
# operations not permitted on undefined
@@ -116,6 +116,7 @@ type.error.instanceof.on.non.object=instanceof must be called with a javascript
type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}"
type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce
type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight
+type.error.assign.constant=Assignment to constant "{0}"
type.error.cannot.get.default.string=Cannot get default string value
type.error.cannot.get.default.number=Cannot get default number value
type.error.cant.apply.with.to.null=Cannot apply "with" to null
@@ -166,6 +167,7 @@ syntax.error.invalid.json=Invalid JSON: {0}
syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
syntax.error.redeclare.variable=Variable "{0}" has already been declared
syntax.error.assign.constant=Assignment to constant "{0}"
+syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
io.error.cant.write=cannot write "{0}"
config.error.no.dest=no destination directory supplied
diff --git a/test/script/basic/JDK-8049407-big-endian.js b/test/script/basic/JDK-8049407-big-endian.js
new file mode 100644
index 00000000..323c4540
--- /dev/null
+++ b/test/script/basic/JDK-8049407-big-endian.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * Verify DataView behavior with little/big endian
+ *
+ * @test
+ * @run
+ * @bigendian
+ */
+
+var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
+load(dir + "JDK-8049407-payload.js");
diff --git a/test/script/basic/JDK-8049407-big-endian.js.EXPECTED b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED
new file mode 100644
index 00000000..c508d536
--- /dev/null
+++ b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED
@@ -0,0 +1 @@
+false
diff --git a/test/script/basic/JDK-8049407-payload.js b/test/script/basic/JDK-8049407-payload.js
new file mode 100644
index 00000000..467d4bb7
--- /dev/null
+++ b/test/script/basic/JDK-8049407-payload.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * Verify DataView behavior with little/big endian
+ *
+ * @subtest
+ * @run
+ */
+
+var littleEndian = (function() {
+ var buffer = new ArrayBuffer(2);
+ new DataView(buffer).setInt16(0, 256, true);
+ return new Int16Array(buffer)[0] === 256;
+ })();
+
+print(littleEndian);
diff --git a/test/script/basic/JDK-8049407.js b/test/script/basic/JDK-8049407.js
new file mode 100644
index 00000000..4bfcd26c
--- /dev/null
+++ b/test/script/basic/JDK-8049407.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+/**
+ * Verify DataView behavior with little/big endian
+ *
+ * @test
+ * @run
+ * @littleendian
+ */
+
+var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
+load(dir + "JDK-8049407-payload.js");
diff --git a/test/script/basic/JDK-8049407.js.EXPECTED b/test/script/basic/JDK-8049407.js.EXPECTED
new file mode 100644
index 00000000..27ba77dd
--- /dev/null
+++ b/test/script/basic/JDK-8049407.js.EXPECTED
@@ -0,0 +1 @@
+true
diff --git a/test/script/basic/JDK-8051778.js b/test/script/basic/JDK-8051778.js
new file mode 100644
index 00000000..2d8d788a
--- /dev/null
+++ b/test/script/basic/JDK-8051778.js
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 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-8051778: support bind on all Nashorn callables
+ *
+ * @test
+ * @run
+ */
+
+var bind = Function.prototype.bind;
+
+// Bind a POJO method
+var l = new java.util.ArrayList();
+var l_add_foo = bind.call(l.add, l, "foo");
+l_add_foo();
+print("l=" + l);
+
+// Bind a BoundCallable
+var l_add = bind.call(l.add, l);
+var l_add_foo2 = bind.call(l_add, null, "foo2");
+l_add_foo2();
+print("l=" + l);
+
+// Bind a POJO method retrieved from one instance to a different but
+// compatible instance.
+var l2 = new java.util.ArrayList();
+var l2_size = bind.call(l.size, l2);
+print("l2_size()=" + l2_size());
+
+// Bind a Java type object (used as a constructor).
+var construct_two = bind.call(java.lang.Integer, null, 2);
+print("Bound Integer(2) constructor: " + new construct_two())
+
+// Bind a @FunctionalInterface proxying to an object literal. NOTE: the
+// expected value of this.a is always "original" and never "bound". This
+// might seem counterintuitive, but we are not binding the apply()
+// function of the object literal that defines the BiFunction behaviour,
+// we are binding the SAM proxy object instead, and it is always
+// forwarding to the apply() function with "this" set to the object
+// literal. Basically, binding "this" for SAM proxies is useless; only
+// binding arguments makes sense.
+var f1 = new java.util.function.BiFunction() {
+ apply: function(x, y) {
+ return "BiFunction with literal: " + this.a + ", " + x + ", " + y;
+ },
+ a: "unbound"
+};
+print((bind.call(f1, {a: "bound"}))(1, 2))
+print((bind.call(f1, {a: "bound"}, 3))(4))
+print((bind.call(f1, {a: "bound"}, 5, 6))())
+
+// Bind a @FunctionalInterface proxying to a function. With the same
+// reasoning as above (binding the proxy vs. binding the JS function),
+// the value of this.a will always be undefined, and never "bound".
+var f2 = new java.util.function.BiFunction(
+ function(x, y) {
+ return "BiFunction with function: " + this.a + ", " + x + ", " + y;
+ }
+);
+print((bind.call(f2, {a: "bound"}))(7, 8))
+print((bind.call(f2, {a: "bound"}, 9))(10))
+print((bind.call(f2, {a: "bound"}, 11, 12))())
diff --git a/test/script/basic/JDK-8051778.js.EXPECTED b/test/script/basic/JDK-8051778.js.EXPECTED
new file mode 100644
index 00000000..4ba3e287
--- /dev/null
+++ b/test/script/basic/JDK-8051778.js.EXPECTED
@@ -0,0 +1,10 @@
+l=[foo]
+l=[foo, foo2]
+l2_size()=0
+Bound Integer(2) constructor: 2
+BiFunction with literal: unbound, 1, 2
+BiFunction with literal: unbound, 3, 4
+BiFunction with literal: unbound, 5, 6
+BiFunction with function: undefined, 7, 8
+BiFunction with function: undefined, 9, 10
+BiFunction with function: undefined, 11, 12
diff --git a/test/script/basic/NASHORN-377-big-endian.js b/test/script/basic/NASHORN-377-big-endian.js
new file mode 100644
index 00000000..30f0cc3e
--- /dev/null
+++ b/test/script/basic/NASHORN-377-big-endian.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * NASHORN-377: Typed arrays.
+ *
+ * @test
+ * @run
+ * @bigendian
+ */
+
+var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
+load(dir + "NASHORN-377-payload.js");
diff --git a/test/script/basic/NASHORN-377-big-endian.js.EXPECTED b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED
new file mode 100644
index 00000000..ed3f19ab
--- /dev/null
+++ b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED
@@ -0,0 +1,34 @@
+8 8 true undefined
+[object ArrayBuffer] [object ArrayBuffer] [object Int8Array]
+0 8 8 1
+0 8 8 1
+0 8 8 1
+0 8 4 2
+0 8 4 2
+0 8 2 4
+0 8 2 4
+0 8 2 4
+0 8 1 8
+7071727374-807677 7071727374807677
+727374-807677 2 6
+72737480 2 4
+71727374 1 4
+717273748076
+7071727374807677 1886483059 1954575991
+70717273-1020305 1886483059 -16909061
+70717273fefdfcfb 1886483059 4278058235
+40490fdafefdfcfb 2
+400921fb4d12d84a 1
+400921fb4d12d84a 1074340347 1293080650
+00000000400921fb4d12d84a
+400921fb4d12-27b6 400921fb4d12d84a
+00-100804d12-27b6 ffff00804d12d84a
+0 1 2 3 4 5 6 7
+0102030405060708
+subarray(2,4)=0304 subarray(-6,-4)=0304
+010203040506
+03040506 0405
+0102030405060708090a0b0c0d0e0f10
+slice(4,8)=05060708 slice(-8,-4)=090a0b0c
+0102030405060708090a0b0c
+060708090a0b
diff --git a/test/script/basic/NASHORN-377-payload.js b/test/script/basic/NASHORN-377-payload.js
new file mode 100644
index 00000000..b47fb7cf
--- /dev/null
+++ b/test/script/basic/NASHORN-377-payload.js
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+/*
+ * NASHORN-377: Typed arrays. Payload for litte and big endian platforms.
+ *
+ * @subtest
+ * @run
+ */
+
+var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];
+
+//---------------------------------------------------------------------------
+// utility functions
+//---------------------------------------------------------------------------
+function tohex(d, w) {
+ var hex = Number(d).toString(16);
+ var pad = (w ? w : 8) - hex.length;
+ hex = "00000000".substr(0, pad) + hex;
+ return hex;
+}
+
+function arrstr(a, n, w) {
+ var s = "";
+ if (typeof n == "undefined") n = a.length;
+ if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2;
+ for (var i = 0; i < n; i++) {
+ s += tohex(a[i], w);
+ }
+ return s;
+}
+function bufstr(b) {
+ if (b.buffer !== undefined) {
+ b = b.buffer;
+ }
+ return arrstr(new Uint8Array(b));
+}
+
+function assertFail(f) {
+ try {
+ f();
+ } catch (e) {
+ //print(e);
+ return;
+ }
+ throw "assertion failed: expected exception";
+}
+
+function assertTrue(f) {
+ if (f() !== true) throw "assertion failed: " + f;
+}
+
+function isUndefined(x) {
+ return typeof x === "undefined";
+}
+
+function fillArray(a, start) {
+ if (typeof start == "undefined") start = 1;
+ for (var i = 0; i < a.length; i++) {
+ a[i] = i + start;
+ }
+ return a;
+}
+
+//---------------------------------------------------------------------------
+// tests
+//---------------------------------------------------------------------------
+(function() {
+ var b = new ArrayBuffer(8);
+ var i8 = new Int8Array(b);
+ print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length);
+ print(b, i8.buffer, i8);
+})();
+
+(function test_attributes() {
+ var b = new ArrayBuffer(8);
+ for (var i in types) {
+ var x = new types[i](b);
+ print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT);
+ assertTrue(function(){ return x.constructor === types[i] });
+ }
+})();
+
+(function() {
+ var b = new ArrayBuffer(8);
+ var i8 = new Int8Array(b);
+ fillArray(i8, 0x70);
+
+ var i8_2 = new Int8Array(b, 2);
+ var i8_2_4 = new Uint8Array(b, 2, 4);
+
+ i8_2_4[3] = 0x80;
+
+ print(arrstr(i8, 8, 2) + " " + bufstr(i8));
+ print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength);
+ print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength);
+
+ var i8_1_5 = i8.subarray(1, 5);
+ i8_2_4.subarray(1, 5);
+ print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength);
+
+ print(bufstr(b.slice(1,7)));
+})();
+
+(function() {
+ var b = new ArrayBuffer(8);
+ fillArray(new Int8Array(b), 0x70);
+ new Int8Array(b)[5] = 0x80;
+
+ var i32 = new Int32Array(b);
+ var u32 = new Uint32Array(b);
+ print(arrstr(i32), i32[0], i32[1]);
+ i32[1] = 0xfefdfcfb;
+ print(arrstr(i32), i32[0], i32[1]);
+ print(arrstr(u32), u32[0], u32[1]);
+
+ var pi = 3.1415926;
+ var f32 = new Float32Array(b);
+ var f64 = new Float64Array(b);
+ f32[0] = pi;
+ print(bufstr(b), f32.length);
+ f64[0] = pi;
+ print(bufstr(b), f64.length);
+ print(arrstr(u32), u32[0], u32[1]);
+
+ var d = new Int32Array(3);
+ d.set(i32,1);
+ print(bufstr(d));
+
+ var s = new Int16Array(b);
+ var t = new Uint16Array(b);
+ print(arrstr(s), arrstr(t));
+ s[0] = -1; s[1] = 0x80;
+ print(arrstr(s), arrstr(t));
+})();
+
+(function enumerate_properties() {
+ var i8 = new Int8Array(new ArrayBuffer(8));
+ var s = ""; for (var i in i8) { s += i + " "; } print(s.trim());
+})();
+
+// check that ScriptObject fallback is still working
+// DISABLED because correct behavior is unclear
+(function() {
+ // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype.
+ var z = new Uint8Array(4);
+ z["asdf"] = "asdf"; print(z["asdf"]);
+ z[0x100000000] = "asdf"; print(z[0x100000000]);
+ z[-1] = "asdf"; print(z[-1]);
+
+ // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype.
+ z[0xf0000000] = "asdf"; print(z[0xf0000000]);
+ z[0xffffffff] = "asdf"; print(z[0xffffffff]);
+ z[0x70000000] = "asdf"; print(z[0x70000000]);
+
+ // this will work in firefox and nashorn (not in v8).
+ Uint8Array.prototype[4] = "asdf"; print(z[4]);
+});
+
+(function test_exceptions() {
+ assertFail(function() { new Int32Array(new ArrayBuffer(7)); });
+ assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); });
+ assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); });
+ assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); });
+})();
+
+(function test_subarray() {
+ var x = fillArray(new Int8Array(8));
+ print(arrstr(x));
+ print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array
+ print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0
+ assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0
+ print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray
+})();
+
+(function test_slice() {
+ var b = new ArrayBuffer(16);
+ fillArray(new Int8Array(b));
+ print(bufstr(b));
+ print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array
+ print(bufstr(b.slice(-20, -4))); // negative index clamped to 0
+ assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0
+ print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice
+})();
+
+(function test_clamped() {
+ var a = new Uint8ClampedArray(10);
+ a[0] = -17; // clamped to 0
+ a[1] = 4711; // clamped to 255
+ a[2] = 17.5; // clamped to 18
+ a[3] = 16.5; // clamped to 16
+ a[4] = 255.9; // clamped to 255
+ a[5] = Infinity; // clamped to 255
+ a[6] = -Infinity; // clamped to 0
+ a[7] = NaN; // 0
+ assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; });
+})();
+
+(function test_out_of_bounds() {
+ var a = new Int32Array(10);
+ a[10] = 10;
+ a[100] = 100;
+ a[1000] = 1000;
+ assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); });
+})();
+
diff --git a/test/script/basic/NASHORN-377.js b/test/script/basic/NASHORN-377.js
index 968e46e8..3484223f 100644
--- a/test/script/basic/NASHORN-377.js
+++ b/test/script/basic/NASHORN-377.js
@@ -26,201 +26,8 @@
*
* @test
* @run
+ * @littleendian
*/
-var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];
-
-//---------------------------------------------------------------------------
-// utility functions
-//---------------------------------------------------------------------------
-function tohex(d, w) {
- var hex = Number(d).toString(16);
- var pad = (w ? w : 8) - hex.length;
- hex = "00000000".substr(0, pad) + hex;
- return hex;
-}
-
-function arrstr(a, n, w) {
- var s = "";
- if (typeof n == "undefined") n = a.length;
- if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2;
- for (var i = 0; i < n; i++) {
- s += tohex(a[i], w);
- }
- return s;
-}
-function bufstr(b) {
- if (b.buffer !== undefined) {
- b = b.buffer;
- }
- return arrstr(new Uint8Array(b));
-}
-
-function assertFail(f) {
- try {
- f();
- } catch (e) {
- //print(e);
- return;
- }
- throw "assertion failed: expected exception";
-}
-
-function assertTrue(f) {
- if (f() !== true) throw "assertion failed: " + f;
-}
-
-function isUndefined(x) {
- return typeof x === "undefined";
-}
-
-function fillArray(a, start) {
- if (typeof start == "undefined") start = 1;
- for (var i = 0; i < a.length; i++) {
- a[i] = i + start;
- }
- return a;
-}
-
-//---------------------------------------------------------------------------
-// tests
-//---------------------------------------------------------------------------
-(function() {
- var b = new ArrayBuffer(8);
- var i8 = new Int8Array(b);
- print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length);
- print(b, i8.buffer, i8);
-})();
-
-(function test_attributes() {
- var b = new ArrayBuffer(8);
- for (var i in types) {
- var x = new types[i](b);
- print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT);
- assertTrue(function(){ return x.constructor === types[i] });
- }
-})();
-
-(function() {
- var b = new ArrayBuffer(8);
- var i8 = new Int8Array(b);
- fillArray(i8, 0x70);
-
- var i8_2 = new Int8Array(b, 2);
- var i8_2_4 = new Uint8Array(b, 2, 4);
-
- i8_2_4[3] = 0x80;
-
- print(arrstr(i8, 8, 2) + " " + bufstr(i8));
- print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength);
- print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength);
-
- var i8_1_5 = i8.subarray(1, 5);
- i8_2_4.subarray(1, 5);
- print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength);
-
- print(bufstr(b.slice(1,7)));
-})();
-
-(function() {
- var b = new ArrayBuffer(8);
- fillArray(new Int8Array(b), 0x70);
- new Int8Array(b)[5] = 0x80;
-
- var i32 = new Int32Array(b);
- var u32 = new Uint32Array(b);
- print(arrstr(i32), i32[0], i32[1]);
- i32[1] = 0xfefdfcfb;
- print(arrstr(i32), i32[0], i32[1]);
- print(arrstr(u32), u32[0], u32[1]);
-
- var pi = 3.1415926;
- var f32 = new Float32Array(b);
- var f64 = new Float64Array(b);
- f32[0] = pi;
- print(bufstr(b), f32.length);
- f64[0] = pi;
- print(bufstr(b), f64.length);
- print(arrstr(u32), u32[0], u32[1]);
-
- var d = new Int32Array(3);
- d.set(i32,1);
- print(bufstr(d));
-
- var s = new Int16Array(b);
- var t = new Uint16Array(b);
- print(arrstr(s), arrstr(t));
- s[0] = -1; s[1] = 0x80;
- print(arrstr(s), arrstr(t));
-})();
-
-(function enumerate_properties() {
- var i8 = new Int8Array(new ArrayBuffer(8));
- var s = ""; for (var i in i8) { s += i + " "; } print(s.trim());
-})();
-
-// check that ScriptObject fallback is still working
-// DISABLED because correct behavior is unclear
-(function() {
- // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype.
- var z = new Uint8Array(4);
- z["asdf"] = "asdf"; print(z["asdf"]);
- z[0x100000000] = "asdf"; print(z[0x100000000]);
- z[-1] = "asdf"; print(z[-1]);
-
- // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype.
- z[0xf0000000] = "asdf"; print(z[0xf0000000]);
- z[0xffffffff] = "asdf"; print(z[0xffffffff]);
- z[0x70000000] = "asdf"; print(z[0x70000000]);
-
- // this will work in firefox and nashorn (not in v8).
- Uint8Array.prototype[4] = "asdf"; print(z[4]);
-});
-
-(function test_exceptions() {
- assertFail(function() { new Int32Array(new ArrayBuffer(7)); });
- assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); });
- assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); });
- assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); });
-})();
-
-(function test_subarray() {
- var x = fillArray(new Int8Array(8));
- print(arrstr(x));
- print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array
- print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0
- assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0
- print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray
-})();
-
-(function test_slice() {
- var b = new ArrayBuffer(16);
- fillArray(new Int8Array(b));
- print(bufstr(b));
- print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array
- print(bufstr(b.slice(-20, -4))); // negative index clamped to 0
- assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0
- print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice
-})();
-
-(function test_clamped() {
- var a = new Uint8ClampedArray(10);
- a[0] = -17; // clamped to 0
- a[1] = 4711; // clamped to 255
- a[2] = 17.5; // clamped to 18
- a[3] = 16.5; // clamped to 16
- a[4] = 255.9; // clamped to 255
- a[5] = Infinity; // clamped to 255
- a[6] = -Infinity; // clamped to 0
- a[7] = NaN; // 0
- assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; });
-})();
-
-(function test_out_of_bounds() {
- var a = new Int32Array(10);
- a[10] = 10;
- a[100] = 100;
- a[1000] = 1000;
- assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); });
-})();
-
+var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__;
+load(dir + "NASHORN-377-payload.js");
diff --git a/test/script/basic/compile-octane-normal.js b/test/script/basic/compile-octane-normal.js
index 769f00b5..c671d572 100644
--- a/test/script/basic/compile-octane-normal.js
+++ b/test/script/basic/compile-octane-normal.js
@@ -38,5 +38,5 @@
*/
var fn = __DIR__ + 'compile-octane.js';
-var url = "file://" + fn;
-loadWithNewGlobal(new java.net.URL(url));
+var url = new java.io.File(fn).toURL();
+loadWithNewGlobal(url);
diff --git a/test/script/basic/compile-octane-splitter.js b/test/script/basic/compile-octane-splitter.js
index 5b4f0e15..58c5966a 100644
--- a/test/script/basic/compile-octane-splitter.js
+++ b/test/script/basic/compile-octane-splitter.js
@@ -40,5 +40,5 @@
*/
var fn = __DIR__ + 'compile-octane.js';
-var url = "file://" + fn;
-loadWithNewGlobal(new java.net.URL(url));
+var url = new java.io.File(fn).toURL();
+loadWithNewGlobal(url);
diff --git a/test/script/basic/compile-octane.js b/test/script/basic/compile-octane.js
index aee105a0..b37038f9 100644
--- a/test/script/basic/compile-octane.js
+++ b/test/script/basic/compile-octane.js
@@ -132,7 +132,7 @@ for (var j in tests) {
str2 += " processing file: " + file + "...";
print_if_verbose(str2);
}
- newGlobal.load("file://" + path + file);
+ newGlobal.load(new java.io.File(path + file).toURL());
}
}
print("Done.");
diff --git a/test/script/basic/es6/const-empty.js b/test/script/basic/es6/const-empty.js
index 0687aa2e..c34d1d51 100644
--- a/test/script/basic/es6/const-empty.js
+++ b/test/script/basic/es6/const-empty.js
@@ -33,5 +33,5 @@ try {
eval('"use strict";\n' +
'const x;\n');
} catch (e) {
- print(e);
+ print(String(e).replace(/\\/g, "/"));
}
diff --git a/test/script/basic/es6/const-redeclare-extra.js b/test/script/basic/es6/const-redeclare-extra.js
index 6d77e18e..94fc53b2 100644
--- a/test/script/basic/es6/const-redeclare-extra.js
+++ b/test/script/basic/es6/const-redeclare-extra.js
@@ -35,7 +35,7 @@ function tryIt (code) {
try {
eval(code)
} catch (e) {
- print(e)
+ print(String(e).replace(/\\/g, "/"))
}
}
diff --git a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED
index 754a75c6..06af782e 100644
--- a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED
+++ b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED
@@ -1,9 +1,9 @@
SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:3:8 Variable "x" has already been declared
var x = {};
^
-SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:2:8 Variable "x" has already been declared
- var x = 2;
- ^
-SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:2:13 Variable "x" has already been declared
- function x () {}
- ^
+SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:3:10 Variable "x" has already been declared
+ const x = {};
+ ^
+SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:3:10 Variable "x" has already been declared
+ const x = 5;
+ ^
diff --git a/test/script/basic/es6/const-redeclare.js b/test/script/basic/es6/const-redeclare.js
index 8e4aa7e4..efe34ac2 100644
--- a/test/script/basic/es6/const-redeclare.js
+++ b/test/script/basic/es6/const-redeclare.js
@@ -34,5 +34,5 @@ try {
'const x = 2;\n' +
'const x = 2;\n');
} catch (e) {
- print(e);
+ print(String(e).replace(/\\/g, "/"));
}
diff --git a/test/script/basic/es6/for-let.js b/test/script/basic/es6/for-let.js
index 949b348c..848dc3ce 100644
--- a/test/script/basic/es6/for-let.js
+++ b/test/script/basic/es6/for-let.js
@@ -39,3 +39,40 @@ try {
} catch (e) {
print(e);
}
+
+let a = [];
+
+for (let i = 0; i < 10; i++) {
+ a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
+
+a = [];
+
+for (let i = 0; i < 10; i++) {
+ if (i == 5) {
+ i = "foo";
+ }
+ a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
+
+try {
+ print(i);
+} catch (e) {
+ print(e);
+}
+
+a = [];
+
+for (let i = 0; i < 20; i++) {
+ if (i % 2 == 1) {
+ i += 2;
+ continue;
+ }
+ a.push(function() { print(i); });
+}
+
+a.forEach(function(f) { f(); });
diff --git a/test/script/basic/es6/for-let.js.EXPECTED b/test/script/basic/es6/for-let.js.EXPECTED
index 4c1ebad8..21787adb 100644
--- a/test/script/basic/es6/for-let.js.EXPECTED
+++ b/test/script/basic/es6/for-let.js.EXPECTED
@@ -9,3 +9,25 @@
8
9
ReferenceError: "i" is not defined
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+0
+1
+2
+3
+4
+foo
+ReferenceError: "i" is not defined
+0
+4
+8
+12
+16
diff --git a/test/script/basic/es6/let-const-statement-context.js b/test/script/basic/es6/let-const-statement-context.js
new file mode 100644
index 00000000..3e662378
--- /dev/null
+++ b/test/script/basic/es6/let-const-statement-context.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 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-8057980: let & const: remaining issues with lexical scoping
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function tryEval(s) {
+ try {
+ eval(s);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"));
+ }
+}
+
+tryEval('if (true) let x = 1;');
+tryEval('if (true) const x = 1;');
+tryEval('while (true) let x = 1;');
+tryEval('while (true) const x = 1;');
+tryEval('for (;;) let x = 1;');
+tryEval('for (;;) const x = 1;');
+tryEval('do let x = 1; while (true);');
+tryEval('do const x = 1; while (true);');
+tryEval('with (y) const x = 1;');
+tryEval('with (y) let x = 1;');
diff --git a/test/script/basic/es6/let-const-statement-context.js.EXPECTED b/test/script/basic/es6/let-const-statement-context.js.EXPECTED
new file mode 100644
index 00000000..1b73e4c7
--- /dev/null
+++ b/test/script/basic/es6/let-const-statement-context.js.EXPECTED
@@ -0,0 +1,30 @@
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found let declaration
+if (true) let x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:10 Expected statement but found const declaration
+if (true) const x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found let declaration
+while (true) let x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:13 Expected statement but found const declaration
+while (true) const x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
+for (;;) let x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
+for (;;) const x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found let declaration
+do let x = 1; while (true);
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:3 Expected statement but found const declaration
+do const x = 1; while (true);
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found const declaration
+with (y) const x = 1;
+ ^
+SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8<eval>:1:9 Expected statement but found let declaration
+with (y) let x = 1;
+ ^
diff --git a/test/script/basic/es6/let-const-switch.js b/test/script/basic/es6/let-const-switch.js
new file mode 100644
index 00000000..8a538b80
--- /dev/null
+++ b/test/script/basic/es6/let-const-switch.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 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-8057980: let & const: remaining issues with lexical scoping
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function tryEval(s) {
+ try {
+ eval(s);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"));
+ }
+}
+
+tryEval('var x = 0; switch (x) { case 0: { let x = 1; print(x); } case 1: { let x = 2; print(x); }} print(x);');
+tryEval('var x = 0; switch (x) { case 0: { const x = 1; print(x); } case 1: { const x = 2; print(x); }} print(x);');
+
+// TODO: the following should not throw
+tryEval('switch (x) { case 0: let x = 1; }');
+tryEval('switch (x) { case 0: const x = 1; }');
diff --git a/test/script/basic/es6/let-const-switch.js.EXPECTED b/test/script/basic/es6/let-const-switch.js.EXPECTED
new file mode 100644
index 00000000..90309bfe
--- /dev/null
+++ b/test/script/basic/es6/let-const-switch.js.EXPECTED
@@ -0,0 +1,12 @@
+1
+2
+0
+1
+2
+0
+SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:25 Unsupported let declaration in unprotected switch statement
+switch (x) { case 0: let x = 1; }
+ ^
+SyntaxError: test/script/basic/es6/let-const-switch.js#34:8<eval>:1:27 Unsupported const declaration in unprotected switch statement
+switch (x) { case 0: const x = 1; }
+ ^
diff --git a/test/script/basic/es6/let-load.js b/test/script/basic/es6/let-load.js
index b4c29465..ff8f4e1c 100644
--- a/test/script/basic/es6/let-load.js
+++ b/test/script/basic/es6/let-load.js
@@ -26,7 +26,8 @@
*
* @test
* @run
- * @option --language=es6 */
+ * @option --language=es6
+ */
"use strict";
@@ -39,22 +40,19 @@ load(__DIR__ + "let-load-lib.js");
}
print("imported var: " + a);
-try {
- print("imported let: " + b);
-} catch (e) {
- print(e);
-}
+print("imported let: " + b);
+print("imported const: " + c);
+
+top();
try {
- print("imported const: " + c);
+ block();
} catch (e) {
print(e);
}
-top();
-
try {
- block();
+ c = "foo";
} catch (e) {
print(e);
}
diff --git a/test/script/basic/es6/let-load.js.EXPECTED b/test/script/basic/es6/let-load.js.EXPECTED
index 510da6e6..a0b2e094 100644
--- a/test/script/basic/es6/let-load.js.EXPECTED
+++ b/test/script/basic/es6/let-load.js.EXPECTED
@@ -2,7 +2,8 @@ top level function
block function
print local defs: 20 30
imported var: 1
-ReferenceError: "b" is not defined
-ReferenceError: "c" is not defined
+imported let: 2
+imported const: 3
top level function
ReferenceError: "block" is not defined
+TypeError: Assignment to constant "c"
diff --git a/test/script/basic/es6/let-redeclare-extra.js b/test/script/basic/es6/let-redeclare-extra.js
index 630513f4..ddb205e4 100644
--- a/test/script/basic/es6/let-redeclare-extra.js
+++ b/test/script/basic/es6/let-redeclare-extra.js
@@ -34,7 +34,7 @@ function tryIt (code) {
try {
eval(code)
} catch (e) {
- print(e)
+ print(String(e).replace(/\\/g, "/"))
}
}
diff --git a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED
index 5e43b694..e0e1afec 100644
--- a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED
+++ b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED
@@ -4,12 +4,12 @@ SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:8 Variabl
SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:3:8 Variable "x" has already been declared
var x = 2;
^
-SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:8 Variable "x" has already been declared
- var x = 2;
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:3:8 Variable "x" has already been declared
+ let x = undefined;
^
SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:10 Variable "x" has already been declared
const x = function (){};
^
-SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:3:13 Variable "a" has already been declared
- function a () {};
- ^
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:8 Variable "a" has already been declared
+ let a = 2;
+ ^
diff --git a/test/script/basic/es6/let-redeclare.js b/test/script/basic/es6/let-redeclare.js
index b6ad0f0a..adc05196 100644
--- a/test/script/basic/es6/let-redeclare.js
+++ b/test/script/basic/es6/let-redeclare.js
@@ -34,5 +34,5 @@ try {
'let x = 2;\n' +
'let x = 2;\n');
} catch (e) {
- print(e);
+ print(String(e).replace(/\\/g, "/"));
}
diff --git a/test/script/basic/es6/let_const_closure.js.EXPECTED b/test/script/basic/es6/let_const_closure.js.EXPECTED
index 5a720d86..f49ca4b9 100644
--- a/test/script/basic/es6/let_const_closure.js.EXPECTED
+++ b/test/script/basic/es6/let_const_closure.js.EXPECTED
@@ -5,9 +5,9 @@
test
test
test
-3
-3
-3
+0
+1
+2
0
1
2
diff --git a/test/script/basic/es6/let_const_reuse.js b/test/script/basic/es6/let_const_reuse.js
index 556c23dc..bc9e8f84 100644
--- a/test/script/basic/es6/let_const_reuse.js
+++ b/test/script/basic/es6/let_const_reuse.js
@@ -34,7 +34,7 @@ function tryIt (code) {
try {
eval(code)
} catch (e) {
- print(e)
+ print(String(e).replace(/\\/g, "/"))
}
}
diff --git a/test/script/basic/es6/lexical-toplevel-def.js b/test/script/basic/es6/lexical-toplevel-def.js
new file mode 100644
index 00000000..c9a44f70
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-def.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+var VAR = "VAR";
+let LET = "LET";
+const CONST = "CONST";
+function FUNC() {}
+this.GLOBAL = "GLOBAL";
diff --git a/test/script/basic/es6/lexical-toplevel-print.js b/test/script/basic/es6/lexical-toplevel-print.js
new file mode 100644
index 00000000..eef030ac
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-print.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+print(VAR);
+print(LET);
+print(CONST);
+print(FUNC);
+print(GLOBAL);
+print(this.VAR);
+print(this.LET); // undefined
+print(this.CONST); // undefined
+print(this.FUNC);
+print(this.GLOBAL);
+print("VAR" in this);
+print("LET" in this); // false
+print("CONST" in this); // false
+print("FUNC" in this);
+print("GLOBAL" in this);
+
+try {
+ LET = LET + "LET";
+ CONST = CONST + "CONST";
+} catch (e) {
+ print(String(e).replace(/\\/g, "/"));
+}
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js
new file mode 100644
index 00000000..bfe7af35
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+function LET() {}
+var SHOULD_NOT_EXIST = 10;
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js
new file mode 100644
index 00000000..64360142
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+let Object = "LEXICAL BUILTIN";
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js
new file mode 100644
index 00000000..44c83964
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+let FUNC = 10;
+var SHOULD_NOT_EXIST = 10;
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js
new file mode 100644
index 00000000..a742fad3
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+let GLOBAL = "LEXICAL GLOBAL";
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js
new file mode 100644
index 00000000..630741f0
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+let VAR = 10;
+var SHOULD_NOT_EXIST = 10;
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js
new file mode 100644
index 00000000..cb4b3822
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @subtest
+ */
+
+var LET = 10;
+var SHOULD_NOT_EXIST = 10;
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js b/test/script/basic/es6/lexical-toplevel-redeclare.js
new file mode 100644
index 00000000..6a76622f
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare.js
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @test
+ * @run
+ * @option -scripting
+ * @option --language=es6
+ */
+
+load(__DIR__ + "lexical-toplevel-def.js");
+
+var global = this;
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+function loadScript(script) {
+ print(script);
+ try {
+ load(__DIR__ + script);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"));
+ }
+ print(VAR);
+ print(LET);
+ print(CONST);
+ print(FUNC);
+ print(GLOBAL);
+ print(global.VAR);
+ print(global.LET);
+ print(global.CONST);
+ print(global.FUNC);
+ print(global.GLOBAL);
+ try {
+ print(SHOULD_NOT_EXIST);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"));
+ }
+ print(global.SHOULD_NOT_EXIST);
+ print(Object);
+ print(global.Object);
+ print();
+}
+
+loadScript("lexical-toplevel-redeclare-var-on-let.js");
+loadScript("lexical-toplevel-redeclare-func-on-let.js");
+loadScript("lexical-toplevel-redeclare-let-on-var.js");
+loadScript("lexical-toplevel-redeclare-let-on-func.js");
+loadScript("lexical-toplevel-redeclare-let-on-builtin.js");
+loadScript("lexical-toplevel-redeclare-let-on-global.js");
diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED
new file mode 100644
index 00000000..d1471c80
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED
@@ -0,0 +1,100 @@
+lexical-toplevel-redeclare-var-on-let.js
+SyntaxError: Variable "LET" has already been declared
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+function Object() { [native code] }
+function Object() { [native code] }
+
+lexical-toplevel-redeclare-func-on-let.js
+SyntaxError: Variable "LET" has already been declared
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+function Object() { [native code] }
+function Object() { [native code] }
+
+lexical-toplevel-redeclare-let-on-var.js
+SyntaxError: Variable "VAR" has already been declared
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+function Object() { [native code] }
+function Object() { [native code] }
+
+lexical-toplevel-redeclare-let-on-func.js
+SyntaxError: Variable "FUNC" has already been declared
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+function Object() { [native code] }
+function Object() { [native code] }
+
+lexical-toplevel-redeclare-let-on-builtin.js
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+LEXICAL BUILTIN
+function Object() { [native code] }
+
+lexical-toplevel-redeclare-let-on-global.js
+VAR
+LET
+CONST
+function FUNC() {}
+LEXICAL GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+ReferenceError: "SHOULD_NOT_EXIST" is not defined
+undefined
+LEXICAL BUILTIN
+function Object() { [native code] }
+
diff --git a/test/script/basic/es6/lexical-toplevel.js b/test/script/basic/es6/lexical-toplevel.js
new file mode 100644
index 00000000..fc272a8a
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, 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-8057691: Nashorn: let & const declarations are not shared between scripts
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+load(__DIR__ + "lexical-toplevel-def.js");
+
+load(__DIR__ + "lexical-toplevel-print.js");
+load(__DIR__ + "lexical-toplevel-print.js");
diff --git a/test/script/basic/es6/lexical-toplevel.js.EXPECTED b/test/script/basic/es6/lexical-toplevel.js.EXPECTED
new file mode 100644
index 00000000..7580af4f
--- /dev/null
+++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED
@@ -0,0 +1,32 @@
+VAR
+LET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+true
+false
+false
+true
+true
+TypeError: Assignment to constant "CONST"
+VAR
+LETLET
+CONST
+function FUNC() {}
+GLOBAL
+VAR
+undefined
+undefined
+function FUNC() {}
+GLOBAL
+true
+false
+false
+true
+true
+TypeError: Assignment to constant "CONST"
diff --git a/test/script/nosecurity/JDK-8050964.js b/test/script/nosecurity/JDK-8050964.js
index 486948aa..eda3d1b6 100644
--- a/test/script/nosecurity/JDK-8050964.js
+++ b/test/script/nosecurity/JDK-8050964.js
@@ -50,6 +50,7 @@ var javahome = System.getProperty("java.home");
var jdepsPath = javahome + "/../bin/jdeps".replaceAll(/\//g, File.separater);
// run jdep on nashorn.jar - only summary but print profile info
+$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin
`${jdepsPath} -s -P ${nashornJar.absolutePath}`
// check for "(compact1)" in output from jdep tool
diff --git a/test/script/nosecurity/JDK-8055034.js b/test/script/nosecurity/JDK-8055034.js
index 76f24be7..a0e5057e 100644
--- a/test/script/nosecurity/JDK-8055034.js
+++ b/test/script/nosecurity/JDK-8055034.js
@@ -49,7 +49,7 @@ var nashornJarDir = nashornJar.parentFile.absolutePath;
var jjsCmd = javahome + "/../bin/jjs";
jjsCmd += " -J-Djava.ext.dirs=" + nashornJarDir;
jjsCmd = jjsCmd.toString().replaceAll(/\//g, File.separater);
-
+$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin
$EXEC(jjsCmd, "var x = Object.create(null);\nx;\nprint('PASSED');\nexit(0)");
// $ERR has all interactions including prompts! Just check for error substring.
diff --git a/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java
new file mode 100644
index 00000000..2cd0bf01
--- /dev/null
+++ b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
+import org.testng.annotations.Test;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import javax.script.SimpleScriptContext;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Top-level lexical binding tests.
+ *
+ * @test
+ * @run testng jdk.nashorn.internal.runtime.LexicalBindingTest
+ */
+@SuppressWarnings("javadoc")
+public class LexicalBindingTest {
+
+ final static String LANGUAGE_ES6 = "--language=es6";
+ final static int NUMBER_OF_CONTEXTS = 20;
+ final static int MEGAMORPHIC_LOOP_COUNT = 20;
+
+ /**
+ * Test access to global var-declared variables for shared script classes with multiple globals.
+ */
+ @Test
+ public static void megamorphicVarTest() throws ScriptException, InterruptedException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine e = factory.getScriptEngine();
+ final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
+ final String sharedScript = "foo";
+
+
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
+ final ScriptContext context = contexts[i] = new SimpleScriptContext();
+ final Bindings b = e.createBindings();
+ context.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ assertEquals(e.eval("var foo = '" + i + "';", context), null);
+ }
+
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
+ final ScriptContext context = contexts[i];
+ assertEquals(e.eval(sharedScript, context), String.valueOf(i));
+ }
+ }
+
+ /**
+ * Test access to global lexically declared variables for shared script classes with multiple globals.
+ */
+ @Test
+ public static void megamorphicMultiGlobalLetTest() throws ScriptException, InterruptedException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
+ final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
+ final String sharedScript = "foo";
+
+
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
+ final ScriptContext context = contexts[i] = new SimpleScriptContext();
+ final Bindings b = e.createBindings();
+ context.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ assertEquals(e.eval("let foo = '" + i + "';", context), null);
+ }
+
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
+ final ScriptContext context = contexts[i];
+ assertEquals(e.eval(sharedScript, context), String.valueOf(i));
+ }
+ }
+
+
+ /**
+ * Test access to global lexically declared variables for shared script classes with single global.
+ */
+ @Test
+ public static void megamorphicSingleGlobalLetTest() throws ScriptException, InterruptedException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
+ final String sharedGetterScript = "foo";
+ final String sharedSetterScript = "foo = 1";
+
+ for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
+ assertEquals(e.eval(sharedSetterScript), 1);
+ assertEquals(e.eval(sharedGetterScript), 1);
+ assertEquals(e.eval("delete foo; a" + i + " = 1; foo = " + i + ";"), i);
+ assertEquals(e.eval(sharedGetterScript), i);
+ }
+
+ assertEquals(e.eval("let foo = 'foo';"), null);
+ assertEquals(e.eval(sharedGetterScript), "foo");
+ assertEquals(e.eval(sharedSetterScript), 1);
+ assertEquals(e.eval(sharedGetterScript), 1);
+ assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
+ }
+
+ /**
+ * Test access to global lexically declared variables for shared script classes with single global.
+ */
+ @Test
+ public static void megamorphicInheritedGlobalLetTest() throws ScriptException, InterruptedException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
+ final String sharedGetterScript = "foo";
+ final String sharedSetterScript = "foo = 1";
+
+ for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
+ assertEquals(e.eval(sharedSetterScript), 1);
+ assertEquals(e.eval(sharedGetterScript), 1);
+ assertEquals(e.eval("delete foo; a" + i + " = 1; Object.prototype.foo = " + i + ";"), i);
+ assertEquals(e.eval(sharedGetterScript), i);
+ }
+
+ assertEquals(e.eval("let foo = 'foo';"), null);
+ assertEquals(e.eval(sharedGetterScript), "foo");
+ assertEquals(e.eval(sharedSetterScript), 1);
+ assertEquals(e.eval(sharedGetterScript), 1);
+ assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
+ }
+
+ /**
+ * Test multi-threaded access to global lexically declared variables for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedLetTest() throws ScriptException, InterruptedException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ final String sharedScript = "foo";
+
+ assertEquals(e.eval("let foo = 'original context';", origContext), null);
+ assertEquals(e.eval("let foo = 'new context';", newCtxt), null);
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ assertEquals(e.eval("foo = 'newer context';", newCtxt), "newer context");
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+
+ assertEquals(e.eval(sharedScript), "original context");
+ assertEquals(e.eval(sharedScript, newCtxt), "newer context");
+ }
+
+ private static class ScriptRunner implements Runnable {
+
+ final ScriptEngine engine;
+ final ScriptContext context;
+ final String source;
+ final Object expected;
+ final int iterations;
+
+ ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
+ this.engine = engine;
+ this.context = context;
+ this.source = source;
+ this.expected = expected;
+ this.iterations = iterations;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < iterations; i++) {
+ assertEquals(engine.eval(source, context), expected);
+ }
+ } catch (final ScriptException se) {
+ throw new RuntimeException(se);
+ }
+ }
+ }
+}
diff --git a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
index ab472d70..32b1cbd5 100644
--- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
+++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
@@ -46,6 +46,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.nio.ByteOrder;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
@@ -264,6 +265,12 @@ public final class TestFinder {
isTest = false;
isNotTest = true;
break;
+ case "@bigendian":
+ shouldRun = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
+ break;
+ case "@littleendian":
+ shouldRun = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
+ break;
case "@runif": {
final String prop = scanner.next();
if (System.getProperty(prop) != null) {