This commit is contained in:
Chris Hegarty 2014-12-03 17:55:36 +00:00
commit 2dbed37b5e
75 changed files with 2417 additions and 611 deletions

View File

@ -135,15 +135,11 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
}
// Named function expressions that end up not referencing themselves won't need a local slot for the self symbol.
if(!functionNode.isDeclared() && !functionNode.usesSelfSymbol() && !functionNode.isAnonymous()) {
if(functionNode.isNamedFunctionExpression() && !functionNode.usesSelfSymbol()) {
final Symbol selfSymbol = functionNode.getBody().getExistingSymbol(functionNode.getIdent().getName());
if(selfSymbol != null) {
if(selfSymbol.isFunctionSelf()) {
selfSymbol.setNeedsSlot(false);
selfSymbol.clearFlag(Symbol.IS_VAR);
}
} else {
assert functionNode.isProgram();
if(selfSymbol != null && selfSymbol.isFunctionSelf()) {
selfSymbol.setNeedsSlot(false);
selfSymbol.clearFlag(Symbol.IS_VAR);
}
}
return functionNode;
@ -189,7 +185,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 +196,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);
}
return 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.setName(ident.setSymbol(symbol));
}
});
}
@ -356,6 +353,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.
@ -485,20 +486,31 @@ final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggabl
final Block body = lc.getCurrentBlock();
initFunctionWideVariables(functionNode, body);
acceptDeclarations(functionNode, body);
defineFunctionSelfSymbol(functionNode, body);
}
if (!functionNode.isProgram() && !functionNode.isDeclared() && !functionNode.isAnonymous()) {
// It's neither declared nor program - it's a function expression then; assign it a self-symbol unless it's
// anonymous.
final String name = functionNode.getIdent().getName();
assert name != null;
assert body.getExistingSymbol(name) == null;
defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
if(functionNode.allVarsInScope()) { // basically, has deep eval
lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
}
private void defineFunctionSelfSymbol(final FunctionNode functionNode, final Block body) {
// Function self-symbol is only declared as a local variable for named function expressions. Declared functions
// don't need it as they are local variables in their declaring scope.
if (!functionNode.isNamedFunctionExpression()) {
return;
}
acceptDeclarations(functionNode, body);
final String name = functionNode.getIdent().getName();
assert name != null; // As it's a named function expression.
if (body.getExistingSymbol(name) != null) {
// Body already has a declaration for the name. It's either a parameter "function x(x)" or a
// top-level variable "function x() { ... var x; ... }".
return;
}
defineSymbol(body, name, functionNode, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
if(functionNode.allVarsInScope()) { // basically, has deep eval
// We must conservatively presume that eval'd code can dynamically use the function symbol.
lc.setFlag(functionNode, FunctionNode.USES_SELF_SYMBOL);
}
}
@Override
@ -540,7 +552,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 +1056,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);

View File

@ -48,11 +48,13 @@ final class AstSerializer {
private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4);
static byte[] serialize(final FunctionNode fn) {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out,
new Deflater(COMPRESSION_LEVEL)))) {
final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
oout.writeObject(removeInnerFunctionBodies(fn));
} catch (final IOException e) {
throw new AssertionError("Unexpected exception serializing function", e);
} finally {
deflater.end();
}
return out.toByteArray();
}

View File

@ -3080,6 +3080,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (isConditionalCatch) {
loadExpressionAsBoolean(exceptionCondition);
nextCatch = new Label("next_catch");
nextCatch.markAsBreakTarget();
method.ifeq(nextCatch);
} else {
nextCatch = null;
@ -3092,7 +3093,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method._goto(afterCatch);
}
if(nextCatch != null) {
method.label(nextCatch);
method.breakLabel(nextCatch, lc.getUsedSlotCount());
}
}
@ -3264,6 +3265,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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
@ -264,4 +264,9 @@ 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;
}
}

View File

@ -1091,6 +1091,15 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return getFlag(USES_SELF_SYMBOL);
}
/**
* Returns true if this is a named function expression (that is, it isn't a declared function, it isn't an
* anonymous function expression, and it isn't a program).
* @return true if this is a named function expression
*/
public boolean isNamedFunctionExpression() {
return !getFlag(IS_PROGRAM | IS_ANONYMOUS | IS_DECLARED);
}
@Override
public Type getType(final Function<Symbol, Type> localVariableTypes) {
return FUNCTION_TYPE;

View File

@ -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();

View File

@ -177,4 +177,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();
}

View File

@ -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) {
@ -259,14 +256,6 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
return setFlags(flags | flag);
}
/**
* 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.

View File

@ -150,4 +150,9 @@ public final class WhileNode extends LoopNode {
}
return test == null;
}
@Override
public boolean hasPerIterationScope() {
return false;
}
}

View File

@ -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;
}
/**
@ -1693,6 +1706,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);
@ -1737,7 +1877,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);
@ -2203,4 +2343,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);
}
}
}

View File

@ -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;
}

View File

@ -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);
}
/**

View File

@ -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;
@ -498,7 +499,7 @@ public final class NativeObject {
final Object obj = JSType.toScriptObject(self);
if (obj instanceof ScriptObject) {
final InvokeByName toStringInvoker = getTO_STRING();
final ScriptObject sobj = (ScriptObject)self;
final ScriptObject sobj = (ScriptObject)obj;
try {
final Object toString = toStringInvoker.getGetter().invokeExact(sobj);
@ -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) {

View File

@ -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);
}

View File

@ -554,7 +554,7 @@ loop:
// Set up new block. Captures first token.
final ParserContextBlockNode newBlock = newBlock();
try {
statement();
statement(false, false, true);
} finally {
restoreBlock(newBlock);
}
@ -703,26 +703,12 @@ loop:
Collections.<IdentNode>emptyList());
lc.push(script);
final ParserContextBlockNode body = newBlock();
// If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
final int startLine = start;
final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
functionDeclarations = new ArrayList<>();
try {
sourceElements(allowPropertyFunction);
addFunctionDeclarations(script);
} finally {
if (outer != null) {
restoreBlock(outer);
appendStatement(new BlockStatement(
startLine,
new Block(
functionToken,
startLine, outer.getFlags(),
outer.getStatements())));
}
}
functionDeclarations = new ArrayList<>();
sourceElements(allowPropertyFunction);
addFunctionDeclarations(script);
functionDeclarations = null;
restoreBlock(body);
body.setFlag(Block.NEEDS_SCOPE);
final Block programBody = new Block(functionToken, functionLine, body.getFlags(), body.getStatements());
@ -784,7 +770,7 @@ loop:
try {
// Get the next element.
statement(true, allowPropertyFunction);
statement(true, allowPropertyFunction, false);
allowPropertyFunction = false;
// check for directive prologues
@ -874,13 +860,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.
@ -944,6 +932,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;
}
@ -1069,7 +1060,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) {
@ -1214,7 +1205,6 @@ loop:
final int startLine = start;
final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
// Create FOR node, capturing FOR token.
final ParserContextLoopNode forNode = new ParserContextLoopNode();
lc.push(forNode);
@ -1242,19 +1232,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) {
flags |= ForNode.PER_ITERATION_SCOPE;
}
// 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;
}
@ -1330,22 +1323,23 @@ loop:
body = getStatement();
} finally {
lc.pop(forNode);
if (vars != null) {
for (final VarNode var : vars) {
appendStatement(var);
}
}
if (body != null) {
appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
}
if (outer != null) {
restoreBlock(outer);
appendStatement(new BlockStatement(startLine, new Block(
outer.getToken(),
body.getFinish(),
outer.getStatements())));
}
if (vars != null) {
for (final VarNode var : vars) {
appendStatement(var);
}
}
if (body != null) {
appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
}
if (outer != null) {
restoreBlock(outer);
appendStatement(new BlockStatement(startLine, new Block(
outer.getToken(),
body.getFinish(),
outer.getStatements())));
}
}
/**
@ -1378,9 +1372,10 @@ loop:
body = getStatement();
} finally {
lc.pop(whileNode);
if (body != null){
appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
}
}
if (body != null) {
appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
}
}
@ -1422,8 +1417,9 @@ loop:
}
} finally {
lc.pop(doWhileNode);
appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
}
appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
}
/**
@ -1621,17 +1617,12 @@ loop:
throw error(AbstractParser.message("strict.no.with"), withToken);
}
Expression expression = null;
Block body = null;
try {
expect(LPAREN);
expression = expression();
expect(RPAREN);
body = getStatement();
} finally {
appendStatement(new WithNode(withLine, withToken, finish, expression, body));
}
expect(LPAREN);
final Expression expression = expression();
expect(RPAREN);
final Block body = getStatement();
appendStatement(new WithNode(withLine, withToken, finish, expression, body));
}
/**
@ -1720,8 +1711,9 @@ loop:
next();
} finally {
lc.pop(switchNode);
appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
}
appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
}
/**
@ -1752,10 +1744,9 @@ loop:
} finally {
assert lc.peek() instanceof ParserContextLabelNode;
lc.pop(labelNode);
if (ident != null){
appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
}
}
appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
}
/**
@ -2300,9 +2291,14 @@ loop:
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
lc.push(functionNode);
final Block functionBody = functionBody(functionNode);
Block functionBody;
lc.pop(functionNode);
try {
functionBody = functionBody(functionNode);
} finally {
lc.pop(functionNode);
}
final FunctionNode function = createFunctionNode(
functionNode,
@ -2340,9 +2336,13 @@ loop:
final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
lc.push(functionNode);
final Block functionBody = functionBody(functionNode);
Block functionBody;
try {
functionBody = functionBody(functionNode);
} finally {
lc.pop(functionNode);
}
lc.pop(functionNode);
final FunctionNode function = createFunctionNode(
functionNode,
@ -2739,12 +2739,9 @@ loop:
functionBody);
if (isStatement) {
int varFlags = VarNode.IS_STATEMENT;
if (!topLevel && useBlockScope()) {
// mark ES6 block functions as lexically scoped
varFlags |= VarNode.IS_LET;
}
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
// mark ES6 block functions as lexically scoped
final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
if (topLevel) {
functionDeclarations.add(varNode);
} else if (useBlockScope()) {

View File

@ -25,7 +25,7 @@
package jdk.nashorn.internal.parser;
/**
* A ParserContextNode that represents a SwithcNode that is currently being parsed
* A ParserContextNode that represents a SwitchNode that is currently being parsed
*/
class ParserContextSwitchNode extends ParserContextBaseNode implements ParserContextBreakableNode {

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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,31 +306,46 @@ 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);
}
} 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 = 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 {
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));
}
}
}
return newMap;
}
/**
* Copy all properties from the array with their receiver bound to the source.
*
@ -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);
}
@ -3666,6 +3693,29 @@ public abstract class ScriptObject implements PropertyAccess {
return true;
}
/**
* 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.

View File

@ -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

View File

@ -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;

View File

@ -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);
}
/**

View File

@ -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();
}
}

View File

@ -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)));
}
}

View File

@ -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);
}
}

View File

@ -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)));
}
}

View File

@ -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);
}
/**

View File

@ -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

View File

@ -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");

View File

@ -0,0 +1 @@
false

View File

@ -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);

View File

@ -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");

View File

@ -0,0 +1 @@
true

View File

@ -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))())

View File

@ -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

View File

@ -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-8066214: Fuzzing bug: Object.prototype.toLocaleString(0)
*
* @test
* @run
*/
function test(func) {
print(func.call(0));
print(func.call("abc"));
print(func.call(true));
try {
print(func.call(undefined));
} catch (e) {
print(e);
}
try {
print(func.call(null));
} catch (e) {
print(e);
}
}
test(Object.prototype.toLocaleString);
test(Object.prototype.toString);
test(Object.prototype.valueOf);

