Issue #2173 - Add accessors to LexicalScopeNode

Based-on: m-c 1479659/7
This commit is contained in:
Martok 2023-04-02 00:45:27 +02:00 • committed by roytam1
commit 3bd300e263
12 changed files with 180 additions and 171 deletions

View file

@ -2380,8 +2380,8 @@ ASTSerializer::tryStatement(TernaryNode* tryNode, MutableHandleValue dst)
if (!guarded.reserve(catchList->count())) if (!guarded.reserve(catchList->count()))
return false; return false;
for (ParseNode* catchScope : catchList->contents()) { for (ParseNode* catchNode : catchList->contents()) {
MOZ_ASSERT(catchScope->isKind(PNK_LEXICALSCOPE)); LexicalScopeNode* catchScope = &catchNode->as<LexicalScopeNode>();
RootedValue clause(cx); RootedValue clause(cx);
bool isGuarded; bool isGuarded;
if (!catchClause(&catchScope->scopeBody()->as<TernaryNode>(), &isGuarded, &clause)) if (!catchClause(&catchScope->scopeBody()->as<TernaryNode>(), &isGuarded, &clause))
@ -2480,7 +2480,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
return builder.emptyStatement(&pn->pn_pos, dst); return builder.emptyStatement(&pn->pn_pos, dst);
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
pn = pn->scopeBody(); pn = pn->as<LexicalScopeNode>().scopeBody();
if (!pn->isKind(PNK_STATEMENTLIST)) if (!pn->isKind(PNK_STATEMENTLIST))
return statement(pn, dst); return statement(pn, dst);
MOZ_FALLTHROUGH; MOZ_FALLTHROUGH;
@ -2578,8 +2578,9 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) { if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) {
RootedValue var(cx); RootedValue var(cx);
if (initNode->isKind(PNK_LEXICALSCOPE)) { if (initNode->is<LexicalScopeNode>()) {
if (!variableDeclaration(&initNode->scopeBody()->as<ListNode>(), true, &var)) LexicalScopeNode* scopeNode = &initNode->as<LexicalScopeNode>();
if (!variableDeclaration(&scopeNode->scopeBody()->as<ListNode>(), true, &var))
return false; return false;
} else if (!initNode->isKind(PNK_VAR) && } else if (!initNode->isKind(PNK_VAR) &&
!initNode->isKind(PNK_LET) && !initNode->isKind(PNK_LET) &&
@ -2810,8 +2811,8 @@ ASTSerializer::comprehensionBlock(ForNode* forNode, MutableHandleValue dst)
bool isForOf = in->isKind(PNK_FOROF); bool isForOf = in->isKind(PNK_FOROF);
ListNode* decl; ListNode* decl;
if (in->kid1()->isKind(PNK_LEXICALSCOPE)) if (in->kid1()->is<LexicalScopeNode>())
decl = &in->kid1()->scopeBody()->as<ListNode>(); decl = &in->kid1()->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
else else
decl = &in->kid1()->as<ListNode>(); decl = &in->kid1()->as<ListNode>();
MOZ_ASSERT(decl->count() == 1); MOZ_ASSERT(decl->count() == 1);
@ -2840,8 +2841,8 @@ ASTSerializer::comprehension(ParseNode* pn, MutableHandleValue dst)
// 1. The kind that was in ES4 for a while: [z for (x in y)] // 1. The kind that was in ES4 for a while: [z for (x in y)]
// 2. The kind that was in ES6 for a while: [for (x of y) z] // 2. The kind that was in ES6 for a while: [for (x of y) z]
// They have slightly different parse trees and scoping. // They have slightly different parse trees and scoping.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE); bool isLegacy = pn->is<LexicalScopeNode>();
ParseNode* next = isLegacy ? pn->scopeBody() : pn; ParseNode* next = isLegacy ? pn->as<LexicalScopeNode>().scopeBody() : pn;
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR)); LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx); NodeVector blocks(cx);
@ -2886,8 +2887,8 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
// Just as there are two kinds of array comprehension (see // Just as there are two kinds of array comprehension (see
// ASTSerializer::comprehension), there are legacy and modern generator // ASTSerializer::comprehension), there are legacy and modern generator
// expression. // expression.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE); bool isLegacy = pn->is<LexicalScopeNode>();
ParseNode* next = isLegacy ? pn->scopeBody() : pn; ParseNode* next = isLegacy ? pn->as<LexicalScopeNode>().scopeBody() : pn;
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR)); LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx); NodeVector blocks(cx);
@ -3653,29 +3654,29 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
MutableHandleValue body, MutableHandleValue rest) MutableHandleValue body, MutableHandleValue rest)
{ {
ListNode* argsList; ListNode* argsList;
ParseNode* pnbody; ParseNode* bodyNode;
/* Extract the args and body separately. */ /* Extract the args and body separately. */
if (pn->isKind(PNK_PARAMSBODY)) { if (pn->isKind(PNK_PARAMSBODY)) {
argsList = &pn->as<ListNode>(); argsList = &pn->as<ListNode>();
pnbody = argsList->last(); bodyNode = argsList->last();
} else { } else {
argsList = nullptr; argsList = nullptr;
pnbody = pn; bodyNode = pn;
} }
if (pnbody->isKind(PNK_LEXICALSCOPE)) if (bodyNode->is<LexicalScopeNode>())
pnbody = pnbody->scopeBody(); bodyNode = bodyNode->as<LexicalScopeNode>().scopeBody();
/* Serialize the arguments and body. */ /* Serialize the arguments and body. */
switch (pnbody->getKind()) { switch (bodyNode->getKind()) {
case PNK_RETURN: /* expression closure, no destructured args */ case PNK_RETURN: /* expression closure, no destructured args */
return functionArgs(pn, argsList, args, defaults, rest) && return functionArgs(pn, argsList, args, defaults, rest) &&
expression(pnbody->as<UnaryNode>().kid(), body); expression(bodyNode->as<UnaryNode>().kid(), body);
case PNK_STATEMENTLIST: /* statement closure */ case PNK_STATEMENTLIST: /* statement closure */
{ {
ParseNode* firstNode = pnbody->as<ListNode>().head(); ParseNode* firstNode = bodyNode->as<ListNode>().head();
// Skip over initial yield in generator. // Skip over initial yield in generator.
if (firstNode && firstNode->isKind(PNK_INITIALYIELD)) { if (firstNode && firstNode->isKind(PNK_INITIALYIELD)) {
@ -3692,7 +3693,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
} }
return functionArgs(pn, argsList, args, defaults, rest) && return functionArgs(pn, argsList, args, defaults, rest) &&
functionBody(firstNode, &pnbody->pn_pos, body); functionBody(firstNode, &bodyNode->pn_pos, body);
} }
default: default:

View file

@ -592,8 +592,8 @@ BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top)
* instruction. nextpn is often a block, in which case the next * instruction. nextpn is often a block, in which case the next
* instruction typically comes from the first statement inside. * instruction typically comes from the first statement inside.
*/ */
if (nextpn->isKind(PNK_LEXICALSCOPE)) if (nextpn->is<LexicalScopeNode>())
nextpn = nextpn->scopeBody(); nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
if (nextpn->isKind(PNK_STATEMENTLIST)) { if (nextpn->isKind(PNK_STATEMENTLIST)) {
if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) { if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
nextpn = firstStatement; nextpn = firstStatement;
@ -612,8 +612,8 @@ BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
{ {
if (nextpn) { if (nextpn) {
/* Update the line number, as for LOOPHEAD. */ /* Update the line number, as for LOOPHEAD. */
if (nextpn->isKind(PNK_LEXICALSCOPE)) if (nextpn->is<LexicalScopeNode>())
nextpn = nextpn->scopeBody(); nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
if (nextpn->isKind(PNK_STATEMENTLIST)) { if (nextpn->isKind(PNK_STATEMENTLIST)) {
if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) { if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
nextpn = firstStatement; nextpn = firstStatement;
@ -1487,7 +1487,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
MOZ_ASSERT(pn->isArity(PN_SCOPE)); MOZ_ASSERT(pn->isArity(PN_SCOPE));
return checkSideEffects(pn->scopeBody(), answer); return checkSideEffects(pn->as<LexicalScopeNode>().scopeBody(), answer);
// We could methodically check every interpolated expression, but it's // We could methodically check every interpolated expression, but it's
// probably not worth the trouble. Treat template strings as effect-free // probably not worth the trouble. Treat template strings as effect-free
@ -2080,8 +2080,7 @@ BytecodeEmitter::emitNumberOp(double dval)
MOZ_NEVER_INLINE bool MOZ_NEVER_INLINE bool
BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt) BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt)
{ {
ParseNode& lexical = switchStmt->lexicalForCaseList(); LexicalScopeNode& lexical = switchStmt->lexicalForCaseList();
MOZ_ASSERT(lexical.isKind(PNK_LEXICALSCOPE));
ListNode* cases = &lexical.scopeBody()->as<ListNode>(); ListNode* cases = &lexical.scopeBody()->as<ListNode>();
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST)); MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
@ -2343,20 +2342,21 @@ BytecodeEmitter::emitScript(ParseNode* body)
setFunctionBodyEndPos(body->pn_pos); setFunctionBodyEndPos(body->pn_pos);
if (sc->isEvalContext() && !sc->strict() && if (sc->isEvalContext() && !sc->strict() &&
body->isKind(PNK_LEXICALSCOPE) && !body->isEmptyScope()) body->is<LexicalScopeNode>() && !body->as<LexicalScopeNode>().isEmptyScope())
{ {
// Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is // Sloppy eval scripts may need to emit DEFFUNs in the prologue. If there is
// an immediately enclosed lexical scope, we need to enter the lexical // an immediately enclosed lexical scope, we need to enter the lexical
// scope in the prologue for the DEFFUNs to pick up the right // scope in the prologue for the DEFFUNs to pick up the right
// environment chain. // environment chain.
EmitterScope lexicalEmitterScope(this); EmitterScope lexicalEmitterScope(this);
LexicalScopeNode* scope = &body->as<LexicalScopeNode>();
switchToPrologue(); switchToPrologue();
if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, body->scopeBindings())) if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, scope->scopeBindings()))
return false; return false;
switchToMain(); switchToMain();
if (!emitLexicalScopeBody(body->scopeBody())) if (!emitLexicalScopeBody(scope->scopeBody()))
return false; return false;
if (!lexicalEmitterScope.leave(this)) if (!lexicalEmitterScope.leave(this))
@ -4272,13 +4272,13 @@ BytecodeEmitter::emitTry(TernaryNode* tryNode)
// code if appropriate, and is also used for the catch-all trynote for // code if appropriate, and is also used for the catch-all trynote for
// capturing exceptions thrown from catch{} blocks. // capturing exceptions thrown from catch{} blocks.
// //
for (ParseNode* lexicalScope : catchList->as<ListNode>().contents()) { for (ParseNode* scopeNode : catchList->as<ListNode>().contents()) {
LexicalScopeNode* catchScope = &scopeNode->as<LexicalScopeNode>();
if (!tryCatch.emitCatch()) if (!tryCatch.emitCatch())
return false; return false;
// Emit the lexical scope and catch body. // Emit the lexical scope and catch body.
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); if (!emitTree(catchScope))
if (!emitTree(lexicalScope))
return false; return false;
} }
} }
@ -4387,14 +4387,12 @@ BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLi
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
// the comment on emitSwitch. // the comment on emitSwitch.
MOZ_NEVER_INLINE bool MOZ_NEVER_INLINE bool
BytecodeEmitter::emitLexicalScope(ParseNode* pn) BytecodeEmitter::emitLexicalScope(LexicalScopeNode* lexicalScope)
{ {
MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
TDZCheckCache tdzCache(this); TDZCheckCache tdzCache(this);
ParseNode* body = pn->scopeBody(); ParseNode* body = lexicalScope->scopeBody();
if (pn->isEmptyScope()) if (lexicalScope->isEmptyScope())
return emitLexicalScopeBody(body); return emitLexicalScopeBody(body);
// Update line number notes before emitting TDZ poison in // Update line number notes before emitting TDZ poison in
@ -4431,7 +4429,7 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn)
} else } else
kind = ScopeKind::Lexical; kind = ScopeKind::Lexical;
if (!emitterScope.enterLexical(this, kind, pn->scopeBindings())) if (!emitterScope.enterLexical(this, kind, lexicalScope->scopeBindings()))
return false; return false;
if (body->isKind(PNK_FOR)) { if (body->isKind(PNK_FOR)) {
@ -5310,7 +5308,7 @@ BytecodeEmitter::emitComprehensionForInOrOfVariables(ParseNode* pn, bool* lexica
// for-in/of loops, and we haven't extended these requirements to // for-in/of loops, and we haven't extended these requirements to
// comprehension syntax. // comprehension syntax.
*lexicalScope = pn->isKind(PNK_LEXICALSCOPE); *lexicalScope = pn->is<LexicalScopeNode>();
if (*lexicalScope) { if (*lexicalScope) {
// This is initially-ES7-tracked syntax, now with considerably murkier // This is initially-ES7-tracked syntax, now with considerably murkier
// outlook. The scope work is done by the caller by instantiating an // outlook. The scope work is done by the caller by instantiating an
@ -5369,9 +5367,10 @@ BytecodeEmitter::emitComprehensionForOf(ForNode* forNode)
Maybe<EmitterScope> emitterScope; Maybe<EmitterScope> emitterScope;
ParseNode* loopVariableName; ParseNode* loopVariableName;
if (lexicalScope) { if (lexicalScope) {
loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->scopeBody()->as<ListNode>()); LexicalScopeNode* scopeNode = &loopDecl->as<LexicalScopeNode>();
loopVariableName = parser->handler.singleBindingFromDeclaration(&scopeNode->scopeBody()->as<ListNode>());
emitterScope.emplace(this); emitterScope.emplace(this);
if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings())) if (!emitterScope->enterComprehensionFor(this, scopeNode->scopeBindings()))
return false; return false;
} else { } else {
loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->as<ListNode>()); loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->as<ListNode>());
@ -5515,7 +5514,8 @@ BytecodeEmitter::emitComprehensionForIn(ForNode* forNode)
Maybe<EmitterScope> emitterScope; Maybe<EmitterScope> emitterScope;
if (lexicalScope) { if (lexicalScope) {
emitterScope.emplace(this); emitterScope.emplace(this);
if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings())) LexicalScopeNode* scopeNode = &loopDecl->as<LexicalScopeNode>();
if (!emitterScope->enterComprehensionFor(this, scopeNode->scopeBindings()))
return false; return false;
} }
@ -8945,7 +8945,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break; break;
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
if (!emitLexicalScope(pn)) if (!emitLexicalScope(&pn->as<LexicalScopeNode>()))
return false; return false;
break; break;

View file

@ -588,7 +588,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitWith(BinaryNode* withNode); MOZ_MUST_USE bool emitWith(BinaryNode* withNode);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(const LabeledStatement* pn); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(const LabeledStatement* pn);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(ParseNode* pn); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(LexicalScopeNode* lexicalScope);
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body, MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
EmitLineNumberNote emitLineNote = EMIT_LINENOTE); EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt);

View file

@ -207,8 +207,8 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
if (tryNode->kid2()) { if (tryNode->kid2()) {
if (ListNode* catchList = &tryNode->kid2()->as<ListNode>()) { if (ListNode* catchList = &tryNode->kid2()->as<ListNode>()) {
for (ParseNode* lexicalScope : catchList->contents()) { for (ParseNode* scopeNode : catchList->contents()) {
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); LexicalScopeNode* lexicalScope = &scopeNode->as<LexicalScopeNode>();
TernaryNode* catchNode = &lexicalScope->scopeBody()->as<TernaryNode>(); TernaryNode* catchNode = &lexicalScope->scopeBody()->as<TernaryNode>();
MOZ_ASSERT(catchNode->isKind(PNK_CATCH)); MOZ_ASSERT(catchNode->isKind(PNK_CATCH));
@ -286,14 +286,14 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
} }
case PNK_LEXICALSCOPE: { case PNK_LEXICALSCOPE: {
MOZ_ASSERT(node->isArity(PN_SCOPE)); LexicalScopeNode* scope = &node->as<LexicalScopeNode>();
ParseNode* expr = node->scopeBody(); ParseNode* expr = scope->scopeBody();
if (expr->isKind(PNK_FOR) || expr->isKind(PNK_FUNCTION)) if (expr->isKind(PNK_FOR) || expr->isKind(PNK_FUNCTION))
return ContainsHoistedDeclaration(cx, expr, result); return ContainsHoistedDeclaration(cx, expr, result);
MOZ_ASSERT(expr->isKind(PNK_STATEMENTLIST)); MOZ_ASSERT(expr->isKind(PNK_STATEMENTLIST));
return ListContainsHoistedDeclaration(cx, &node->scopeBody()->as<ListNode>(), result); return ListContainsHoistedDeclaration(cx, &scope->scopeBody()->as<ListNode>(), result);
} }
// List nodes with all non-null children. // List nodes with all non-null children.
@ -1966,11 +1966,12 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_DOT: case PNK_DOT:
return FoldDottedProperty(cx, &pn->as<PropertyAccessBase>(), parser, inGenexpLambda); return FoldDottedProperty(cx, &pn->as<PropertyAccessBase>(), parser, inGenexpLambda);
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE: {
MOZ_ASSERT(pn->isArity(PN_SCOPE)); LexicalScopeNode* node = &pn->as<LexicalScopeNode>();
if (!pn->scopeBody()) if (!node->scopeBody())
return true; return true;
return Fold(cx, &pn->pn_u.scope.body, parser, inGenexpLambda); return Fold(cx, node->unsafeScopeBodyReference(), parser, inGenexpLambda);
}
case PNK_NAME: case PNK_NAME:
return FoldName(cx, &pn->as<NameNode>(), parser, inGenexpLambda); return FoldName(cx, &pn->as<NameNode>(), parser, inGenexpLambda);

View file

@ -648,7 +648,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
} }
SwitchStatementType newSwitchStatement(uint32_t begin, Node discriminant, SwitchStatementType newSwitchStatement(uint32_t begin, Node discriminant,
Node lexicalForCaseList, bool hasDefault) LexicalScopeNodeType lexicalForCaseList, bool hasDefault)
{ {
return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList, hasDefault); return new_<SwitchStatement>(begin, discriminant, lexicalForCaseList, hasDefault);
} }
@ -714,7 +714,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return new_<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin, end); return new_<OptionalPropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
} }
inline MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, ParseNode* lexicalScope, inline MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, LexicalScopeNodeType lexicalScope,
ParseNode* catchBinding, ParseNode* catchGuard, ParseNode* catchBinding, ParseNode* catchGuard,
ParseNode* catchBody); ParseNode* catchBody);
@ -759,7 +759,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
void addFunctionFormalParameter(CodeNodeType funNode, Node argpn) { void addFunctionFormalParameter(CodeNodeType funNode, Node argpn) {
addList(/* list = */ funNode->body(), /* child = */ argpn); addList(/* list = */ funNode->body(), /* child = */ argpn);
} }
void setFunctionBody(CodeNodeType funNode, Node body) { void setFunctionBody(CodeNodeType funNode, LexicalScopeNodeType body) {
MOZ_ASSERT(funNode->body()->isKind(PNK_PARAMSBODY)); MOZ_ASSERT(funNode->body()->isKind(PNK_PARAMSBODY));
addList(/* list = */ funNode->body(), /* child = */ body); addList(/* list = */ funNode->body(), /* child = */ body);
} }
@ -772,7 +772,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return new_<BinaryNode>(PNK_NEW, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args); return new_<BinaryNode>(PNK_NEW, JSOP_NEW, TokenPos(begin, args->pn_pos.end), ctor, args);
} }
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) { LexicalScopeNodeType newLexicalScope(LexicalScope::Data* bindings, Node body) {
return new_<LexicalScopeNode>(bindings, body); return new_<LexicalScopeNode>(bindings, body);
} }
@ -1002,7 +1002,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
}; };
inline bool inline bool
FullParseHandler::addCatchBlock(ListNodeType catchList, ParseNode* lexicalScope, FullParseHandler::addCatchBlock(ListNodeType catchList, LexicalScopeNodeType lexicalScope,
ParseNode* catchBinding, ParseNode* catchGuard, ParseNode* catchBody) ParseNode* catchBinding, ParseNode* catchGuard, ParseNode* catchBody)
{ {
ParseNode* catchpn = newTernary(PNK_CATCH, catchBinding, catchGuard, catchBody); ParseNode* catchpn = newTernary(PNK_CATCH, catchBinding, catchGuard, catchBody);

View file

@ -828,10 +828,10 @@ class NameResolver
case PNK_CATCHLIST: { case PNK_CATCHLIST: {
ListNode* catchList = &cur->as<ListNode>(); ListNode* catchList = &cur->as<ListNode>();
for (ParseNode* catchNode : catchList->contents()) { for (ParseNode* catchNode : catchList->contents()) {
MOZ_ASSERT(catchNode->isKind(PNK_LEXICALSCOPE)); LexicalScopeNode* catchScope = &catchNode->as<LexicalScopeNode>();
MOZ_ASSERT(catchNode->scopeBody()->isKind(PNK_CATCH)); MOZ_ASSERT(catchScope->scopeBody()->isKind(PNK_CATCH));
MOZ_ASSERT(catchNode->scopeBody()->isArity(PN_TERNARY)); MOZ_ASSERT(catchScope->scopeBody()->isArity(PN_TERNARY));
if (!resolve(catchNode->scopeBody(), prefix)) if (!resolve(catchScope->scopeBody(), prefix))
return false; return false;
} }
break; break;
@ -862,8 +862,7 @@ class NameResolver
break; break;
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
MOZ_ASSERT(cur->isArity(PN_SCOPE)); if (!resolve(cur->as<LexicalScopeNode>().scopeBody(), prefix))
if (!resolve(cur->scopeBody(), prefix))
return false; return false;
break; break;

View file

@ -96,8 +96,6 @@ enum class PushResult { Recyclable, CleanUpLater };
static PushResult static PushResult
PushCodeNodeChildren(CodeNode* node, NodeStack* stack) PushCodeNodeChildren(CodeNode* node, NodeStack* stack)
{ {
MOZ_ASSERT(node->isArity(PN_CODE));
/* /*
* Function nodes are linked into the function box tree, and may appear * Function nodes are linked into the function box tree, and may appear
* on method lists. Both of those lists are singly-linked, so trying to * on method lists. Both of those lists are singly-linked, so trying to
@ -133,10 +131,8 @@ PushNameNodeChildren(NameNode* node, NodeStack* stack)
} }
static PushResult static PushResult
PushScopeNodeChildren(ParseNode* node, NodeStack* stack) PushScopeNodeChildren(LexicalScopeNode* node, NodeStack* stack)
{ {
MOZ_ASSERT(node->isArity(PN_SCOPE));
if (node->scopeBody()) if (node->scopeBody())
stack->push(node->scopeBody()); stack->push(node->scopeBody());
node->setScopeBody(nullptr); node->setScopeBody(nullptr);
@ -146,7 +142,6 @@ PushScopeNodeChildren(ParseNode* node, NodeStack* stack)
static PushResult static PushResult
PushListNodeChildren(ListNode* node, NodeStack* stack) PushListNodeChildren(ListNode* node, NodeStack* stack)
{ {
MOZ_ASSERT(node->isArity(PN_LIST));
node->checkConsistency(); node->checkConsistency();
stack->pushList(node); stack->pushList(node);
@ -508,7 +503,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushNameNodeChildren(&pn->as<NameNode>(), stack); return PushNameNodeChildren(&pn->as<NameNode>(), stack);
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
return PushScopeNodeChildren(pn, stack); return PushScopeNodeChildren(&pn->as<LexicalScopeNode>(), stack);
case PNK_FUNCTION: case PNK_FUNCTION:
case PNK_MODULE: case PNK_MODULE:
@ -701,7 +696,7 @@ ParseNode::dump(int indent)
as<LoopControlStatement>().dump(indent); as<LoopControlStatement>().dump(indent);
return; return;
case PN_SCOPE: case PN_SCOPE:
((LexicalScopeNode*) this)->dump(indent); as<LexicalScopeNode>().dump(indent);
return; return;
} }
fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>", fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>",

View file

@ -312,9 +312,9 @@ IsTypeofKind(ParseNodeKind kind)
* kid1: try block * kid1: try block
* kid2: null or PNK_CATCHLIST list * kid2: null or PNK_CATCHLIST list
* kid3: null or finally block * kid3: null or finally block
* PNK_CATCHLIST list pn_head: list of PNK_LEXICALSCOPE nodes, one per * PNK_CATCHLIST (ListNode)
* catch-block, each with scopeBody pointing * head: list of PNK_LEXICALSCOPE nodes, one per catch-block,
* to a PNK_CATCH node * each with scopeBody pointing to a PNK_CATCH node
* PNK_CATCH (TernaryNode) * PNK_CATCH (TernaryNode)
* kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch binding node (PNK_ARRAY or PNK_OBJECT if destructuring) * kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch binding node (PNK_ARRAY or PNK_OBJECT if destructuring)
or null if optional catch binding or null if optional catch binding
@ -524,8 +524,9 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_SETTHIS (BinaryNode) * PNK_SETTHIS (BinaryNode)
* left: '.this' Name * left: '.this' Name
* right: SuperCall * right: SuperCall
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings * PNK_LEXICALSCOPE (LexicalScopeNode)
* pn_u.scope.body: scope body * scopeBindings: scope bindings
* scopeBody: scope body
* PNK_GENERATOR (NullaryNode) * PNK_GENERATOR (NullaryNode)
* PNK_INITIALYIELD (UnaryNode) * PNK_INITIALYIELD (UnaryNode)
* kid: generator object * kid: generator object
@ -567,6 +568,8 @@ enum ParseNodeArity
\ \
macro(CodeNode, CodeNodeType, asCode) \ macro(CodeNode, CodeNodeType, asCode) \
\ \
macro(LexicalScopeNode, LexicalScopeNodeType, asLexicalScope) \
\
macro(ListNode, ListNodeType, asList) \ macro(ListNode, ListNodeType, asList) \
macro(CallSiteNode, CallSiteNodeType, asCallSite) \ macro(CallSiteNode, CallSiteNodeType, asCallSite) \
\ \
@ -732,6 +735,8 @@ class ParseNode
ParseNode* body; /* module or function body */ ParseNode* body; /* module or function body */
} code; } code;
struct { struct {
private:
friend class LexicalScopeNode;
LexicalScope::Data* bindings; LexicalScope::Data* bindings;
ParseNode* body; ParseNode* body;
} scope; } scope;
@ -759,28 +764,6 @@ class ParseNode
inline PropertyName* name() const; inline PropertyName* name() const;
bool isEmptyScope() const {
MOZ_ASSERT(pn_arity == PN_SCOPE);
return !pn_u.scope.bindings;
}
Handle<LexicalScope::Data*> scopeBindings() const {
MOZ_ASSERT(!isEmptyScope());
// Bindings' GC safety depend on the presence of an AutoKeepAtoms that
// the rest of the frontend also depends on.
return Handle<LexicalScope::Data*>::fromMarkedLocation(&pn_u.scope.bindings);
}
ParseNode* scopeBody() const {
MOZ_ASSERT(pn_arity == PN_SCOPE);
return pn_u.scope.body;
}
void setScopeBody(ParseNode* body) {
MOZ_ASSERT(pn_arity == PN_SCOPE);
pn_u.scope.body = body;
}
/* True if pn is a parsenode representing a literal constant. */ /* True if pn is a parsenode representing a literal constant. */
bool isLiteral() const { bool isLiteral() const {
return isKind(PNK_NUMBER) || return isKind(PNK_NUMBER) ||
@ -1523,8 +1506,9 @@ class NumericLiteral : public ParseNode
} }
}; };
struct LexicalScopeNode : public ParseNode class LexicalScopeNode : public ParseNode
{ {
public:
LexicalScopeNode(LexicalScope::Data* bindings, ParseNode* body) LexicalScopeNode(LexicalScope::Data* bindings, ParseNode* body)
: ParseNode(PNK_LEXICALSCOPE, JSOP_NOP, PN_SCOPE, body->pn_pos) : ParseNode(PNK_LEXICALSCOPE, JSOP_NOP, PN_SCOPE, body->pn_pos)
{ {
@ -1533,12 +1517,37 @@ struct LexicalScopeNode : public ParseNode
} }
static bool test(const ParseNode& node) { static bool test(const ParseNode& node) {
return node.isKind(PNK_LEXICALSCOPE); bool match = node.isKind(PNK_LEXICALSCOPE);
MOZ_ASSERT_IF(match, node.isArity(PN_SCOPE));
return match;
} }
#ifdef DEBUG #ifdef DEBUG
void dump(int indent); void dump(int indent);
#endif #endif
Handle<LexicalScope::Data*> scopeBindings() const {
MOZ_ASSERT(!isEmptyScope());
// Bindings' GC safety depend on the presence of an AutoKeepAtoms that
// the rest of the frontend also depends on.
return Handle<LexicalScope::Data*>::fromMarkedLocation(&pn_u.scope.bindings);
}
ParseNode* scopeBody() const {
return pn_u.scope.body;
}
void setScopeBody(ParseNode* body) {
pn_u.scope.body = body;
}
bool isEmptyScope() const {
return !pn_u.scope.bindings;
}
ParseNode** unsafeScopeBodyReference() {
return &pn_u.scope.body;
}
}; };
class LabeledStatement : public NameNode class LabeledStatement : public NameNode
@ -1983,14 +1992,13 @@ class ClassMethod : public BinaryNode
class SwitchStatement : public BinaryNode class SwitchStatement : public BinaryNode
{ {
public: public:
SwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* lexicalForCaseList, SwitchStatement(uint32_t begin, ParseNode* discriminant, LexicalScopeNode* lexicalForCaseList,
bool hasDefault) bool hasDefault)
: BinaryNode(PNK_SWITCH, JSOP_NOP, : BinaryNode(PNK_SWITCH, JSOP_NOP,
TokenPos(begin, lexicalForCaseList->pn_pos.end), TokenPos(begin, lexicalForCaseList->pn_pos.end),
discriminant, lexicalForCaseList) discriminant, lexicalForCaseList)
{ {
#ifdef DEBUG #ifdef DEBUG
MOZ_ASSERT(lexicalForCaseList->isKind(PNK_LEXICALSCOPE));
ListNode* cases = &lexicalForCaseList->scopeBody()->as<ListNode>(); ListNode* cases = &lexicalForCaseList->scopeBody()->as<ListNode>();
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST)); MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
bool found = false; bool found = false;
@ -2016,8 +2024,8 @@ class SwitchStatement : public BinaryNode
ParseNode& discriminant() const { ParseNode& discriminant() const {
return *left(); return *left();
} }
ParseNode& lexicalForCaseList() const {; LexicalScopeNode& lexicalForCaseList() const {
return *right(); return right()->as<LexicalScopeNode>();
} }
bool hasDefault() const { bool hasDefault() const {
return pn_u.binary.hasDefault; return pn_u.binary.hasDefault;
@ -2090,15 +2098,13 @@ class ClassNode : public TernaryNode
if (methodsOrBlock->isKind(PNK_CLASSMETHODLIST)) if (methodsOrBlock->isKind(PNK_CLASSMETHODLIST))
return &methodsOrBlock->as<ListNode>(); return &methodsOrBlock->as<ListNode>();
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>()); ListNode* list = &methodsOrBlock->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
ListNode* list = &methodsOrBlock->scopeBody()->as<ListNode>();
MOZ_ASSERT(list->isKind(PNK_CLASSMETHODLIST)); MOZ_ASSERT(list->isKind(PNK_CLASSMETHODLIST));
return list; return list;
} }
Handle<LexicalScope::Data*> scopeBindings() const { Handle<LexicalScope::Data*> scopeBindings() const {
ParseNode* scope = kid3(); ParseNode* scope = kid3();
MOZ_ASSERT(scope->is<LexicalScopeNode>()); return scope->as<LexicalScopeNode>().scopeBindings();
return scope->scopeBindings();
} }
}; };
@ -2221,8 +2227,8 @@ FunctionFormalParametersList(ParseNode* fn, unsigned* numFormals)
MOZ_ASSERT(argsBody->isKind(PNK_PARAMSBODY)); MOZ_ASSERT(argsBody->isKind(PNK_PARAMSBODY));
*numFormals = argsBody->count(); *numFormals = argsBody->count();
if (*numFormals > 0 && if (*numFormals > 0 &&
argsBody->last()->isKind(PNK_LEXICALSCOPE) && argsBody->last()->is<LexicalScopeNode>() &&
argsBody->last()->scopeBody()->isKind(PNK_STATEMENTLIST)) argsBody->last()->as<LexicalScopeNode>().scopeBody()->isKind(PNK_STATEMENTLIST))
{ {
(*numFormals)--; (*numFormals)--;
} }

