зеркало из https://github.com/mozilla/gecko-dev.git
Bug 589199 - Parse and emit bytecode for global lexicals. (r=efaust)
This commit is contained in:
Родитель
aedb453377
Коммит
2c1ffa9a18
|
@ -640,7 +640,6 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
|
||||||
|
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
case PNK_LET: {
|
case PNK_LET: {
|
||||||
MOZ_ASSERT(kid->isArity(PN_LIST));
|
MOZ_ASSERT(kid->isArity(PN_LIST));
|
||||||
for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
|
for (ParseNode* var = kid->pn_head; var; var = var->pn_next) {
|
||||||
|
|
|
@ -2166,7 +2166,6 @@ ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(pn->isKind(PNK_FUNCTION) ||
|
MOZ_ASSERT(pn->isKind(PNK_FUNCTION) ||
|
||||||
pn->isKind(PNK_VAR) ||
|
pn->isKind(PNK_VAR) ||
|
||||||
pn->isKind(PNK_GLOBALCONST) ||
|
|
||||||
pn->isKind(PNK_LET) ||
|
pn->isKind(PNK_LET) ||
|
||||||
pn->isKind(PNK_CONST));
|
pn->isKind(PNK_CONST));
|
||||||
|
|
||||||
|
@ -2175,7 +2174,6 @@ ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst)
|
||||||
return function(pn, AST_FUNC_DECL, dst);
|
return function(pn, AST_FUNC_DECL, dst);
|
||||||
|
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
return variableDeclaration(pn, false, dst);
|
return variableDeclaration(pn, false, dst);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2188,7 +2186,7 @@ bool
|
||||||
ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst)
|
ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
|
MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
|
||||||
MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST));
|
MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR));
|
||||||
|
|
||||||
VarDeclKind kind = VARDECL_ERR;
|
VarDeclKind kind = VARDECL_ERR;
|
||||||
// Treat both the toplevel const binding (secretly var-like) and the lexical const
|
// Treat both the toplevel const binding (secretly var-like) and the lexical const
|
||||||
|
@ -2345,9 +2343,8 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst)
|
||||||
|
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
if (!variableDeclaration(kid, (kind == PNK_LET || kind == PNK_CONST), &decl))
|
if (!variableDeclaration(kid, kind != PNK_VAR, &decl))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2494,7 +2491,7 @@ ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST))
|
return (pn->isKind(PNK_VAR))
|
||||||
? variableDeclaration(pn, false, dst)
|
? variableDeclaration(pn, false, dst)
|
||||||
: expression(pn, dst);
|
: expression(pn, dst);
|
||||||
}
|
}
|
||||||
|
@ -2544,7 +2541,6 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
|
||||||
switch (pn->getKind()) {
|
switch (pn->getKind()) {
|
||||||
case PNK_FUNCTION:
|
case PNK_FUNCTION:
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
return declaration(pn, dst);
|
return declaration(pn, dst);
|
||||||
|
|
||||||
case PNK_LETBLOCK:
|
case PNK_LETBLOCK:
|
||||||
|
|
|
@ -76,6 +76,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||||
bool insideNonGlobalEval = false);
|
bool insideNonGlobalEval = false);
|
||||||
bool isEvalCompilationUnit();
|
bool isEvalCompilationUnit();
|
||||||
bool isNonGlobalEvalCompilationUnit();
|
bool isNonGlobalEvalCompilationUnit();
|
||||||
|
bool isNonSyntacticCompilationUnit();
|
||||||
bool createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
|
bool createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
|
||||||
SharedContext& globalsc, uint32_t blockScopeDepth = 0);
|
SharedContext& globalsc, uint32_t blockScopeDepth = 0);
|
||||||
bool saveCallerFun(HandleScript evalCaller, ParseContext<FullParseHandler>& parseContext);
|
bool saveCallerFun(HandleScript evalCaller, ParseContext<FullParseHandler>& parseContext);
|
||||||
|
@ -280,7 +281,7 @@ BytecodeCompiler::createEmitter(SharedContext* sharedContext, HandleScript evalC
|
||||||
bool
|
bool
|
||||||
BytecodeCompiler::isEvalCompilationUnit()
|
BytecodeCompiler::isEvalCompilationUnit()
|
||||||
{
|
{
|
||||||
return enclosingStaticScope && enclosingStaticScope->is<StaticEvalObject>();
|
return enclosingStaticScope->is<StaticEvalObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -290,6 +291,12 @@ BytecodeCompiler::isNonGlobalEvalCompilationUnit()
|
||||||
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
enclosingStaticScope->as<StaticEvalObject>().enclosingScopeForStaticScopeIter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeCompiler::isNonSyntacticCompilationUnit()
|
||||||
|
{
|
||||||
|
return enclosingStaticScope->is<StaticNonSyntacticScopeObjects>();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeCompiler::createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
|
BytecodeCompiler::createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
|
||||||
SharedContext& globalsc, uint32_t blockScopeDepth)
|
SharedContext& globalsc, uint32_t blockScopeDepth)
|
||||||
|
|
|
@ -823,7 +823,7 @@ BytecodeEmitter::computeLocalOffset(Handle<StaticBlockObject*> blockObj)
|
||||||
if (StmtInfoBCE* stmt = innermostScopeStmt()) {
|
if (StmtInfoBCE* stmt = innermostScopeStmt()) {
|
||||||
Rooted<NestedScopeObject*> outer(cx, stmt->staticScope);
|
Rooted<NestedScopeObject*> outer(cx, stmt->staticScope);
|
||||||
for (; outer; outer = outer->enclosingNestedScope()) {
|
for (; outer; outer = outer->enclosingNestedScope()) {
|
||||||
if (outer->is<StaticBlockObject>()) {
|
if (outer->is<StaticBlockObject>() && !IsStaticGlobalLexicalScope(outer)) {
|
||||||
StaticBlockObject& outerBlock = outer->as<StaticBlockObject>();
|
StaticBlockObject& outerBlock = outer->as<StaticBlockObject>();
|
||||||
localOffset = outerBlock.localOffset() + outerBlock.numVariables();
|
localOffset = outerBlock.localOffset() + outerBlock.numVariables();
|
||||||
break;
|
break;
|
||||||
|
@ -1354,15 +1354,15 @@ BytecodeEmitter::emitVarIncDec(ParseNode* pn)
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::atBodyLevel() const
|
BytecodeEmitter::atBodyLevel() const
|
||||||
{
|
{
|
||||||
// 'eval' scripts are always under an invisible lexical scope, but
|
// 'eval' and non-syntactic scripts are always under an invisible lexical
|
||||||
// since it is not syntactic, it should still be considered at body
|
// scope, but since it is not syntactic, it should still be considered at
|
||||||
// level.
|
// body level.
|
||||||
if (sc->staticScope() && sc->staticScope()->is<StaticEvalObject>()) {
|
if (sc->staticScope()->is<StaticEvalObject>()) {
|
||||||
bool bl = !innermostStmt()->enclosing;
|
bool bl = !innermostStmt()->enclosing;
|
||||||
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
||||||
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
||||||
->as<StaticBlockObject>()
|
->as<StaticBlockObject>()
|
||||||
.maybeEnclosingEval() == sc->staticScope());
|
.enclosingStaticScope() == sc->staticScope());
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
return !innermostStmt() || sc->isModuleBox();
|
return !innermostStmt() || sc->isModuleBox();
|
||||||
|
@ -1429,7 +1429,6 @@ BytecodeEmitter::isAliasedName(BytecodeEmitter* bceOfDef, ParseNode* pn)
|
||||||
*/
|
*/
|
||||||
return script->formalIsAliased(pn->pn_scopecoord.slot());
|
return script->formalIsAliased(pn->pn_scopecoord.slot());
|
||||||
case Definition::VAR:
|
case Definition::VAR:
|
||||||
case Definition::GLOBALCONST:
|
|
||||||
MOZ_ASSERT_IF(sc->allLocalsAliased(), script->localIsAliased(pn->pn_scopecoord.slot()));
|
MOZ_ASSERT_IF(sc->allLocalsAliased(), script->localIsAliased(pn->pn_scopecoord.slot()));
|
||||||
return script->localIsAliased(pn->pn_scopecoord.slot());
|
return script->localIsAliased(pn->pn_scopecoord.slot());
|
||||||
case Definition::PLACEHOLDER:
|
case Definition::PLACEHOLDER:
|
||||||
|
@ -1645,12 +1644,11 @@ BytecodeEmitter::tryConvertFreeName(ParseNode* pn)
|
||||||
switch (pn->getOp()) {
|
switch (pn->getOp()) {
|
||||||
case JSOP_GETNAME: op = JSOP_GETGNAME; break;
|
case JSOP_GETNAME: op = JSOP_GETGNAME; break;
|
||||||
case JSOP_SETNAME: op = strictifySetNameOp(JSOP_SETGNAME); break;
|
case JSOP_SETNAME: op = strictifySetNameOp(JSOP_SETGNAME); break;
|
||||||
case JSOP_SETCONST:
|
|
||||||
// Not supported.
|
|
||||||
return false;
|
|
||||||
default: MOZ_CRASH("gname");
|
default: MOZ_CRASH("gname");
|
||||||
}
|
}
|
||||||
pn->setOp(op);
|
pn->setOp(op);
|
||||||
|
MOZ_ASSERT_IF(op == JSOP_INITGLEXICAL,
|
||||||
|
IsStaticGlobalLexicalScope(blockScopeOfDef(pn->resolve())));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1704,7 +1702,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn)
|
||||||
// Throw an error on attempts to mutate const-declared bindings.
|
// Throw an error on attempts to mutate const-declared bindings.
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case JSOP_GETNAME:
|
case JSOP_GETNAME:
|
||||||
case JSOP_SETCONST:
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (pn->isConst()) {
|
if (pn->isConst()) {
|
||||||
|
@ -1789,7 +1786,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Definition::VAR:
|
case Definition::VAR:
|
||||||
case Definition::GLOBALCONST:
|
|
||||||
case Definition::CONST:
|
case Definition::CONST:
|
||||||
case Definition::LET:
|
case Definition::LET:
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -1798,8 +1794,6 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn)
|
||||||
case JSOP_SETNAME:
|
case JSOP_SETNAME:
|
||||||
case JSOP_STRICTSETNAME:
|
case JSOP_STRICTSETNAME:
|
||||||
op = JSOP_SETLOCAL; break;
|
op = JSOP_SETLOCAL; break;
|
||||||
case JSOP_SETCONST:
|
|
||||||
op = JSOP_SETLOCAL; break;
|
|
||||||
default: MOZ_CRASH("local");
|
default: MOZ_CRASH("local");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2163,7 +2157,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||||
*answer = true;
|
*answer = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -3001,8 +2994,7 @@ BytecodeEmitter::enterBlockScope(StmtInfoBCE* stmtInfo, ObjectBox* objbox, JSOp
|
||||||
{
|
{
|
||||||
// This is so terrible. The eval body-level lexical scope needs to be
|
// This is so terrible. The eval body-level lexical scope needs to be
|
||||||
// emitted in the prologue so DEFFUN can pick up the right scope chain.
|
// emitted in the prologue so DEFFUN can pick up the right scope chain.
|
||||||
bool isEvalBodyLexicalScope = sc->staticScope() &&
|
bool isEvalBodyLexicalScope = sc->staticScope()->is<StaticEvalObject>() &&
|
||||||
sc->staticScope()->is<StaticEvalObject>() &&
|
|
||||||
!innermostStmt();
|
!innermostStmt();
|
||||||
if (isEvalBodyLexicalScope) {
|
if (isEvalBodyLexicalScope) {
|
||||||
MOZ_ASSERT(code().length() == 0);
|
MOZ_ASSERT(code().length() == 0);
|
||||||
|
@ -3704,7 +3696,7 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio
|
||||||
case JSOP_STRICTSETNAME:
|
case JSOP_STRICTSETNAME:
|
||||||
case JSOP_SETGNAME:
|
case JSOP_SETGNAME:
|
||||||
case JSOP_STRICTSETGNAME:
|
case JSOP_STRICTSETGNAME:
|
||||||
case JSOP_SETCONST: {
|
case JSOP_INITGLEXICAL: {
|
||||||
// This is like ordinary assignment, but with one difference.
|
// This is like ordinary assignment, but with one difference.
|
||||||
//
|
//
|
||||||
// In `a = b`, we first determine a binding for `a` (using
|
// In `a = b`, we first determine a binding for `a` (using
|
||||||
|
@ -3719,7 +3711,9 @@ BytecodeEmitter::emitDestructuringLHS(ParseNode* target, VarEmitOption emitOptio
|
||||||
if (!makeAtomIndex(target->pn_atom, &atomIndex))
|
if (!makeAtomIndex(target->pn_atom, &atomIndex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!target->isOp(JSOP_SETCONST)) {
|
// INITGLEXICAL always initializes a binding on the global
|
||||||
|
// lexical scope and does not need a BINDGNAME.
|
||||||
|
if (!target->isOp(JSOP_INITGLEXICAL)) {
|
||||||
bool global = target->isOp(JSOP_SETGNAME) || target->isOp(JSOP_STRICTSETGNAME);
|
bool global = target->isOp(JSOP_SETGNAME) || target->isOp(JSOP_STRICTSETGNAME);
|
||||||
JSOp bindOp = global ? JSOP_BINDGNAME : JSOP_BINDNAME;
|
JSOp bindOp = global ? JSOP_BINDGNAME : JSOP_BINDNAME;
|
||||||
if (!emitIndex32(bindOp, atomIndex))
|
if (!emitIndex32(bindOp, atomIndex))
|
||||||
|
@ -4341,7 +4335,7 @@ BytecodeEmitter::emitVariables(ParseNode* pn, VarEmitOption emitOption, bool isL
|
||||||
if (!emitTree(pn3))
|
if (!emitTree(pn3))
|
||||||
return false;
|
return false;
|
||||||
emittingForInit = oldEmittingForInit;
|
emittingForInit = oldEmittingForInit;
|
||||||
} else if (op == JSOP_INITLEXICAL || isLetExpr) {
|
} else if (op == JSOP_INITLEXICAL || op == JSOP_INITGLEXICAL || isLetExpr) {
|
||||||
// 'let' bindings cannot be used before they are
|
// 'let' bindings cannot be used before they are
|
||||||
// initialized. JSOP_INITLEXICAL distinguishes the binding site.
|
// initialized. JSOP_INITLEXICAL distinguishes the binding site.
|
||||||
MOZ_ASSERT(emitOption != DefineVars);
|
MOZ_ASSERT(emitOption != DefineVars);
|
||||||
|
@ -7382,13 +7376,6 @@ BytecodeEmitter::emitDefaultsAndDestructuring(ParseNode* pn)
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp)
|
BytecodeEmitter::emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* This function is significantly more complicated than it needs to be.
|
|
||||||
* In fact, it shouldn't exist at all. This should all be a
|
|
||||||
* JSOP_INITLEXIAL. Unfortunately, toplevel lexicals are broken, and
|
|
||||||
* are emitted as vars :(. As such, we have to do these ministrations to
|
|
||||||
* to make sure that all works properly.
|
|
||||||
*/
|
|
||||||
MOZ_ASSERT(pn->isKind(PNK_NAME));
|
MOZ_ASSERT(pn->isKind(PNK_NAME));
|
||||||
|
|
||||||
if (!bindNameToSlot(pn))
|
if (!bindNameToSlot(pn))
|
||||||
|
@ -7398,14 +7385,6 @@ BytecodeEmitter::emitLexicalInitialization(ParseNode* pn, JSOp globalDefOp)
|
||||||
if (!maybeEmitVarDecl(globalDefOp, pn, &atomIndex))
|
if (!maybeEmitVarDecl(globalDefOp, pn, &atomIndex))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (pn->getOp() != JSOP_INITLEXICAL) {
|
|
||||||
bool global = IsGlobalOp(pn->getOp());
|
|
||||||
if (!emitIndex32(global ? JSOP_BINDGNAME : JSOP_BINDNAME, atomIndex))
|
|
||||||
return false;
|
|
||||||
if (!emit1(JSOP_SWAP))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pn->pn_scopecoord.isFree()) {
|
if (!pn->pn_scopecoord.isFree()) {
|
||||||
if (!emitVarOp(pn, pn->getOp()))
|
if (!emitVarOp(pn, pn->getOp()))
|
||||||
return false;
|
return false;
|
||||||
|
@ -7509,7 +7488,7 @@ BytecodeEmitter::emitClass(ParseNode* pn)
|
||||||
|
|
||||||
ParseNode* outerName = names->outerBinding();
|
ParseNode* outerName = names->outerBinding();
|
||||||
if (outerName) {
|
if (outerName) {
|
||||||
if (!emitLexicalInitialization(outerName, JSOP_DEFVAR))
|
if (!emitLexicalInitialization(outerName, JSOP_DEFLET))
|
||||||
return false;
|
return false;
|
||||||
// Only class statements make outer bindings, and they do not leave
|
// Only class statements make outer bindings, and they do not leave
|
||||||
// themselves on the stack.
|
// themselves on the stack.
|
||||||
|
@ -7675,7 +7654,6 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
if (!emitVariables(pn, InitializeVars))
|
if (!emitVariables(pn, InitializeVars))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -75,7 +75,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||||
// Non-global lexical declarations are block-scoped (ergo not hoistable).
|
// Non-global lexical declarations are block-scoped (ergo not hoistable).
|
||||||
// (Global lexical declarations, in addition to being irrelevant here as
|
// (Global lexical declarations, in addition to being irrelevant here as
|
||||||
// ContainsHoistedDeclaration is only used on the arms of an |if|
|
// ContainsHoistedDeclaration is only used on the arms of an |if|
|
||||||
// statement, are handled by PNK_GLOBALCONST and PNK_VAR.)
|
// statement, are handled by PNK_VAR.)
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||||
|
@ -417,10 +417,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||||
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
|
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
|
||||||
"some parent node without recurring to test this node");
|
"some parent node without recurring to test this node");
|
||||||
|
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
MOZ_CRASH("ContainsHoistedDeclaration is only called on nested nodes where "
|
|
||||||
"globalconst nodes should never have been generated");
|
|
||||||
|
|
||||||
case PNK_LIMIT: // invalid sentinel value
|
case PNK_LIMIT: // invalid sentinel value
|
||||||
MOZ_CRASH("unexpected PNK_LIMIT in node");
|
MOZ_CRASH("unexpected PNK_LIMIT in node");
|
||||||
}
|
}
|
||||||
|
@ -1837,7 +1833,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
||||||
case PNK_TEMPLATE_STRING_LIST:
|
case PNK_TEMPLATE_STRING_LIST:
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
case PNK_ARGSBODY:
|
case PNK_ARGSBODY:
|
||||||
case PNK_CALLSITEOBJ:
|
case PNK_CALLSITEOBJ:
|
||||||
|
|
|
@ -720,6 +720,7 @@ class FullParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
|
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
|
||||||
|
inline void setLexicalDeclarationOp(ParseNode* pn, JSOp op);
|
||||||
|
|
||||||
void setBeginPosition(ParseNode* pn, ParseNode* oth) {
|
void setBeginPosition(ParseNode* pn, ParseNode* oth) {
|
||||||
setBeginPosition(pn, oth->pn_pos.begin);
|
setBeginPosition(pn, oth->pn_pos.begin);
|
||||||
|
@ -752,8 +753,7 @@ class FullParseHandler
|
||||||
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
|
return new_<ListNode>(kind, op, TokenPos(begin, begin + 1));
|
||||||
}
|
}
|
||||||
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||||
kind == PNK_GLOBALCONST);
|
|
||||||
return new_<ListNode>(kind, op, pos());
|
return new_<ListNode>(kind, op, pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +763,7 @@ class FullParseHandler
|
||||||
return new_<ListNode>(kind, op, kid);
|
return new_<ListNode>(kind, op, kid);
|
||||||
}
|
}
|
||||||
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
|
||||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||||
kind == PNK_GLOBALCONST);
|
|
||||||
return new_<ListNode>(kind, op, kid);
|
return new_<ListNode>(kind, op, kid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,12 +992,8 @@ FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init, JS
|
||||||
pn->pn_expr = init;
|
pn->pn_expr = init;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == JSOP_INITLEXICAL)
|
if (pn->pn_dflags & PND_BOUND)
|
||||||
pn->setOp(op);
|
|
||||||
else if (pn->pn_dflags & PND_BOUND)
|
|
||||||
pn->setOp(JSOP_SETLOCAL);
|
pn->setOp(JSOP_SETLOCAL);
|
||||||
else if (op == JSOP_DEFCONST)
|
|
||||||
pn->setOp(JSOP_SETCONST);
|
|
||||||
else
|
else
|
||||||
pn->setOp(JSOP_SETNAME);
|
pn->setOp(JSOP_SETNAME);
|
||||||
|
|
||||||
|
@ -1009,6 +1004,19 @@ FullParseHandler::finishInitializerAssignment(ParseNode* pn, ParseNode* init, JS
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
FullParseHandler::setLexicalDeclarationOp(ParseNode* pn, JSOp op)
|
||||||
|
{
|
||||||
|
if (op == JSOP_DEFLET || op == JSOP_DEFCONST) {
|
||||||
|
// Subtlety here. Lexical definitions that are PND_BOUND but whose
|
||||||
|
// scope coordinates are free are global lexicals. They cannot use
|
||||||
|
// scope coordinate lookup because we rely on being able to clone
|
||||||
|
// scripts to run on multiple globals. However, they always go on the
|
||||||
|
// global lexical scope, so in that sense they are bound.
|
||||||
|
pn->setOp(pn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline ParseNode*
|
inline ParseNode*
|
||||||
FullParseHandler::makeAssignment(ParseNode* pn, ParseNode* rhs)
|
FullParseHandler::makeAssignment(ParseNode* pn, ParseNode* rhs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -682,7 +682,6 @@ class NameResolver
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
MOZ_ASSERT(cur->isArity(PN_LIST));
|
MOZ_ASSERT(cur->isArity(PN_LIST));
|
||||||
for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
|
for (ParseNode* element = cur->pn_head; element; element = element->pn_next) {
|
||||||
if (!resolve(element, prefix))
|
if (!resolve(element, prefix))
|
||||||
|
|
|
@ -497,7 +497,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
||||||
case PNK_CALLSITEOBJ:
|
case PNK_CALLSITEOBJ:
|
||||||
case PNK_VAR:
|
case PNK_VAR:
|
||||||
case PNK_CONST:
|
case PNK_CONST:
|
||||||
case PNK_GLOBALCONST:
|
|
||||||
case PNK_LET:
|
case PNK_LET:
|
||||||
case PNK_CATCHLIST:
|
case PNK_CATCHLIST:
|
||||||
case PNK_STATEMENTLIST:
|
case PNK_STATEMENTLIST:
|
||||||
|
@ -656,7 +655,6 @@ Definition::kindString(Kind kind)
|
||||||
"",
|
"",
|
||||||
js_var_str,
|
js_var_str,
|
||||||
js_const_str,
|
js_const_str,
|
||||||
js_const_str,
|
|
||||||
js_let_str,
|
js_let_str,
|
||||||
"argument",
|
"argument",
|
||||||
js_function_str,
|
js_function_str,
|
||||||
|
|
|
@ -131,7 +131,6 @@ class PackedScopeCoordinate
|
||||||
F(CONTINUE) \
|
F(CONTINUE) \
|
||||||
F(VAR) \
|
F(VAR) \
|
||||||
F(CONST) \
|
F(CONST) \
|
||||||
F(GLOBALCONST) \
|
|
||||||
F(WITH) \
|
F(WITH) \
|
||||||
F(RETURN) \
|
F(RETURN) \
|
||||||
F(NEW) \
|
F(NEW) \
|
||||||
|
@ -1571,7 +1570,6 @@ struct Definition : public ParseNode
|
||||||
enum Kind {
|
enum Kind {
|
||||||
MISSING = 0,
|
MISSING = 0,
|
||||||
VAR,
|
VAR,
|
||||||
GLOBALCONST,
|
|
||||||
CONST,
|
CONST,
|
||||||
LET,
|
LET,
|
||||||
ARG,
|
ARG,
|
||||||
|
@ -1601,8 +1599,6 @@ struct Definition : public ParseNode
|
||||||
return IMPORT;
|
return IMPORT;
|
||||||
if (isLexical())
|
if (isLexical())
|
||||||
return isConst() ? CONST : LET;
|
return isConst() ? CONST : LET;
|
||||||
if (isConst())
|
|
||||||
return GLOBALCONST;
|
|
||||||
return VAR;
|
return VAR;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -241,7 +241,6 @@ ParseContext<FullParseHandler>::define(TokenStream& ts,
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Definition::GLOBALCONST:
|
|
||||||
case Definition::VAR:
|
case Definition::VAR:
|
||||||
if (!sc->isGlobalContext()) {
|
if (!sc->isGlobalContext()) {
|
||||||
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
|
dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL);
|
||||||
|
@ -262,7 +261,8 @@ ParseContext<FullParseHandler>::define(TokenStream& ts,
|
||||||
|
|
||||||
case Definition::LET:
|
case Definition::LET:
|
||||||
case Definition::CONST:
|
case Definition::CONST:
|
||||||
dn->setOp(JSOP_INITLEXICAL);
|
// See FullParseHandler::setLexicalDeclarationOp.
|
||||||
|
dn->setOp(dn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL);
|
||||||
dn->pn_dflags |= (PND_LEXICAL | PND_BOUND);
|
dn->pn_dflags |= (PND_LEXICAL | PND_BOUND);
|
||||||
if (atModuleLevel())
|
if (atModuleLevel())
|
||||||
dn->pn_dflags |= PND_CLOSED;
|
dn->pn_dflags |= PND_CLOSED;
|
||||||
|
@ -394,7 +394,6 @@ AppendPackedBindings(const ParseContext<ParseHandler>* pc, const DeclVector& vec
|
||||||
kind = Binding::VARIABLE;
|
kind = Binding::VARIABLE;
|
||||||
break;
|
break;
|
||||||
case Definition::CONST:
|
case Definition::CONST:
|
||||||
case Definition::GLOBALCONST:
|
|
||||||
kind = Binding::CONSTANT;
|
kind = Binding::CONSTANT;
|
||||||
break;
|
break;
|
||||||
case Definition::ARG:
|
case Definition::ARG:
|
||||||
|
@ -780,8 +779,9 @@ Parser<ParseHandler>::parse()
|
||||||
* an object lock before it finishes generating bytecode into a script
|
* an object lock before it finishes generating bytecode into a script
|
||||||
* protected from the GC by a root or a stack frame reference.
|
* protected from the GC by a root or a stack frame reference.
|
||||||
*/
|
*/
|
||||||
|
Rooted<ScopeObject*> staticLexical(context, &context->global()->lexicalScope().staticBlock());
|
||||||
Directives directives(options().strictOption);
|
Directives directives(options().strictOption);
|
||||||
GlobalSharedContext globalsc(context, /* staticScope = */ nullptr, directives,
|
GlobalSharedContext globalsc(context, staticLexical, directives,
|
||||||
options().extraWarningsOption);
|
options().extraWarningsOption);
|
||||||
ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
|
ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
|
||||||
&globalsc, /* newDirectives = */ nullptr,
|
&globalsc, /* newDirectives = */ nullptr,
|
||||||
|
@ -1316,17 +1316,17 @@ struct BindData
|
||||||
: kind_(Uninitialized), nameNode_(ParseHandler::null()), letData_(cx)
|
: kind_(Uninitialized), nameNode_(ParseHandler::null()), letData_(cx)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void initLexical(VarContext varContext, StaticBlockObject* blockObj, unsigned overflow,
|
void initLexical(VarContext varContext, JSOp op, StaticBlockObject* blockObj,
|
||||||
bool isConst = false)
|
unsigned overflow)
|
||||||
{
|
{
|
||||||
init(LexicalBinding, JSOP_INITLEXICAL, isConst);
|
init(LexicalBinding, op, op == JSOP_DEFCONST);
|
||||||
letData_.varContext = varContext;
|
letData_.varContext = varContext;
|
||||||
letData_.blockObj = blockObj;
|
letData_.blockObj = blockObj;
|
||||||
letData_.overflow = overflow;
|
letData_.overflow = overflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initVarOrGlobalConst(JSOp op) {
|
void initVar(JSOp op) {
|
||||||
init(VarBinding, op, op == JSOP_DEFCONST);
|
init(VarBinding, op, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initDestructuring(JSOp op) {
|
void initDestructuring(JSOp op) {
|
||||||
|
@ -1365,7 +1365,7 @@ struct BindData
|
||||||
case LexicalBinding:
|
case LexicalBinding:
|
||||||
return Parser<ParseHandler>::bindLexical(this, name, parser);
|
return Parser<ParseHandler>::bindLexical(this, name, parser);
|
||||||
case VarBinding:
|
case VarBinding:
|
||||||
return Parser<ParseHandler>::bindVarOrGlobalConst(this, name, parser);
|
return Parser<ParseHandler>::bindVar(this, name, parser);
|
||||||
case DestructuringBinding:
|
case DestructuringBinding:
|
||||||
return Parser<ParseHandler>::bindDestructuringArg(this, name, parser);
|
return Parser<ParseHandler>::bindDestructuringArg(this, name, parser);
|
||||||
default:
|
default:
|
||||||
|
@ -2084,8 +2084,7 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
||||||
MOZ_ASSERT(!dn->isUsed());
|
MOZ_ASSERT(!dn->isUsed());
|
||||||
MOZ_ASSERT(dn->isDefn());
|
MOZ_ASSERT(dn->isDefn());
|
||||||
|
|
||||||
bool throwRedeclarationError = dn->kind() == Definition::GLOBALCONST ||
|
bool throwRedeclarationError = dn->kind() == Definition::CONST ||
|
||||||
dn->kind() == Definition::CONST ||
|
|
||||||
dn->kind() == Definition::LET;
|
dn->kind() == Definition::LET;
|
||||||
if (options().extraWarningsOption || throwRedeclarationError) {
|
if (options().extraWarningsOption || throwRedeclarationError) {
|
||||||
JSAutoByteString name;
|
JSAutoByteString name;
|
||||||
|
@ -2317,10 +2316,7 @@ Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
||||||
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
|
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
|
||||||
*/
|
*/
|
||||||
if (DefinitionNode dn = pc->decls().lookupFirst(funName)) {
|
if (DefinitionNode dn = pc->decls().lookupFirst(funName)) {
|
||||||
if (dn == Definition::GLOBALCONST ||
|
if (dn == Definition::CONST || dn == Definition::LET) {
|
||||||
dn == Definition::CONST ||
|
|
||||||
dn == Definition::LET)
|
|
||||||
{
|
|
||||||
JSAutoByteString name;
|
JSAutoByteString name;
|
||||||
if (!AtomToPrintableString(context, funName, &name) ||
|
if (!AtomToPrintableString(context, funName, &name) ||
|
||||||
!report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
|
!report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
|
||||||
|
@ -3267,31 +3263,37 @@ Parser<FullParseHandler>::bindLexical(BindData<FullParseHandler>* data,
|
||||||
ExclusiveContext* cx = parser->context;
|
ExclusiveContext* cx = parser->context;
|
||||||
Rooted<StaticBlockObject*> blockObj(cx, data->letData().blockObj);
|
Rooted<StaticBlockObject*> blockObj(cx, data->letData().blockObj);
|
||||||
|
|
||||||
unsigned index;
|
uint32_t index;
|
||||||
if (blockObj) {
|
if (blockObj) {
|
||||||
index = blockObj->numVariables();
|
// Leave the scope coordinate free on global lexicals.
|
||||||
if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) {
|
//
|
||||||
parser->report(ParseError, false, pn, data->letData().overflow);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If we don't have a block object, we are parsing a body-level let,
|
|
||||||
// in which case we use a bogus index. See comment block below in
|
|
||||||
// setting the pn_scopecoord for explanation on how it gets adjusted.
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For block-level lets, assign block-local index to pn->pn_scopecoord
|
// For block-level lets, assign block-local index to pn->pn_scopecoord
|
||||||
// right away. The emitter will adjust the node's slot based on its
|
// right away. The emitter will adjust the node's slot based on its
|
||||||
// stack depth model -- and, for global and eval code,
|
// stack depth model -- and, for global and eval code,
|
||||||
// js::frontend::CompileScript will adjust the slot again to include
|
// js::frontend::CompileScript will adjust the slot again to include
|
||||||
// script->nfixed and body-level lets.
|
// script->nfixed and body-level lets.
|
||||||
//
|
//
|
||||||
// For body-level lets, the index is bogus at this point and is adjusted
|
// XXXshu: I should like to optimize global lexicals, but we rely on
|
||||||
// when creating Bindings. See ParseContext::generateBindings and
|
// being able to clone JSScripts to run on multiple globals and to be
|
||||||
// AppendPackedBindings.
|
// able to parse scripts off-thread in a different compartment.
|
||||||
|
if (!blockObj->isGlobal()) {
|
||||||
|
index = blockObj->numVariables();
|
||||||
|
if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) {
|
||||||
|
parser->report(ParseError, false, pn, data->letData().overflow);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index))
|
if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!pc->sc->isGlobalContext()) {
|
||||||
|
// If we don't have a block object and are parsing a function
|
||||||
|
// body-level let, use a bogus index. It is adjusted when creating the
|
||||||
|
// function's Bindings. See ParseContext::generateFunctionBindings and
|
||||||
|
// AppendPackedBindings.
|
||||||
|
index = 0;
|
||||||
|
if (!pn->pn_scopecoord.setSlot(parser->tokenStream, index))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Definition::Kind bindingKind;
|
Definition::Kind bindingKind;
|
||||||
if (pn->isImport())
|
if (pn->isImport())
|
||||||
|
@ -3315,6 +3317,7 @@ Parser<FullParseHandler>::bindLexical(BindData<FullParseHandler>* data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockObj) {
|
if (blockObj) {
|
||||||
|
if (!blockObj->isGlobal()) {
|
||||||
bool redeclared;
|
bool redeclared;
|
||||||
RootedId id(cx, NameToId(name));
|
RootedId id(cx, NameToId(name));
|
||||||
RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id,
|
RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id,
|
||||||
|
@ -3333,6 +3336,7 @@ Parser<FullParseHandler>::bindLexical(BindData<FullParseHandler>* data,
|
||||||
|
|
||||||
/* Store pn in the static block object. */
|
/* Store pn in the static block object. */
|
||||||
blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition*>(pn));
|
blockObj->setDefinitionParseNode(index, reinterpret_cast<Definition*>(pn));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Body-level lets are hoisted and need to have been defined via
|
// Body-level lets are hoisted and need to have been defined via
|
||||||
// pc->define above.
|
// pc->define above.
|
||||||
|
@ -3491,13 +3495,12 @@ OuterLet(ParseContext<ParseHandler>* pc, StmtInfoPC* stmt, HandleAtom atom)
|
||||||
|
|
||||||
template <typename ParseHandler>
|
template <typename ParseHandler>
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
Parser<ParseHandler>::bindVarOrGlobalConst(BindData<ParseHandler>* data,
|
Parser<ParseHandler>::bindVar(BindData<ParseHandler>* data,
|
||||||
HandlePropertyName name, Parser<ParseHandler>* parser)
|
HandlePropertyName name, Parser<ParseHandler>* parser)
|
||||||
{
|
{
|
||||||
ExclusiveContext* cx = parser->context;
|
ExclusiveContext* cx = parser->context;
|
||||||
ParseContext<ParseHandler>* pc = parser->pc;
|
ParseContext<ParseHandler>* pc = parser->pc;
|
||||||
Node pn = data->nameNode();
|
Node pn = data->nameNode();
|
||||||
bool isConstDecl = data->op() == JSOP_DEFCONST;
|
|
||||||
|
|
||||||
/* Default best op for pn is JSOP_GETNAME; we'll try to improve below. */
|
/* Default best op for pn is JSOP_GETNAME; we'll try to improve below. */
|
||||||
parser->handler.setOp(pn, JSOP_GETNAME);
|
parser->handler.setOp(pn, JSOP_GETNAME);
|
||||||
|
@ -3530,10 +3533,8 @@ Parser<ParseHandler>::bindVarOrGlobalConst(BindData<ParseHandler>* data,
|
||||||
DefinitionList::Range defs = pc->decls().lookupMulti(name);
|
DefinitionList::Range defs = pc->decls().lookupMulti(name);
|
||||||
MOZ_ASSERT_IF(stmt, !defs.empty());
|
MOZ_ASSERT_IF(stmt, !defs.empty());
|
||||||
|
|
||||||
if (defs.empty()) {
|
if (defs.empty())
|
||||||
return pc->define(parser->tokenStream, name, pn,
|
return pc->define(parser->tokenStream, name, pn, Definition::VAR);
|
||||||
isConstDecl ? Definition::GLOBALCONST : Definition::VAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There was a previous declaration with the same name. The standard
|
* There was a previous declaration with the same name. The standard
|
||||||
|
@ -3548,19 +3549,12 @@ Parser<ParseHandler>::bindVarOrGlobalConst(BindData<ParseHandler>* data,
|
||||||
JSAutoByteString bytes;
|
JSAutoByteString bytes;
|
||||||
if (!AtomToPrintableString(cx, name, &bytes))
|
if (!AtomToPrintableString(cx, name, &bytes))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (isConstDecl) {
|
|
||||||
parser->report(ParseError, false, pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
|
if (!parser->report(ParseExtraWarning, false, pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
bool inCatchBody = (stmt && stmt->type == StmtType::CATCH);
|
bool inCatchBody = (stmt && stmt->type == StmtType::CATCH);
|
||||||
bool error = (isConstDecl ||
|
bool error = (dn_kind == Definition::IMPORT ||
|
||||||
dn_kind == Definition::IMPORT ||
|
|
||||||
dn_kind == Definition::CONST ||
|
dn_kind == Definition::CONST ||
|
||||||
dn_kind == Definition::GLOBALCONST ||
|
|
||||||
(dn_kind == Definition::LET &&
|
(dn_kind == Definition::LET &&
|
||||||
(!inCatchBody || OuterLet(pc, stmt, name))));
|
(!inCatchBody || OuterLet(pc, stmt, name))));
|
||||||
|
|
||||||
|
@ -3681,12 +3675,10 @@ Parser<FullParseHandler>::bindInitialized(BindData<FullParseHandler>* data, Pars
|
||||||
* Select the appropriate name-setting opcode, respecting eager selection
|
* Select the appropriate name-setting opcode, respecting eager selection
|
||||||
* done by the data->bind function.
|
* done by the data->bind function.
|
||||||
*/
|
*/
|
||||||
if (data->op() == JSOP_INITLEXICAL)
|
if (data->op() == JSOP_DEFLET || data->op() == JSOP_DEFCONST)
|
||||||
pn->setOp(JSOP_INITLEXICAL);
|
pn->setOp(pn->pn_scopecoord.isFree() ? JSOP_INITGLEXICAL : JSOP_INITLEXICAL);
|
||||||
else if (pn->pn_dflags & PND_BOUND)
|
else if (pn->pn_dflags & PND_BOUND)
|
||||||
pn->setOp(JSOP_SETLOCAL);
|
pn->setOp(JSOP_SETLOCAL);
|
||||||
else if (data->op() == JSOP_DEFCONST)
|
|
||||||
pn->setOp(JSOP_SETCONST);
|
|
||||||
else
|
else
|
||||||
pn->setOp(JSOP_SETNAME);
|
pn->setOp(JSOP_SETNAME);
|
||||||
|
|
||||||
|
@ -4012,6 +4004,9 @@ Parser<ParseHandler>::deprecatedLetBlock(YieldHandling yieldHandling)
|
||||||
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
||||||
if (!blockObj)
|
if (!blockObj)
|
||||||
return null();
|
return null();
|
||||||
|
// Initialize the enclosing scope manually for the call to |variables|
|
||||||
|
// below.
|
||||||
|
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
|
||||||
|
|
||||||
uint32_t begin = pos().begin;
|
uint32_t begin = pos().begin;
|
||||||
|
|
||||||
|
@ -4106,14 +4101,7 @@ Parser<ParseHandler>::variables(YieldHandling yieldHandling,
|
||||||
ForInitLocation location,
|
ForInitLocation location,
|
||||||
bool* psimple, StaticBlockObject* blockObj, VarContext varContext)
|
bool* psimple, StaticBlockObject* blockObj, VarContext varContext)
|
||||||
{
|
{
|
||||||
/*
|
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||||
* The four options here are:
|
|
||||||
* - PNK_VAR: We're parsing var declarations.
|
|
||||||
* - PNK_CONST: We're parsing const declarations.
|
|
||||||
* - PNK_GLOBALCONST: We're parsing const declarations at toplevel (see bug 589119).
|
|
||||||
* - PNK_LET: We are parsing a let declaration.
|
|
||||||
*/
|
|
||||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET || kind == PNK_GLOBALCONST);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The simple flag is set if the declaration has the form 'var x', with
|
* The simple flag is set if the declaration has the form 'var x', with
|
||||||
|
@ -4121,28 +4109,23 @@ Parser<ParseHandler>::variables(YieldHandling yieldHandling,
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT_IF(psimple, *psimple);
|
MOZ_ASSERT_IF(psimple, *psimple);
|
||||||
|
|
||||||
JSOp op = JSOP_NOP;
|
JSOp op;
|
||||||
if (kind == PNK_VAR)
|
switch (kind) {
|
||||||
op = JSOP_DEFVAR;
|
case PNK_VAR: op = JSOP_DEFVAR; break;
|
||||||
else if (kind == PNK_GLOBALCONST)
|
case PNK_CONST: op = JSOP_DEFCONST; break;
|
||||||
op = JSOP_DEFCONST;
|
case PNK_LET: op = JSOP_DEFLET; break;
|
||||||
|
default: MOZ_CRASH("unknown variable kind");
|
||||||
|
}
|
||||||
|
|
||||||
Node pn = handler.newDeclarationList(kind, op);
|
Node pn = handler.newDeclarationList(kind, op);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
/*
|
|
||||||
* SpiderMonkey const is really "write once per initialization evaluation"
|
|
||||||
* var, whereas let is block scoped. ES-Harmony wants block-scoped const so
|
|
||||||
* this code will change soon.
|
|
||||||
*/
|
|
||||||
BindData<ParseHandler> data(context);
|
BindData<ParseHandler> data(context);
|
||||||
if (kind == PNK_VAR || kind == PNK_GLOBALCONST) {
|
if (kind == PNK_VAR)
|
||||||
data.initVarOrGlobalConst(op);
|
data.initVar(op);
|
||||||
} else {
|
else
|
||||||
data.initLexical(varContext, blockObj, JSMSG_TOO_MANY_LOCALS,
|
data.initLexical(varContext, op, blockObj, JSMSG_TOO_MANY_LOCALS);
|
||||||
/* isConst = */ kind == PNK_CONST);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
Node pn2;
|
Node pn2;
|
||||||
|
@ -4228,7 +4211,7 @@ Parser<ParseHandler>::variables(YieldHandling yieldHandling,
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedPropertyName name(context, tokenStream.currentName());
|
RootedPropertyName name(context, tokenStream.currentName());
|
||||||
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_GLOBALCONST, varContext);
|
pn2 = newBindingNode(name, kind == PNK_VAR, varContext);
|
||||||
if (!pn2)
|
if (!pn2)
|
||||||
return null();
|
return null();
|
||||||
if (data.isConst())
|
if (data.isConst())
|
||||||
|
@ -4309,6 +4292,7 @@ Parser<ParseHandler>::variables(YieldHandling yieldHandling,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handler.setLexicalDeclarationOp(pn2, data.op());
|
||||||
handler.setEndPosition(pn, pn2);
|
handler.setEndPosition(pn, pn2);
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
|
@ -4348,14 +4332,9 @@ Parser<FullParseHandler>::checkAndPrepareLexical(bool isConst, const TokenPos& e
|
||||||
MOZ_ASSERT(pc->atBodyLevel());
|
MOZ_ASSERT(pc->atBodyLevel());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When bug 589199 is fixed, let variables will be stored in
|
* Self-hosted code must be usable against *any* global object,
|
||||||
* the slots of a new scope chain object, encountered just
|
* including ones with other let variables -- variables possibly
|
||||||
* before the global object in the overall chain. This extra
|
* placed in conflicting slots. Forbid top-level let declarations to
|
||||||
* object is present in the scope chain for all code in that
|
|
||||||
* global, including self-hosted code. But self-hosted code
|
|
||||||
* must be usable against *any* global object, including ones
|
|
||||||
* with other let variables -- variables possibly placed in
|
|
||||||
* conflicting slots. Forbid top-level let declarations to
|
|
||||||
* prevent such conflicts from ever occurring.
|
* prevent such conflicts from ever occurring.
|
||||||
*/
|
*/
|
||||||
bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->innermostScopeStmt();
|
bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->innermostScopeStmt();
|
||||||
|
@ -4409,8 +4388,12 @@ Parser<FullParseHandler>::checkAndPrepareLexical(bool isConst, const TokenPos& e
|
||||||
static StaticBlockObject*
|
static StaticBlockObject*
|
||||||
CurrentLexicalStaticBlock(ParseContext<FullParseHandler>* pc)
|
CurrentLexicalStaticBlock(ParseContext<FullParseHandler>* pc)
|
||||||
{
|
{
|
||||||
return !pc->innermostStmt() ? nullptr :
|
if (pc->innermostStaticScope()->is<StaticBlockObject>())
|
||||||
&pc->innermostStmt()->staticScope->as<StaticBlockObject>();
|
return &pc->innermostStaticScope()->as<StaticBlockObject>();
|
||||||
|
MOZ_ASSERT(pc->atBodyLevel() &&
|
||||||
|
(!pc->sc->isGlobalContext() ||
|
||||||
|
HasNonSyntacticStaticScopeChain(pc->innermostStaticScope())));
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -4418,16 +4401,12 @@ ParseNode*
|
||||||
Parser<FullParseHandler>::makeInitializedLexicalBinding(HandlePropertyName name, bool isConst,
|
Parser<FullParseHandler>::makeInitializedLexicalBinding(HandlePropertyName name, bool isConst,
|
||||||
const TokenPos& pos)
|
const TokenPos& pos)
|
||||||
{
|
{
|
||||||
// Handle the silliness of global and body level lexical decls.
|
|
||||||
BindData<FullParseHandler> data(context);
|
BindData<FullParseHandler> data(context);
|
||||||
if (pc->atGlobalLevel()) {
|
|
||||||
data.initVarOrGlobalConst(isConst ? JSOP_DEFCONST : JSOP_DEFVAR);
|
|
||||||
} else {
|
|
||||||
if (!checkAndPrepareLexical(isConst, pos))
|
if (!checkAndPrepareLexical(isConst, pos))
|
||||||
return null();
|
return null();
|
||||||
data.initLexical(HoistVars, CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS, isConst);
|
data.initLexical(HoistVars, isConst ? JSOP_DEFCONST : JSOP_DEFLET,
|
||||||
}
|
CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS);
|
||||||
ParseNode* dn = newBindingNode(name, pc->atGlobalLevel());
|
ParseNode* dn = newBindingNode(name, false);
|
||||||
if (!dn)
|
if (!dn)
|
||||||
return null();
|
return null();
|
||||||
handler.setPosition(dn, pos);
|
handler.setPosition(dn, pos);
|
||||||
|
@ -4457,16 +4436,8 @@ Parser<FullParseHandler>::lexicalDeclaration(YieldHandling yieldHandling, bool i
|
||||||
* requires that uninitialized lets throw ReferenceError on use.
|
* requires that uninitialized lets throw ReferenceError on use.
|
||||||
*
|
*
|
||||||
* See 8.1.1.1.6 and the note in 13.2.1.
|
* See 8.1.1.1.6 and the note in 13.2.1.
|
||||||
*
|
|
||||||
* FIXME global-level lets are still considered vars until
|
|
||||||
* other bugs are fixed.
|
|
||||||
*/
|
*/
|
||||||
ParseNodeKind kind = PNK_LET;
|
ParseNodeKind kind = isConst ? PNK_CONST : PNK_LET;
|
||||||
if (pc->atGlobalLevel())
|
|
||||||
kind = isConst ? PNK_GLOBALCONST : PNK_VAR;
|
|
||||||
else if (isConst)
|
|
||||||
kind = PNK_CONST;
|
|
||||||
|
|
||||||
ParseNode* pn = variables(yieldHandling, kind, NotInForInit,
|
ParseNode* pn = variables(yieldHandling, kind, NotInForInit,
|
||||||
nullptr, CurrentLexicalStaticBlock(pc), HoistVars);
|
nullptr, CurrentLexicalStaticBlock(pc), HoistVars);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
|
@ -4532,7 +4503,7 @@ Parser<FullParseHandler>::newBoundImportForCurrentName()
|
||||||
|
|
||||||
importNode->pn_dflags |= PND_CONST | PND_IMPORT;
|
importNode->pn_dflags |= PND_CONST | PND_IMPORT;
|
||||||
BindData<FullParseHandler> data(context);
|
BindData<FullParseHandler> data(context);
|
||||||
data.initLexical(HoistVars, nullptr, JSMSG_TOO_MANY_LOCALS);
|
data.initLexical(HoistVars, JSOP_DEFLET, nullptr, JSMSG_TOO_MANY_LOCALS);
|
||||||
handler.setPosition(importNode, pos());
|
handler.setPosition(importNode, pos());
|
||||||
if (!bindUninitialized(&data, importNode))
|
if (!bindUninitialized(&data, importNode))
|
||||||
return null();
|
return null();
|
||||||
|
@ -5271,6 +5242,9 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
|
||||||
blockObj = StaticBlockObject::create(context);
|
blockObj = StaticBlockObject::create(context);
|
||||||
if (!blockObj)
|
if (!blockObj)
|
||||||
return null();
|
return null();
|
||||||
|
// Initialize the enclosing scope manually for the call to
|
||||||
|
// |variables| below.
|
||||||
|
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
|
||||||
pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
|
pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
|
||||||
nullptr, blockObj, DontHoistVars);
|
nullptr, blockObj, DontHoistVars);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5287,7 +5261,7 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
|
MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
|
||||||
MOZ_ASSERT(!!blockObj == (isForDecl && pn1->isOp(JSOP_NOP)));
|
MOZ_ASSERT(!!blockObj == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST))));
|
||||||
|
|
||||||
// All forms of for-loop (for(;;), for-in, for-of) generate an implicit
|
// All forms of for-loop (for(;;), for-in, for-of) generate an implicit
|
||||||
// block to store any lexical variables declared by the loop-head. We
|
// block to store any lexical variables declared by the loop-head. We
|
||||||
|
@ -6298,7 +6272,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
|
||||||
* scoped, not a property of a new Object instance. This is
|
* scoped, not a property of a new Object instance. This is
|
||||||
* an intentional change that anticipates ECMA Ed. 4.
|
* an intentional change that anticipates ECMA Ed. 4.
|
||||||
*/
|
*/
|
||||||
data.initLexical(HoistVars,
|
data.initLexical(HoistVars, JSOP_DEFLET,
|
||||||
&stmtInfo->staticScope->template as<StaticBlockObject>(),
|
&stmtInfo->staticScope->template as<StaticBlockObject>(),
|
||||||
JSMSG_TOO_MANY_CATCH_VARS);
|
JSMSG_TOO_MANY_CATCH_VARS);
|
||||||
MOZ_ASSERT(data.letData().blockObj);
|
MOZ_ASSERT(data.letData().blockObj);
|
||||||
|
@ -7798,7 +7772,7 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
|
||||||
|
|
||||||
MOZ_ASSERT(pc->innermostScopeStmt() &&
|
MOZ_ASSERT(pc->innermostScopeStmt() &&
|
||||||
pc->innermostScopeStmt()->staticScope == pn->pn_objbox->object);
|
pc->innermostScopeStmt()->staticScope == pn->pn_objbox->object);
|
||||||
data.initLexical(HoistVars,
|
data.initLexical(HoistVars, JSOP_DEFLET,
|
||||||
&pc->innermostScopeStmt()->staticScope->as<StaticBlockObject>(),
|
&pc->innermostScopeStmt()->staticScope->as<StaticBlockObject>(),
|
||||||
JSMSG_ARRAY_INIT_TOO_BIG);
|
JSMSG_ARRAY_INIT_TOO_BIG);
|
||||||
|
|
||||||
|
@ -7916,7 +7890,7 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
|
||||||
* These are lets to tell the bytecode emitter to emit initialization
|
* These are lets to tell the bytecode emitter to emit initialization
|
||||||
* code for the temporal dead zone.
|
* code for the temporal dead zone.
|
||||||
*/
|
*/
|
||||||
ParseNode* lets = handler.newList(PNK_LET, pn3);
|
ParseNode* lets = handler.newDeclarationList(PNK_LET, pn3, JSOP_DEFLET);
|
||||||
if (!lets)
|
if (!lets)
|
||||||
return null();
|
return null();
|
||||||
lets->pn_xflags |= PNX_POPVAR;
|
lets->pn_xflags |= PNX_POPVAR;
|
||||||
|
@ -8227,10 +8201,15 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
|
||||||
|
|
||||||
AutoPushStmtInfoPC stmtInfo(*this, StmtType::BLOCK);
|
AutoPushStmtInfoPC stmtInfo(*this, StmtType::BLOCK);
|
||||||
BindData<ParseHandler> data(context);
|
BindData<ParseHandler> data(context);
|
||||||
|
|
||||||
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
|
||||||
if (!blockObj)
|
if (!blockObj)
|
||||||
return null();
|
return null();
|
||||||
data.initLexical(DontHoistVars, blockObj, JSMSG_TOO_MANY_LOCALS);
|
// Initialize the enclosing scope manually for the call to |bind|
|
||||||
|
// below, which is before the call to |pushLetScope|.
|
||||||
|
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
|
||||||
|
|
||||||
|
data.initLexical(DontHoistVars, JSOP_DEFLET, blockObj, JSMSG_TOO_MANY_LOCALS);
|
||||||
Node decls = handler.newList(PNK_LET, lhs);
|
Node decls = handler.newList(PNK_LET, lhs);
|
||||||
if (!decls)
|
if (!decls)
|
||||||
return null();
|
return null();
|
||||||
|
|
|
@ -301,15 +301,15 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
|
||||||
// if (cond) { function f3() { if (cond) { function f4() { } } } }
|
// if (cond) { function f3() { if (cond) { function f4() { } } } }
|
||||||
//
|
//
|
||||||
bool atBodyLevel() {
|
bool atBodyLevel() {
|
||||||
// 'eval' scripts are always under an invisible lexical scope, but
|
// 'eval' and non-syntactic scripts are always under an invisible
|
||||||
// since it is not syntactic, it should still be considered at body
|
// lexical scope, but since it is not syntactic, it should still be
|
||||||
// level.
|
// considered at body level.
|
||||||
if (sc->staticScope() && sc->staticScope()->is<StaticEvalObject>()) {
|
if (sc->staticScope()->is<StaticEvalObject>()) {
|
||||||
bool bl = !innermostStmt()->enclosing;
|
bool bl = !innermostStmt()->enclosing;
|
||||||
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
MOZ_ASSERT_IF(bl, innermostStmt()->type == StmtType::BLOCK);
|
||||||
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
MOZ_ASSERT_IF(bl, innermostStmt()->staticScope
|
||||||
->template as<StaticBlockObject>()
|
->template as<StaticBlockObject>()
|
||||||
.maybeEnclosingEval() == sc->staticScope());
|
.enclosingStaticScope() == sc->staticScope());
|
||||||
return bl;
|
return bl;
|
||||||
}
|
}
|
||||||
return !innermostStmt();
|
return !innermostStmt();
|
||||||
|
@ -578,9 +578,11 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
|
|
||||||
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
bool maybeParseDirective(Node list, Node pn, bool* cont);
|
||||||
|
|
||||||
// Parse the body of an eval. It is distinguished from global scripts in
|
// Parse the body of an eval.
|
||||||
// that in ES6, per 18.2.1.1 steps 9 and 10, all eval scripts are executed
|
//
|
||||||
// under a fresh lexical scope.
|
// Eval scripts are distinguished from global scripts in that in ES6, per
|
||||||
|
// 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
|
||||||
|
// lexical scope.
|
||||||
Node evalBody();
|
Node evalBody();
|
||||||
|
|
||||||
// Parse a module.
|
// Parse a module.
|
||||||
|
@ -850,7 +852,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
||||||
HandlePropertyName name, Parser<ParseHandler>* parser);
|
HandlePropertyName name, Parser<ParseHandler>* parser);
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
bindVarOrGlobalConst(BindData<ParseHandler>* data,
|
bindVar(BindData<ParseHandler>* data,
|
||||||
HandlePropertyName name, Parser<ParseHandler>* parser);
|
HandlePropertyName name, Parser<ParseHandler>* parser);
|
||||||
|
|
||||||
static Node null() { return ParseHandler::null(); }
|
static Node null() { return ParseHandler::null(); }
|
||||||
|
|
|
@ -349,6 +349,7 @@ class SyntaxParseHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
|
bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
|
||||||
|
void setLexicalDeclarationOp(Node pn, JSOp op) {}
|
||||||
|
|
||||||
void setBeginPosition(Node pn, Node oth) {}
|
void setBeginPosition(Node pn, Node oth) {}
|
||||||
void setBeginPosition(Node pn, uint32_t begin) {}
|
void setBeginPosition(Node pn, uint32_t begin) {}
|
||||||
|
@ -371,8 +372,7 @@ class SyntaxParseHandler
|
||||||
return NodeGeneric;
|
return NodeGeneric;
|
||||||
}
|
}
|
||||||
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
|
||||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||||
kind == PNK_GLOBALCONST);
|
|
||||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||||
}
|
}
|
||||||
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||||
|
@ -380,8 +380,7 @@ class SyntaxParseHandler
|
||||||
return NodeGeneric;
|
return NodeGeneric;
|
||||||
}
|
}
|
||||||
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
|
||||||
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
|
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET);
|
||||||
kind == PNK_GLOBALCONST);
|
|
||||||
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
function qualified_tests(prefix) {
|
function qualified_tests(prefix) {
|
||||||
let scope = evalReturningScope(prefix + "let x = 1");
|
let scope = evalReturningScope(prefix + "var x = 1");
|
||||||
assertEq(scope.x, 1);
|
|
||||||
|
|
||||||
scope = evalReturningScope(prefix + "var x = 1");
|
|
||||||
assertEq(scope.x, 1);
|
|
||||||
|
|
||||||
scope = evalReturningScope(prefix + "const x = 1");
|
|
||||||
assertEq(scope.x, 1);
|
assertEq(scope.x, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3470,20 +3470,28 @@ IsFunctionCloneable(HandleFunction fun)
|
||||||
// If a function was compiled to be lexically nested inside some other
|
// If a function was compiled to be lexically nested inside some other
|
||||||
// script, we cannot clone it without breaking the compiler's assumptions.
|
// script, we cannot clone it without breaking the compiler's assumptions.
|
||||||
if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) {
|
if (JSObject* scope = fun->nonLazyScript()->enclosingStaticScope()) {
|
||||||
// If the script already deals with a non-syntactic scope, we can clone
|
|
||||||
// it.
|
|
||||||
if (scope->is<StaticNonSyntacticScopeObjects>())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If the script is directly under the global scope, we can clone it.
|
// If the script is directly under the global scope, we can clone it.
|
||||||
if (IsStaticGlobalLexicalScope(scope))
|
if (IsStaticGlobalLexicalScope(scope))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If the script is an indirect eval that is immediately scoped under
|
// 'eval' and non-syntactic scopes are always scoped immediately under
|
||||||
// the global, we can clone it.
|
// a non-extensible lexical scope.
|
||||||
if (scope->is<StaticBlockObject>()) {
|
if (scope->is<StaticBlockObject>()) {
|
||||||
if (StaticEvalObject* staticEval = scope->as<StaticBlockObject>().maybeEnclosingEval())
|
StaticBlockObject& block = scope->as<StaticBlockObject>();
|
||||||
return !staticEval->isDirect();
|
if (block.needsClone())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JSObject* enclosing = block.enclosingStaticScope();
|
||||||
|
|
||||||
|
// If the script is an indirect eval that is immediately scoped
|
||||||
|
// under the global, we can clone it.
|
||||||
|
if (enclosing->is<StaticEvalObject>())
|
||||||
|
return !enclosing->as<StaticEvalObject>().isDirect();
|
||||||
|
|
||||||
|
// If the script already deals with a non-syntactic scope, we can
|
||||||
|
// clone it.
|
||||||
|
if (enclosing->is<StaticNonSyntacticScopeObjects>())
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any other enclosing static scope (e.g., function, block) cannot be
|
// Any other enclosing static scope (e.g., function, block) cannot be
|
||||||
|
|
|
@ -590,8 +590,9 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleObject enclosingScope, Han
|
||||||
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
|
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
|
||||||
if (uint16_t(flagsword) & JSFunction::EXTENDED)
|
if (uint16_t(flagsword) & JSFunction::EXTENDED)
|
||||||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||||
|
RootedObject globalLexical(cx, &cx->global()->lexicalScope());
|
||||||
fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
|
fun = NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED,
|
||||||
/* enclosingDynamicScope = */ nullptr, nullptr, proto,
|
globalLexical, nullptr, proto,
|
||||||
allocKind, TenuredObject);
|
allocKind, TenuredObject);
|
||||||
if (!fun)
|
if (!fun)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -990,10 +990,14 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
|
||||||
uint32_t enclosingStaticScopeIndex = 0;
|
uint32_t enclosingStaticScopeIndex = 0;
|
||||||
if (mode == XDR_ENCODE) {
|
if (mode == XDR_ENCODE) {
|
||||||
NestedScopeObject& scope = (*objp)->as<NestedScopeObject>();
|
NestedScopeObject& scope = (*objp)->as<NestedScopeObject>();
|
||||||
if (NestedScopeObject* enclosing = scope.enclosingNestedScope())
|
if (NestedScopeObject* enclosing = scope.enclosingNestedScope()) {
|
||||||
enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
|
if (IsStaticGlobalLexicalScope(enclosing))
|
||||||
else
|
|
||||||
enclosingStaticScopeIndex = UINT32_MAX;
|
enclosingStaticScopeIndex = UINT32_MAX;
|
||||||
|
else
|
||||||
|
enclosingStaticScopeIndex = FindScopeObjectIndex(script, *enclosing);
|
||||||
|
} else {
|
||||||
|
enclosingStaticScopeIndex = UINT32_MAX;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!xdr->codeUint32(&enclosingStaticScopeIndex))
|
if (!xdr->codeUint32(&enclosingStaticScopeIndex))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1056,8 +1060,12 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
|
||||||
MOZ_ASSERT_IF(ssi.done() || ssi.type() != StaticScopeIter<NoGC>::Function, !fun);
|
MOZ_ASSERT_IF(ssi.done() || ssi.type() != StaticScopeIter<NoGC>::Function, !fun);
|
||||||
funEnclosingScopeIndex = UINT32_MAX;
|
funEnclosingScopeIndex = UINT32_MAX;
|
||||||
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
|
} else if (ssi.type() == StaticScopeIter<NoGC>::Block) {
|
||||||
|
if (ssi.block().isGlobal()) {
|
||||||
|
funEnclosingScopeIndex = UINT32_MAX;
|
||||||
|
} else {
|
||||||
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
|
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.block());
|
||||||
MOZ_ASSERT(funEnclosingScopeIndex < i);
|
MOZ_ASSERT(funEnclosingScopeIndex < i);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith());
|
funEnclosingScopeIndex = FindScopeObjectIndex(script, ssi.staticWith());
|
||||||
MOZ_ASSERT(funEnclosingScopeIndex < i);
|
MOZ_ASSERT(funEnclosingScopeIndex < i);
|
||||||
|
@ -3295,10 +3303,16 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
|
||||||
Rooted<NestedScopeObject*> innerBlock(cx, &obj->as<NestedScopeObject>());
|
Rooted<NestedScopeObject*> innerBlock(cx, &obj->as<NestedScopeObject>());
|
||||||
|
|
||||||
RootedObject enclosingScope(cx);
|
RootedObject enclosingScope(cx);
|
||||||
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope())
|
if (NestedScopeObject* enclosingBlock = innerBlock->enclosingNestedScope()) {
|
||||||
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
|
if (IsStaticGlobalLexicalScope(enclosingBlock)) {
|
||||||
else
|
MOZ_ASSERT(IsStaticGlobalLexicalScope(scriptStaticScope));
|
||||||
enclosingScope = scriptStaticScope;
|
enclosingScope = scriptStaticScope;
|
||||||
|
} else {
|
||||||
|
enclosingScope = objects[FindScopeObjectIndex(src, *enclosingBlock)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enclosingScope = scriptStaticScope;
|
||||||
|
}
|
||||||
|
|
||||||
clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
|
clone = CloneNestedScopeObject(cx, enclosingScope, innerBlock);
|
||||||
} else if (obj->is<JSFunction>()) {
|
} else if (obj->is<JSFunction>()) {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "jsiter.h"
|
#include "jsiter.h"
|
||||||
#include "jspubtd.h"
|
#include "jspubtd.h"
|
||||||
|
|
||||||
|
#include "frontend/ParseNode.h"
|
||||||
|
|
||||||
#include "vm/Stack.h"
|
#include "vm/Stack.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
|
@ -214,15 +214,9 @@
|
||||||
* Stack: v1, v2 => v1, v2, v1, v2
|
* Stack: v1, v2 => v1, v2, v1, v2
|
||||||
*/ \
|
*/ \
|
||||||
macro(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, JOF_BYTE) \
|
macro(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, JOF_BYTE) \
|
||||||
/*
|
\
|
||||||
* Defines a readonly property on the frame's current variables-object (the
|
macro(JSOP_UNUSED14, 14, "unused14", NULL, 1, 0, 0, JOF_BYTE) \
|
||||||
* scope object on the scope chain designated to receive new variables).
|
\
|
||||||
* Category: Variables and Scopes
|
|
||||||
* Type: Variables
|
|
||||||
* Operands: uint32_t nameIndex
|
|
||||||
* Stack: val => val
|
|
||||||
*/ \
|
|
||||||
macro(JSOP_SETCONST, 14, "setconst", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET) \
|
|
||||||
/*
|
/*
|
||||||
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
|
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
|
||||||
* the result of the operation applied to the two operands, converting
|
* the result of the operation applied to the two operands, converting
|
||||||
|
@ -1295,14 +1289,10 @@
|
||||||
* Stack: =>
|
* Stack: =>
|
||||||
*/ \
|
*/ \
|
||||||
macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \
|
macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \
|
||||||
/*
|
/* Defines the new constant binding on global lexical scope.
|
||||||
* Defines the new binding on the frame's current variables-object (the
|
|
||||||
* scope object on the scope chain designated to receive new variables) with
|
|
||||||
* 'READONLY' attribute. The binding is *not* JSPROP_PERMANENT. See bug
|
|
||||||
* 1019181 for the reason.
|
|
||||||
*
|
*
|
||||||
* This is used for global scripts and also in some cases for function
|
* Throws if a binding with the same name already exists on the scope, or
|
||||||
* scripts where use of dynamic scoping inhibits optimization.
|
* if a var binding with the same name exists on the global.
|
||||||
* Category: Variables and Scopes
|
* Category: Variables and Scopes
|
||||||
* Type: Variables
|
* Type: Variables
|
||||||
* Operands: uint32_t nameIndex
|
* Operands: uint32_t nameIndex
|
||||||
|
@ -1313,6 +1303,9 @@
|
||||||
* Defines the new binding on the frame's current variables-object (the
|
* Defines the new binding on the frame's current variables-object (the
|
||||||
* scope object on the scope chain designated to receive new variables).
|
* scope object on the scope chain designated to receive new variables).
|
||||||
*
|
*
|
||||||
|
* Throws if the current variables-object is the global object and a
|
||||||
|
* binding with the same name exists on the global lexical scope.
|
||||||
|
*
|
||||||
* This is used for global scripts and also in some cases for function
|
* This is used for global scripts and also in some cases for function
|
||||||
* scripts where use of dynamic scoping inhibits optimization.
|
* scripts where use of dynamic scoping inhibits optimization.
|
||||||
* Category: Variables and Scopes
|
* Category: Variables and Scopes
|
||||||
|
@ -1655,8 +1648,27 @@
|
||||||
*/ \
|
*/ \
|
||||||
macro(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, JOF_REGEXP) \
|
macro(JSOP_REGEXP, 160,"regexp", NULL, 5, 0, 1, JOF_REGEXP) \
|
||||||
\
|
\
|
||||||
macro(JSOP_UNUSED161, 161,"unused161", NULL, 1, 0, 0, JOF_BYTE) \
|
/*
|
||||||
macro(JSOP_UNUSED162, 162,"unused162", NULL, 1, 0, 0, JOF_BYTE) \
|
* Initializes an uninitialized global lexical binding with the top of
|
||||||
|
* stack value.
|
||||||
|
* Category: Variables and Scopes
|
||||||
|
* Type: Free Variables
|
||||||
|
* Operands: uint32_t nameIndex
|
||||||
|
* Stack: val => val
|
||||||
|
*/ \
|
||||||
|
macro(JSOP_INITGLEXICAL, 161,"initglexical", NULL, 5, 1, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) \
|
||||||
|
\
|
||||||
|
/* Defines the new mutable binding on global lexical scope.
|
||||||
|
*
|
||||||
|
* Throws if a binding with the same name already exists on the scope, or
|
||||||
|
* if a var binding with the same name exists on the global.
|
||||||
|
* Category: Variables and Scopes
|
||||||
|
* Type: Variables
|
||||||
|
* Operands: uint32_t nameIndex
|
||||||
|
* Stack: =>
|
||||||
|
*/ \
|
||||||
|
macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \
|
||||||
|
\
|
||||||
macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 0, JOF_BYTE) \
|
macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 0, JOF_BYTE) \
|
||||||
macro(JSOP_UNUSED164, 164,"unused164", NULL, 1, 0, 0, JOF_BYTE) \
|
macro(JSOP_UNUSED164, 164,"unused164", NULL, 1, 0, 0, JOF_BYTE) \
|
||||||
macro(JSOP_UNUSED165, 165,"unused165", NULL, 1, 0, 0, JOF_BYTE) \
|
macro(JSOP_UNUSED165, 165,"unused165", NULL, 1, 0, 0, JOF_BYTE) \
|
||||||
|
|
|
@ -1038,11 +1038,13 @@ js::XDRStaticBlockObject(XDRState<mode>* xdr, HandleObject enclosingScope,
|
||||||
|
|
||||||
Rooted<StaticBlockObject*> obj(cx);
|
Rooted<StaticBlockObject*> obj(cx);
|
||||||
uint32_t count = 0, offset = 0;
|
uint32_t count = 0, offset = 0;
|
||||||
|
uint8_t extensible = 0;
|
||||||
|
|
||||||
if (mode == XDR_ENCODE) {
|
if (mode == XDR_ENCODE) {
|
||||||
obj = objp;
|
obj = objp;
|
||||||
count = obj->numVariables();
|
count = obj->numVariables();
|
||||||
offset = obj->localOffset();
|
offset = obj->localOffset();
|
||||||
|
extensible = obj->isExtensible() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == XDR_DECODE) {
|
if (mode == XDR_DECODE) {
|
||||||
|
@ -1057,6 +1059,8 @@ js::XDRStaticBlockObject(XDRState<mode>* xdr, HandleObject enclosingScope,
|
||||||
return false;
|
return false;
|
||||||
if (!xdr->codeUint32(&offset))
|
if (!xdr->codeUint32(&offset))
|
||||||
return false;
|
return false;
|
||||||
|
if (!xdr->codeUint8(&extensible))
|
||||||
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XDR the block object's properties. We know that there are 'count'
|
* XDR the block object's properties. We know that there are 'count'
|
||||||
|
@ -1090,6 +1094,11 @@ js::XDRStaticBlockObject(XDRState<mode>* xdr, HandleObject enclosingScope,
|
||||||
bool aliased = !!(propFlags >> 1);
|
bool aliased = !!(propFlags >> 1);
|
||||||
obj->setAliased(i, aliased);
|
obj->setAliased(i, aliased);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!extensible) {
|
||||||
|
if (!obj->makeNonExtensible(cx))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
|
Rooted<ShapeVector> shapes(cx, ShapeVector(cx));
|
||||||
if (!shapes.growBy(count))
|
if (!shapes.growBy(count))
|
||||||
|
|
|
@ -661,14 +661,6 @@ class StaticBlockObject : public BlockObject
|
||||||
*/
|
*/
|
||||||
inline StaticBlockObject* enclosingBlock() const;
|
inline StaticBlockObject* enclosingBlock() const;
|
||||||
|
|
||||||
StaticEvalObject* maybeEnclosingEval() const {
|
|
||||||
if (JSObject* enclosing = enclosingStaticScope()) {
|
|
||||||
if (enclosing->is<StaticEvalObject>())
|
|
||||||
return &enclosing->as<StaticEvalObject>();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t localOffset() {
|
uint32_t localOffset() {
|
||||||
return getReservedSlot(LOCAL_OFFSET_SLOT).toPrivateUint32();
|
return getReservedSlot(LOCAL_OFFSET_SLOT).toPrivateUint32();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче