8051889: Implement block scoping in symbol assignment and scope computation
Reviewed-by: attila, lagergren
This commit is contained in:
parent
917f13e5db
commit
7ecdd47620
nashorn
make
src/jdk.scripting.nashorn/share/classes/jdk/nashorn
internal
codegen
AssignSymbols.javaCodeGenerator.javaCompiler.javaFieldObjectCreator.javaMapCreator.javaMethodEmitter.javaTypeEvaluator.java
ir
parser
runtime
tools
test
script
basic/es6
block-function-decl.jsblock-function-decl.js.EXPECTEDconst-empty.jsconst-empty.js.EXPECTEDconst-reassign.jsconst-reassign.js.EXPECTEDconst-redeclare.jsconst-redeclare.js.EXPECTEDconst-self.jsconst-self.js.EXPECTEDconst-tdz.jsconst-tdz.js.EXPECTEDconst.jsconst.js.EXPECTEDfor-let.jsfor-let.js.EXPECTEDlet-eval.jslet-eval.js.EXPECTEDlet-load-lib.jslet-load.jslet-load.js.EXPECTEDlet-nodeclare.jslet-nodeclare.js.EXPECTEDlet-redeclare.jslet-redeclare.js.EXPECTEDlet-self.jslet-self.js.EXPECTEDlet-tdz.jslet-tdz.js.EXPECTEDlet.jslet.js.EXPECTED
trusted
src/jdk/nashorn/internal
@ -341,6 +341,13 @@ grant codeBase "file:/${basedir}/test/script/basic/parser/*" {
|
||||
permission java.util.PropertyPermission "nashorn.test.*", "read";
|
||||
};
|
||||
|
||||
grant codeBase "file:/${basedir}/test/script/basic/es6/*" {
|
||||
permission java.io.FilePermission "${basedir}/test/script/-", "read";
|
||||
permission java.io.FilePermission "$${user.dir}", "read";
|
||||
permission java.util.PropertyPermission "user.dir", "read";
|
||||
permission java.util.PropertyPermission "nashorn.test.*", "read";
|
||||
};
|
||||
|
||||
grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
|
||||
permission java.util.PropertyPermission "java.security.policy", "read";
|
||||
};
|
||||
|
@ -36,6 +36,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
|
||||
import static jdk.nashorn.internal.ir.Symbol.HAS_OBJECT_VALUE;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_CONST;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
|
||||
@ -83,11 +84,13 @@ import jdk.nashorn.internal.ir.TryNode;
|
||||
import jdk.nashorn.internal.ir.UnaryNode;
|
||||
import jdk.nashorn.internal.ir.VarNode;
|
||||
import jdk.nashorn.internal.ir.WithNode;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ECMAErrors;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.JSErrorType;
|
||||
import jdk.nashorn.internal.runtime.ParserException;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.runtime.logging.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.logging.Loggable;
|
||||
import jdk.nashorn.internal.runtime.logging.Logger;
|
||||
@ -101,7 +104,7 @@ import jdk.nashorn.internal.runtime.logging.Logger;
|
||||
* visitor.
|
||||
*/
|
||||
@Logger(name="symbols")
|
||||
final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements Loggable {
|
||||
final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggable {
|
||||
private final DebugLogger log;
|
||||
private final boolean debug;
|
||||
|
||||
@ -190,8 +193,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
* @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 function declarations (which are taken care
|
||||
// in a separate step above) and "var" declarations in for loop initializers.
|
||||
// This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
|
||||
//
|
||||
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
|
||||
@Override
|
||||
@ -204,8 +206,8 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
if (varNode.isStatement()) {
|
||||
final IdentNode ident = varNode.getName();
|
||||
final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR);
|
||||
functionNode.addDeclaredSymbol(symbol);
|
||||
final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body;
|
||||
final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags());
|
||||
if (varNode.isFunctionDeclaration()) {
|
||||
symbol.setIsFunctionDeclaration();
|
||||
}
|
||||
@ -303,23 +305,31 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return functionNode.setBody(lc, body.setStatements(lc, newStatements));
|
||||
}
|
||||
|
||||
private Symbol defineGlobalSymbol(final Block block, final String name) {
|
||||
return defineSymbol(block, name, IS_GLOBAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new symbol in the given block.
|
||||
*
|
||||
* @param block the block in which to define the symbol
|
||||
* @param name name of symbol.
|
||||
* @param origin origin node
|
||||
* @param symbolFlags Symbol flags.
|
||||
*
|
||||
* @return Symbol for given name or null for redefinition.
|
||||
*/
|
||||
private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
|
||||
private Symbol defineSymbol(final Block block, final String name, final Node origin, final int symbolFlags) {
|
||||
int flags = symbolFlags;
|
||||
Symbol symbol = findSymbol(block, name); // Locate symbol.
|
||||
final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
|
||||
final boolean isBlockScope = (flags & IS_LET) != 0 || (flags & IS_CONST) != 0;
|
||||
final boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
|
||||
|
||||
Symbol symbol;
|
||||
final FunctionNode function;
|
||||
if (isBlockScope) {
|
||||
// block scoped variables always live in current block, no need to look for existing symbols in parent blocks.
|
||||
symbol = block.getExistingSymbol(name);
|
||||
function = lc.getCurrentFunction();
|
||||
} else {
|
||||
symbol = findSymbol(block, name);
|
||||
function = lc.getFunction(block);
|
||||
}
|
||||
|
||||
// Global variables are implicitly always scope variables too.
|
||||
if (isGlobal) {
|
||||
@ -333,7 +343,6 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
final boolean isParam = (flags & KINDMASK) == IS_PARAM;
|
||||
final boolean isVar = (flags & KINDMASK) == IS_VAR;
|
||||
|
||||
final FunctionNode function = lc.getFunction(block);
|
||||
if (symbol != null) {
|
||||
// Symbol was already defined. Check if it needs to be redefined.
|
||||
if (isParam) {
|
||||
@ -345,10 +354,21 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
throw new AssertionError("duplicate parameter");
|
||||
}
|
||||
} else if (isVar) {
|
||||
if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
|
||||
if (isBlockScope) {
|
||||
// Check redeclaration in same block
|
||||
if (symbol.hasBeenDeclared()) {
|
||||
throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
|
||||
} else {
|
||||
symbol.setHasBeenDeclared();
|
||||
}
|
||||
} else if ((flags & IS_INTERNAL) != 0) {
|
||||
// Always create a new definition.
|
||||
symbol = null;
|
||||
} else {
|
||||
// Found LET or CONST in parent scope of same function - s SyntaxError
|
||||
if (symbol.isBlockScoped() && isLocal(lc.getCurrentFunction(), symbol)) {
|
||||
throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin);
|
||||
}
|
||||
// Not defined in this function. Create a new definition.
|
||||
if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
|
||||
symbol = null;
|
||||
@ -359,10 +379,10 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
|
||||
if (symbol == null) {
|
||||
// If not found, then create a new one.
|
||||
Block symbolBlock;
|
||||
final Block symbolBlock;
|
||||
|
||||
// Determine where to create it.
|
||||
if (isVar && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
|
||||
if (isVar && ((flags & IS_INTERNAL) != 0 || isBlockScope)) {
|
||||
symbolBlock = block; //internal vars are always defined in the block closest to them
|
||||
} else if (isGlobal) {
|
||||
symbolBlock = lc.getOutermostFunction().getBody();
|
||||
@ -420,9 +440,9 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
@Override
|
||||
public boolean enterBlock(final Block block) {
|
||||
start(block);
|
||||
block.clearSymbols();
|
||||
|
||||
if (lc.isFunctionBody()) {
|
||||
block.clearSymbols();
|
||||
enterFunctionBody();
|
||||
}
|
||||
|
||||
@ -441,7 +461,10 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
// If the name of the exception starts with ":e", this is a synthetic catch block, likely a catch-all. Its
|
||||
// symbol is naturally internal, and should be treated as such.
|
||||
final boolean isInternal = exname.startsWith(EXCEPTION_PREFIX.symbolName());
|
||||
defineSymbol(block, exname, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
|
||||
// IS_LET flag is required to make sure symbol is not visible outside catch block. However, we need to
|
||||
// clear the IS_LET flag after creation to allow redefinition of symbol inside the catch block.
|
||||
final Symbol symbol = defineSymbol(block, exname, catchNode, IS_VAR | IS_LET | (isInternal ? IS_INTERNAL : 0) | HAS_OBJECT_VALUE);
|
||||
symbol.clearFlag(IS_LET);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -452,15 +475,13 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
|
||||
initFunctionWideVariables(functionNode, body);
|
||||
|
||||
if (functionNode.isProgram()) {
|
||||
initGlobalSymbols(body);
|
||||
} else if (!functionNode.isDeclared() && !functionNode.isAnonymous()) {
|
||||
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, IS_VAR | IS_FUNCTION_SELF | HAS_OBJECT_VALUE);
|
||||
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);
|
||||
}
|
||||
@ -485,7 +506,8 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
if (functionNode.isDeclared()) {
|
||||
final Iterator<Block> blocks = lc.getBlocks();
|
||||
if (blocks.hasNext()) {
|
||||
defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
|
||||
final IdentNode ident = functionNode.getIdent();
|
||||
defineSymbol(blocks.next(), ident.getName(), ident, IS_VAR | (functionNode.isAnonymous()? IS_INTERNAL : 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,10 +517,16 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
@Override
|
||||
public boolean enterVarNode(final VarNode varNode) {
|
||||
start(varNode);
|
||||
defineSymbol(lc.getCurrentBlock(), varNode.getName().getName(), IS_VAR | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
final IdentNode ident = varNode.getName();
|
||||
defineSymbol(lc.getCurrentBlock(), ident.getName(), ident, varNode.getSymbolFlags() | (lc.getCurrentFunction().isProgram() ? IS_SCOPE : 0));
|
||||
return super.leaveVarNode(varNode);
|
||||
}
|
||||
|
||||
private Symbol exceptionSymbol() {
|
||||
return newObjectInternal(EXCEPTION_PREFIX);
|
||||
}
|
||||
@ -597,7 +625,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
}
|
||||
|
||||
private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
|
||||
defineSymbol(block, cc.symbolName(), flags).setNeedsSlot(true);
|
||||
defineSymbol(block, cc.symbolName(), null, flags).setNeedsSlot(true);
|
||||
}
|
||||
|
||||
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
|
||||
@ -608,7 +636,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL | HAS_OBJECT_VALUE);
|
||||
if (functionNode.needsArguments()) {
|
||||
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | HAS_OBJECT_VALUE);
|
||||
defineSymbol(body, ARGUMENTS_VAR.symbolName(), IS_VAR | HAS_OBJECT_VALUE);
|
||||
defineSymbol(body, ARGUMENTS_VAR.symbolName(), null, IS_VAR | HAS_OBJECT_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,20 +645,6 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move any properties from the global map into the scope of this function (which must be a program function).
|
||||
* @param block the function node body for which to init scope vars
|
||||
*/
|
||||
private void initGlobalSymbols(final Block block) {
|
||||
final PropertyMap map = Context.getGlobalMap();
|
||||
|
||||
for (final Property property : map.getProperties()) {
|
||||
final Symbol symbol = defineGlobalSymbol(block, property.getKey());
|
||||
log.info("Added global symbol from property map ", symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize parameters for function node.
|
||||
* @param functionNode the function node
|
||||
@ -639,7 +653,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
final boolean isVarArg = functionNode.isVarArg();
|
||||
final boolean scopeParams = functionNode.allVarsInScope() || isVarArg;
|
||||
for (final IdentNode param : functionNode.getParameters()) {
|
||||
final Symbol symbol = defineSymbol(body, param.getName(), IS_PARAM);
|
||||
final Symbol symbol = defineSymbol(body, param.getName(), param, IS_PARAM);
|
||||
if(scopeParams) {
|
||||
// NOTE: this "set is scope" is a poor substitute for clear expression of where the symbol is stored.
|
||||
// It will force creation of scopes where they would otherwise not necessarily be needed (functions
|
||||
@ -665,10 +679,29 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return definingFn == function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveASSIGN(final BinaryNode binaryNode) {
|
||||
// If we're assigning a property of the this object ("this.foo = ..."), record it.
|
||||
private void checkConstAssignment(final IdentNode ident) {
|
||||
// Check for reassignment of constant
|
||||
final Symbol symbol = ident.getSymbol();
|
||||
if (symbol.isConst()) {
|
||||
throwParserException(ECMAErrors.getMessage("syntax.error.assign.constant", symbol.getName()), ident);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveBinaryNode(final BinaryNode binaryNode) {
|
||||
if (binaryNode.isAssignment() && binaryNode.lhs() instanceof IdentNode) {
|
||||
checkConstAssignment((IdentNode) binaryNode.lhs());
|
||||
}
|
||||
switch (binaryNode.tokenType()) {
|
||||
case ASSIGN:
|
||||
return leaveASSIGN(binaryNode);
|
||||
default:
|
||||
return super.leaveBinaryNode(binaryNode);
|
||||
}
|
||||
}
|
||||
|
||||
private Node leaveASSIGN(final BinaryNode binaryNode) {
|
||||
// If we're assigning a property of the this object ("this.foo = ..."), record it.
|
||||
final Expression lhs = binaryNode.lhs();
|
||||
if (lhs instanceof AccessNode) {
|
||||
final AccessNode accessNode = (AccessNode) lhs;
|
||||
@ -683,6 +716,21 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return binaryNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveUnaryNode(final UnaryNode unaryNode) {
|
||||
if (unaryNode.isAssignment() && unaryNode.getExpression() instanceof IdentNode) {
|
||||
checkConstAssignment((IdentNode) unaryNode.getExpression());
|
||||
}
|
||||
switch (unaryNode.tokenType()) {
|
||||
case DELETE:
|
||||
return leaveDELETE(unaryNode);
|
||||
case TYPEOF:
|
||||
return leaveTYPEOF(unaryNode);
|
||||
default:
|
||||
return super.leaveUnaryNode(unaryNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveBlock(final Block block) {
|
||||
// It's not necessary to guard the marking of symbols as locals with this "if"condition for correctness, it's
|
||||
@ -699,8 +747,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveDELETE(final UnaryNode unaryNode) {
|
||||
private Node leaveDELETE(final UnaryNode unaryNode) {
|
||||
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
|
||||
final boolean strictMode = currentFunctionNode.isStrict();
|
||||
final Expression rhs = unaryNode.getExpression();
|
||||
@ -799,9 +846,8 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
// if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
|
||||
maybeForceScope(symbol);
|
||||
} else {
|
||||
log.info("No symbol exists. Declare as global: ", symbol);
|
||||
symbol = defineGlobalSymbol(block, name);
|
||||
Symbol.setSymbolIsScope(lc, symbol);
|
||||
log.info("No symbol exists. Declare as global: ", name);
|
||||
symbol = defineSymbol(block, name, identNode, IS_GLOBAL | IS_SCOPE);
|
||||
}
|
||||
|
||||
functionUsesSymbol(symbol);
|
||||
@ -810,7 +856,15 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
symbol.increaseUseCount();
|
||||
}
|
||||
|
||||
return end(identNode.setSymbol(symbol));
|
||||
IdentNode newIdentNode = identNode.setSymbol(symbol);
|
||||
|
||||
// If a block-scoped var is used before its declaration mark it as dead.
|
||||
// We can only statically detect this for local vars, cross-function symbols require runtime checks.
|
||||
if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
|
||||
newIdentNode = newIdentNode.markDead();
|
||||
}
|
||||
|
||||
return end(newIdentNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -834,8 +888,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return tryNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveTYPEOF(final UnaryNode unaryNode) {
|
||||
private Node leaveTYPEOF(final UnaryNode unaryNode) {
|
||||
final Expression rhs = unaryNode.getExpression();
|
||||
|
||||
final List<Expression> args = new ArrayList<>();
|
||||
@ -875,7 +928,7 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
}
|
||||
|
||||
private Symbol newInternal(final CompilerConstants cc, final int flags) {
|
||||
return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), IS_VAR | IS_INTERNAL | flags); //NASHORN-73
|
||||
return defineSymbol(lc.getCurrentBlock(), lc.getCurrentFunction().uniqueName(cc.symbolName()), null, IS_VAR | IS_INTERNAL | flags); //NASHORN-73
|
||||
}
|
||||
|
||||
private Symbol newObjectInternal(final CompilerConstants cc) {
|
||||
@ -915,7 +968,8 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lc.getCurrentFunction().allVarsInScope()) {
|
||||
final FunctionNode func = lc.getCurrentFunction();
|
||||
if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -955,4 +1009,16 @@ final class AssignSymbols extends NodeOperatorVisitor<LexicalContext> implements
|
||||
final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
|
||||
return !(units == null || units.isEmpty());
|
||||
}
|
||||
|
||||
private void throwParserException(final String message, final Node origin) {
|
||||
if (origin == null) {
|
||||
throw new ParserException(message);
|
||||
}
|
||||
final Source source = compiler.getSource();
|
||||
final long token = origin.getToken();
|
||||
final int line = source.getLine(origin.getStart());
|
||||
final int column = source.getColumn(origin.getStart());
|
||||
final String formatted = ErrorManager.format(message, source, line, column, token);
|
||||
throw new ParserException(JSErrorType.SYNTAX_ERROR, formatted, source, line, column, token);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_APPLY_TO_CALL;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_DECLARE;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_FAST_SCOPE;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
|
||||
@ -302,6 +303,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
* @return the method generator used
|
||||
*/
|
||||
private MethodEmitter loadIdent(final IdentNode identNode, final TypeBounds resultBounds) {
|
||||
checkTemporalDeadZone(identNode);
|
||||
final Symbol symbol = identNode.getSymbol();
|
||||
|
||||
if (!symbol.isScope()) {
|
||||
@ -334,6 +336,15 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return method;
|
||||
}
|
||||
|
||||
// Any access to LET and CONST variables before their declaration must throw ReferenceError.
|
||||
// This is called the temporal dead zone (TDZ). See https://gist.github.com/rwaldron/f0807a758aa03bcdd58a
|
||||
private void checkTemporalDeadZone(final IdentNode identNode) {
|
||||
if (identNode.isDead()) {
|
||||
method.load(identNode.getSymbol().getName());
|
||||
method.invoke(ScriptRuntime.THROW_REFERENCE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRestOf() {
|
||||
return continuationEntryPoints != null;
|
||||
}
|
||||
@ -3216,27 +3227,34 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
return false;
|
||||
}
|
||||
final Expression init = varNode.getInit();
|
||||
final IdentNode identNode = varNode.getName();
|
||||
final Symbol identSymbol = identNode.getSymbol();
|
||||
assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
|
||||
final boolean needsScope = identSymbol.isScope();
|
||||
|
||||
if (init == null) {
|
||||
if (needsScope && varNode.isBlockScoped()) {
|
||||
// block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
method.loadUndefined(Type.OBJECT);
|
||||
final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
|
||||
assert isFastScope(identSymbol);
|
||||
storeFastScopeVar(identSymbol, flags);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
enterStatement(varNode);
|
||||
|
||||
final IdentNode identNode = varNode.getName();
|
||||
final Symbol identSymbol = identNode.getSymbol();
|
||||
assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol";
|
||||
|
||||
assert method != null;
|
||||
|
||||
final boolean needsScope = identSymbol.isScope();
|
||||
if (needsScope) {
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
}
|
||||
|
||||
if (needsScope) {
|
||||
loadExpressionUnbounded(init);
|
||||
final int flags = CALLSITE_SCOPE | getCallSiteFlags();
|
||||
// block scoped variables need a DECLARE flag to signal end of temporal dead zone (TDZ)
|
||||
final int flags = CALLSITE_SCOPE | getCallSiteFlags() | (varNode.isBlockScoped() ? CALLSITE_DECLARE : 0);
|
||||
if (isFastScope(identSymbol)) {
|
||||
storeFastScopeVar(identSymbol, flags);
|
||||
} else {
|
||||
@ -4343,6 +4361,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
|
||||
protected abstract void evaluate();
|
||||
|
||||
void store() {
|
||||
if (target instanceof IdentNode) {
|
||||
checkTemporalDeadZone((IdentNode)target);
|
||||
}
|
||||
prologue();
|
||||
evaluate(); // leaves an operation of whatever the operationType was on the stack
|
||||
storeNonDiscard();
|
||||
|
@ -59,7 +59,9 @@ import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
|
||||
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
|
||||
import jdk.nashorn.internal.runtime.CodeInstaller;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.FunctionInitializer;
|
||||
import jdk.nashorn.internal.runtime.ParserException;
|
||||
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
|
||||
import jdk.nashorn.internal.runtime.ScriptEnvironment;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
@ -89,6 +91,8 @@ public final class Compiler implements Loggable {
|
||||
|
||||
private final String sourceName;
|
||||
|
||||
private final ErrorManager errors;
|
||||
|
||||
private final boolean optimistic;
|
||||
|
||||
private final Map<String, byte[]> bytecode;
|
||||
@ -311,6 +315,7 @@ public final class Compiler implements Loggable {
|
||||
* @param env script environment
|
||||
* @param installer code installer
|
||||
* @param source source to compile
|
||||
* @param errors error manager
|
||||
* @param isStrict is this a strict compilation
|
||||
*/
|
||||
public Compiler(
|
||||
@ -318,8 +323,9 @@ public final class Compiler implements Loggable {
|
||||
final ScriptEnvironment env,
|
||||
final CodeInstaller<ScriptEnvironment> installer,
|
||||
final Source source,
|
||||
final ErrorManager errors,
|
||||
final boolean isStrict) {
|
||||
this(context, env, installer, source, isStrict, false, null, null, null, null, null, null);
|
||||
this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,6 +335,7 @@ public final class Compiler implements Loggable {
|
||||
* @param env script environment
|
||||
* @param installer code installer
|
||||
* @param source source to compile
|
||||
* @param errors error manager
|
||||
* @param isStrict is this a strict compilation
|
||||
* @param isOnDemand is this an on demand compilation
|
||||
* @param compiledFunction compiled function, if any
|
||||
@ -343,6 +350,7 @@ public final class Compiler implements Loggable {
|
||||
final ScriptEnvironment env,
|
||||
final CodeInstaller<ScriptEnvironment> installer,
|
||||
final Source source,
|
||||
final ErrorManager errors,
|
||||
final boolean isStrict,
|
||||
final boolean isOnDemand,
|
||||
final RecompilableScriptFunctionData compiledFunction,
|
||||
@ -359,6 +367,7 @@ public final class Compiler implements Loggable {
|
||||
this.bytecode = new LinkedHashMap<>();
|
||||
this.log = initLogger(context);
|
||||
this.source = source;
|
||||
this.errors = errors;
|
||||
this.sourceName = FunctionNode.getSourceName(source);
|
||||
this.onDemand = isOnDemand;
|
||||
this.compiledFunction = compiledFunction;
|
||||
@ -524,7 +533,17 @@ public final class Compiler implements Loggable {
|
||||
|
||||
for (final CompilationPhase phase : phases) {
|
||||
log.fine(phase, " starting for ", quote(name));
|
||||
newFunctionNode = phase.apply(this, phases, newFunctionNode);
|
||||
|
||||
try {
|
||||
newFunctionNode = phase.apply(this, phases, newFunctionNode);
|
||||
} catch (final ParserException error) {
|
||||
errors.error(error);
|
||||
if (env._dump_on_error) {
|
||||
error.printStackTrace(env.getErr());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
log.fine(phase, " done for function ", quote(name));
|
||||
|
||||
if (env._print_mem_usage) {
|
||||
|
12
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java
12
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java
@ -69,9 +69,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator<T> {
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen code generator
|
||||
* @param keys keys for fields in object
|
||||
* @param symbols symbols for fields in object
|
||||
* @param values list of values corresponding to keys
|
||||
* @param tuples tuples for fields in object
|
||||
*/
|
||||
FieldObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples) {
|
||||
this(codegen, tuples, false, false);
|
||||
@ -81,9 +79,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator<T> {
|
||||
* Constructor
|
||||
*
|
||||
* @param codegen code generator
|
||||
* @param keys keys for fields in object
|
||||
* @param symbols symbols for fields in object
|
||||
* @param values values (or null where no value) to be written to the fields
|
||||
* @param tuples tuples for fields in object
|
||||
* @param isScope is this a scope object
|
||||
* @param hasArguments does the created object have an "arguments" property
|
||||
*/
|
||||
@ -165,7 +161,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator<T> {
|
||||
* @param method Script method.
|
||||
* @param key Property key.
|
||||
* @param fieldIndex Field number.
|
||||
* @param value Value to store.
|
||||
* @param tuple Tuple to store.
|
||||
*/
|
||||
private void putField(final MethodEmitter method, final String key, final int fieldIndex, final MapTuple<T> tuple) {
|
||||
method.dup();
|
||||
@ -188,7 +184,7 @@ public abstract class FieldObjectCreator<T> extends ObjectCreator<T> {
|
||||
*
|
||||
* @param method Script method.
|
||||
* @param index Slot index.
|
||||
* @param value Value to store.
|
||||
* @param tuple Tuple to store.
|
||||
*/
|
||||
private void putSlot(final MethodEmitter method, final long index, final MapTuple<T> tuple) {
|
||||
method.dup();
|
||||
|
@ -52,8 +52,7 @@ public class MapCreator<T> {
|
||||
* Constructor
|
||||
*
|
||||
* @param structure structure to generate map for (a JO subclass)
|
||||
* @param keys list of keys for map
|
||||
* @param symbols list of symbols for map
|
||||
* @param tuples list of tuples for map
|
||||
*/
|
||||
MapCreator(final Class<? extends ScriptObject> structure, final List<MapTuple<T>> tuples) {
|
||||
this.structure = structure;
|
||||
@ -149,6 +148,15 @@ public class MapCreator<T> {
|
||||
flags |= Property.IS_FUNCTION_DECLARATION;
|
||||
}
|
||||
|
||||
if (symbol.isConst()) {
|
||||
flags |= Property.NOT_WRITABLE;
|
||||
}
|
||||
|
||||
// Mark symbol as needing declaration. Access before declaration will throw a ReferenceError.
|
||||
if (symbol.isBlockScoped() && symbol.isScope()) {
|
||||
flags |= Property.NEEDS_DECLARATION;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
@ -2233,9 +2233,8 @@ public class MethodEmitter implements Emitter {
|
||||
/**
|
||||
* Generate dynamic setter. Pop receiver and property from stack.
|
||||
*
|
||||
* @param valueType the type of the value to set
|
||||
* @param name name of property
|
||||
* @param flags call site flags
|
||||
* @param name name of property
|
||||
* @param flags call site flags
|
||||
*/
|
||||
void dynamicSet(final String name, final int flags) {
|
||||
assert !isOptimistic(flags);
|
||||
@ -2462,7 +2461,6 @@ public class MethodEmitter implements Emitter {
|
||||
* Register line number at a label
|
||||
*
|
||||
* @param line line number
|
||||
* @param label label
|
||||
*/
|
||||
void lineNumber(final int line) {
|
||||
if (context.getEnv()._debug_lines) {
|
||||
|
@ -108,7 +108,7 @@ final class TypeEvaluator {
|
||||
|
||||
// Safely evaluate the property, and return the narrowest type for the actual value (e.g. Type.INT for a boxed
|
||||
// integer).
|
||||
final Object value = property.getObjectValue(owner, owner);
|
||||
final Object value = property.needsDeclaration() ? ScriptRuntime.UNDEFINED : property.getObjectValue(owner, owner);
|
||||
if (value == ScriptRuntime.UNDEFINED) {
|
||||
return null;
|
||||
}
|
||||
|
@ -138,10 +138,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
/** Last token of function. **/
|
||||
private final long lastToken;
|
||||
|
||||
/** Declared symbols in this function node */
|
||||
@Ignore
|
||||
private final Set<Symbol> declaredSymbols;
|
||||
|
||||
/** Method's namespace. */
|
||||
private final Namespace namespace;
|
||||
|
||||
@ -330,7 +326,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
this.lastToken = token;
|
||||
this.namespace = namespace;
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
|
||||
this.declaredSymbols = new HashSet<>();
|
||||
this.flags = flags;
|
||||
this.compileUnit = null;
|
||||
this.body = null;
|
||||
@ -369,7 +364,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
this.id = functionNode.id;
|
||||
this.ident = functionNode.ident;
|
||||
this.namespace = functionNode.namespace;
|
||||
this.declaredSymbols = functionNode.declaredSymbols;
|
||||
this.kind = functionNode.kind;
|
||||
this.firstToken = functionNode.firstToken;
|
||||
}
|
||||
@ -723,24 +717,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
return ident;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a set of symbols declared in this function node. This
|
||||
* is only relevant after Attr, otherwise it will be an empty
|
||||
* set as no symbols have been introduced
|
||||
* @return set of declared symbols in function
|
||||
*/
|
||||
public Set<Symbol> getDeclaredSymbols() {
|
||||
return Collections.unmodifiableSet(declaredSymbols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a declared symbol to this function node
|
||||
* @param symbol symbol that is declared
|
||||
*/
|
||||
public void addDeclaredSymbol(final Symbol symbol) {
|
||||
declaredSymbols.add(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function body
|
||||
* @return the function body
|
||||
@ -970,13 +946,13 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
|
||||
* Check if this function should have all its variables in its own scope. Split sub-functions, and
|
||||
* functions having with and/or eval blocks are such.
|
||||
*
|
||||
* @return true if all variables should be in scope
|
||||
*/
|
||||
public boolean allVarsInScope() {
|
||||
return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE);
|
||||
return getFlag(HAS_ALL_VARS_IN_SCOPE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,6 +46,8 @@ public final class IdentNode extends Expression implements PropertyKey, Function
|
||||
private static final int INITIALIZED_HERE = 1 << 1;
|
||||
private static final int FUNCTION = 1 << 2;
|
||||
private static final int FUTURESTRICT_NAME = 1 << 3;
|
||||
private static final int IS_DECLARED_HERE = 1 << 4;
|
||||
private static final int IS_DEAD = 1 << 5;
|
||||
|
||||
/** Identifier. */
|
||||
private final String name;
|
||||
@ -246,6 +248,45 @@ public final class IdentNode extends Expression implements PropertyKey, Function
|
||||
return new IdentNode(this, name, type, flags | INITIALIZED_HERE, programPoint, conversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a LET or CONST identifier used before its declaration?
|
||||
*
|
||||
* @return true if identifier is dead
|
||||
*/
|
||||
public boolean isDead() {
|
||||
return (flags & IS_DEAD) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this IdentNode as a LET or CONST identifier used before its declaration.
|
||||
*
|
||||
* @return a new IdentNode equivalent to this but marked as dead.
|
||||
*/
|
||||
public IdentNode markDead() {
|
||||
return new IdentNode(this, name, type, flags | IS_DEAD, programPoint, conversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this IdentNode declared here?
|
||||
*
|
||||
* @return true if identifier is declared here
|
||||
*/
|
||||
public boolean isDeclaredHere() {
|
||||
return (flags & IS_DECLARED_HERE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this IdentNode as being declared here.
|
||||
*
|
||||
* @return a new IdentNode equivalent to this but marked as declared here.
|
||||
*/
|
||||
public IdentNode setIsDeclaredHere() {
|
||||
if (isDeclaredHere()) {
|
||||
return this;
|
||||
}
|
||||
return new IdentNode(this, name, type, flags | IS_DECLARED_HERE, programPoint, conversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the name of this IdentNode is same as that of a compile-time property (currently __DIR__, __FILE__, and
|
||||
* __LINE__).
|
||||
|
@ -54,17 +54,17 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
public static final int IS_VAR = 2;
|
||||
/** Is this a parameter */
|
||||
public static final int IS_PARAM = 3;
|
||||
/** Is this a constant */
|
||||
public static final int IS_CONSTANT = 4;
|
||||
/** Mask for kind flags */
|
||||
public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
|
||||
public static final int KINDMASK = (1 << 2) - 1; // Kinds are represented by lower two bits
|
||||
|
||||
/** Is this symbol in scope */
|
||||
public static final int IS_SCOPE = 1 << 3;
|
||||
public static final int IS_SCOPE = 1 << 2;
|
||||
/** Is this a this symbol */
|
||||
public static final int IS_THIS = 1 << 4;
|
||||
public static final int IS_THIS = 1 << 3;
|
||||
/** Is this a let */
|
||||
public static final int IS_LET = 1 << 5;
|
||||
public static final int IS_LET = 1 << 4;
|
||||
/** Is this a const */
|
||||
public static final int IS_CONST = 1 << 5;
|
||||
/** Is this an internal symbol, never represented explicitly in source code */
|
||||
public static final int IS_INTERNAL = 1 << 6;
|
||||
/** Is this a function self-reference symbol */
|
||||
@ -83,6 +83,8 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
public static final int HAS_DOUBLE_VALUE = 1 << 13;
|
||||
/** Is this symbol known to store an object value ? */
|
||||
public static final int HAS_OBJECT_VALUE = 1 << 14;
|
||||
/** Is this symbol seen a declaration? Used for block scoped LET and CONST symbols only. */
|
||||
public static final int HAS_BEEN_DECLARED = 1 << 15;
|
||||
|
||||
/** Null or name identifying symbol. */
|
||||
private final String name;
|
||||
@ -184,14 +186,17 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
sb.append(" global");
|
||||
break;
|
||||
case IS_VAR:
|
||||
sb.append(" var");
|
||||
if (isConst()) {
|
||||
sb.append(" const");
|
||||
} else if (isLet()) {
|
||||
sb.append(" let");
|
||||
} else {
|
||||
sb.append(" var");
|
||||
}
|
||||
break;
|
||||
case IS_PARAM:
|
||||
sb.append(" param");
|
||||
break;
|
||||
case IS_CONSTANT:
|
||||
sb.append(" const");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -204,10 +209,6 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
sb.append(" internal");
|
||||
}
|
||||
|
||||
if (isLet()) {
|
||||
sb.append(" let");
|
||||
}
|
||||
|
||||
if (isThis()) {
|
||||
sb.append(" this");
|
||||
}
|
||||
@ -410,8 +411,8 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
* Check if this symbol is a constant
|
||||
* @return true if a constant
|
||||
*/
|
||||
public boolean isConstant() {
|
||||
return (flags & KINDMASK) == IS_CONSTANT;
|
||||
public boolean isConst() {
|
||||
return (flags & IS_CONST) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,15 +440,6 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
return (flags & IS_LET) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this symbol as a let
|
||||
*/
|
||||
public void setIsLet() {
|
||||
if (!isLet()) {
|
||||
flags |= IS_LET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this symbol as a function's self-referencing symbol.
|
||||
* @return true if this symbol as a function's self-referencing symbol.
|
||||
@ -456,6 +448,20 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
return (flags & IS_FUNCTION_SELF) != 0;
|
||||
}
|
||||
|
||||
public boolean isBlockScoped() {
|
||||
return isLet() || isConst();
|
||||
}
|
||||
|
||||
public boolean hasBeenDeclared() {
|
||||
return (flags & HAS_BEEN_DECLARED) != 0;
|
||||
}
|
||||
|
||||
public void setHasBeenDeclared() {
|
||||
if (!hasBeenDeclared()) {
|
||||
flags |= HAS_BEEN_DECLARED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the field used to store this symbol, should it be an AccessorProperty
|
||||
* and get allocated in a JO-prefixed ScriptObject subclass.
|
||||
|
@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
|
||||
/**
|
||||
* Node represents a var/let declaration.
|
||||
@ -43,12 +44,18 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
private final int flags;
|
||||
|
||||
/** Flag that determines if this function node is a statement */
|
||||
public static final int IS_STATEMENT = 1 << 0;
|
||||
public static final int IS_STATEMENT = 1 << 0;
|
||||
|
||||
/** Flag for ES6 LET declaration */
|
||||
public static final int IS_LET = 1 << 1;
|
||||
|
||||
/** Flag for ES6 CONST declaration */
|
||||
public static final int IS_CONST = 1 << 2;
|
||||
|
||||
/** 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 << 1;
|
||||
public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -108,6 +115,43 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
return isAssignment() ? getInit() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a VAR node block scoped? This returns true for ECMAScript 6 LET and CONST nodes.
|
||||
* @return true if an ES6 LET or CONST node
|
||||
*/
|
||||
public boolean isBlockScoped() {
|
||||
return getFlag(IS_LET) || getFlag(IS_CONST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an ECMAScript 6 LET node?
|
||||
* @return true if LET node
|
||||
*/
|
||||
public boolean isLet() {
|
||||
return getFlag(IS_LET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an ECMAScript 6 CONST node?
|
||||
* @return true if CONST node
|
||||
*/
|
||||
public boolean isConst() {
|
||||
return getFlag(IS_CONST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the flags to use for symbols for this declaration.
|
||||
* @return the symbol flags
|
||||
*/
|
||||
public int getSymbolFlags() {
|
||||
if (isLet()) {
|
||||
return Symbol.IS_VAR | Symbol.IS_LET;
|
||||
} else if (isConst()) {
|
||||
return Symbol.IS_VAR | Symbol.IS_CONST;
|
||||
}
|
||||
return Symbol.IS_VAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this variable declaration have an init value
|
||||
* @return true if an init exists, false otherwise
|
||||
@ -139,7 +183,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb, final boolean printType) {
|
||||
sb.append("var ");
|
||||
sb.append(Token.descType(getToken()).getName()).append(' ');
|
||||
name.toString(sb, printType);
|
||||
|
||||
if (init != null) {
|
||||
|
@ -45,6 +45,7 @@ import static jdk.nashorn.internal.parser.TokenType.IDENT;
|
||||
import static jdk.nashorn.internal.parser.TokenType.IF;
|
||||
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
|
||||
import static jdk.nashorn.internal.parser.TokenType.LBRACE;
|
||||
import static jdk.nashorn.internal.parser.TokenType.LET;
|
||||
import static jdk.nashorn.internal.parser.TokenType.LPAREN;
|
||||
import static jdk.nashorn.internal.parser.TokenType.RBRACE;
|
||||
import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
|
||||
@ -579,6 +580,10 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useBlockScope() {
|
||||
return env._es6;
|
||||
}
|
||||
|
||||
private static boolean isArguments(final String name) {
|
||||
return ARGUMENTS_NAME.equals(name);
|
||||
}
|
||||
@ -694,9 +699,20 @@ loop:
|
||||
FunctionNode.Kind.SCRIPT,
|
||||
functionLine);
|
||||
|
||||
// If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations.
|
||||
final int startLine = start;
|
||||
Block outer = useBlockScope() ? newBlock() : null;
|
||||
functionDeclarations = new ArrayList<>();
|
||||
sourceElements(allowPropertyFunction);
|
||||
addFunctionDeclarations(script);
|
||||
|
||||
try {
|
||||
sourceElements(allowPropertyFunction);
|
||||
addFunctionDeclarations(script);
|
||||
} finally {
|
||||
if (outer != null) {
|
||||
outer = restoreBlock(outer);
|
||||
appendStatement(new BlockStatement(startLine, outer));
|
||||
}
|
||||
}
|
||||
functionDeclarations = null;
|
||||
|
||||
expect(EOF);
|
||||
@ -868,7 +884,7 @@ loop:
|
||||
block();
|
||||
break;
|
||||
case VAR:
|
||||
variableStatement(true);
|
||||
variableStatement(type, true);
|
||||
break;
|
||||
case SEMICOLON:
|
||||
emptyStatement();
|
||||
@ -918,8 +934,12 @@ loop:
|
||||
expect(SEMICOLON);
|
||||
break;
|
||||
default:
|
||||
if (useBlockScope() && (type == LET || type == CONST)) {
|
||||
variableStatement(type, true);
|
||||
break;
|
||||
}
|
||||
if (env._const_as_var && type == CONST) {
|
||||
variableStatement(true);
|
||||
variableStatement(TokenType.VAR, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1035,11 +1055,17 @@ loop:
|
||||
* Parse a VAR statement.
|
||||
* @param isStatement True if a statement (not used in a FOR.)
|
||||
*/
|
||||
private List<VarNode> variableStatement(final boolean isStatement) {
|
||||
private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) {
|
||||
// VAR tested in caller.
|
||||
next();
|
||||
|
||||
final List<VarNode> vars = new ArrayList<>();
|
||||
int varFlags = VarNode.IS_STATEMENT;
|
||||
if (varType == LET) {
|
||||
varFlags |= VarNode.IS_LET;
|
||||
} else if (varType == CONST) {
|
||||
varFlags |= VarNode.IS_CONST;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// Get starting token.
|
||||
@ -1063,10 +1089,12 @@ loop:
|
||||
} finally {
|
||||
defaultNames.pop();
|
||||
}
|
||||
} else if (varType == CONST) {
|
||||
throw error(AbstractParser.message("missing.const.assignment", name.getName()));
|
||||
}
|
||||
|
||||
// Allocate var node.
|
||||
final VarNode var = new VarNode(varLine, varToken, finish, name, init);
|
||||
final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags);
|
||||
vars.add(var);
|
||||
appendStatement(var);
|
||||
|
||||
@ -1180,9 +1208,12 @@ loop:
|
||||
* Parse a FOR statement.
|
||||
*/
|
||||
private void forStatement() {
|
||||
// When ES6 for-let is enabled we create a container block to capture the LET.
|
||||
final int startLine = start;
|
||||
Block outer = useBlockScope() ? newBlock() : null;
|
||||
|
||||
// Create FOR node, capturing FOR token.
|
||||
ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
|
||||
|
||||
lc.push(forNode);
|
||||
|
||||
try {
|
||||
@ -1203,14 +1234,19 @@ loop:
|
||||
switch (type) {
|
||||
case VAR:
|
||||
// Var statements captured in for outer block.
|
||||
vars = variableStatement(false);
|
||||
vars = variableStatement(type, false);
|
||||
break;
|
||||
case SEMICOLON:
|
||||
break;
|
||||
default:
|
||||
if (useBlockScope() && (type == LET || type == CONST)) {
|
||||
// LET/CONST 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.
|
||||
vars = variableStatement(false);
|
||||
vars = variableStatement(TokenType.VAR, false);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1290,8 +1326,13 @@ loop:
|
||||
appendStatement(forNode);
|
||||
} finally {
|
||||
lc.pop(forNode);
|
||||
if (outer != null) {
|
||||
outer.setFinish(forNode.getFinish());
|
||||
outer = restoreBlock(outer);
|
||||
appendStatement(new BlockStatement(startLine, outer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ... IterationStatement :
|
||||
@ -1722,7 +1763,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* ThrowStatement :
|
||||
* throw Expression ; // [no LineTerminator here]
|
||||
*
|
||||
@ -2609,7 +2650,7 @@ loop:
|
||||
FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
|
||||
|
||||
if (isStatement) {
|
||||
if (topLevel) {
|
||||
if (topLevel || useBlockScope()) {
|
||||
functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
|
||||
} else if (isStrictMode) {
|
||||
throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
|
||||
@ -2661,9 +2702,16 @@ loop:
|
||||
}
|
||||
|
||||
if (isStatement) {
|
||||
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
|
||||
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, functionNode, varFlags);
|
||||
if (topLevel) {
|
||||
functionDeclarations.add(varNode);
|
||||
} else if (useBlockScope()) {
|
||||
prependStatement(varNode); // Hoist to beginning of current block
|
||||
} else {
|
||||
appendStatement(varNode);
|
||||
}
|
||||
@ -2838,7 +2886,6 @@ loop:
|
||||
}
|
||||
|
||||
private void addFunctionDeclarations(final FunctionNode functionNode) {
|
||||
assert lc.peek() == lc.getFunctionBody(functionNode);
|
||||
VarNode lastDecl = null;
|
||||
for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
|
||||
Statement decl = functionDeclarations.get(i);
|
||||
|
28
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
28
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
@ -549,6 +549,8 @@ public class AccessorProperty extends Property {
|
||||
type == Object.class :
|
||||
"invalid getter type " + type + " for " + getKey();
|
||||
|
||||
checkUndeclared();
|
||||
|
||||
//all this does is add a return value filter for object fields only
|
||||
final MethodHandle[] getterCache = GETTER_CACHE;
|
||||
final MethodHandle cachedGetter = getterCache[i];
|
||||
@ -579,6 +581,8 @@ public class AccessorProperty extends Property {
|
||||
return getOptimisticPrimitiveGetter(type, programPoint);
|
||||
}
|
||||
|
||||
checkUndeclared();
|
||||
|
||||
return debug(
|
||||
createGetter(
|
||||
getCurrentType(),
|
||||
@ -608,6 +612,13 @@ public class AccessorProperty extends Property {
|
||||
return newMap;
|
||||
}
|
||||
|
||||
private void checkUndeclared() {
|
||||
if ((getFlags() & NEEDS_DECLARATION) != 0) {
|
||||
// a lexically defined variable that hasn't seen its declaration - throw ReferenceError
|
||||
throw ECMAErrors.referenceError("not.defined", getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// the final three arguments are for debug printout purposes only
|
||||
@SuppressWarnings("unused")
|
||||
private static Object replaceMap(final Object sobj, final PropertyMap newMap) {
|
||||
@ -635,13 +646,14 @@ public class AccessorProperty extends Property {
|
||||
|
||||
@Override
|
||||
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
|
||||
final int i = getAccessorTypeIndex(type);
|
||||
final int ci = isUndefined() ? -1 : getAccessorTypeIndex(getCurrentType());
|
||||
final Class<?> forType = isUndefined() ? type : getCurrentType();
|
||||
checkUndeclared();
|
||||
|
||||
final int typeIndex = getAccessorTypeIndex(type);
|
||||
final int currentTypeIndex = getAccessorTypeIndex(getCurrentType());
|
||||
|
||||
//if we are asking for an object setter, but are still a primitive type, we might try to box it
|
||||
MethodHandle mh;
|
||||
if (needsInvalidator(i, ci)) {
|
||||
if (needsInvalidator(typeIndex, currentTypeIndex)) {
|
||||
final Property newProperty = getWiderProperty(type);
|
||||
final PropertyMap newMap = getWiderMap(currentMap, newProperty);
|
||||
|
||||
@ -652,6 +664,7 @@ public class AccessorProperty extends Property {
|
||||
mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh);
|
||||
}
|
||||
} else {
|
||||
final Class<?> forType = isUndefined() ? type : getCurrentType();
|
||||
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
|
||||
}
|
||||
|
||||
@ -692,11 +705,12 @@ public class AccessorProperty extends Property {
|
||||
if (OBJECT_FIELDS_ONLY) {
|
||||
return false;
|
||||
}
|
||||
return getCurrentType() != Object.class && (isConfigurable() || isWritable());
|
||||
// Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST.
|
||||
return getCurrentType() == null || (getCurrentType() != Object.class && (isConfigurable() || isWritable()));
|
||||
}
|
||||
|
||||
private boolean needsInvalidator(final int ti, final int fti) {
|
||||
return canChangeType() && ti > fti;
|
||||
private boolean needsInvalidator(final int typeIndex, final int currentTypeIndex) {
|
||||
return canChangeType() && typeIndex > currentTypeIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1132,7 +1132,7 @@ public final class Context {
|
||||
if (storedScript == null) {
|
||||
functionNode = new Parser(env, source, errMan, strict, getLogger(Parser.class)).parse();
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
if (errMan.hasErrors()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1162,9 +1162,13 @@ public final class Context {
|
||||
env,
|
||||
installer,
|
||||
source,
|
||||
errMan,
|
||||
strict | functionNode.isStrict());
|
||||
|
||||
final FunctionNode compiledFunction = compiler.compile(functionNode, phases);
|
||||
if (errMan.hasErrors()) {
|
||||
return null;
|
||||
}
|
||||
script = compiledFunction.getRootClass();
|
||||
compiler.persistClassInfo(cacheKey, compiledFunction);
|
||||
} else {
|
||||
|
@ -57,6 +57,18 @@ public final class FindProperty {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this FindProperty with a different property.
|
||||
*
|
||||
* @param newProperty the new property
|
||||
* @return the new FindProperty instance
|
||||
*/
|
||||
public FindProperty replaceProperty(final Property newProperty) {
|
||||
assert this.property.getKey().equals(newProperty.getKey());
|
||||
assert this.property.getSlot() == newProperty.getSlot();
|
||||
return new FindProperty(self, prototype, newProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask for a getter that returns the given type. The type has nothing to do with the
|
||||
* internal representation of the property. It may be an Object (boxing primitives) or
|
||||
|
@ -82,11 +82,14 @@ public abstract class Property implements Serializable {
|
||||
* is narrower than object, e.g. Math.PI which is declared
|
||||
* as a double
|
||||
*/
|
||||
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
|
||||
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
|
||||
|
||||
/** 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 << 8;
|
||||
public static final int IS_BOUND = 1 << 7;
|
||||
|
||||
/** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */
|
||||
public static final int NEEDS_DECLARATION = 1 << 8;
|
||||
|
||||
/** Property key. */
|
||||
private final String key;
|
||||
@ -286,6 +289,15 @@ public abstract class Property implements Serializable {
|
||||
return (flags & IS_BOUND) == IS_BOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a LET or CONST property that needs to see its declaration before being usable?
|
||||
*
|
||||
* @return true if this is a block-scoped variable
|
||||
*/
|
||||
public boolean needsDeclaration() {
|
||||
return (flags & NEEDS_DECLARATION) == NEEDS_DECLARATION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add more property flags to the property. Properties are immutable here,
|
||||
* so any property change that results in a larger flag set results in the
|
||||
|
@ -394,6 +394,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
context.getEnv(),
|
||||
installer,
|
||||
functionNode.getSource(), // source
|
||||
context.getErrorManager(),
|
||||
isStrict() | functionNode.isStrict(), // is strict
|
||||
true, // is on demand
|
||||
this, // compiledFunction, i.e. this RecompilableScriptFunctionData
|
||||
|
12
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
12
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@ -94,6 +94,9 @@ public final class ScriptEnvironment {
|
||||
/** Use single Global instance per jsr223 engine instance. */
|
||||
public final boolean _global_per_engine;
|
||||
|
||||
/** Enable experimental ECMAScript 6 features. */
|
||||
public final boolean _es6;
|
||||
|
||||
/** Argument passed to compile only if optimistic compilation should take place */
|
||||
public static final String COMPILE_ONLY_OPTIMISTIC_ARG = "optimistic";
|
||||
|
||||
@ -258,6 +261,15 @@ public final class ScriptEnvironment {
|
||||
_version = options.getBoolean("version");
|
||||
_verify_code = options.getBoolean("verify.code");
|
||||
|
||||
final String language = options.getString("language");
|
||||
if (language == null || language.equals("es5")) {
|
||||
_es6 = false;
|
||||
} else if (language.equals("es6")) {
|
||||
_es6 = true;
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported language: " + language);
|
||||
}
|
||||
|
||||
String dir = null;
|
||||
String func = null;
|
||||
final String pc = options.getString("print.code");
|
||||
|
@ -158,6 +158,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
|
||||
static final MethodHandle MEGAMORPHIC_GET = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class);
|
||||
static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
|
||||
static final MethodHandle DECLARE_AND_SET = findOwnMH_V("declareAndSet", void.class, String.class, Object.class);
|
||||
|
||||
private static final MethodHandle TRUNCATINGFILTER = findOwnMH_S("truncatingFilter", Object[].class, int.class, Object[].class);
|
||||
private static final MethodHandle KNOWNFUNCPROPGUARDSELF = findOwnMH_S("knownFunctionPropertyGuardSelf", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, ScriptFunction.class);
|
||||
@ -2027,6 +2028,22 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
return isMethod ? getNoSuchMethod(key, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
|
||||
}
|
||||
|
||||
// Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
|
||||
@SuppressWarnings("unused")
|
||||
private void declareAndSet(final String key, final Object value) {
|
||||
final PropertyMap map = getMap();
|
||||
final FindProperty find = findProperty(key, false);
|
||||
assert find != null;
|
||||
|
||||
final Property property = find.getProperty();
|
||||
assert property != null;
|
||||
assert property.needsDeclaration();
|
||||
|
||||
final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
|
||||
setMap(newMap);
|
||||
set(key, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the appropriate GETINDEX method for an invoke dynamic call.
|
||||
*
|
||||
@ -2140,7 +2157,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
}
|
||||
|
||||
if (find != null) {
|
||||
if (!find.getProperty().isWritable()) {
|
||||
if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) {
|
||||
// Existing, non-writable property
|
||||
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
|
||||
}
|
||||
|
@ -107,6 +107,11 @@ public final class ScriptRuntime {
|
||||
*/
|
||||
public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class);
|
||||
|
||||
/**
|
||||
* Throws a reference error for an undefined variable.
|
||||
*/
|
||||
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
|
||||
|
||||
/**
|
||||
* Converts a switch tag value to a simple integer. deflt value if it can't.
|
||||
*
|
||||
@ -381,6 +386,15 @@ public final class ScriptRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a reference error for an undefined variable.
|
||||
*
|
||||
* @param name the variable name
|
||||
*/
|
||||
public static void throwReferenceError(final String name) {
|
||||
throw referenceError("not.defined", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a script function as a constructor with given args.
|
||||
*
|
||||
|
24
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
24
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
@ -140,7 +140,29 @@ final class SetMethodCreator {
|
||||
|
||||
private SetMethod createExistingPropertySetter() {
|
||||
final Property property = find.getProperty();
|
||||
final MethodHandle methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
|
||||
final MethodHandle methodHandle;
|
||||
|
||||
if (NashornCallSiteDescriptor.isDeclaration(desc)) {
|
||||
assert property.needsDeclaration();
|
||||
// This is a LET or CONST being declared. The property is already there but flagged as needing declaration.
|
||||
// We create a new PropertyMap with the flag removed. The map is installed with a fast compare-and-set
|
||||
// method if the pre-callsite map is stable (which should be the case for function scopes except for
|
||||
// non-strict functions containing eval() with var). Otherwise we have to use a slow setter that creates
|
||||
// a new PropertyMap on the fly.
|
||||
final PropertyMap oldMap = getMap();
|
||||
final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
|
||||
final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
|
||||
final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
|
||||
final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
|
||||
|
||||
// cas map used as guard, if true that means we can do the set fast
|
||||
MethodHandle casMap = MH.insertArguments(ScriptObject.CAS_MAP, 1, oldMap, newMap);
|
||||
casMap = MH.dropArguments(casMap, 1, type);
|
||||
casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
|
||||
methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
|
||||
} else {
|
||||
methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
|
||||
}
|
||||
|
||||
assert methodHandle != null;
|
||||
assert property != null;
|
||||
|
@ -54,23 +54,25 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
|
||||
public static final int CALLSITE_OPTIMISTIC = 1 << 3;
|
||||
/** Is this really an apply that we try to call as a call? */
|
||||
public static final int CALLSITE_APPLY_TO_CALL = 1 << 4;
|
||||
/** Does this a callsite for a variable declaration? */
|
||||
public static final int CALLSITE_DECLARE = 1 << 5;
|
||||
|
||||
/** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
|
||||
* code where call sites have this flag set. */
|
||||
public static final int CALLSITE_PROFILE = 1 << 5;
|
||||
public static final int CALLSITE_PROFILE = 1 << 6;
|
||||
/** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
|
||||
* call sites have this flag set. */
|
||||
public static final int CALLSITE_TRACE = 1 << 6;
|
||||
public static final int CALLSITE_TRACE = 1 << 7;
|
||||
/** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
|
||||
* {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
|
||||
public static final int CALLSITE_TRACE_MISSES = 1 << 7;
|
||||
public static final int CALLSITE_TRACE_MISSES = 1 << 8;
|
||||
/** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
|
||||
* {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
|
||||
public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 8;
|
||||
public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 9;
|
||||
/** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
|
||||
* that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
|
||||
* have this flag set. */
|
||||
public static final int CALLSITE_TRACE_VALUES = 1 << 9;
|
||||
public static final int CALLSITE_TRACE_VALUES = 1 << 10;
|
||||
|
||||
//we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
|
||||
//right now given the program points
|
||||
@ -82,10 +84,10 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
|
||||
* TODO: rethink if we need the various profile/trace flags or the linker can use the Context instead to query its
|
||||
* trace/profile settings.
|
||||
*/
|
||||
public static final int CALLSITE_PROGRAM_POINT_SHIFT = 10;
|
||||
public static final int CALLSITE_PROGRAM_POINT_SHIFT = 11;
|
||||
|
||||
/**
|
||||
* Maximum program point value. 22 bits should be enough for anyone
|
||||
* Maximum program point value. 21 bits should be enough for anyone
|
||||
*/
|
||||
public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
|
||||
|
||||
@ -123,6 +125,9 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
|
||||
assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
|
||||
sb.append("scope ");
|
||||
}
|
||||
if ((flags & CALLSITE_DECLARE) != 0) {
|
||||
sb.append("declare ");
|
||||
}
|
||||
}
|
||||
if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
|
||||
sb.append("apply2call ");
|
||||
@ -328,6 +333,15 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
|
||||
return isFlag(desc, CALLSITE_OPTIMISTIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this callsite contain a declaration for its target?
|
||||
* @param desc descriptor
|
||||
* @return true if contains declaration
|
||||
*/
|
||||
public static boolean isDeclaration(final CallSiteDescriptor desc) {
|
||||
return isFlag(desc, CALLSITE_DECLARE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a program point from a descriptor (must be optimistic)
|
||||
* @param desc descriptor
|
||||
|
@ -58,6 +58,7 @@ parser.error.regex.unsupported.flag=Unsupported RegExp flag: {0}
|
||||
parser.error.regex.repeated.flag=Repeated RegExp flag: {0}
|
||||
parser.error.regex.syntax={0}
|
||||
parser.error.trailing.comma.in.json=Trailing comma is not allowed in JSON
|
||||
parser.error.missing.const.assignment=Missing assignment to constant "{0}"
|
||||
|
||||
# strict mode error messages
|
||||
parser.error.strict.no.with="with" statement cannot be used in strict mode
|
||||
@ -162,6 +163,8 @@ reference.error.cant.be.used.as.lhs="{0}" can not be used as the left-hand side
|
||||
|
||||
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}"
|
||||
|
||||
io.error.cant.write=cannot write "{0}"
|
||||
config.error.no.dest=no destination directory supplied
|
||||
|
@ -329,6 +329,14 @@ nashorn.option.scripting = { \
|
||||
desc="Enable scripting features." \
|
||||
}
|
||||
|
||||
nashorn.option.language = { \
|
||||
name="--language", \
|
||||
type=String, \
|
||||
params=[es5|es6], \
|
||||
default=es5, \
|
||||
desc="Specify ECMAScript language version." \
|
||||
}
|
||||
|
||||
nashorn.option.stdout = { \
|
||||
name="--stdout", \
|
||||
is_undocumented=true, \
|
||||
|
@ -252,6 +252,15 @@ public class Shell {
|
||||
return COMPILATION_ERROR;
|
||||
}
|
||||
|
||||
new Compiler(
|
||||
context,
|
||||
env,
|
||||
null, //null - pass no code installer - this is compile only
|
||||
functionNode.getSource(),
|
||||
context.getErrorManager(),
|
||||
env._strict | functionNode.isStrict()).
|
||||
compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
|
||||
|
||||
if (env._print_ast) {
|
||||
context.getErr().println(new ASTWriter(functionNode));
|
||||
}
|
||||
@ -260,14 +269,9 @@ public class Shell {
|
||||
context.getErr().println(new PrintVisitor(functionNode));
|
||||
}
|
||||
|
||||
//null - pass no code installer - this is compile only
|
||||
new Compiler(
|
||||
context,
|
||||
env,
|
||||
null,
|
||||
functionNode.getSource(),
|
||||
env._strict | functionNode.isStrict()).
|
||||
compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
|
||||
if (errors.getNumberOfErrors() != 0) {
|
||||
return COMPILATION_ERROR;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
env.getOut().flush();
|
||||
|
51
nashorn/test/script/basic/es6/block-function-decl.js
Normal file
51
nashorn/test/script/basic/es6/block-function-decl.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
// f is defined on block level
|
||||
print(f);
|
||||
f();
|
||||
function f() {
|
||||
print("in f");
|
||||
}
|
||||
print(f);
|
||||
f();
|
||||
}
|
||||
|
||||
try {
|
||||
print(typeof f);
|
||||
f();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
function f() {
|
||||
print("in f");
|
||||
}
|
||||
in f
|
||||
function f() {
|
||||
print("in f");
|
||||
}
|
||||
in f
|
||||
undefined
|
||||
ReferenceError: "f" is not defined
|
37
nashorn/test/script/basic/es6/const-empty.js
Normal file
37
nashorn/test/script/basic/es6/const-empty.js
Normal 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x;\n');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
3
nashorn/test/script/basic/es6/const-empty.js.EXPECTED
Normal file
3
nashorn/test/script/basic/es6/const-empty.js.EXPECTED
Normal file
@ -0,0 +1,3 @@
|
||||
SyntaxError: test/script/basic/es6/const-empty.js#33:4<eval>@1:2:7 Missing assignment to constant "x"
|
||||
const x;
|
||||
^
|
174
nashorn/test/script/basic/es6/const-reassign.js
Normal file
174
nashorn/test/script/basic/es6/const-reassign.js
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x = 1;\n');
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x++;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x--;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'++x;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'--x;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x += 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x *= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x /= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x %= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x |= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x &= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x ^= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x <<= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x >>= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'x >>>= 1;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'delete x;\n');
|
||||
fail("const assignment didn't throw");
|
||||
} catch (e) {
|
||||
print(e.name);
|
||||
}
|
16
nashorn/test/script/basic/es6/const-reassign.js.EXPECTED
Normal file
16
nashorn/test/script/basic/es6/const-reassign.js.EXPECTED
Normal file
@ -0,0 +1,16 @@
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
||||
SyntaxError
|
38
nashorn/test/script/basic/es6/const-redeclare.js
Normal file
38
nashorn/test/script/basic/es6/const-redeclare.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const x = 2;\n' +
|
||||
'const x = 2;\n');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
SyntaxError: test/script/basic/es6/const-redeclare.js#33:4<eval>@1:2:6 Variable "x" has already been declared
|
||||
const x = 2;
|
||||
^
|
42
nashorn/test/script/basic/es6/const-self.js
Normal file
42
nashorn/test/script/basic/es6/const-self.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
const a = 1, b = a;
|
||||
|
||||
print(a, b);
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'const a = a;\n');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
2
nashorn/test/script/basic/es6/const-self.js.EXPECTED
Normal file
2
nashorn/test/script/basic/es6/const-self.js.EXPECTED
Normal file
@ -0,0 +1,2 @@
|
||||
1 1
|
||||
ReferenceError: "a" is not defined
|
81
nashorn/test/script/basic/es6/const-tdz.js
Normal file
81
nashorn/test/script/basic/es6/const-tdz.js
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
print("test 1");
|
||||
|
||||
function f() {
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
const a = 1;
|
||||
f();
|
||||
}
|
||||
|
||||
{
|
||||
print("test 2");
|
||||
|
||||
function f() {
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
const a = 2;
|
||||
f();
|
||||
}
|
||||
|
||||
{
|
||||
print("test 3");
|
||||
{
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
const a = 3;
|
||||
|
||||
{
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
9
nashorn/test/script/basic/es6/const-tdz.js.EXPECTED
Normal file
9
nashorn/test/script/basic/es6/const-tdz.js.EXPECTED
Normal file
@ -0,0 +1,9 @@
|
||||
test 1
|
||||
ReferenceError: "a" is not defined
|
||||
1
|
||||
test 2
|
||||
ReferenceError: "a" is not defined
|
||||
2
|
||||
test 3
|
||||
ReferenceError: "a" is not defined
|
||||
3
|
69
nashorn/test/script/basic/es6/const.js
Normal file
69
nashorn/test/script/basic/es6/const.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const a = 2;
|
||||
const c = 2;
|
||||
print(a, c);
|
||||
|
||||
function f(x) {
|
||||
const a = 5;
|
||||
const c = 10;
|
||||
print(a, c);
|
||||
if (x) {
|
||||
const a = 42;
|
||||
const c = 43;
|
||||
print(a, c);
|
||||
}
|
||||
print(a, c);
|
||||
|
||||
function inner() {
|
||||
(function() {
|
||||
print(a, c);
|
||||
})();
|
||||
}
|
||||
inner();
|
||||
}
|
||||
|
||||
f(true);
|
||||
f(false);
|
||||
|
||||
(function() {
|
||||
(function() {
|
||||
print(a, c);
|
||||
})();
|
||||
})();
|
||||
|
||||
function outer() {
|
||||
print(a, c);
|
||||
}
|
||||
outer();
|
10
nashorn/test/script/basic/es6/const.js.EXPECTED
Normal file
10
nashorn/test/script/basic/es6/const.js.EXPECTED
Normal file
@ -0,0 +1,10 @@
|
||||
2 2
|
||||
5 10
|
||||
42 43
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
2 2
|
||||
2 2
|
41
nashorn/test/script/basic/es6/for-let.js
Normal file
41
nashorn/test/script/basic/es6/for-let.js
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
print(i);
|
||||
}
|
||||
|
||||
try {
|
||||
print(i);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
11
nashorn/test/script/basic/es6/for-let.js.EXPECTED
Normal file
11
nashorn/test/script/basic/es6/for-let.js.EXPECTED
Normal file
@ -0,0 +1,11 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
ReferenceError: "i" is not defined
|
98
nashorn/test/script/basic/es6/let-eval.js
Normal file
98
nashorn/test/script/basic/es6/let-eval.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
var a;
|
||||
let b;
|
||||
const c = 0;
|
||||
|
||||
print(a, b, c);
|
||||
|
||||
try {
|
||||
eval("x = 1; print('x: ' + x);");
|
||||
print("assignment to x succeeded");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
try {
|
||||
eval("'use strict'; let z = 1; print('z: ' + z);");
|
||||
print("assignment to z succeeded");
|
||||
eval("print('z: ' + z);");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
try {
|
||||
eval("a = 1; print(a);");
|
||||
print("assignment to a succeeded");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
print("a: " + a);
|
||||
|
||||
try {
|
||||
eval("b = 1; print('b: ' + b);");
|
||||
print("assignment to b succeeded");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
print("b: " + b);
|
||||
|
||||
try {
|
||||
eval("c = 1; print('c: ' + c);");
|
||||
print("assignment to c succeeded");
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
print("c: " + c);
|
||||
|
||||
eval("a = 2; let b = 3;");
|
||||
|
||||
try {
|
||||
print(a, b, c);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
let x;
|
||||
|
||||
try {
|
||||
print(a, b, c, x);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
print(typeof a, typeof b, typeof c, typeof x, typeof z);
|
16
nashorn/test/script/basic/es6/let-eval.js.EXPECTED
Normal file
16
nashorn/test/script/basic/es6/let-eval.js.EXPECTED
Normal file
@ -0,0 +1,16 @@
|
||||
undefined undefined 0
|
||||
ReferenceError: "x" is not defined
|
||||
z: 1
|
||||
assignment to z succeeded
|
||||
ReferenceError: "z" is not defined
|
||||
1
|
||||
assignment to a succeeded
|
||||
a: 1
|
||||
b: 1
|
||||
assignment to b succeeded
|
||||
b: 1
|
||||
TypeError: "c" is not a writable property of [object Object]
|
||||
c: 0
|
||||
2 1 0
|
||||
2 1 0 undefined
|
||||
undefined undefined undefined undefined undefined
|
48
nashorn/test/script/basic/es6/let-load-lib.js
Normal file
48
nashorn/test/script/basic/es6/let-load-lib.js
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @subtest
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// var should be visible in other script, let and const not
|
||||
var a = 1;
|
||||
let b = 2;
|
||||
const c = 3;
|
||||
|
||||
// top level function should be visible
|
||||
function top() {
|
||||
print("top level function");
|
||||
}
|
||||
|
||||
// block level function not visible outside script
|
||||
{
|
||||
function block() {
|
||||
print("block function");
|
||||
}
|
||||
|
||||
top();
|
||||
block();
|
||||
}
|
62
nashorn/test/script/basic/es6/let-load.js
Normal file
62
nashorn/test/script/basic/es6/let-load.js
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
load(__DIR__ + "let-load-lib.js");
|
||||
|
||||
{
|
||||
let a = 20;
|
||||
const c = 30;
|
||||
print("print local defs: " + a, c);
|
||||
}
|
||||
|
||||
print("imported var: " + a);
|
||||
try {
|
||||
print("imported let: " + b);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
try {
|
||||
print("imported const: " + c);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
top();
|
||||
|
||||
try {
|
||||
block();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
|
8
nashorn/test/script/basic/es6/let-load.js.EXPECTED
Normal file
8
nashorn/test/script/basic/es6/let-load.js.EXPECTED
Normal file
@ -0,0 +1,8 @@
|
||||
top level function
|
||||
block function
|
||||
print local defs: 20 30
|
||||
imported var: 1
|
||||
ReferenceError: "b" is not defined
|
||||
ReferenceError: "c" is not defined
|
||||
top level function
|
||||
ReferenceError: "block" is not defined
|
52
nashorn/test/script/basic/es6/let-nodeclare.js
Normal file
52
nashorn/test/script/basic/es6/let-nodeclare.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
try {
|
||||
if (true) {
|
||||
let x = 2;
|
||||
print(x);
|
||||
}
|
||||
print(x);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (true) {
|
||||
const x = 2;
|
||||
print(x);
|
||||
}
|
||||
print(x);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
4
nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED
Normal file
4
nashorn/test/script/basic/es6/let-nodeclare.js.EXPECTED
Normal file
@ -0,0 +1,4 @@
|
||||
2
|
||||
ReferenceError: "x" is not defined
|
||||
2
|
||||
ReferenceError: "x" is not defined
|
38
nashorn/test/script/basic/es6/let-redeclare.js
Normal file
38
nashorn/test/script/basic/es6/let-redeclare.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6
|
||||
*/
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'let x = 2;\n' +
|
||||
'let x = 2;\n');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
3
nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
Normal file
3
nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED
Normal file
@ -0,0 +1,3 @@
|
||||
SyntaxError: test/script/basic/es6/let-redeclare.js#33:4<eval>@1:2:4 Variable "x" has already been declared
|
||||
let x = 2;
|
||||
^
|
42
nashorn/test/script/basic/es6/let-self.js
Normal file
42
nashorn/test/script/basic/es6/let-self.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
let a, b = a;
|
||||
|
||||
print(a, b);
|
||||
|
||||
try {
|
||||
eval('"use strict";\n' +
|
||||
'let a = a;\n');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
2
nashorn/test/script/basic/es6/let-self.js.EXPECTED
Normal file
2
nashorn/test/script/basic/es6/let-self.js.EXPECTED
Normal file
@ -0,0 +1,2 @@
|
||||
undefined undefined
|
||||
ReferenceError: "a" is not defined
|
97
nashorn/test/script/basic/es6/let-tdz.js
Normal file
97
nashorn/test/script/basic/es6/let-tdz.js
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
print("test 1");
|
||||
|
||||
function f() {
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
let a = 1;
|
||||
f();
|
||||
}
|
||||
|
||||
{
|
||||
print("test 2");
|
||||
|
||||
function f() {
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
||||
let a = 2;
|
||||
f();
|
||||
}
|
||||
|
||||
{
|
||||
print("test 3");
|
||||
|
||||
{
|
||||
try {
|
||||
print(a);
|
||||
} catch (a) {
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
let a = 3;
|
||||
|
||||
{
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
print("test 4");
|
||||
let a;
|
||||
|
||||
{
|
||||
print(a);
|
||||
}
|
||||
|
||||
a = 4;
|
||||
|
||||
{
|
||||
print(a);
|
||||
}
|
||||
}
|
||||
|
12
nashorn/test/script/basic/es6/let-tdz.js.EXPECTED
Normal file
12
nashorn/test/script/basic/es6/let-tdz.js.EXPECTED
Normal file
@ -0,0 +1,12 @@
|
||||
test 1
|
||||
ReferenceError: "a" is not defined
|
||||
1
|
||||
test 2
|
||||
ReferenceError: "a" is not defined
|
||||
2
|
||||
test 3
|
||||
ReferenceError: "a" is not defined
|
||||
3
|
||||
test 4
|
||||
undefined
|
||||
4
|
69
nashorn/test/script/basic/es6/let.js
Normal file
69
nashorn/test/script/basic/es6/let.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8051889: Implement block scoping in symbol assignment and scope computation
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
* @option --language=es6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
let a = 2;
|
||||
let c = 2;
|
||||
print(a, c);
|
||||
|
||||
function f(x) {
|
||||
let a = 5;
|
||||
const c = 10;
|
||||
print(a, c);
|
||||
if (x) {
|
||||
let a = 42;
|
||||
const c = 43;
|
||||
print(a, c);
|
||||
}
|
||||
print(a, c);
|
||||
|
||||
function inner() {
|
||||
(function() {
|
||||
print(a, c);
|
||||
})();
|
||||
}
|
||||
inner();
|
||||
}
|
||||
|
||||
f(true);
|
||||
f(false);
|
||||
|
||||
(function() {
|
||||
(function() {
|
||||
print(a, c);
|
||||
})();
|
||||
})();
|
||||
|
||||
function outer() {
|
||||
print(a, c);
|
||||
}
|
||||
outer();
|
||||
|
10
nashorn/test/script/basic/es6/let.js.EXPECTED
Normal file
10
nashorn/test/script/basic/es6/let.js.EXPECTED
Normal file
@ -0,0 +1,10 @@
|
||||
2 2
|
||||
5 10
|
||||
42 43
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
5 10
|
||||
2 2
|
||||
2 2
|
@ -120,7 +120,7 @@ var getEnvMethod = Context.class.getMethod("getEnv")
|
||||
|
||||
var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
|
||||
var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
|
||||
var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, boolean.class);
|
||||
var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, ErrorManager.class, boolean.class);
|
||||
|
||||
// compile(script) -- compiles a script specified as a string with its
|
||||
// source code, returns a jdk.nashorn.internal.ir.FunctionNode object
|
||||
@ -134,7 +134,7 @@ function compile(source, phases) {
|
||||
var parser = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
|
||||
var func = parseMethod.invoke(parser);
|
||||
|
||||
var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, false);
|
||||
var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, null, false);
|
||||
|
||||
return compileMethod.invoke(compiler, func, phases);
|
||||
};
|
||||
|
@ -98,11 +98,16 @@ public class CompilerTest {
|
||||
compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
|
||||
@Override
|
||||
public boolean exclude(final File file, final String content) {
|
||||
return content.indexOf("@negative") != -1;
|
||||
return content != null && content.contains("@negative");
|
||||
}
|
||||
});
|
||||
}
|
||||
compileTestSet(new File(TEST_BASIC_DIR), null);
|
||||
compileTestSet(new File(TEST_BASIC_DIR), new TestFilter() {
|
||||
@Override
|
||||
public boolean exclude(final File file, final String content) {
|
||||
return file.getName().equals("es6");
|
||||
}
|
||||
});
|
||||
compileTestSet(new File(TEST_NODE_DIR, "node"), null);
|
||||
compileTestSet(new File(TEST_NODE_DIR, "src"), null);
|
||||
}
|
||||
@ -136,6 +141,9 @@ public class CompilerTest {
|
||||
private int skipped;
|
||||
|
||||
private void compileJSDirectory(final File dir, final TestFilter filter) {
|
||||
if (filter != null && filter.exclude(dir, null)) {
|
||||
return;
|
||||
}
|
||||
for (final File f : dir.listFiles()) {
|
||||
if (f.isDirectory()) {
|
||||
compileJSDirectory(f, filter);
|
||||
|
@ -82,11 +82,16 @@ public class ParserTest {
|
||||
parseTestSet(TEST262_SUITE_DIR, new TestFilter() {
|
||||
@Override
|
||||
public boolean exclude(final File file, final String content) {
|
||||
return content.indexOf("@negative") != -1;
|
||||
return content != null && content.contains("@negative");
|
||||
}
|
||||
});
|
||||
}
|
||||
parseTestSet(TEST_BASIC_DIR, null);
|
||||
parseTestSet(TEST_BASIC_DIR, new TestFilter() {
|
||||
@Override
|
||||
public boolean exclude(final File file, final String content) {
|
||||
return file.getName().equals("es6");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void parseTestSet(final String testSet, final TestFilter filter) {
|
||||
@ -120,6 +125,9 @@ public class ParserTest {
|
||||
private int skipped;
|
||||
|
||||
private void parseJSDirectory(final File dir, final TestFilter filter) {
|
||||
if (filter != null && filter.exclude(dir, null)) {
|
||||
return;
|
||||
}
|
||||
for (final File f : dir.listFiles()) {
|
||||
if (f.isDirectory()) {
|
||||
parseJSDirectory(f, filter);
|
||||
|
Loading…
x
Reference in New Issue
Block a user