View file

@ -2066,16 +2066,16 @@ Parser<FullParseHandler>::newLexicalScopeData(ParseContext::Scope& scope)
} }
template <> template <>
SyntaxParseHandler::Node SyntaxParseHandler::LexicalScopeNodeType
Parser<SyntaxParseHandler>::finishLexicalScope(ParseContext::Scope& scope, Node body) Parser<SyntaxParseHandler>::finishLexicalScope(ParseContext::Scope& scope, Node body)
{ {
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) if (!propagateFreeNamesAndMarkClosedOverBindings(scope))
return null(); return null();
return body; return handler.newLexicalScope(body);
} }
template <> template <>
ParseNode* LexicalScopeNode*
Parser<FullParseHandler>::finishLexicalScope(ParseContext::Scope& scope, ParseNode* body) Parser<FullParseHandler>::finishLexicalScope(ParseContext::Scope& scope, ParseNode* body)
{ {
if (!propagateFreeNamesAndMarkClosedOverBindings(scope)) if (!propagateFreeNamesAndMarkClosedOverBindings(scope))
@ -2108,7 +2108,7 @@ IsArgumentsUsedInLegacyGenerator(ExclusiveContext* cx, Scope* scope)
} }
template <> template <>
ParseNode* LexicalScopeNode*
Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc) Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
{ {
ParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr); ParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
@ -2119,21 +2119,24 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
if (!varScope.init(pc)) if (!varScope.init(pc))
return nullptr; return nullptr;
LexicalScopeNode* body;
{
// All evals have an implicit non-extensible lexical scope. // All evals have an implicit non-extensible lexical scope.
ParseContext::Scope lexicalScope(this); ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc)) if (!lexicalScope.init(pc))
return nullptr; return nullptr;
ParseNode* body = statementList(YieldIsName); ParseNode* list = statementList(YieldIsName);
if (!body) if (!list)
return nullptr; return nullptr;
if (!checkStatementsEOF()) if (!checkStatementsEOF())
return nullptr; return nullptr;
body = finishLexicalScope(lexicalScope, body); body = finishLexicalScope(lexicalScope, list);
if (!body) if (!body)
return nullptr; return nullptr;
}
// It's an error to use 'arguments' in a legacy generator expression. // It's an error to use 'arguments' in a legacy generator expression.
// //
@ -2170,8 +2173,10 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
} }
#endif #endif
if (!FoldConstants(context, &body, this)) ParseNode* node = body;
if (!FoldConstants(context, &node, this))
return nullptr; return nullptr;
body = handler.asLexicalScope(node);
Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc->varScope()); Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc->varScope());
if (!bindings) if (!bindings)
@ -2663,7 +2668,7 @@ Parser<ParseHandler>::declareFunctionArgumentsObject()
} }
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHandling, Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionBodyType type) FunctionSyntaxKind kind, FunctionBodyType type)
{ {
@ -3721,7 +3726,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// Whereas the |yield| in the function body is always parsed as a name. // Whereas the |yield| in the function body is always parsed as a name.
// The same goes when parsing |await| in arrow functions. // The same goes when parsing |await| in arrow functions.
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind()); YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
Node body; LexicalScopeNodeType body;
{ {
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync()); AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync());
body = functionBody(inHandling, bodyYieldHandling, kind, bodyType); body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
@ -4620,7 +4625,7 @@ Parser<ParseHandler>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin
} }
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber) Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber)
{ {
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
@ -6532,7 +6537,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
handler.addCaseStatementToList(caseList, caseClause); handler.addCaseStatementToList(caseList, caseClause);
} }
Node lexicalForCaseList = finishLexicalScope(scope, caseList); LexicalScopeNodeType lexicalForCaseList = finishLexicalScope(scope, caseList);
if (!lexicalForCaseList) if (!lexicalForCaseList)
return null(); return null();
@ -6983,7 +6988,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
* finally nodes are TOK_LC statement lists. * finally nodes are TOK_LC statement lists.
*/ */
Node innerBlock; LexicalScopeNodeType innerBlock;
{ {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
@ -6994,11 +6999,11 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc)) if (!scope.init(pc))
return null(); return null();
innerBlock = statementList(yieldHandling); ListNodeType list = statementList(yieldHandling);
if (!innerBlock) if (!list)
return null(); return null();
innerBlock = finishLexicalScope(scope, innerBlock); innerBlock = finishLexicalScope(scope, list);
if (!innerBlock) if (!innerBlock)
return null(); return null();
@ -7018,8 +7023,6 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
return null(); return null();
do { do {
Node pnblock;
/* Check for another catch after unconditional catch. */ /* Check for another catch after unconditional catch. */
if (hasUnconditionalCatch) { if (hasUnconditionalCatch) {
error(JSMSG_CATCH_AFTER_GENERAL); error(JSMSG_CATCH_AFTER_GENERAL);
@ -7100,28 +7103,28 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
} }
Node catchBody = catchBlockStatement(yieldHandling, scope); LexicalScopeNodeType catchBody = catchBlockStatement(yieldHandling, scope);
if (!catchBody) if (!catchBody)
return null(); return null();
if (!catchGuard) if (!catchGuard)
hasUnconditionalCatch = true; hasUnconditionalCatch = true;
pnblock = finishLexicalScope(scope, catchBody); LexicalScopeNodeType catchScope = finishLexicalScope(scope, catchBody);
if (!pnblock) if (!catchScope)
return null(); return null();
if (!handler.addCatchBlock(catchList, pnblock, catchName, catchGuard, catchBody)) if (!handler.addCatchBlock(catchList, catchScope, catchName, catchGuard, catchBody))
return null(); return null();
handler.setEndPosition(catchList, pos().end); handler.setEndPosition(catchList, pos().end);
handler.setEndPosition(pnblock, pos().end); handler.setEndPosition(catchScope, pos().end);
if (!tokenStream.getToken(&tt, TokenStream::Operand)) if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null(); return null();
} while (tt == TOK_CATCH); } while (tt == TOK_CATCH);
} }
Node finallyBlock = null(); LexicalScopeNodeType finallyBlock = null();
if (tt == TOK_FINALLY) { if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY); MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
@ -7133,11 +7136,11 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc)) if (!scope.init(pc))
return null(); return null();
finallyBlock = statementList(yieldHandling); ListNodeType list = statementList(yieldHandling);
if (!finallyBlock) if (!list)
return null(); return null();
finallyBlock = finishLexicalScope(scope, finallyBlock); finallyBlock = finishLexicalScope(scope, list);
if (!finallyBlock) if (!finallyBlock)
return null(); return null();
@ -7156,7 +7159,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
} }
template <typename ParseHandler> template <typename ParseHandler>
typename ParseHandler::Node typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling, Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
ParseContext::Scope& catchParamScope) ParseContext::Scope& catchParamScope)
{ {
@ -7427,7 +7430,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!innerName) if (!innerName)
return null(); return null();
Node classBlock = finishLexicalScope(*innerScope, classMethods); LexicalScopeNodeType classBlock = finishLexicalScope(*innerScope, classMethods);
if (!classBlock) if (!classBlock)
return null(); return null();
@ -8937,7 +8940,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
return null(); return null();
// Finish the lexical scope after parsing the tail. // Finish the lexical scope after parsing the tail.
Node lexicalScope = finishLexicalScope(scope, decls); LexicalScopeNodeType lexicalScope = finishLexicalScope(scope, decls);
if (!lexicalScope) if (!lexicalScope)
return null(); return null();

View file

@ -1132,7 +1132,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
// Eval scripts are distinguished from global scripts in that in ES6, per // 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 // 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
// lexical scope. // lexical scope.
Node evalBody(EvalSharedContext* evalsc); LexicalScopeNodeType evalBody(EvalSharedContext* evalsc);
// Parse the body of a global script. // Parse the body of a global script.
ListNodeType globalBody(GlobalSharedContext* globalsc); ListNodeType globalBody(GlobalSharedContext* globalsc);
@ -1196,7 +1196,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
ListNodeType statementList(YieldHandling yieldHandling); ListNodeType statementList(YieldHandling yieldHandling);
Node blockStatement(YieldHandling yieldHandling, LexicalScopeNodeType blockStatement(YieldHandling yieldHandling,
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND); unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
BinaryNodeType doWhileStatement(YieldHandling yieldHandling); BinaryNodeType doWhileStatement(YieldHandling yieldHandling);
BinaryNodeType whileStatement(YieldHandling yieldHandling); BinaryNodeType whileStatement(YieldHandling yieldHandling);
@ -1217,7 +1217,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
BinaryNodeType withStatement(YieldHandling yieldHandling); BinaryNodeType withStatement(YieldHandling yieldHandling);
UnaryNodeType throwStatement(YieldHandling yieldHandling); UnaryNodeType throwStatement(YieldHandling yieldHandling);
TernaryNodeType tryStatement(YieldHandling yieldHandling); TernaryNodeType tryStatement(YieldHandling yieldHandling);
Node catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope); LexicalScopeNodeType catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope);
DebuggerStatementType debuggerStatement(); DebuggerStatementType debuggerStatement();
Node variableStatement(YieldHandling yieldHandling); Node variableStatement(YieldHandling yieldHandling);
@ -1363,8 +1363,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
// Parse a function body. Pass StatementListBody if the body is a list of // Parse a function body. Pass StatementListBody if the body is a list of
// statements; pass ExpressionBody if the body is a single expression. // statements; pass ExpressionBody if the body is a single expression.
enum FunctionBodyType { StatementListBody, ExpressionBody }; enum FunctionBodyType { StatementListBody, ExpressionBody };
Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind, LexicalScopeNodeType functionBody(InHandling inHandling, YieldHandling yieldHandling,
FunctionBodyType type); FunctionSyntaxKind kind, FunctionBodyType type);
UnaryNodeType unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin); UnaryNodeType unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
@ -1514,7 +1514,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
bool hasParameterExprs); bool hasParameterExprs);
mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope); mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope);
mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope); mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope);
Node finishLexicalScope(ParseContext::Scope& scope, Node body); LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope, Node body);
Node propertyName(YieldHandling yieldHandling, Node propertyName(YieldHandling yieldHandling,
const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType propList, const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType propList,

View file

@ -316,6 +316,10 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; } ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
ClassNodeType newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; } ClassNodeType newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; }
LexicalScopeNodeType newLexicalScope(Node body) {
return NodeLexicalDeclaration;
}
BinaryNodeType newNewTarget(NullaryNodeType newHolder, NullaryNodeType targetHolder) { BinaryNodeType newNewTarget(NullaryNodeType newHolder, NullaryNodeType targetHolder) {
return NodeGeneric; return NodeGeneric;
} }
@ -362,7 +366,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
} }
BinaryNodeType newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; } BinaryNodeType newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; }
BinaryNodeType newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } BinaryNodeType newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
SwitchStatementType newSwitchStatement(uint32_t begin, Node discriminant, Node lexicalForCaseList, bool hasDefault) SwitchStatementType newSwitchStatement(uint32_t begin, Node discriminant,
LexicalScopeNodeType lexicalForCaseList, bool hasDefault)
{ {
return NodeGeneric; return NodeGeneric;
} }
@ -399,8 +404,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
Node newOptionalPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeOptionalElement; } Node newOptionalPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeOptionalElement; }
MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, Node letBlock, Node catchBinding, MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, LexicalScopeNodeType lexicalScope,
Node catchGuard, Node catchBody) { return true; } Node catchBinding, Node catchGuard, Node catchBody) { return true; }
MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(CodeNodeType funNode, Node pn) { return true; } MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(CodeNodeType funNode, Node pn) { return true; }
@ -412,7 +417,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
bool setComprehensionLambdaBody(CodeNodeType funNode, ListNodeType body) { return true; } bool setComprehensionLambdaBody(CodeNodeType funNode, ListNodeType body) { return true; }
void setFunctionFormalParametersAndBody(CodeNodeType funNode, ListNodeType paramsBody) {} void setFunctionFormalParametersAndBody(CodeNodeType funNode, ListNodeType paramsBody) {}
void setFunctionBody(CodeNodeType funNode, Node body) {} void setFunctionBody(CodeNodeType funNode, LexicalScopeNodeType body) {}
void setFunctionBox(CodeNodeType funNode, FunctionBox* funbox) {} void setFunctionBox(CodeNodeType funNode, FunctionBox* funbox) {}
void addFunctionFormalParameter(CodeNodeType funNode, Node argpn) {} void addFunctionFormalParameter(CodeNodeType funNode, Node argpn) {}

View file

@ -668,8 +668,7 @@ static inline ParseNode*
FunctionStatementList(CodeNode* funNode) FunctionStatementList(CodeNode* funNode)
{ {
MOZ_ASSERT(funNode->body()->isKind(PNK_PARAMSBODY)); MOZ_ASSERT(funNode->body()->isKind(PNK_PARAMSBODY));
ParseNode* last = funNode->body()->as<ListNode>().last(); LexicalScopeNode* last = &funNode->body()->as<ListNode>().last()->as<LexicalScopeNode>();
MOZ_ASSERT(last->isKind(PNK_LEXICALSCOPE));
MOZ_ASSERT(last->isEmptyScope()); MOZ_ASSERT(last->isEmptyScope());
ParseNode* body = last->scopeBody(); ParseNode* body = last->scopeBody();
MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST));
@ -6807,10 +6806,11 @@ CheckSwitch(FunctionValidator& f, ParseNode* switchStmt)
ParseNode* switchExpr = BinaryLeft(switchStmt); ParseNode* switchExpr = BinaryLeft(switchStmt);
ParseNode* switchBody = BinaryRight(switchStmt); ParseNode* switchBody = BinaryRight(switchStmt);
if (switchBody->isKind(PNK_LEXICALSCOPE)) { if (switchBody->is<LexicalScopeNode>()) {
if (!switchBody->isEmptyScope()) LexicalScopeNode* scope = &switchBody->as<LexicalScopeNode>();
return f.fail(switchBody, "switch body may not contain lexical declarations"); if (!scope->isEmptyScope())
switchBody = switchBody->scopeBody(); return f.fail(scope, "switch body may not contain lexical declarations");
switchBody = scope->scopeBody();
} }
ParseNode* stmt = ListHead(switchBody); ParseNode* stmt = ListHead(switchBody);
@ -6984,10 +6984,9 @@ CheckStatementList(FunctionValidator& f, ParseNode* stmtList, const NameVector*
} }
static bool static bool
CheckLexicalScope(FunctionValidator& f, ParseNode* lexicalScope) CheckLexicalScope(FunctionValidator& f, ParseNode* node)
{ {
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); LexicalScopeNode* lexicalScope = &node->as<LexicalScopeNode>();
if (!lexicalScope->isEmptyScope()) if (!lexicalScope->isEmptyScope())
return f.fail(lexicalScope, "cannot have 'let' or 'const' declarations"); return f.fail(lexicalScope, "cannot have 'let' or 'const' declarations");