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()))
return false;
for (ParseNode* catchScope : catchList->contents()) {
MOZ_ASSERT(catchScope->isKind(PNK_LEXICALSCOPE));
for (ParseNode* catchNode : catchList->contents()) {
LexicalScopeNode* catchScope = &catchNode->as<LexicalScopeNode>();
RootedValue clause(cx);
bool isGuarded;
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);
case PNK_LEXICALSCOPE:
pn = pn->scopeBody();
pn = pn->as<LexicalScopeNode>().scopeBody();
if (!pn->isKind(PNK_STATEMENTLIST))
return statement(pn, dst);
MOZ_FALLTHROUGH;
@ -2578,8 +2578,9 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) {
RootedValue var(cx);
if (initNode->isKind(PNK_LEXICALSCOPE)) {
if (!variableDeclaration(&initNode->scopeBody()->as<ListNode>(), true, &var))
if (initNode->is<LexicalScopeNode>()) {
LexicalScopeNode* scopeNode = &initNode->as<LexicalScopeNode>();
if (!variableDeclaration(&scopeNode->scopeBody()->as<ListNode>(), true, &var))
return false;
} else if (!initNode->isKind(PNK_VAR) &&
!initNode->isKind(PNK_LET) &&
@ -2810,8 +2811,8 @@ ASTSerializer::comprehensionBlock(ForNode* forNode, MutableHandleValue dst)
bool isForOf = in->isKind(PNK_FOROF);
ListNode* decl;
if (in->kid1()->isKind(PNK_LEXICALSCOPE))
decl = &in->kid1()->scopeBody()->as<ListNode>();
if (in->kid1()->is<LexicalScopeNode>())
decl = &in->kid1()->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
else
decl = &in->kid1()->as<ListNode>();
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)]
// 2. The kind that was in ES6 for a while: [for (x of y) z]
// They have slightly different parse trees and scoping.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
ParseNode* next = isLegacy ? pn->scopeBody() : pn;
bool isLegacy = pn->is<LexicalScopeNode>();
ParseNode* next = isLegacy ? pn->as<LexicalScopeNode>().scopeBody() : pn;
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx);
@ -2886,8 +2887,8 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
// Just as there are two kinds of array comprehension (see
// ASTSerializer::comprehension), there are legacy and modern generator
// expression.
bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
ParseNode* next = isLegacy ? pn->scopeBody() : pn;
bool isLegacy = pn->is<LexicalScopeNode>();
ParseNode* next = isLegacy ? pn->as<LexicalScopeNode>().scopeBody() : pn;
LOCAL_ASSERT(next->isKind(PNK_COMPREHENSIONFOR));
NodeVector blocks(cx);
@ -3653,29 +3654,29 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
MutableHandleValue body, MutableHandleValue rest)
{
ListNode* argsList;
ParseNode* pnbody;
ParseNode* bodyNode;
/* Extract the args and body separately. */
if (pn->isKind(PNK_PARAMSBODY)) {
argsList = &pn->as<ListNode>();
pnbody = argsList->last();
bodyNode = argsList->last();
} else {
argsList = nullptr;
pnbody = pn;
bodyNode = pn;
}
if (pnbody->isKind(PNK_LEXICALSCOPE))
pnbody = pnbody->scopeBody();
if (bodyNode->is<LexicalScopeNode>())
bodyNode = bodyNode->as<LexicalScopeNode>().scopeBody();
/* Serialize the arguments and body. */
switch (pnbody->getKind()) {
switch (bodyNode->getKind()) {
case PNK_RETURN: /* expression closure, no destructured args */
return functionArgs(pn, argsList, args, defaults, rest) &&
expression(pnbody->as<UnaryNode>().kid(), body);
expression(bodyNode->as<UnaryNode>().kid(), body);
case PNK_STATEMENTLIST: /* statement closure */
{
ParseNode* firstNode = pnbody->as<ListNode>().head();
ParseNode* firstNode = bodyNode->as<ListNode>().head();
// Skip over initial yield in generator.
if (firstNode && firstNode->isKind(PNK_INITIALYIELD)) {
@ -3692,7 +3693,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
}
return functionArgs(pn, argsList, args, defaults, rest) &&
functionBody(firstNode, &pnbody->pn_pos, body);
functionBody(firstNode, &bodyNode->pn_pos, body);
}
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 typically comes from the first statement inside.
*/
if (nextpn->isKind(PNK_LEXICALSCOPE))
nextpn = nextpn->scopeBody();
if (nextpn->is<LexicalScopeNode>())
nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
if (nextpn->isKind(PNK_STATEMENTLIST)) {
if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
nextpn = firstStatement;
@ -612,8 +612,8 @@ BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump)
{
if (nextpn) {
/* Update the line number, as for LOOPHEAD. */
if (nextpn->isKind(PNK_LEXICALSCOPE))
nextpn = nextpn->scopeBody();
if (nextpn->is<LexicalScopeNode>())
nextpn = nextpn->as<LexicalScopeNode>().scopeBody();
if (nextpn->isKind(PNK_STATEMENTLIST)) {
if (ParseNode* firstStatement = nextpn->as<ListNode>().head()) {
nextpn = firstStatement;
@ -1487,7 +1487,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_LEXICALSCOPE:
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
// probably not worth the trouble. Treat template strings as effect-free
@ -2080,8 +2080,7 @@ BytecodeEmitter::emitNumberOp(double dval)
MOZ_NEVER_INLINE bool
BytecodeEmitter::emitSwitch(SwitchStatement* switchStmt)
{
ParseNode& lexical = switchStmt->lexicalForCaseList();
MOZ_ASSERT(lexical.isKind(PNK_LEXICALSCOPE));
LexicalScopeNode& lexical = switchStmt->lexicalForCaseList();
ListNode* cases = &lexical.scopeBody()->as<ListNode>();
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
@ -2343,20 +2342,21 @@ BytecodeEmitter::emitScript(ParseNode* body)
setFunctionBodyEndPos(body->pn_pos);
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
// an immediately enclosed lexical scope, we need to enter the lexical
// scope in the prologue for the DEFFUNs to pick up the right
// environment chain.
EmitterScope lexicalEmitterScope(this);
LexicalScopeNode* scope = &body->as<LexicalScopeNode>();
switchToPrologue();
if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, body->scopeBindings()))
if (!lexicalEmitterScope.enterLexical(this, ScopeKind::Lexical, scope->scopeBindings()))
return false;
switchToMain();
if (!emitLexicalScopeBody(body->scopeBody()))
if (!emitLexicalScopeBody(scope->scopeBody()))
return false;
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
// 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())
return false;
// Emit the lexical scope and catch body.
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE));
if (!emitTree(lexicalScope))
if (!emitTree(catchScope))
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
// the comment on emitSwitch.
MOZ_NEVER_INLINE bool
BytecodeEmitter::emitLexicalScope(ParseNode* pn)
BytecodeEmitter::emitLexicalScope(LexicalScopeNode* lexicalScope)
{
MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
TDZCheckCache tdzCache(this);
ParseNode* body = pn->scopeBody();
if (pn->isEmptyScope())
ParseNode* body = lexicalScope->scopeBody();
if (lexicalScope->isEmptyScope())
return emitLexicalScopeBody(body);
// Update line number notes before emitting TDZ poison in
@ -4431,7 +4429,7 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn)
} else
kind = ScopeKind::Lexical;
if (!emitterScope.enterLexical(this, kind, pn->scopeBindings()))
if (!emitterScope.enterLexical(this, kind, lexicalScope->scopeBindings()))
return false;
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
// comprehension syntax.
*lexicalScope = pn->isKind(PNK_LEXICALSCOPE);
*lexicalScope = pn->is<LexicalScopeNode>();
if (*lexicalScope) {
// This is initially-ES7-tracked syntax, now with considerably murkier
// outlook. The scope work is done by the caller by instantiating an
@ -5369,9 +5367,10 @@ BytecodeEmitter::emitComprehensionForOf(ForNode* forNode)
Maybe<EmitterScope> emitterScope;
ParseNode* loopVariableName;
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);
if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings()))
if (!emitterScope->enterComprehensionFor(this, scopeNode->scopeBindings()))
return false;
} else {
loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->as<ListNode>());
@ -5515,7 +5514,8 @@ BytecodeEmitter::emitComprehensionForIn(ForNode* forNode)
Maybe<EmitterScope> emitterScope;
if (lexicalScope) {
emitterScope.emplace(this);
if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings()))
LexicalScopeNode* scopeNode = &loopDecl->as<LexicalScopeNode>();
if (!emitterScope->enterComprehensionFor(this, scopeNode->scopeBindings()))
return false;
}
@ -8945,7 +8945,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_LEXICALSCOPE:
if (!emitLexicalScope(pn))
if (!emitLexicalScope(&pn->as<LexicalScopeNode>()))
return false;
break;