View File

@ -0,0 +1,15 @@
0
abc
true
TypeError: undefined is not an Object
TypeError: null is not an Object
[object Number]
[object String]
[object Boolean]
[object Undefined]
[object Null]
0
abc
true
TypeError: undefined is not an Object
TypeError: null is not an Object

View File

@ -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-8066222: too strong assertion on function expression names
*
* @test
* @run
*/
// Has to print "SUCCESS"
(function x (x){print(x)})("SUCCESS");
// Has to print "undefined" and "1", not the function source in any case.
(function x(){print(x); var x=1; print(x)})();

View File

@ -0,0 +1,3 @@
SUCCESS
undefined
1

View File

@ -0,0 +1,36 @@
/*
* 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-8066232: problem with conditional catch compilation
*
* @test
* @run
*/
(function () {
try {
x;
} catch(e if 1) {
}
})()

View File

@ -0,0 +1 @@
SUCCESS

View File

@ -0,0 +1,43 @@
/*
* 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.
*/
/**
* Parser should not crash on invalid property function bodies.
*
* @test
* @run
*/
try {
eval("function f() { L: ({ set prop(){0 = null} }); }");
} catch (e) {
if (!(e instanceof ReferenceError)) {
throw e;
}
}
try {
eval("function g() { do ; while({ get x()1-- }); }");
} catch (e) {
if (!(e instanceof ReferenceError)) {
throw e;
}
}

View File

@ -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");

View File

@ -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

View File

@ -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]); });
})();

View File

@ -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");

View File

@ -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;
^

View File

@ -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(); });

View File

@ -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

View File

@ -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;');

View File

@ -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;
^

View File

@ -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; }');

View File

@ -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; }
^

View File

@ -26,7 +26,8 @@
*
* @test
* @run
* @option --language=es6 */
* @option --language=es6
*/
"use strict";
@ -39,17 +40,8 @@ load(__DIR__ + "let-load-lib.js");
}
print("imported var: " + a);
try {
print("imported let: " + b);
} catch (e) {
print(e);
}
try {
print("imported const: " + c);
} catch (e) {
print(e);
}
print("imported let: " + b);
print("imported const: " + c);
top();
@ -59,4 +51,10 @@ try {
print(e);
}
try {
c = "foo";
} catch (e) {
print(e);
}

View File

@ -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"

View File

@ -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;
^

View File

@ -5,9 +5,9 @@
test
test
test
3
3
3
0
1
2
0
1
2

View File

@ -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";

View File

@ -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, "/"));
}

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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] }

View File

@ -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");

View File

@ -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"

View File

@ -53,6 +53,7 @@ if (! new File(jdepsPath).isFile()) {
}
// 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

View File

@ -54,6 +54,7 @@ if (! new File(jjsCmd).isFile()) {
}
jjsCmd += " -J-Xbootclasspath/a:" + nashornJarDir;
$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.

View File

@ -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);
}
}
}
}

View File

@ -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) {