View file

@ -588,7 +588,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
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 emitLexicalScope(ParseNode* pn);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(LexicalScopeNode* lexicalScope);
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
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 (ListNode* catchList = &tryNode->kid2()->as<ListNode>()) {
for (ParseNode* lexicalScope : catchList->contents()) {
MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE));
for (ParseNode* scopeNode : catchList->contents()) {
LexicalScopeNode* lexicalScope = &scopeNode->as<LexicalScopeNode>();
TernaryNode* catchNode = &lexicalScope->scopeBody()->as<TernaryNode>();
MOZ_ASSERT(catchNode->isKind(PNK_CATCH));
@ -286,14 +286,14 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
}
case PNK_LEXICALSCOPE: {
MOZ_ASSERT(node->isArity(PN_SCOPE));
ParseNode* expr = node->scopeBody();
LexicalScopeNode* scope = &node->as<LexicalScopeNode>();
ParseNode* expr = scope->scopeBody();
if (expr->isKind(PNK_FOR) || expr->isKind(PNK_FUNCTION))
return ContainsHoistedDeclaration(cx, expr, result);
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.
@ -1966,11 +1966,12 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_DOT:
return FoldDottedProperty(cx, &pn->as<PropertyAccessBase>(), parser, inGenexpLambda);
case PNK_LEXICALSCOPE:
MOZ_ASSERT(pn->isArity(PN_SCOPE));
if (!pn->scopeBody())
case PNK_LEXICALSCOPE: {
LexicalScopeNode* node = &pn->as<LexicalScopeNode>();
if (!node->scopeBody())
return true;
return Fold(cx, &pn->pn_u.scope.body, parser, inGenexpLambda);
return Fold(cx, node->unsafeScopeBodyReference(), parser, inGenexpLambda);
}
case PNK_NAME:
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,
Node lexicalForCaseList, bool hasDefault)
LexicalScopeNodeType lexicalForCaseList, bool 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);
}
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* catchBody);
@ -759,7 +759,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
void addFunctionFormalParameter(CodeNodeType funNode, Node 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));
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);
}
ParseNode* newLexicalScope(LexicalScope::Data* bindings, ParseNode* body) {
LexicalScopeNodeType newLexicalScope(LexicalScope::Data* bindings, Node body) {
return new_<LexicalScopeNode>(bindings, body);
}
@ -1002,7 +1002,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
};
inline bool
FullParseHandler::addCatchBlock(ListNodeType catchList, ParseNode* lexicalScope,
FullParseHandler::addCatchBlock(ListNodeType catchList, LexicalScopeNodeType lexicalScope,
ParseNode* catchBinding, ParseNode* catchGuard, ParseNode* catchBody)
{
ParseNode* catchpn = newTernary(PNK_CATCH, catchBinding, catchGuard, catchBody);

View file

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

View file

@ -96,8 +96,6 @@ enum class PushResult { Recyclable, CleanUpLater };
static PushResult
PushCodeNodeChildren(CodeNode* node, NodeStack* stack)
{
MOZ_ASSERT(node->isArity(PN_CODE));
/*
* 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
@ -133,10 +131,8 @@ PushNameNodeChildren(NameNode* node, NodeStack* stack)
}
static PushResult
PushScopeNodeChildren(ParseNode* node, NodeStack* stack)
PushScopeNodeChildren(LexicalScopeNode* node, NodeStack* stack)
{
MOZ_ASSERT(node->isArity(PN_SCOPE));
if (node->scopeBody())
stack->push(node->scopeBody());
node->setScopeBody(nullptr);
@ -146,7 +142,6 @@ PushScopeNodeChildren(ParseNode* node, NodeStack* stack)
static PushResult
PushListNodeChildren(ListNode* node, NodeStack* stack)
{
MOZ_ASSERT(node->isArity(PN_LIST));
node->checkConsistency();
stack->pushList(node);
@ -508,7 +503,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
return PushNameNodeChildren(&pn->as<NameNode>(), stack);
case PNK_LEXICALSCOPE:
return PushScopeNodeChildren(pn, stack);
return PushScopeNodeChildren(&pn->as<LexicalScopeNode>(), stack);
case PNK_FUNCTION:
case PNK_MODULE:
@ -701,7 +696,7 @@ ParseNode::dump(int indent)
as<LoopControlStatement>().dump(indent);
return;
case PN_SCOPE:
((LexicalScopeNode*) this)->dump(indent);
as<LexicalScopeNode>().dump(indent);
return;
}
fprintf(stderr, "#<BAD NODE %p, kind=%u, arity=%u>",

View file

@ -312,9 +312,9 @@ IsTypeofKind(ParseNodeKind kind)
* kid1: try block
* kid2: null or PNK_CATCHLIST list
* kid3: null or finally block
* PNK_CATCHLIST list pn_head: list of PNK_LEXICALSCOPE nodes, one per
* catch-block, each with scopeBody pointing
* to a PNK_CATCH node
* PNK_CATCHLIST (ListNode)
* head: list of PNK_LEXICALSCOPE nodes, one per catch-block,
* each with scopeBody pointing to a PNK_CATCH node
* PNK_CATCH (TernaryNode)
* kid1: PNK_NAME, PNK_ARRAY, or PNK_OBJECT catch binding node (PNK_ARRAY or PNK_OBJECT if destructuring)
or null if optional catch binding
@ -524,8 +524,9 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_SETTHIS (BinaryNode)
* left: '.this' Name
* right: SuperCall
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
* pn_u.scope.body: scope body
* PNK_LEXICALSCOPE (LexicalScopeNode)
* scopeBindings: scope bindings
* scopeBody: scope body
* PNK_GENERATOR (NullaryNode)
* PNK_INITIALYIELD (UnaryNode)
* kid: generator object
@ -567,6 +568,8 @@ enum ParseNodeArity
\
macro(CodeNode, CodeNodeType, asCode) \
\
macro(LexicalScopeNode, LexicalScopeNodeType, asLexicalScope) \
\
macro(ListNode, ListNodeType, asList) \
macro(CallSiteNode, CallSiteNodeType, asCallSite) \
\
@ -732,6 +735,8 @@ class ParseNode
ParseNode* body; /* module or function body */
} code;
struct {
private:
friend class LexicalScopeNode;
LexicalScope::Data* bindings;
ParseNode* body;
} scope;
@ -759,28 +764,6 @@ class ParseNode
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. */
bool isLiteral() const {
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)
: ParseNode(PNK_LEXICALSCOPE, JSOP_NOP, PN_SCOPE, body->pn_pos)
{
@ -1533,12 +1517,37 @@ struct LexicalScopeNode : public ParseNode
}
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
void dump(int indent);
#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
@ -1983,14 +1992,13 @@ class ClassMethod : public BinaryNode
class SwitchStatement : public BinaryNode
{
public:
SwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* lexicalForCaseList,
SwitchStatement(uint32_t begin, ParseNode* discriminant, LexicalScopeNode* lexicalForCaseList,
bool hasDefault)
: BinaryNode(PNK_SWITCH, JSOP_NOP,
TokenPos(begin, lexicalForCaseList->pn_pos.end),
discriminant, lexicalForCaseList)
{
#ifdef DEBUG
MOZ_ASSERT(lexicalForCaseList->isKind(PNK_LEXICALSCOPE));
ListNode* cases = &lexicalForCaseList->scopeBody()->as<ListNode>();
MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST));
bool found = false;
@ -2016,8 +2024,8 @@ class SwitchStatement : public BinaryNode
ParseNode& discriminant() const {
return *left();
}
ParseNode& lexicalForCaseList() const {;
return *right();
LexicalScopeNode& lexicalForCaseList() const {
return right()->as<LexicalScopeNode>();
}
bool hasDefault() const {
return pn_u.binary.hasDefault;
@ -2090,15 +2098,13 @@ class ClassNode : public TernaryNode
if (methodsOrBlock->isKind(PNK_CLASSMETHODLIST))
return &methodsOrBlock->as<ListNode>();
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>());
ListNode* list = &methodsOrBlock->scopeBody()->as<ListNode>();
ListNode* list = &methodsOrBlock->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
MOZ_ASSERT(list->isKind(PNK_CLASSMETHODLIST));
return list;
}
Handle<LexicalScope::Data*> scopeBindings() const {
ParseNode* scope = kid3();
MOZ_ASSERT(scope->is<LexicalScopeNode>());
return scope->scopeBindings();
return scope->as<LexicalScopeNode>().scopeBindings();
}
};
@ -2221,8 +2227,8 @@ FunctionFormalParametersList(ParseNode* fn, unsigned* numFormals)
MOZ_ASSERT(argsBody->isKind(PNK_PARAMSBODY));
*numFormals = argsBody->count();
if (*numFormals > 0 &&
argsBody->last()->isKind(PNK_LEXICALSCOPE) &&
argsBody->last()->scopeBody()->isKind(PNK_STATEMENTLIST))
argsBody->last()->is<LexicalScopeNode>() &&
argsBody->last()->as<LexicalScopeNode>().scopeBody()->isKind(PNK_STATEMENTLIST))
{
(*numFormals)--;
}

View file

@ -2066,16 +2066,16 @@ Parser<FullParseHandler>::newLexicalScopeData(ParseContext::Scope& scope)
}
template <>
SyntaxParseHandler::Node
SyntaxParseHandler::LexicalScopeNodeType
Parser<SyntaxParseHandler>::finishLexicalScope(ParseContext::Scope& scope, Node body)
{
if (!propagateFreeNamesAndMarkClosedOverBindings(scope))
return null();
return body;
return handler.newLexicalScope(body);
}
template <>
ParseNode*
LexicalScopeNode*
Parser<FullParseHandler>::finishLexicalScope(ParseContext::Scope& scope, ParseNode* body)
{
if (!propagateFreeNamesAndMarkClosedOverBindings(scope))
@ -2108,7 +2108,7 @@ IsArgumentsUsedInLegacyGenerator(ExclusiveContext* cx, Scope* scope)
}
template <>
ParseNode*
LexicalScopeNode*
Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
{
ParseContext evalpc(this, evalsc, /* newDirectives = */ nullptr);
@ -2119,21 +2119,24 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
if (!varScope.init(pc))
return nullptr;
// All evals have an implicit non-extensible lexical scope.
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc))
return nullptr;
LexicalScopeNode* body;
{
// All evals have an implicit non-extensible lexical scope.
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc))
return nullptr;
ParseNode* body = statementList(YieldIsName);
if (!body)
return nullptr;
ParseNode* list = statementList(YieldIsName);
if (!list)
return nullptr;
if (!checkStatementsEOF())
return nullptr;
if (!checkStatementsEOF())
return nullptr;
body = finishLexicalScope(lexicalScope, body);
if (!body)
return nullptr;
body = finishLexicalScope(lexicalScope, list);
if (!body)
return nullptr;
}
// It's an error to use 'arguments' in a legacy generator expression.
//
@ -2170,8 +2173,10 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
}
#endif
if (!FoldConstants(context, &body, this))
ParseNode* node = body;
if (!FoldConstants(context, &node, this))
return nullptr;
body = handler.asLexicalScope(node);
Maybe<EvalScope::Data*> bindings = newEvalScopeData(pc->varScope());
if (!bindings)
@ -2663,7 +2668,7 @@ Parser<ParseHandler>::declareFunctionArgumentsObject()
}
template <typename ParseHandler>
typename ParseHandler::Node
typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHandling,
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.
// The same goes when parsing |await| in arrow functions.
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
Node body;
LexicalScopeNodeType body;
{
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync());
body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
@ -4620,7 +4625,7 @@ Parser<ParseHandler>::destructuringDeclarationWithoutYieldOrAwait(DeclarationKin
}
template <typename ParseHandler>
typename ParseHandler::Node
typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
@ -6532,7 +6537,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
handler.addCaseStatementToList(caseList, caseClause);
}
Node lexicalForCaseList = finishLexicalScope(scope, caseList);
LexicalScopeNodeType lexicalForCaseList = finishLexicalScope(scope, caseList);
if (!lexicalForCaseList)
return null();
@ -6983,7 +6988,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
* finally nodes are TOK_LC statement lists.
*/
Node innerBlock;
LexicalScopeNodeType innerBlock;
{
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
@ -6994,11 +6999,11 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc))
return null();
innerBlock = statementList(yieldHandling);
if (!innerBlock)
ListNodeType list = statementList(yieldHandling);
if (!list)
return null();
innerBlock = finishLexicalScope(scope, innerBlock);
innerBlock = finishLexicalScope(scope, list);
if (!innerBlock)
return null();
@ -7018,8 +7023,6 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
return null();
do {
Node pnblock;
/* Check for another catch after unconditional catch. */
if (hasUnconditionalCatch) {
error(JSMSG_CATCH_AFTER_GENERAL);
@ -7100,28 +7103,28 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);
}
Node catchBody = catchBlockStatement(yieldHandling, scope);
LexicalScopeNodeType catchBody = catchBlockStatement(yieldHandling, scope);
if (!catchBody)
return null();
if (!catchGuard)
hasUnconditionalCatch = true;
pnblock = finishLexicalScope(scope, catchBody);
if (!pnblock)
LexicalScopeNodeType catchScope = finishLexicalScope(scope, catchBody);
if (!catchScope)
return null();
if (!handler.addCatchBlock(catchList, pnblock, catchName, catchGuard, catchBody))
if (!handler.addCatchBlock(catchList, catchScope, catchName, catchGuard, catchBody))
return null();
handler.setEndPosition(catchList, pos().end);
handler.setEndPosition(pnblock, pos().end);
handler.setEndPosition(catchScope, pos().end);
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
} while (tt == TOK_CATCH);
}
Node finallyBlock = null();
LexicalScopeNodeType finallyBlock = null();
if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
@ -7133,11 +7136,11 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc))
return null();
finallyBlock = statementList(yieldHandling);
if (!finallyBlock)
ListNodeType list = statementList(yieldHandling);
if (!list)
return null();
finallyBlock = finishLexicalScope(scope, finallyBlock);
finallyBlock = finishLexicalScope(scope, list);
if (!finallyBlock)
return null();
@ -7156,7 +7159,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
}
template <typename ParseHandler>
typename ParseHandler::Node
typename ParseHandler::LexicalScopeNodeType
Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
ParseContext::Scope& catchParamScope)
{
@ -7427,7 +7430,7 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!innerName)
return null();
Node classBlock = finishLexicalScope(*innerScope, classMethods);
LexicalScopeNodeType classBlock = finishLexicalScope(*innerScope, classMethods);
if (!classBlock)
return null();
@ -8937,7 +8940,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
return null();
// Finish the lexical scope after parsing the tail.
Node lexicalScope = finishLexicalScope(scope, decls);
LexicalScopeNodeType lexicalScope = finishLexicalScope(scope, decls);
if (!lexicalScope)
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
// 18.2.1.1 steps 9 and 10, all eval scripts are executed under a fresh
// lexical scope.
Node evalBody(EvalSharedContext* evalsc);
LexicalScopeNodeType evalBody(EvalSharedContext* evalsc);
// Parse the body of a global script.
ListNodeType globalBody(GlobalSharedContext* globalsc);
@ -1196,8 +1196,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
ListNodeType statementList(YieldHandling yieldHandling);
Node blockStatement(YieldHandling yieldHandling,
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
LexicalScopeNodeType blockStatement(YieldHandling yieldHandling,
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
BinaryNodeType doWhileStatement(YieldHandling yieldHandling);
BinaryNodeType whileStatement(YieldHandling yieldHandling);
@ -1217,7 +1217,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
BinaryNodeType withStatement(YieldHandling yieldHandling);
UnaryNodeType throwStatement(YieldHandling yieldHandling);
TernaryNodeType tryStatement(YieldHandling yieldHandling);
Node catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope);
LexicalScopeNodeType catchBlockStatement(YieldHandling yieldHandling, ParseContext::Scope& catchParamScope);
DebuggerStatementType debuggerStatement();
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
// statements; pass ExpressionBody if the body is a single expression.
enum FunctionBodyType { StatementListBody, ExpressionBody };
Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
FunctionBodyType type);
LexicalScopeNodeType functionBody(InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionBodyType type);
UnaryNodeType unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
@ -1514,7 +1514,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
bool hasParameterExprs);
mozilla::Maybe<VarScope::Data*> newVarScopeData(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,
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; }
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) {
return NodeGeneric;
}
@ -362,7 +366,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
}
BinaryNodeType newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { 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;
}
@ -399,8 +404,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
Node newOptionalPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeOptionalElement; }
MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, Node letBlock, Node catchBinding,
Node catchGuard, Node catchBody) { return true; }
MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, LexicalScopeNodeType lexicalScope,
Node catchBinding, Node catchGuard, Node catchBody) { 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; }
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 addFunctionFormalParameter(CodeNodeType funNode, Node argpn) {}

View file

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