From 9c17ec05334ad5e4599040d1d12568f72e584d05 Mon Sep 17 00:00:00 2001 From: Martok Date: Sat, 25 Mar 2023 22:16:04 +0100 Subject: [PATCH] Issue #2173 - Add accessors to ListNode Based-on: m-c 1479659/{1,12} --- js/src/builtin/ModuleObject.cpp | 30 +- js/src/builtin/ModuleObject.h | 5 +- js/src/builtin/ReflectParse.cpp | 358 ++++++++-------- js/src/frontend/BytecodeEmitter.cpp | 450 +++++++++----------- js/src/frontend/BytecodeEmitter.h | 49 ++- js/src/frontend/FoldConstants.cpp | 136 +++--- js/src/frontend/FullParseHandler.h | 185 ++++----- js/src/frontend/NameFunctions.cpp | 59 ++- js/src/frontend/ParseNode.cpp | 63 ++- js/src/frontend/ParseNode.h | 596 +++++++++++++++++++-------- js/src/frontend/Parser.cpp | 213 +++++----- js/src/frontend/Parser.h | 63 +-- js/src/frontend/SyntaxParseHandler.h | 77 ++-- js/src/wasm/AsmJS.cpp | 14 +- 14 files changed, 1250 insertions(+), 1048 deletions(-) diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index c21660c039..ede904f279 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -1172,7 +1172,7 @@ ModuleBuilder::processImport(frontend::ParseNode* pn) if (!maybeAppendRequestedModule(module)) return false; - for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) { + for (ParseNode* spec : pn->pn_left->as().contents()) { MOZ_ASSERT(spec->isKind(PNK_IMPORT_SPEC)); MOZ_ASSERT(spec->pn_left->isArity(PN_NAME)); MOZ_ASSERT(spec->pn_right->isArity(PN_NAME)); @@ -1215,7 +1215,7 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) switch (kid->getKind()) { case PNK_EXPORT_SPEC_LIST: MOZ_ASSERT(!isDefault); - for (ParseNode* spec = kid->pn_head; spec; spec = spec->pn_next) { + for (ParseNode* spec : kid->as().contents()) { MOZ_ASSERT(spec->isKind(PNK_EXPORT_SPEC)); RootedAtom localName(cx_, spec->pn_left->pn_atom); RootedAtom exportName(cx_, spec->pn_right->pn_atom); @@ -1238,7 +1238,7 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) case PNK_CONST: case PNK_LET: { MOZ_ASSERT(kid->isArity(PN_LIST)); - for (ParseNode* binding = kid->pn_head; binding; binding = binding->pn_next) { + for (ParseNode* binding : kid->as().contents()) { if (binding->isKind(PNK_ASSIGN)) binding = binding->pn_left; else @@ -1250,11 +1250,11 @@ ModuleBuilder::processExport(frontend::ParseNode* pn) if (!appendExportEntry(exportName, localName)) return false; } else if (binding->isKind(PNK_ARRAY)) { - if (!processExportArrayBinding(binding)) + if (!processExportArrayBinding(&binding->as())) return false; } else { MOZ_ASSERT(binding->isKind(PNK_OBJECT)); - if (!processExportObjectBinding(binding)) + if (!processExportObjectBinding(&binding->as())) return false; } } @@ -1288,19 +1288,18 @@ ModuleBuilder::processExportBinding(frontend::ParseNode* binding) } if (binding->isKind(PNK_ARRAY)) - return processExportArrayBinding(binding); + return processExportArrayBinding(&binding->as()); MOZ_ASSERT(binding->isKind(PNK_OBJECT)); - return processExportObjectBinding(binding); + return processExportObjectBinding(&binding->as()); } bool -ModuleBuilder::processExportArrayBinding(frontend::ParseNode* pn) +ModuleBuilder::processExportArrayBinding(frontend::ListNode* array) { - MOZ_ASSERT(pn->isKind(PNK_ARRAY)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(array->isKind(PNK_ARRAY)); - for (ParseNode* node = pn->pn_head; node; node = node->pn_next) { + for (ParseNode* node : array->contents()) { if (node->isKind(PNK_ELISION)) continue; @@ -1317,12 +1316,11 @@ ModuleBuilder::processExportArrayBinding(frontend::ParseNode* pn) } bool -ModuleBuilder::processExportObjectBinding(frontend::ParseNode* pn) +ModuleBuilder::processExportObjectBinding(frontend::ListNode* obj) { - MOZ_ASSERT(pn->isKind(PNK_OBJECT)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(obj->isKind(PNK_OBJECT)); - for (ParseNode* node = pn->pn_head; node; node = node->pn_next) { + for (ParseNode* node : obj->contents()) { MOZ_ASSERT(node->isKind(PNK_MUTATEPROTO) || node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND) || @@ -1360,7 +1358,7 @@ ModuleBuilder::processExportFrom(frontend::ParseNode* pn) if (!maybeAppendRequestedModule(module)) return false; - for (ParseNode* spec = pn->pn_left->pn_head; spec; spec = spec->pn_next) { + for (ParseNode* spec : pn->pn_left->as().contents()) { if (spec->isKind(PNK_EXPORT_SPEC)) { RootedAtom bindingName(cx_, spec->pn_left->pn_atom); RootedAtom exportName(cx_, spec->pn_right->pn_atom); diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index f2d94a9c5d..9c10f8465e 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -24,6 +24,7 @@ class ModuleEnvironmentObject; class ModuleObject; namespace frontend { +class ListNode; class ParseNode; class TokenStream; } /* namespace frontend */ @@ -353,8 +354,8 @@ class MOZ_STACK_CLASS ModuleBuilder ImportEntryObject* importEntryFor(JSAtom* localName) const; bool processExportBinding(frontend::ParseNode* pn); - bool processExportArrayBinding(frontend::ParseNode* pn); - bool processExportObjectBinding(frontend::ParseNode* pn); + bool processExportArrayBinding(frontend::ListNode* pn); + bool processExportObjectBinding(frontend::ListNode* pn); bool appendExportEntry(HandleAtom exportName, HandleAtom localName, frontend::ParseNode* node = nullptr); diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index d63c1dd493..4c7d7cad8c 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -1790,17 +1790,17 @@ class ASTSerializer UnaryOperator unop(ParseNodeKind kind, JSOp op); AssignmentOperator aop(JSOp op); - bool statements(ParseNode* pn, NodeVector& elts); - bool expressions(ParseNode* pn, NodeVector& elts); - bool leftAssociate(ParseNode* pn, MutableHandleValue dst); - bool rightAssociate(ParseNode* pn, MutableHandleValue dst); - bool functionArgs(ParseNode* pn, ParseNode* pnargs, + bool statements(ListNode* stmtList, NodeVector& elts); + bool expressions(ListNode* exprList, NodeVector& elts); + bool leftAssociate(ListNode* node, MutableHandleValue dst); + bool rightAssociate(ListNode* node, MutableHandleValue dst); + bool functionArgs(ParseNode* pn, ListNode* argsList, NodeVector& args, NodeVector& defaults, MutableHandleValue rest); bool sourceElement(ParseNode* pn, MutableHandleValue dst); bool declaration(ParseNode* pn, MutableHandleValue dst); - bool variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst); + bool variableDeclaration(ListNode* declList, bool lexical, MutableHandleValue dst); bool variableDeclarator(ParseNode* pn, MutableHandleValue dst); bool importDeclaration(ParseNode* pn, MutableHandleValue dst); bool importSpecifier(ParseNode* pn, MutableHandleValue dst); @@ -1822,7 +1822,7 @@ class ASTSerializer bool forOf(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt, MutableHandleValue dst); bool statement(ParseNode* pn, MutableHandleValue dst); - bool blockStatement(ParseNode* pn, MutableHandleValue dst); + bool blockStatement(ListNode* node, MutableHandleValue dst); bool switchStatement(ParseNode* pn, MutableHandleValue dst); bool switchCase(ParseNode* pn, MutableHandleValue dst); bool tryStatement(ParseNode* pn, MutableHandleValue dst); @@ -1864,8 +1864,8 @@ class ASTSerializer } bool pattern(ParseNode* pn, MutableHandleValue dst); - bool arrayPattern(ParseNode* pn, MutableHandleValue dst); - bool objectPattern(ParseNode* pn, MutableHandleValue dst); + bool arrayPattern(ListNode* array, MutableHandleValue dst); + bool objectPattern(ListNode* obj, MutableHandleValue dst); bool function(ParseNode* pn, ASTType type, MutableHandleValue dst); bool functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults, @@ -1897,7 +1897,7 @@ class ASTSerializer builder.setTokenStream(&p->tokenStream); } - bool program(ParseNode* pn, MutableHandleValue dst); + bool program(ListNode* node, MutableHandleValue dst); }; } /* anonymous namespace */ @@ -2021,19 +2021,18 @@ ASTSerializer::binop(ParseNodeKind kind, JSOp op) } bool -ASTSerializer::statements(ParseNode* pn, NodeVector& elts) +ASTSerializer::statements(ListNode* stmtList, NodeVector& elts) { - MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST)); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(stmtList->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* stmt : stmtList->contents()) { + MOZ_ASSERT(stmtList->pn_pos.encloses(stmt->pn_pos)); RootedValue elt(cx); - if (!sourceElement(next, &elt)) + if (!sourceElement(stmt, &elt)) return false; elts.infallibleAppend(elt); } @@ -2042,16 +2041,16 @@ ASTSerializer::statements(ParseNode* pn, NodeVector& elts) } bool -ASTSerializer::expressions(ParseNode* pn, NodeVector& elts) +ASTSerializer::expressions(ListNode* exprList, NodeVector& elts) { - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(exprList->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* expr : exprList->contents()) { + MOZ_ASSERT(exprList->pn_pos.encloses(expr->pn_pos)); RootedValue elt(cx); - if (!expression(next, &elt)) + if (!expression(expr, &elt)) return false; elts.infallibleAppend(elt); } @@ -2060,23 +2059,23 @@ ASTSerializer::expressions(ParseNode* pn, NodeVector& elts) } bool -ASTSerializer::blockStatement(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::blockStatement(ListNode* node, MutableHandleValue dst) { - MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST)); + MOZ_ASSERT(node->isKind(PNK_STATEMENTLIST)); NodeVector stmts(cx); - return statements(pn, stmts) && - builder.blockStatement(stmts, &pn->pn_pos, dst); + return statements(node, stmts) && + builder.blockStatement(stmts, &node->pn_pos, dst); } bool -ASTSerializer::program(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::program(ListNode* node, MutableHandleValue dst) { - MOZ_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno); + MOZ_ASSERT(parser->tokenStream.srcCoords.lineNum(node->pn_pos.begin) == lineno); NodeVector stmts(cx); - return statements(pn, stmts) && - builder.program(stmts, &pn->pn_pos, dst); + return statements(node, stmts) && + builder.program(stmts, &node->pn_pos, dst); } bool @@ -2099,38 +2098,38 @@ ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst) return function(pn, AST_FUNC_DECL, dst); case PNK_VAR: - return variableDeclaration(pn, false, dst); + return variableDeclaration(&pn->as(), false, dst); default: MOZ_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_CONST)); - return variableDeclaration(pn, true, dst); + return variableDeclaration(&pn->as(), true, dst); } } bool -ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst) +ASTSerializer::variableDeclaration(ListNode* declList, bool lexical, MutableHandleValue dst) { - MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST)); - MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR)); + MOZ_ASSERT_IF(lexical, declList->isKind(PNK_LET) || declList->isKind(PNK_CONST)); + MOZ_ASSERT_IF(!lexical, declList->isKind(PNK_VAR)); VarDeclKind kind = VARDECL_ERR; // Treat both the toplevel const binding (secretly var-like) and the lexical const // the same way if (lexical) - kind = pn->isKind(PNK_LET) ? VARDECL_LET : VARDECL_CONST; + kind = declList->isKind(PNK_LET) ? VARDECL_LET : VARDECL_CONST; else - kind = pn->isKind(PNK_VAR) ? VARDECL_VAR : VARDECL_CONST; + kind = declList->isKind(PNK_VAR) ? VARDECL_VAR : VARDECL_CONST; NodeVector dtors(cx); - if (!dtors.reserve(pn->pn_count)) + if (!dtors.reserve(declList->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { + for (ParseNode* decl : declList->contents()) { RootedValue child(cx); - if (!variableDeclarator(next, &child)) + if (!variableDeclarator(decl, &child)) return false; dtors.infallibleAppend(child); } - return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst); + return builder.variableDeclaration(dtors, kind, &declList->pn_pos, dst); } bool @@ -2168,13 +2167,15 @@ ASTSerializer::importDeclaration(ParseNode* pn, MutableHandleValue dst) MOZ_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST)); MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING)); + ListNode* specList = &pn->pn_left->as(); + NodeVector elts(cx); - if (!elts.reserve(pn->pn_left->pn_count)) + if (!elts.reserve(specList->count())) return false; - for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) { + for (ParseNode* spec : specList->contents()) { RootedValue elt(cx); - if (!importSpecifier(next, &elt)) + if (!importSpecifier(spec, &elt)) return false; elts.infallibleAppend(elt); } @@ -2210,14 +2211,15 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst) ParseNode* kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left; switch (ParseNodeKind kind = kid->getKind()) { - case PNK_EXPORT_SPEC_LIST: - if (!elts.reserve(pn->pn_left->pn_count)) + case PNK_EXPORT_SPEC_LIST: { + ListNode* specList = &pn->pn_left->as(); + if (!elts.reserve(specList->count())) return false; - for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) { + for (ParseNode* spec : specList->contents()) { RootedValue elt(cx); - if (next->isKind(PNK_EXPORT_SPEC)) { - if (!exportSpecifier(next, &elt)) + if (spec->isKind(PNK_EXPORT_SPEC)) { + if (!exportSpecifier(spec, &elt)) return false; } else { if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt)) @@ -2226,6 +2228,7 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst) elts.infallibleAppend(elt); } break; + } case PNK_FUNCTION: if (!function(kid, AST_FUNC_DECL, &decl)) @@ -2240,7 +2243,7 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst) case PNK_VAR: case PNK_CONST: case PNK_LET: - if (!variableDeclaration(kid, kind != PNK_VAR, &decl)) + if (!variableDeclaration(&kid->as(), kind != PNK_VAR, &decl)) return false; break; @@ -2299,29 +2302,22 @@ ASTSerializer::switchStatement(ParseNode* pn, MutableHandleValue dst) if (!expression(pn->pn_left, &disc)) return false; - ParseNode* listNode; - bool lexical; - if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) { - listNode = pn->pn_right->pn_expr; - lexical = true; - } else { - listNode = pn->pn_right; - lexical = false; - } + MOZ_ASSERT(pn->pn_right->isKind(PNK_LEXICALSCOPE)); + ListNode* caseList = &pn->pn_right->scopeBody()->as(); NodeVector cases(cx); - if (!cases.reserve(listNode->pn_count)) + if (!cases.reserve(caseList->count())) return false; - for (ParseNode* next = listNode->pn_head; next; next = next->pn_next) { + for (ParseNode* caseNode : caseList->contents()) { RootedValue child(cx); - if (!switchCase(next, &child)) + if (!switchCase(caseNode, &child)) return false; cases.infallibleAppend(child); } - return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst); + return builder.switchStatement(disc, cases, /* lexical = */ true, &pn->pn_pos, dst); } bool @@ -2358,11 +2354,11 @@ ASTSerializer::tryStatement(ParseNode* pn, MutableHandleValue dst) NodeVector guarded(cx); RootedValue unguarded(cx, NullValue()); - if (ParseNode* catchList = pn->pn_kid2) { - if (!guarded.reserve(catchList->pn_count)) + if (ListNode* catchList = &pn->pn_kid2->as()) { + if (!guarded.reserve(catchList->count())) return false; - for (ParseNode* next = catchList->pn_head; next; next = next->pn_next) { + for (ParseNode* next : catchList->contents()) { RootedValue clause(cx); bool isGuarded; if (!catchClause(next->pn_expr, &isGuarded, &clause)) @@ -2389,7 +2385,7 @@ ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst) bool lexical = pn->isKind(PNK_LET) || pn->isKind(PNK_CONST); return (lexical || pn->isKind(PNK_VAR)) - ? variableDeclaration(pn, lexical, dst) + ? variableDeclaration(&pn->as(), lexical, dst) : expression(pn, dst); } @@ -2467,7 +2463,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) MOZ_FALLTHROUGH; case PNK_STATEMENTLIST: - return blockStatement(pn, dst); + return blockStatement(&pn->as(), dst); case PNK_IF: { @@ -2535,7 +2531,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) { RootedValue var(cx); if (head->pn_kid1->isKind(PNK_LEXICALSCOPE)) { - if (!variableDeclaration(head->pn_kid1->pn_expr, true, &var)) + if (!variableDeclaration(&head->pn_kid1->scopeBody()->as(), true, &var)) return false; } else if (!head->pn_kid1->isKind(PNK_VAR) && !head->pn_kid1->isKind(PNK_LET) && @@ -2544,7 +2540,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) if (!pattern(head->pn_kid1, &var)) return false; } else { - if (!variableDeclaration(head->pn_kid1, + if (!variableDeclaration(&head->pn_kid1->as(), head->pn_kid1->isKind(PNK_LET) || head->pn_kid1->isKind(PNK_CONST), &var)) @@ -2615,15 +2611,16 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) case PNK_CLASSMETHODLIST: { + ListNode* methodList = &pn->as(); NodeVector methods(cx); - if (!methods.reserve(pn->pn_count)) + if (!methods.reserve(methodList->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* method : methodList->contents()) { + MOZ_ASSERT(methodList->pn_pos.encloses(method->pn_pos)); RootedValue prop(cx); - if (!classMethod(next, &prop)) + if (!classMethod(method, &prop)) return false; methods.infallibleAppend(prop); } @@ -2668,32 +2665,31 @@ ASTSerializer::classMethod(ParseNode* pn, MutableHandleValue dst) } bool -ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::leftAssociate(ListNode* node, MutableHandleValue dst) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count >= 1); + MOZ_ASSERT(!node->empty()); - ParseNodeKind kind = pn->getKind(); + ParseNodeKind kind = node->getKind(); bool logop = (kind == PNK_COALESCE || kind == PNK_OR || kind == PNK_AND); - ParseNode* head = pn->pn_head; + ParseNode* head = node->head(); RootedValue left(cx); if (!expression(head, &left)) return false; - for (ParseNode* next = head->pn_next; next; next = next->pn_next) { + for (ParseNode* next : node->contentsFrom(head->pn_next)) { RootedValue right(cx); if (!expression(next, &right)) return false; - TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end); + TokenPos subpos(node->pn_pos.begin, next->pn_pos.end); if (logop) { if (!builder.logicalExpression(kind, left, right, &subpos, &left)) return false; } else { - BinaryOperator op = binop(pn->getKind(), pn->getOp()); + BinaryOperator op = binop(node->getKind(), node->getOp()); LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT); if (!builder.binaryExpression(op, left, right, &subpos, &left)) @@ -2706,15 +2702,14 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst) } bool -ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::rightAssociate(ListNode* node, MutableHandleValue dst) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count >= 1); + MOZ_ASSERT(!node->empty()); // First, we need to reverse the list, so that we can traverse it in the right order. // It's OK to destructively reverse the list, because there are no other consumers. - ParseNode* head = pn->pn_head; + ParseNode* head = node->head(); ParseNode* prev = nullptr; ParseNode* current = head; ParseNode* next; @@ -2735,9 +2730,9 @@ ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst) if (!expression(next, &left)) return false; - TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end); + TokenPos subpos(node->pn_pos.begin, next->pn_pos.end); - BinaryOperator op = binop(pn->getKind(), pn->getOp()); + BinaryOperator op = binop(node->getKind(), node->getOp()); LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT); if (!builder.binaryExpression(op, left, right, &subpos, &right)) @@ -2760,13 +2755,15 @@ ASTSerializer::comprehensionBlock(ParseNode* pn, MutableHandleValue dst) bool isForEach = in->isKind(PNK_FORIN) && (pn->pn_iflags & JSITER_FOREACH); bool isForOf = in->isKind(PNK_FOROF); - ParseNode* decl = in->pn_kid1; - if (decl->isKind(PNK_LEXICALSCOPE)) - decl = decl->pn_expr; - MOZ_ASSERT(decl->pn_count == 1); + ListNode* decl; + if (in->pn_kid1->isKind(PNK_LEXICALSCOPE)) + decl = &in->pn_kid1->pn_expr->as(); + else + decl = &in->pn_kid1->as(); + MOZ_ASSERT(decl->count() == 1); RootedValue patt(cx), src(cx); - return pattern(decl->pn_head, &patt) && + return pattern(decl->head(), &patt) && expression(in->pn_kid3, &src) && builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst); } @@ -2885,7 +2882,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_COMMA: { NodeVector exprs(cx); - return expressions(pn, exprs) && + return expressions(&pn->as(), exprs) && builder.sequenceExpression(exprs, &pn->pn_pos, dst); } @@ -2906,7 +2903,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_COALESCE: case PNK_OR: case PNK_AND: - return leftAssociate(pn, dst); + return leftAssociate(&pn->as(), dst); case PNK_PREINCREMENT: case PNK_PREDECREMENT: @@ -2977,10 +2974,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_BITAND: case PNK_IN: case PNK_INSTANCEOF: - return leftAssociate(pn, dst); + return leftAssociate(&pn->as(), dst); case PNK_POW: - return rightAssociate(pn, dst); + return rightAssociate(&pn->as(), dst); case PNK_DELETENAME: case PNK_DELETEPROP: @@ -3004,8 +3001,19 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) builder.unaryExpression(op, expr, &pn->pn_pos, dst); } - case PNK_GENEXP: - return generatorExpression(pn->generatorExpr(), dst); + case PNK_GENEXP: { + ParseNode* callee = pn->pn_left; + MOZ_ASSERT(callee->isKind(PNK_FUNCTION)); + + ListNode* paramsBody = &callee->pn_body->as(); + MOZ_ASSERT(paramsBody->isKind(PNK_PARAMSBODY)); + + ListNode* body = ¶msBody->last()->as(); + MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); + MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || + body->last()->isKind(PNK_COMPREHENSIONFOR)); + return generatorExpression(body->last(), dst); + } case PNK_DELETEOPTCHAIN: { RootedValue expr(cx); @@ -3026,7 +3034,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_SUPERCALL: { ParseNode* pn_callee = pn->pn_left; - ParseNode* pn_args = pn->pn_right; + ListNode* argsList = &pn->pn_right->as(); MOZ_ASSERT(pn->pn_pos.encloses(pn_callee->pn_pos)); RootedValue callee(cx); @@ -3040,14 +3048,14 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) } NodeVector args(cx); - if (!args.reserve(pn_args->pn_count)) + if (!args.reserve(argsList->count())) return false; - for (ParseNode* next = pn_args->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* argNode : argsList->contents()) { + MOZ_ASSERT(pn->pn_pos.encloses(argNode->pn_pos)); RootedValue arg(cx); - if (!expression(next, &arg)) + if (!expression(argNode, &arg)) return false; args.infallibleAppend(arg); } @@ -3118,57 +3126,62 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_CALLSITEOBJ: { + CallSiteNode* callSiteObj = &pn->as(); + ListNode* rawNodes = callSiteObj->rawNodes(); NodeVector raw(cx); - if (!raw.reserve(pn->pn_head->pn_count)) + if (!raw.reserve(rawNodes->count())) return false; - for (ParseNode* next = pn->pn_head->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* rawItem : rawNodes->contents()) { + MOZ_ASSERT(callSiteObj->pn_pos.encloses(rawItem->pn_pos)); RootedValue expr(cx); - expr.setString(next->pn_atom); + expr.setString(rawItem->pn_atom); raw.infallibleAppend(expr); } NodeVector cooked(cx); - if (!cooked.reserve(pn->pn_count - 1)) + if (!cooked.reserve(callSiteObj->count() - 1)) return false; - for (ParseNode* next = pn->pn_head->pn_next; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* cookedItem = callSiteObj->head()->pn_next; + cookedItem; + cookedItem = cookedItem->pn_next) { + MOZ_ASSERT(callSiteObj->pn_pos.encloses(cookedItem->pn_pos)); RootedValue expr(cx); - if (next->isKind(PNK_RAW_UNDEFINED)) { + if (cookedItem->isKind(PNK_RAW_UNDEFINED)) { expr.setUndefined(); } else { - MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING)); - expr.setString(next->pn_atom); + MOZ_ASSERT(cookedItem->isKind(PNK_TEMPLATE_STRING)); + expr.setString(cookedItem->pn_atom); } cooked.infallibleAppend(expr); } - return builder.callSiteObj(raw, cooked, &pn->pn_pos, dst); + return builder.callSiteObj(raw, cooked, &callSiteObj->pn_pos, dst); } case PNK_ARRAY: { + ListNode* array = &pn->as(); NodeVector elts(cx); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(array->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* item : array->contents()) { + MOZ_ASSERT(array->pn_pos.encloses(item->pn_pos)); - if (next->isKind(PNK_ELISION)) { + if (item->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); } else { RootedValue expr(cx); - if (!expression(next, &expr)) + if (!expression(item, &expr)) return false; elts.infallibleAppend(expr); } } - return builder.arrayExpression(elts, &pn->pn_pos, dst); + return builder.arrayExpression(elts, &array->pn_pos, dst); } case PNK_SPREAD: @@ -3187,20 +3200,21 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_OBJECT: { + ListNode* obj = &pn->as(); NodeVector elts(cx); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(obj->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* item : obj->contents()) { + MOZ_ASSERT(obj->pn_pos.encloses(item->pn_pos)); RootedValue prop(cx); - if (!property(next, &prop)) + if (!property(item, &prop)) return false; elts.infallibleAppend(prop); } - return builder.objectExpression(elts, &pn->pn_pos, dst); + return builder.objectExpression(elts, &obj->pn_pos, dst); } case PNK_NAME: @@ -3211,20 +3225,21 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_TEMPLATE_STRING_LIST: { + ListNode* list = &pn->as(); NodeVector elts(cx); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(list->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos)); + for (ParseNode* item : list->contents()) { + MOZ_ASSERT(list->pn_pos.encloses(item->pn_pos)); RootedValue expr(cx); - if (!expression(next, &expr)) + if (!expression(item, &expr)) return false; elts.infallibleAppend(expr); } - return builder.templateLiteral(elts, &pn->pn_pos, dst); + return builder.templateLiteral(elts, &list->pn_pos, dst); } case PNK_TEMPLATE_STRING: @@ -3256,11 +3271,14 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) } case PNK_ARRAYCOMP: - MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos)); + { + ListNode* literal = &pn->as(); + MOZ_ASSERT(pn->pn_pos.encloses(literal->head()->pn_pos)); /* NB: it's no longer the case that pn_count could be 2. */ - LOCAL_ASSERT(pn->pn_count == 1); - return comprehension(pn->pn_head, dst); + LOCAL_ASSERT(literal->count() == 1); + return comprehension(literal->head(), dst); + } case PNK_CLASS: return classDefinition(pn, true, dst); @@ -3397,46 +3415,46 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst) } bool -ASTSerializer::arrayPattern(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::arrayPattern(ListNode* array, MutableHandleValue dst) { - MOZ_ASSERT(pn->isKind(PNK_ARRAY)); + MOZ_ASSERT(array->isKind(PNK_ARRAY)); NodeVector elts(cx); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(array->count())) return false; - for (ParseNode* next = pn->pn_head; next; next = next->pn_next) { - if (next->isKind(PNK_ELISION)) { + for (ParseNode* item : array->contents()) { + if (item->isKind(PNK_ELISION)) { elts.infallibleAppend(NullValue()); - } else if (next->isKind(PNK_SPREAD)) { + } else if (item->isKind(PNK_SPREAD)) { RootedValue target(cx); RootedValue spread(cx); - if (!pattern(next->pn_kid, &target)) + if (!pattern(item->pn_kid, &target)) return false; - if(!builder.spreadExpression(target, &next->pn_pos, &spread)) + if(!builder.spreadExpression(target, &item->pn_pos, &spread)) return false; elts.infallibleAppend(spread); } else { RootedValue patt(cx); - if (!pattern(next, &patt)) + if (!pattern(item, &patt)) return false; elts.infallibleAppend(patt); } } - return builder.arrayPattern(elts, &pn->pn_pos, dst); + return builder.arrayPattern(elts, &array->pn_pos, dst); } bool -ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) +ASTSerializer::objectPattern(ListNode* obj, MutableHandleValue dst) { - MOZ_ASSERT(pn->isKind(PNK_OBJECT)); + MOZ_ASSERT(obj->isKind(PNK_OBJECT)); NodeVector elts(cx); - if (!elts.reserve(pn->pn_count)) + if (!elts.reserve(obj->count())) return false; - for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + for (ParseNode* propdef : obj->contents()) { if (propdef->isKind(PNK_SPREAD)) { RootedValue target(cx); RootedValue spread(cx); @@ -3473,7 +3491,7 @@ ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst) elts.infallibleAppend(prop); } - return builder.objectPattern(elts, &pn->pn_pos, dst); + return builder.objectPattern(elts, &obj->pn_pos, dst); } bool @@ -3482,10 +3500,10 @@ ASTSerializer::pattern(ParseNode* pn, MutableHandleValue dst) JS_CHECK_RECURSION(cx, return false); switch (pn->getKind()) { case PNK_OBJECT: - return objectPattern(pn, dst); + return objectPattern(&pn->as(), dst); case PNK_ARRAY: - return arrayPattern(pn, dst); + return arrayPattern(&pn->as(), dst); default: return expression(pn, dst); @@ -3547,15 +3565,15 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& bool isAsync, bool isExpression, MutableHandleValue body, MutableHandleValue rest) { - ParseNode* pnargs; + ListNode* argsList; ParseNode* pnbody; /* Extract the args and body separately. */ if (pn->isKind(PNK_PARAMSBODY)) { - pnargs = pn; - pnbody = pn->last(); + argsList = &pn->as(); + pnbody = argsList->last(); } else { - pnargs = nullptr; + argsList = nullptr; pnbody = pn; } @@ -3565,29 +3583,29 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& /* Serialize the arguments and body. */ switch (pnbody->getKind()) { case PNK_RETURN: /* expression closure, no destructured args */ - return functionArgs(pn, pnargs, args, defaults, rest) && + return functionArgs(pn, argsList, args, defaults, rest) && expression(pnbody->pn_kid, body); case PNK_STATEMENTLIST: /* statement closure */ { - ParseNode* pnstart = pnbody->pn_head; + ParseNode* firstNode = pnbody->as().head(); // Skip over initial yield in generator. - if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) { - MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD); - pnstart = pnstart->pn_next; + if (firstNode && firstNode->isKind(PNK_INITIALYIELD)) { + MOZ_ASSERT(firstNode->getOp() == JSOP_INITIALYIELD); + firstNode = firstNode->pn_next; } // Async arrow with expression body is converted into STATEMENTLIST // to insert initial yield. if (isAsync && isExpression) { - MOZ_ASSERT(pnstart->getKind() == PNK_RETURN); - return functionArgs(pn, pnargs, args, defaults, rest) && - expression(pnstart->pn_kid, body); + MOZ_ASSERT(firstNode->getKind() == PNK_RETURN); + return functionArgs(pn, argsList, args, defaults, rest) && + expression(firstNode->pn_kid, body); } - return functionArgs(pn, pnargs, args, defaults, rest) && - functionBody(pnstart, &pnbody->pn_pos, body); + return functionArgs(pn, argsList, args, defaults, rest) && + functionBody(firstNode, &pnbody->pn_pos, body); } default: @@ -3596,11 +3614,11 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& } bool -ASTSerializer::functionArgs(ParseNode* pn, ParseNode* pnargs, +ASTSerializer::functionArgs(ParseNode* pn, ListNode* argsList, NodeVector& args, NodeVector& defaults, MutableHandleValue rest) { - if (!pnargs) + if (!argsList) return true; RootedValue node(cx); @@ -3609,7 +3627,7 @@ ASTSerializer::functionArgs(ParseNode* pn, ParseNode* pnargs, "must be initially empty for it to be proper to clear this " "when there are no defaults"); - for (ParseNode* arg = pnargs->pn_head; arg && arg != pnargs->last(); arg = arg->pn_next) { + for (ParseNode* arg : argsList->contentsTo(argsList->last())) { ParseNode* pat; ParseNode* defNode; if (arg->isKind(PNK_NAME) || arg->isKind(PNK_ARRAY) || arg->isKind(PNK_OBJECT)) { @@ -3625,7 +3643,7 @@ ASTSerializer::functionArgs(ParseNode* pn, ParseNode* pnargs, MOZ_ASSERT(pat->isKind(PNK_NAME) || pat->isKind(PNK_ARRAY) || pat->isKind(PNK_OBJECT)); if (!pattern(pat, &node)) return false; - if (rest.isUndefined() && arg->pn_next == pnargs->last()) { + if (rest.isUndefined() && arg->pn_next == argsList->last()) { rest.setObject(node.toObject()); } else { if (!args.append(node)) @@ -3837,7 +3855,7 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp) } RootedValue val(cx); - if (!serialize.program(pn, &val)) { + if (!serialize.program(&pn->as(), &val)) { args.rval().setNull(); return false; } diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index f2acb2942f..ffaf99a444 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -594,9 +594,11 @@ BytecodeEmitter::emitLoopHead(ParseNode* nextpn, JumpTarget* top) */ if (nextpn->isKind(PNK_LEXICALSCOPE)) nextpn = nextpn->scopeBody(); - MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST)); - if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head) - nextpn = nextpn->pn_head; + if (nextpn->isKind(PNK_STATEMENTLIST)) { + if (ParseNode* firstStatement = nextpn->as().head()) { + nextpn = firstStatement; + } + } if (!updateSourceCoordNotes(nextpn->pn_pos.begin)) return false; } @@ -612,9 +614,11 @@ BytecodeEmitter::emitLoopEntry(ParseNode* nextpn, JumpList entryJump) /* Update the line number, as for LOOPHEAD. */ if (nextpn->isKind(PNK_LEXICALSCOPE)) nextpn = nextpn->scopeBody(); - MOZ_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST)); - if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head) - nextpn = nextpn->pn_head; + if (nextpn->isKind(PNK_STATEMENTLIST)) { + if (ParseNode* firstStatement = nextpn->as().head()) { + nextpn = firstStatement; + } + } if (!updateSourceCoordNotes(nextpn->pn_pos.begin)) return false; } @@ -1222,13 +1226,12 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_STRICTNE: // Any subexpression of a comma expression could be effectful. case PNK_COMMA: - MOZ_ASSERT(pn->pn_count > 0); + MOZ_ASSERT(!pn->as().empty()); MOZ_FALLTHROUGH; // Subcomponents of a literal may be effectful. case PNK_ARRAY: case PNK_OBJECT: - MOZ_ASSERT(pn->isArity(PN_LIST)); - for (ParseNode* item = pn->pn_head; item; item = item->pn_next) { + for (ParseNode* item : pn->as().contents()) { if (!checkSideEffects(item, answer)) return false; if (*answer) @@ -1262,8 +1265,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_DIV: case PNK_MOD: case PNK_POW: - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count >= 2); + MOZ_ASSERT(pn->as().count() >= 2); *answer = true; return true; @@ -1314,7 +1316,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_VAR: case PNK_CONST: case PNK_LET: - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(pn->is()); *answer = true; return true; @@ -1347,7 +1349,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) // this only causes side-effects if one of the arguments does, but since // the call being made will always trigger side-effects, it isn't needed. case PNK_ARGUMENTS: - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(pn->is()); *answer = true; return true; @@ -1464,19 +1466,21 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) // We could methodically check every interpolated expression, but it's // probably not worth the trouble. Treat template strings as effect-free // only if they don't contain any substitutions. - case PNK_TEMPLATE_STRING_LIST: - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count > 0); - MOZ_ASSERT((pn->pn_count % 2) == 1, + case PNK_TEMPLATE_STRING_LIST: { + ListNode* list = &pn->as(); + MOZ_ASSERT(!list->empty()); + MOZ_ASSERT((list->count() % 2) == 1, "template strings must alternate template and substitution " "parts"); - *answer = pn->pn_count > 1; + *answer = list->count() > 1; return true; + } - case PNK_ARRAYCOMP: - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count == 1); - return checkSideEffects(pn->pn_head, answer); + case PNK_ARRAYCOMP: { + ListNode* list = &pn->as(); + MOZ_ASSERT(list->count() == 1); + return checkSideEffects(list->head(), answer); + } // This should be unreachable but is left as-is for now. case PNK_PARAMSBODY: @@ -2051,7 +2055,7 @@ BytecodeEmitter::emitSwitch(SwitchStatement* pn) { ParseNode& lexical = pn->lexicalForCaseList(); MOZ_ASSERT(lexical.isKind(PNK_LEXICALSCOPE)); - ParseNode* cases = lexical.scopeBody(); + ListNode* cases = &lexical.scopeBody()->as(); MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST)); SwitchEmitter se(this); @@ -2069,25 +2073,26 @@ BytecodeEmitter::emitSwitch(SwitchStatement* pn) // A switch statement may contain hoisted functions inside its // cases. The PNX_FUNCDEFS flag is propagated from the STATEMENTLIST // bodies of the cases to the case list. - if (cases->pn_xflags & PNX_FUNCDEFS) { - for (ParseNode* caseNode = cases->pn_head; caseNode; caseNode = caseNode->pn_next) { - if (caseNode->pn_right->pn_xflags & PNX_FUNCDEFS) { - if (!emitHoistedFunctionsInList(caseNode->pn_right)) + if (cases->hasTopLevelFunctionDeclarations()) { + for (ParseNode* caseNode : cases->contents()) { + ListNode* statements = &caseNode->pn_right->as(); + if (statements->hasTopLevelFunctionDeclarations()) { + if (!emitHoistedFunctionsInList(statements)) return false; } } } } else { - MOZ_ASSERT(!(cases->pn_xflags & PNX_FUNCDEFS)); + MOZ_ASSERT(!cases->hasTopLevelFunctionDeclarations()); } SwitchEmitter::TableGenerator tableGen(this); - uint32_t caseCount = cases->pn_count - (pn->hasDefault() ? 1 : 0); - CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as() : nullptr; + uint32_t caseCount = cases->count() - (pn->hasDefault() ? 1 : 0); if (caseCount == 0) { tableGen.finish(0); } else { - for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) { + for (ParseNode* item : cases->contents()) { + CaseClause* caseNode = &item->as(); if (caseNode->isDefault()) continue; @@ -2122,7 +2127,8 @@ BytecodeEmitter::emitSwitch(SwitchStatement* pn) return false; // Emit code for evaluating cases and jumping to case statements. - for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) { + for (ParseNode* item : cases->contents()) { + CaseClause* caseNode = &item->as(); if (caseNode->isDefault()) continue; @@ -2141,7 +2147,8 @@ BytecodeEmitter::emitSwitch(SwitchStatement* pn) } // Emit code for each case's statements. - for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) { + for (ParseNode* item : cases->contents()) { + CaseClause* caseNode = &item->as(); if (caseNode->isDefault()) { if (!se.emitDefaultBody()) return false; @@ -2412,52 +2419,6 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body) return true; } -template -bool -BytecodeEmitter::emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName) -{ - if (pattern->isKind(PNK_ARRAY)) { - for (ParseNode* element = pattern->pn_head; element; element = element->pn_next) { - if (element->isKind(PNK_ELISION)) - continue; - ParseNode* target = element; - if (element->isKind(PNK_SPREAD)) { - target = element->pn_kid; - } - if (target->isKind(PNK_ASSIGN)) - target = target->pn_left; - if (target->isKind(PNK_NAME)) { - if (!emitName(this, target)) - return false; - } else { - if (!emitDestructuringDeclsWithEmitter(target, emitName)) - return false; - } - } - return true; - } - - MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); - for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { - MOZ_ASSERT(member->isKind(PNK_MUTATEPROTO) || - member->isKind(PNK_COLON) || - member->isKind(PNK_SHORTHAND)); - - ParseNode* target = member->isKind(PNK_MUTATEPROTO) ? member->pn_kid : member->pn_right; - - if (target->isKind(PNK_ASSIGN)) - target = target->pn_left; - if (target->isKind(PNK_NAME)) { - if (!emitName(this, target)) - return false; - } else { - if (!emitDestructuringDeclsWithEmitter(target, emitName)) - return false; - } - } - return true; -} - bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted) { @@ -2567,7 +2528,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri else if (target->isKind(PNK_ASSIGN)) target = target->pn_left; if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) { - if (!emitDestructuringOps(target, flav)) + if (!emitDestructuringOps(&target->as(), flav)) return false; // Per its post-condition, emitDestructuringOps has left the // to-be-destructured value on top of the stack. @@ -3031,10 +2992,9 @@ BytecodeEmitter::emitInitializerInBranch(ParseNode* initializer, ParseNode* patt } bool -BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlavor flav) +BytecodeEmitter::emitDestructuringOpsArray(ListNode* pattern, DestructuringFlavor flav) { MOZ_ASSERT(pattern->isKind(PNK_ARRAY)); - MOZ_ASSERT(pattern->isArity(PN_LIST)); MOZ_ASSERT(this->stackDepth != 0); // Here's pseudo code for |let [a, b, , c=y, ...d] = x;| @@ -3131,7 +3091,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav // For an empty pattern [], call IteratorClose unconditionally. Nothing // else needs to be done. - if (!pattern->pn_head) + if (!pattern->head()) return emitIteratorCloseInInnermostScope(); // ... OBJ // Push an initial FALSE value for DONE. @@ -3143,8 +3103,8 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav // IteratorClose is called upon exception only if done is false. int32_t tryNoteDepth = stackDepth; - for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { - bool isFirst = member == pattern->pn_head; + for (ParseNode* member : pattern->contents()) { + bool isFirst = member == pattern->head(); DebugOnly hasNext = !!member->pn_next; size_t emitted = 0; @@ -3349,17 +3309,16 @@ BytecodeEmitter::emitComputedPropertyName(ParseNode* computedPropName) } bool -BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav) +BytecodeEmitter::emitDestructuringOpsObject(ListNode* pattern, DestructuringFlavor flav) { MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); - MOZ_ASSERT(pattern->isArity(PN_LIST)); MOZ_ASSERT(this->stackDepth > 0); // ... RHS if (!emitRequireObjectCoercible()) // ... RHS return false; - bool needsRestPropertyExcludedSet = pattern->pn_count > 1 && + bool needsRestPropertyExcludedSet = pattern->count() > 1 && pattern->last()->isKind(PNK_SPREAD); if (needsRestPropertyExcludedSet) { if (!emitDestructuringObjRestExclusionSet(pattern)) // ... RHS SET @@ -3369,7 +3328,7 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla return false; } - for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + for (ParseNode* member : pattern->contents()) { ParseNode* subpattern; if (member->isKind(PNK_MUTATEPROTO) || member->isKind(PNK_SPREAD)) subpattern = member->pn_kid; @@ -3482,10 +3441,9 @@ BytecodeEmitter::emitDestructuringOpsObject(ParseNode* pattern, DestructuringFla } bool -BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) +BytecodeEmitter::emitDestructuringObjRestExclusionSet(ListNode* pattern) { MOZ_ASSERT(pattern->isKind(PNK_OBJECT)); - MOZ_ASSERT(pattern->isArity(PN_LIST)); MOZ_ASSERT(pattern->last()->isKind(PNK_SPREAD)); ptrdiff_t offset = this->offset(); @@ -3500,13 +3458,13 @@ BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) // No need to do any guessing for the object kind, since we know the upper // bound of how many properties we plan to have. - gc::AllocKind kind = gc::GetGCObjectKind(pattern->pn_count - 1); + gc::AllocKind kind = gc::GetGCObjectKind(pattern->count() - 1); RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, kind, TenuredObject)); if (!obj) return false; RootedAtom pnatom(cx); - for (ParseNode* member = pattern->pn_head; member; member = member->pn_next) { + for (ParseNode* member : pattern->contents()) { if (member->isKind(PNK_SPREAD)) break; @@ -3570,7 +3528,7 @@ BytecodeEmitter::emitDestructuringObjRestExclusionSet(ParseNode* pattern) } bool -BytecodeEmitter::emitDestructuringOps(ParseNode* pattern, DestructuringFlavor flav) +BytecodeEmitter::emitDestructuringOps(ListNode* pattern, DestructuringFlavor flav) { if (pattern->isKind(PNK_ARRAY)) return emitDestructuringOpsArray(pattern, flav); @@ -3578,28 +3536,26 @@ BytecodeEmitter::emitDestructuringOps(ParseNode* pattern, DestructuringFlavor fl } bool -BytecodeEmitter::emitTemplateString(ParseNode* pn) +BytecodeEmitter::emitTemplateString(ListNode* templateString) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - bool pushedString = false; - for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) { - bool isString = (pn2->getKind() == PNK_STRING || pn2->getKind() == PNK_TEMPLATE_STRING); + for (ParseNode* item : templateString->contents()) { + bool isString = (item->getKind() == PNK_STRING || item->getKind() == PNK_TEMPLATE_STRING); // Skip empty strings. These are very common: a template string like // `${a}${b}` has three empty strings and without this optimization // we'd emit four JSOP_ADD operations instead of just one. - if (isString && pn2->pn_atom->empty()) + if (isString && item->pn_atom->empty()) continue; if (!isString) { // We update source notes before emitting the expression - if (!updateSourceCoordNotes(pn2->pn_pos.begin)) + if (!updateSourceCoordNotes(item->pn_pos.begin)) return false; } - if (!emitTree(pn2)) + if (!emitTree(item)) return false; if (!isString) { @@ -3628,20 +3584,16 @@ BytecodeEmitter::emitTemplateString(ParseNode* pn) } bool -BytecodeEmitter::emitDeclarationList(ParseNode* declList) +BytecodeEmitter::emitDeclarationList(ListNode* declList) { - MOZ_ASSERT(declList->isArity(PN_LIST)); - - ParseNode* next; - for (ParseNode* decl = declList->pn_head; decl; decl = next) { + for (ParseNode* decl : declList->contents()) { if (!updateSourceCoordNotes(decl->pn_pos.begin)) return false; - next = decl->pn_next; if (decl->isKind(PNK_ASSIGN)) { MOZ_ASSERT(decl->isOp(JSOP_NOP)); - ParseNode* pattern = decl->pn_left; + ListNode* pattern = &decl->pn_left->as(); MOZ_ASSERT(pattern->isKind(PNK_ARRAY) || pattern->isKind(PNK_OBJECT)); if (!emitTree(decl->pn_right)) @@ -3933,7 +3885,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp compoundOp, ParseNode* rhs) } case PNK_ARRAY: case PNK_OBJECT: - if (!emitDestructuringOps(lhs, DestructuringAssignment)) + if (!emitDestructuringOps(&lhs->as(), DestructuringAssignment)) return false; break; default: @@ -3986,12 +3938,12 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje } if (getKind() == PNK_CALLSITEOBJ) { - count = pn_count - 1; - pn = pn_head->pn_next; + count = as().count() - 1; + pn = as().head()->pn_next; } else { - MOZ_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); - count = pn_count; - pn = pn_head; + MOZ_ASSERT(isOp(JSOP_NEWINIT) && !as().hasNonConstInitializer()); + count = as().count(); + pn = as().head(); } AutoValueVector values(cx); @@ -4021,7 +3973,7 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje } case PNK_OBJECT: { MOZ_ASSERT(isOp(JSOP_NEWINIT)); - MOZ_ASSERT(!(pn_xflags & PNX_NONCONST)); + MOZ_ASSERT(!as().hasNonConstInitializer()); if (allowObjects == DontAllowObjects) { vp.setMagic(JS_GENERIC_MAGIC); @@ -4032,21 +3984,22 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje Rooted properties(cx, IdValueVector(cx)); RootedValue value(cx), idvalue(cx); - for (ParseNode* pn = pn_head; pn; pn = pn->pn_next) { - if (!pn->pn_right->getConstantValue(cx, allowObjects, &value)) + for (ParseNode* prop : as().contents()) { + if (!prop->pn_right->getConstantValue(cx, allowObjects, &value)) return false; if (value.isMagic(JS_GENERIC_MAGIC)) { vp.setMagic(JS_GENERIC_MAGIC); return true; } - ParseNode* pnid = pn->pn_left; - if (pnid->isKind(PNK_NUMBER)) { - idvalue = NumberValue(pnid->pn_dval); + ParseNode* key = prop->pn_left; + if (key->isKind(PNK_NUMBER)) { + idvalue = NumberValue(key->pn_dval); } else { - MOZ_ASSERT(pnid->isKind(PNK_OBJECT_PROPERTY_NAME) || pnid->isKind(PNK_STRING)); - MOZ_ASSERT(pnid->pn_atom != cx->names().proto); - idvalue = StringValue(pnid->pn_atom); + MOZ_ASSERT(key->isKind(PNK_OBJECT_PROPERTY_NAME) || + key->isKind(PNK_STRING)); + MOZ_ASSERT(key->pn_atom != cx->names().proto); + idvalue = StringValue(key->pn_atom); } RootedId id(cx); @@ -4093,10 +4046,10 @@ BytecodeEmitter::emitSingletonInitialiser(ParseNode* pn) } bool -BytecodeEmitter::emitCallSiteObject(ParseNode* pn) +BytecodeEmitter::emitCallSiteObject(CallSiteNode* callSiteObj) { RootedValue value(cx); - if (!pn->getConstantValue(cx, ParseNode::AllowObjects, &value)) + if (!callSiteObj->getConstantValue(cx, ParseNode::AllowObjects, &value)) return false; MOZ_ASSERT(value.isObject()); @@ -4105,7 +4058,7 @@ BytecodeEmitter::emitCallSiteObject(ParseNode* pn) if (!objbox1) return false; - if (!pn->as().getRawArrayValue(cx, &value)) + if (!callSiteObj->getRawArrayValue(cx, &value)) return false; MOZ_ASSERT(value.isObject()); @@ -4160,7 +4113,7 @@ BytecodeEmitter::emitCatch(ParseNode* pn) switch (pn2->getKind()) { case PNK_ARRAY: case PNK_OBJECT: - if (!emitDestructuringOps(pn2, DestructuringDeclaration)) + if (!emitDestructuringOps(&pn2->as(), DestructuringDeclaration)) return false; if (!emit1(JSOP_POP)) return false; @@ -4276,13 +4229,13 @@ BytecodeEmitter::emitTry(ParseNode* pn) // code if appropriate, and is also used for the catch-all trynote for // capturing exceptions thrown from catch{} blocks. // - for (ParseNode* pn3 = catchList->pn_head; pn3; pn3 = pn3->pn_next) { + for (ParseNode* lexicalScope : catchList->as().contents()) { if (!tryCatch.emitCatch()) return false; // Emit the lexical scope and catch body. - MOZ_ASSERT(pn3->isKind(PNK_LEXICALSCOPE)); - if (!emitTree(pn3)) + MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); + if (!emitTree(lexicalScope)) return false; } } @@ -4350,12 +4303,12 @@ BytecodeEmitter::emitIf(ParseNode* pn) } bool -BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list) +BytecodeEmitter::emitHoistedFunctionsInList(ListNode* stmtList) { - MOZ_ASSERT(list->pn_xflags & PNX_FUNCDEFS); + MOZ_ASSERT(stmtList->hasTopLevelFunctionDeclarations()); - for (ParseNode* pn = list->pn_head; pn; pn = pn->pn_next) { - ParseNode* maybeFun = pn; + for (ParseNode* stmt : stmtList->contents()) { + ParseNode* maybeFun = stmt; if (!sc->strict()) { while (maybeFun->isKind(PNK_LABEL)) @@ -4374,11 +4327,13 @@ BytecodeEmitter::emitHoistedFunctionsInList(ParseNode* list) bool BytecodeEmitter::emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLineNote) { - if (body->isKind(PNK_STATEMENTLIST) && body->pn_xflags & PNX_FUNCDEFS) { + if (body->isKind(PNK_STATEMENTLIST) && + body->as().hasTopLevelFunctionDeclarations()) + { // This block contains function statements whose definitions are // hoisted to the top of the block. Emit these as a separate pass // before the rest of the block. - if (!emitHoistedFunctionsInList(body)) + if (!emitHoistedFunctionsInList(&body->as())) return false; } @@ -4414,8 +4369,11 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn) // number L1, and the Debugger will pause there. if (!ParseNodeRequiresSpecialLineNumberNotes(body)) { ParseNode* pnForPos = body; - if (body->isKind(PNK_STATEMENTLIST) && body->pn_head) - pnForPos = body->pn_head; + if (body->isKind(PNK_STATEMENTLIST)) { + if (ParseNode* pn2 = body->as().head()) { + pnForPos = pn2; + } + } if (!updateLineNumberNotes(pnForPos->pn_pos.begin)) return false; } @@ -4733,7 +4691,7 @@ BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead) return false; MOZ_ASSERT(target->isForLoopDeclaration()); - target = parser->handler.singleBindingFromDeclaration(target); + target = parser->handler.singleBindingFromDeclaration(&target->as()); if (target->isKind(PNK_NAME)) { NameOpEmitter noe(this, target->name(), NameOpEmitter::Kind::Initialize); @@ -4766,7 +4724,7 @@ BytecodeEmitter::emitInitializeForInOrOfTarget(ParseNode* forHead) "for-in/of loop destructuring declarations can't have initializers"); MOZ_ASSERT(target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)); - return emitDestructuringOps(target, DestructuringDeclaration); + return emitDestructuringOps(&target->as(), DestructuringDeclaration); } bool @@ -4959,7 +4917,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte // |for (var i = initializer in expr) { ... }| ParseNode* forInTarget = forInHead->pn_kid1; if (parser->handler.isDeclarationList(forInTarget)) { - ParseNode* decl = parser->handler.singleBindingFromDeclaration(forInTarget); + ParseNode* decl = parser->handler.singleBindingFromDeclaration(&forInTarget->as()); if (decl->isKind(PNK_NAME)) { if (ParseNode* initializer = decl->expr()) { MOZ_ASSERT(forInTarget->isKind(PNK_VAR), @@ -5320,9 +5278,9 @@ BytecodeEmitter::emitComprehensionForInOrOfVariables(ParseNode* pn, bool* lexica // this declaration manually, we must also initialize manually to avoid // triggering dead zone checks. MOZ_ASSERT(pn->isKind(PNK_LET)); - MOZ_ASSERT(pn->pn_count == 1); + MOZ_ASSERT(pn->as().count() == 1); - if (!emitDeclarationList(pn)) + if (!emitDeclarationList(&pn->as())) return false; } @@ -5367,12 +5325,12 @@ BytecodeEmitter::emitComprehensionForOf(ParseNode* pn) Maybe emitterScope; ParseNode* loopVariableName; if (lexicalScope) { - loopVariableName = parser->handler.singleBindingFromDeclaration(loopDecl->pn_expr); + loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->pn_expr->as()); emitterScope.emplace(this); if (!emitterScope->enterComprehensionFor(this, loopDecl->scopeBindings())) return false; } else { - loopVariableName = parser->handler.singleBindingFromDeclaration(loopDecl); + loopVariableName = parser->handler.singleBindingFromDeclaration(&loopDecl->as()); } LoopControl loopInfo(this, StatementKind::ForOfLoop); @@ -6609,11 +6567,10 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter) } bool -BytecodeEmitter::emitStatementList(ParseNode* pn) +BytecodeEmitter::emitStatementList(ListNode* stmtList) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - for (ParseNode* pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { - if (!emitTree(pn2)) + for (ParseNode* stmt : stmtList->contents()) { + if (!emitTree(stmt)) return false; } return true; @@ -6974,11 +6931,11 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) // argc is set to the amount of actually emitted args and the // emitting of args below is disabled by setting emitArgs to false. ParseNode* pn_callee = pn->pn_left; - ParseNode* pn_args = pn->pn_right; + ListNode* argsList = &pn->pn_right->as(); const char* errorName = SelfHostedCallFunctionName(pn_callee->name(), cx); - if (pn_args->pn_count < 2) { + if (argsList->count() < 2) { reportError(pn, JSMSG_MORE_ARGS_NEEDED, errorName, "2", "s"); return false; } @@ -6990,7 +6947,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) } bool constructing = pn_callee->name() == cx->names().constructContentFunction; - ParseNode* funNode = pn_args->pn_head; + ParseNode* funNode = argsList->head(); if (constructing) callOp = JSOP_NEW; else if (funNode->getKind() == PNK_NAME && funNode->name() == cx->names().std_Function_apply) @@ -7030,7 +6987,7 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) return false; } - uint32_t argc = pn_args->pn_count - 2; + uint32_t argc = argsList->count() - 2; if (!emitCall(callOp, argc)) return false; @@ -7041,15 +6998,15 @@ BytecodeEmitter::emitSelfHostedCallFunction(ParseNode* pn) bool BytecodeEmitter::emitSelfHostedResumeGenerator(ParseNode* pn) { - ParseNode* pn_args = pn->pn_right; + ListNode* argsList = &pn->pn_right->as(); // Syntax: resumeGenerator(gen, value, 'next'|'throw'|'close') - if (pn_args->pn_count != 3) { + if (argsList->count() != 3) { reportError(pn, JSMSG_MORE_ARGS_NEEDED, "resumeGenerator", "1", "s"); return false; } - ParseNode* genNode = pn_args->pn_head; + ParseNode* genNode = argsList->head(); if (!emitTree(genNode)) return false; @@ -7081,15 +7038,15 @@ BytecodeEmitter::emitSelfHostedForceInterpreter(ParseNode* pn) bool BytecodeEmitter::emitSelfHostedAllowContentIter(ParseNode* pn) { - ParseNode* pn_args = pn->pn_right; + ListNode* argsList = &pn->pn_right->as(); - if (pn_args->pn_count != 1) { + if (argsList->count() != 1) { reportError(pn, JSMSG_MORE_ARGS_NEEDED, "allowContentIter", "1", ""); return false; } // We're just here as a sentinel. Pass the value through directly. - return emitTree(pn_args->pn_head); + return emitTree(argsList->head()); } bool @@ -7108,7 +7065,7 @@ BytecodeEmitter::isRestParameter(ParseNode* pn) ParseNode* pn_callee = pn->pn_left; if (pn_callee->getKind() == PNK_NAME && pn_callee->name() == cx->names().allowContentIter) - return isRestParameter(pn->pn_right->pn_head); + return isRestParameter(pn->pn_right->as().head()); } return false; } @@ -7279,15 +7236,15 @@ BytecodeEmitter::emitOptionalCall( ValueUsage valueUsage) { ParseNode* calleeNode = callNode->pn_left; - ParseNode* argsList = callNode->pn_right; + ListNode* argsList = &callNode->pn_right->as(); bool isCall = true; bool isSpread = IsSpreadOp(callNode->getOp()); - uint32_t argc = argsList->pn_count; + uint32_t argc = argsList->count(); JSOp op = callNode->getOp(); CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(argsList->pn_head->pn_kid) + isRestParameter(argsList->head()->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); @@ -7320,7 +7277,7 @@ BytecodeEmitter::emitOptionalCall( ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, ParseNode* calleeNode, - ParseNode* argsList) { + ListNode* argsList) { ParseNode* coordNode = pn; if (pn->isOp(JSOP_CALL) || pn->isOp(JSOP_SPREADCALL) || pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY)) { @@ -7355,10 +7312,10 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, } bool -BytecodeEmitter::emitArguments(ParseNode* pn, bool isCall, bool isSpread, +BytecodeEmitter::emitArguments(ListNode* argsList, bool isCall, bool isSpread, CallOrNewEmitter& cone) { - uint32_t argc = pn->pn_count; + uint32_t argc = argsList->count(); if (argc >= ARGC_LIMIT) { parser->tokenStream.reportError(isCall @@ -7370,21 +7327,22 @@ BytecodeEmitter::emitArguments(ParseNode* pn, bool isCall, bool isSpread, if (!cone.prepareForNonSpreadArguments()) { // CALLEE THIS return false; } - for (ParseNode* arg = pn->pn_head; arg; arg = arg->pn_next) { + for (ParseNode* arg : argsList->contents()) { if (!emitTree(arg)) { return false; } } } else { if (cone.wantSpreadOperand()) { - if (!emitTree(pn->pn_head->pn_kid)) { // CALLEE THIS ARG0 + ParseNode* spreadNode = argsList->head(); + if (!emitTree(spreadNode->pn_kid)) { // CALLEE THIS ARG0 return false; } } if (!cone.emitSpreadArgumentsTest()) { // CALLEE THIS return false; } - if (!emitArray(pn->pn_head, argc, JSOP_SPREADCALLARRAY)) { // CALLEE THIS ARR + if (!emitArray(argsList->head(), argc, JSOP_SPREADCALLARRAY)) { // CALLEE THIS ARR return false; } } @@ -7414,7 +7372,7 @@ BytecodeEmitter::emitCallOrNew( */ bool isCall = callNode->isKind(PNK_CALL) || callNode->isKind(PNK_TAGGED_TEMPLATE); ParseNode* calleeNode = callNode->pn_left; - ParseNode* argsList = callNode->pn_right; + ListNode* argsList = &callNode->pn_right->as(); bool isSpread = IsSpreadOp(callNode->getOp()); @@ -7440,11 +7398,11 @@ BytecodeEmitter::emitCallOrNew( // Fall through. } - uint32_t argc = argsList->pn_count; + uint32_t argc = argsList->count(); JSOp op = callNode->getOp(); CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(argsList->pn_head->pn_kid) + isRestParameter(argsList->head()->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); @@ -7551,18 +7509,17 @@ BytecodeEmitter::emitCalleeAndThis( } bool -BytecodeEmitter::emitRightAssociative(ParseNode* pn) +BytecodeEmitter::emitRightAssociative(ListNode* node) { // ** is the only right-associative operator. - MOZ_ASSERT(pn->isKind(PNK_POW)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(node->isKind(PNK_POW)); // Right-associative operator chain. - for (ParseNode* subexpr = pn->pn_head; subexpr; subexpr = subexpr->pn_next) { + for (ParseNode* subexpr : node->contents()) { if (!emitTree(subexpr)) return false; } - for (uint32_t i = 0; i < pn->pn_count - 1; i++) { + for (uint32_t i = 0; i < node->count() - 1; i++) { if (!emit1(JSOP_POW)) return false; } @@ -7570,15 +7527,13 @@ BytecodeEmitter::emitRightAssociative(ParseNode* pn) } bool -BytecodeEmitter::emitLeftAssociative(ParseNode* pn) +BytecodeEmitter::emitLeftAssociative(ListNode* node) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - // Left-associative operator chain. - if (!emitTree(pn->pn_head)) + if (!emitTree(node->head())) return false; - JSOp op = pn->getOp(); - ParseNode* nextExpr = pn->pn_head->pn_next; + JSOp op = node->getOp(); + ParseNode* nextExpr = node->head()->pn_next; do { if (!emitTree(nextExpr)) return false; @@ -7589,9 +7544,9 @@ BytecodeEmitter::emitLeftAssociative(ParseNode* pn) } bool -BytecodeEmitter::emitLogical(ParseNode* pn) +BytecodeEmitter::emitLogical(ListNode* node) { - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(node->isKind(PNK_COALESCE) || node->isKind(PNK_OR) || node->isKind(PNK_AND)); /* * JSOP_OR converts the operand on the stack to boolean, leaves the original @@ -7606,10 +7561,10 @@ BytecodeEmitter::emitLogical(ParseNode* pn) TDZCheckCache tdzCache(this); /* Left-associative operator chain: avoid too much recursion. */ - ParseNode* pn2 = pn->pn_head; - if (!emitTree(pn2)) + ParseNode* expr = node->head(); + if (!emitTree(expr)) return false; - JSOp op = pn->getOp(); + JSOp op = node->getOp(); JumpList jump; if (!emitJump(op, &jump)) return false; @@ -7617,15 +7572,15 @@ BytecodeEmitter::emitLogical(ParseNode* pn) return false; /* Emit nodes between the head and the tail. */ - while ((pn2 = pn2->pn_next)->pn_next) { - if (!emitTree(pn2)) + while ((expr = expr->pn_next)->pn_next) { + if (!emitTree(expr)) return false; if (!emitJump(op, &jump)) return false; if (!emit1(JSOP_POP)) return false; } - if (!emitTree(pn2)) + if (!emitTree(expr)) return false; if (!emitJumpTargetAndPatch(jump)) @@ -7634,10 +7589,10 @@ BytecodeEmitter::emitLogical(ParseNode* pn) } bool -BytecodeEmitter::emitSequenceExpr(ParseNode* pn, +BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage /* = ValueUsage::WantValue */) { - for (ParseNode* child = pn->pn_head; ; child = child->pn_next) { + for (ParseNode* child = node->head(); ; child = child->pn_next) { if (!updateSourceCoordNotes(child->pn_pos.begin)) return false; if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage)) @@ -7731,9 +7686,9 @@ BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional, } bool -BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type) +BytecodeEmitter::emitPropertyList(ListNode* obj, MutableHandlePlainObject objp, PropListType type) { - for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) { + for (ParseNode* propdef : obj->contents()) { if (!updateSourceCoordNotes(propdef->pn_pos.begin)) return false; @@ -7897,10 +7852,10 @@ BytecodeEmitter::emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See // the comment on emitSwitch. MOZ_NEVER_INLINE bool -BytecodeEmitter::emitObject(ParseNode* pn) +BytecodeEmitter::emitObject(ListNode* objNode) { - if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && checkSingletonContext()) - return emitSingletonInitialiser(pn); + if (!objNode->hasNonConstInitializer() && objNode->head() && checkSingletonContext()) + return emitSingletonInitialiser(objNode); /* * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing @@ -7919,12 +7874,12 @@ BytecodeEmitter::emitObject(ParseNode* pn) // No need to do any guessing for the object kind, since we know the upper // bound of how many properties we plan to have. - gc::AllocKind kind = gc::GetGCObjectKind(pn->pn_count); + gc::AllocKind kind = gc::GetGCObjectKind(objNode->count()); RootedPlainObject obj(cx, NewBuiltinClassInstance(cx, kind, TenuredObject)); if (!obj) return false; - if (!emitPropertyList(pn, &obj, ObjectLiteral)) + if (!emitPropertyList(objNode, &obj, ObjectLiteral)) return false; if (obj) { @@ -7961,7 +7916,7 @@ BytecodeEmitter::replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset) } bool -BytecodeEmitter::emitArrayComp(ParseNode* pn) +BytecodeEmitter::emitArrayComp(ListNode* pn) { if (!emitNewInit(JSProto_Array)) return false; @@ -7974,7 +7929,7 @@ BytecodeEmitter::emitArrayComp(ParseNode* pn) MOZ_ASSERT(stackDepth > 0); uint32_t saveDepth = arrayCompDepth; arrayCompDepth = (uint32_t) (stackDepth - 1); - if (!emitTree(pn->pn_head)) + if (!emitTree(pn->head())) return false; arrayCompDepth = saveDepth; @@ -7982,20 +7937,23 @@ BytecodeEmitter::emitArrayComp(ParseNode* pn) } bool -BytecodeEmitter::emitArrayLiteral(ParseNode* pn) +BytecodeEmitter::emitArrayLiteral(ListNode* array) { - if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head) { + if (!array->hasNonConstInitializer() && array->head()) { if (checkSingletonContext()) { // Bake in the object entirely if it will only be created once. - return emitSingletonInitialiser(pn); + return emitSingletonInitialiser(array); } // If the array consists entirely of primitive values, make a // template object with copy on write elements that can be reused - // every time the initializer executes. - if (emitterMode != BytecodeEmitter::SelfHosting && pn->pn_count != 0) { + // every time the initializer executes. Don't do this if the array is + // small: copying the elements lazily is not worth it in that case. + static const size_t MinElementsForCopyOnWrite = 5; + if (emitterMode != BytecodeEmitter::SelfHosting && + array->count() >= MinElementsForCopyOnWrite) { RootedValue value(cx); - if (!pn->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value)) + if (!array->getConstantValue(cx, ParseNode::ForCopyOnWriteArray, &value)) return false; if (!value.isMagic(JS_GENERIC_MAGIC)) { // Note: the group of the template object might not yet reflect @@ -8018,11 +7976,11 @@ BytecodeEmitter::emitArrayLiteral(ParseNode* pn) } } - return emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY); + return emitArray(array->head(), array->count(), JSOP_NEWARRAY); } bool -BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) +BytecodeEmitter::emitArray(ParseNode* arrayHead, uint32_t count, JSOp op) { /* @@ -8036,8 +7994,8 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY); uint32_t nspread = 0; - for (ParseNode* elt = pn; elt; elt = elt->pn_next) { - if (elt->isKind(PNK_SPREAD)) + for (ParseNode* elem = arrayHead; elem; elem = elem->pn_next) { + if (elem->isKind(PNK_SPREAD)) nspread++; } @@ -8057,26 +8015,26 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) if (!emitUint32Operand(op, count - nspread)) // ARRAY return false; - ParseNode* pn2 = pn; + ParseNode* elem = arrayHead; uint32_t index; bool afterSpread = false; - for (index = 0; pn2; index++, pn2 = pn2->pn_next) { - if (!afterSpread && pn2->isKind(PNK_SPREAD)) { + for (index = 0; elem; index++, elem = elem->pn_next) { + if (!afterSpread && elem->isKind(PNK_SPREAD)) { afterSpread = true; if (!emitNumberOp(index)) // ARRAY INDEX return false; } - if (!updateSourceCoordNotes(pn2->pn_pos.begin)) + if (!updateSourceCoordNotes(elem->pn_pos.begin)) return false; bool allowSelfHostedIter = false; - if (pn2->isKind(PNK_ELISION)) { + if (elem->isKind(PNK_ELISION)) { if (!emit1(JSOP_HOLE)) return false; } else { ParseNode* expr; - if (pn2->isKind(PNK_SPREAD)) { - expr = pn2->pn_kid; + if (elem->isKind(PNK_SPREAD)) { + expr = elem->pn_kid; if (emitterMode == BytecodeEmitter::SelfHosting && expr->isKind(PNK_CALL) && @@ -8085,12 +8043,12 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op) allowSelfHostedIter = true; } } else { - expr = pn2; + expr = elem; } if (!emitTree(expr)) // ARRAY INDEX? VALUE return false; } - if (pn2->isKind(PNK_SPREAD)) { + if (elem->isKind(PNK_SPREAD)) { if (!emitIterator()) // ARRAY INDEX ITER return false; if (!emit2(JSOP_PICK, 2)) // INDEX ITER ARRAY @@ -8146,11 +8104,11 @@ BytecodeEmitter::emitTypeof(ParseNode* node, JSOp op) } bool -BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn) +BytecodeEmitter::emitFunctionFormalParametersAndBody(ListNode* paramsBody) { - MOZ_ASSERT(pn->isKind(PNK_PARAMSBODY)); + MOZ_ASSERT(paramsBody->isKind(PNK_PARAMSBODY)); - ParseNode* funBody = pn->last(); + ParseNode* funBody = paramsBody->last(); FunctionBox* funbox = sc->asFunctionBox(); TDZCheckCache tdzCache(this); @@ -8163,7 +8121,7 @@ BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn) if (!emitInitializeFunctionSpecialNames()) return false; - if (!emitFunctionFormalParameters(pn)) + if (!emitFunctionFormalParameters(paramsBody)) return false; { @@ -8240,7 +8198,7 @@ BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn) return false; switchToMain(); - if (!emitFunctionFormalParameters(pn)) + if (!emitFunctionFormalParameters(paramsBody)) return false; if (!emitFunctionBody(funBody)) @@ -8250,9 +8208,9 @@ BytecodeEmitter::emitFunctionFormalParametersAndBody(ParseNode *pn) } bool -BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) +BytecodeEmitter::emitFunctionFormalParameters(ListNode* paramsBody) { - ParseNode* funBody = pn->last(); + ParseNode* funBody = paramsBody->last(); FunctionBox* funbox = sc->asFunctionBox(); EmitterScope* funScope = innermostEmitterScope(); @@ -8260,7 +8218,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) bool hasRest = funbox->hasRest(); uint16_t argSlot = 0; - for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) { + for (ParseNode* arg = paramsBody->head(); arg != funBody; arg = arg->pn_next, argSlot++) { ParseNode* bindingElement = arg; ParseNode* initializer = nullptr; if (arg->isKind(PNK_ASSIGN)) { @@ -8335,7 +8293,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn) // If there's an parameter expression var scope, the destructuring // declaration needs to initialize the name in the function scope, // which is not the innermost scope. - if (!emitDestructuringOps(bindingElement, + if (!emitDestructuringOps(&bindingElement->as(), paramExprVarScope ? DestructuringFormalParameterInVarScope : DestructuringDeclaration)) @@ -8508,9 +8466,9 @@ BytecodeEmitter::emitClass(ParseNode* pn) ParseNode* heritageExpression = classNode.heritage(); - ParseNode* classMethods = classNode.methodList(); + ListNode* classMethods = classNode.methodList(); ParseNode* constructor = nullptr; - for (ParseNode* mn = classMethods->pn_head; mn; mn = mn->pn_next) { + for (ParseNode* mn : classMethods->contents()) { ClassMethod& method = mn->as(); ParseNode& methodName = method.name(); if (!method.isStatic() && @@ -8646,7 +8604,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_PARAMSBODY: - if (!emitFunctionFormalParametersAndBody(pn)) + if (!emitFunctionFormalParametersAndBody(&pn->as())) return false; break; @@ -8706,7 +8664,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_VAR: - if (!emitDeclarationList(pn)) + if (!emitDeclarationList(&pn->as())) return false; break; @@ -8741,7 +8699,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_STATEMENTLIST: - if (!emitStatementList(pn)) + if (!emitStatementList(&pn->as())) return false; break; @@ -8756,7 +8714,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_COMMA: - if (!emitSequenceExpr(pn, valueUsage)) + if (!emitSequenceExpr(&pn->as(), valueUsage)) return false; break; @@ -8785,7 +8743,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: case PNK_COALESCE: case PNK_OR: case PNK_AND: - if (!emitLogical(pn)) + if (!emitLogical(&pn->as())) return false; break; @@ -8810,12 +8768,12 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: case PNK_STAR: case PNK_DIV: case PNK_MOD: - if (!emitLeftAssociative(pn)) + if (!emitLeftAssociative(&pn->as())) return false; break; case PNK_POW: - if (!emitRightAssociative(pn)) + if (!emitRightAssociative(&pn->as())) return false; break; @@ -8942,7 +8900,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: case PNK_CONST: case PNK_LET: - if (!emitDeclarationList(pn)) + if (!emitDeclarationList(&pn->as())) return false; break; @@ -8989,22 +8947,22 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_CALLSITEOBJ: - if (!emitCallSiteObject(pn)) + if (!emitCallSiteObject(&pn->as())) return false; break; case PNK_ARRAY: - if (!emitArrayLiteral(pn)) + if (!emitArrayLiteral(&pn->as())) return false; break; case PNK_ARRAYCOMP: - if (!emitArrayComp(pn)) + if (!emitArrayComp(&pn->as())) return false; break; case PNK_OBJECT: - if (!emitObject(pn)) + if (!emitObject(&pn->as())) return false; break; @@ -9014,7 +8972,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_TEMPLATE_STRING_LIST: - if (!emitTemplateString(pn)) + if (!emitTemplateString(&pn->as())) return false; break; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 1a2c87580a..e2fb16e224 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -498,9 +498,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitAtomOp(JSAtom* atom, JSOp op); MOZ_MUST_USE bool emitAtomOp(uint32_t atomIndex, JSOp op); - MOZ_MUST_USE bool emitArrayLiteral(ParseNode* pn); - MOZ_MUST_USE bool emitArray(ParseNode* pn, uint32_t count, JSOp op); - MOZ_MUST_USE bool emitArrayComp(ParseNode* pn); + MOZ_MUST_USE bool emitArrayLiteral(ListNode* array); + MOZ_MUST_USE bool emitArray(ParseNode* arrayHead, uint32_t count, JSOp op); + MOZ_MUST_USE bool emitArrayComp(ListNode* pn); MOZ_MUST_USE bool emitInternedScopeOp(uint32_t index, JSOp op); MOZ_MUST_USE bool emitInternedObjectOp(uint32_t index, JSOp op); @@ -509,13 +509,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitRegExp(uint32_t index); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitFunction(ParseNode* pn, bool needsProto = false); - MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ParseNode* pn); + MOZ_NEVER_INLINE MOZ_MUST_USE bool emitObject(ListNode* objNode); MOZ_MUST_USE bool replaceNewInitWithNewObject(JSObject* obj, ptrdiff_t offset); - MOZ_MUST_USE bool emitHoistedFunctionsInList(ParseNode* pn); + MOZ_MUST_USE bool emitHoistedFunctionsInList(ListNode* stmtList); - MOZ_MUST_USE bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, + MOZ_MUST_USE bool emitPropertyList(ListNode* obj, MutableHandlePlainObject objp, PropListType type); // To catch accidental misuse, emitUint16Operand/emit3 assert that they are @@ -538,8 +538,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitNameIncDec(ParseNode* incDec); - MOZ_MUST_USE bool emitDeclarationList(ParseNode* decls); - MOZ_MUST_USE bool emitSingleDeclaration(ParseNode* decls, ParseNode* decl, + MOZ_MUST_USE bool emitDeclarationList(ListNode* declList); + MOZ_MUST_USE bool emitSingleDeclaration(ParseNode* declList, ParseNode* decl, ParseNode* initializer); MOZ_MUST_USE bool emitNewInit(JSProtoKey key); @@ -624,21 +624,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter // emitDestructuringObjRestExclusionSet emits the property exclusion set // for the rest-property in an object pattern. - MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ParseNode* pattern); + MOZ_MUST_USE bool emitDestructuringObjRestExclusionSet(ListNode* pattern); // emitDestructuringOps assumes the to-be-destructured value has been // pushed on the stack and emits code to destructure each part of a [] or // {} lhs expression. - MOZ_MUST_USE bool emitDestructuringOps(ParseNode* pattern, DestructuringFlavor flav); - MOZ_MUST_USE bool emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlavor flav); - MOZ_MUST_USE bool emitDestructuringOpsObject(ParseNode* pattern, DestructuringFlavor flav); + MOZ_MUST_USE bool emitDestructuringOps(ListNode* pattern, DestructuringFlavor flav); + MOZ_MUST_USE bool emitDestructuringOpsArray(ListNode* pattern, DestructuringFlavor flav); + MOZ_MUST_USE bool emitDestructuringOpsObject(ListNode* pattern, DestructuringFlavor flav); typedef bool (*DestructuringDeclEmitter)(BytecodeEmitter* bce, ParseNode* pn); - template - MOZ_MUST_USE bool emitDestructuringDeclsWithEmitter(ParseNode* pattern, NameEmitter emitName); - // Throw a TypeError if the value atop the stack isn't convertible to an // object, with no overall effect on the stack. MOZ_MUST_USE bool emitRequireObjectCoercible(); @@ -694,13 +691,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitInitializer(ParseNode* initializer, ParseNode* pattern); MOZ_MUST_USE bool emitInitializerInBranch(ParseNode* initializer, ParseNode* pattern); - MOZ_MUST_USE bool emitCallSiteObject(ParseNode* pn); - MOZ_MUST_USE bool emitTemplateString(ParseNode* pn); + MOZ_MUST_USE bool emitCallSiteObject(CallSiteNode* callSiteObj); + MOZ_MUST_USE bool emitTemplateString(ListNode* templateString); MOZ_MUST_USE bool emitAssignment(ParseNode* lhs, JSOp compoundOp, ParseNode* rhs); MOZ_MUST_USE bool emitReturn(ParseNode* pn); MOZ_MUST_USE bool emitStatement(ParseNode* pn); - MOZ_MUST_USE bool emitStatementList(ParseNode* pn); + MOZ_MUST_USE bool emitStatementList(ListNode* stmtList); MOZ_MUST_USE bool emitDeleteName(ParseNode* pn); MOZ_MUST_USE bool emitDeleteProperty(ParseNode* pn); @@ -735,10 +732,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op); MOZ_MUST_USE bool emitUnary(ParseNode* pn); - MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn); - MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn); - MOZ_MUST_USE bool emitLogical(ParseNode* pn); - MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn, + MOZ_MUST_USE bool emitRightAssociative(ListNode* node); + MOZ_MUST_USE bool emitLeftAssociative(ListNode* node); + MOZ_MUST_USE bool emitLogical(ListNode* node); + MOZ_MUST_USE bool emitSequenceExpr(ListNode* node, ValueUsage valueUsage = ValueUsage::WantValue); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn); @@ -750,8 +747,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted); MOZ_MUST_USE ParseNode* getCoordNode(ParseNode* callNode, ParseNode* calleeNode, - ParseNode* firstArgNode); - MOZ_MUST_USE bool emitArguments(ParseNode* argsList, bool isCall, bool isSpread, + ListNode* argsList); + MOZ_MUST_USE bool emitArguments(ListNode* argsList, bool isCall, bool isSpread, CallOrNewEmitter& cone); MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); @@ -786,8 +783,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitBreak(PropertyName* label); MOZ_MUST_USE bool emitContinue(PropertyName* label); - MOZ_MUST_USE bool emitFunctionFormalParametersAndBody(ParseNode* pn); - MOZ_MUST_USE bool emitFunctionFormalParameters(ParseNode* pn); + MOZ_MUST_USE bool emitFunctionFormalParametersAndBody(ListNode* paramsBody); + MOZ_MUST_USE bool emitFunctionFormalParameters(ListNode* paramsBody); MOZ_MUST_USE bool emitInitializeFunctionSpecialNames(); MOZ_MUST_USE bool emitFunctionBody(ParseNode* pn); MOZ_MUST_USE bool emitLexicalInitialization(ParseNode* pn); diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 3b11e8de37..4ad1b4d6fe 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -33,7 +33,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result); static bool ListContainsHoistedDeclaration(ExclusiveContext* cx, ListNode* list, bool* result) { - for (ParseNode* node = list->pn_head; node; node = node->pn_next) { + for (ParseNode* node : list->contents()) { if (!ContainsHoistedDeclaration(cx, node, result)) return false; if (*result) @@ -74,7 +74,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) // Non-global lexical declarations are block-scoped (ergo not hoistable). case PNK_LET: case PNK_CONST: - MOZ_ASSERT(node->isArity(PN_LIST)); + MOZ_ASSERT(node->is()); *result = false; return true; @@ -202,21 +202,20 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) if (*result) return true; - if (ParseNode* catchList = node->pn_kid2) { - for (ParseNode* lexicalScope = catchList->pn_head; - lexicalScope; - lexicalScope = lexicalScope->pn_next) - { - MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); + if (node->pn_kid2) { + if (ListNode* catchList = &node->pn_kid2->as()) { + for (ParseNode* lexicalScope : catchList->contents()) { + MOZ_ASSERT(lexicalScope->isKind(PNK_LEXICALSCOPE)); - ParseNode* catchNode = lexicalScope->pn_expr; - MOZ_ASSERT(catchNode->isKind(PNK_CATCH)); + ParseNode* catchNode = lexicalScope->scopeBody(); + MOZ_ASSERT(catchNode->isKind(PNK_CATCH)); - ParseNode* catchStatements = catchNode->pn_kid3; - if (!ContainsHoistedDeclaration(cx, catchStatements, result)) - return false; - if (*result) - return true; + ParseNode* catchStatements = catchNode->pn_kid3; + if (!ContainsHoistedDeclaration(cx, catchStatements, result)) + return false; + if (*result) + return true; + } } } @@ -764,16 +763,15 @@ static bool FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser& parser, bool inGenexpLambda) { - ParseNode* node = *nodePtr; + ListNode* node = &(*nodePtr)->as(); bool isCoalesceNode = node->isKind(PNK_COALESCE); bool isOrNode = node->isKind(PNK_OR); bool isAndNode = node->isKind(PNK_AND); MOZ_ASSERT(isCoalesceNode || isOrNode || isAndNode); - MOZ_ASSERT(node->isArity(PN_LIST)); - ParseNode** elem = &node->pn_head; + ParseNode** elem = node->unsafeHeadReference(); do { if (!Fold(cx, elem, parser, inGenexpLambda)) return false; @@ -802,7 +800,7 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser& for (ParseNode* next = (*elem)->pn_next; next; next = afterNext) { afterNext = next->pn_next; parser.handler.freeTree(next); - --node->pn_count; + node->unsafeDecrementCount(); } // Terminate the original and/or list at the known-truthiness @@ -820,7 +818,7 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser& ParseNode* elt = *elem; *elem = elt->pn_next; parser.handler.freeTree(elt); - --node->pn_count; + node->unsafeDecrementCount(); } else { // Otherwise this node is the result of the overall expression, // so leave it alone. And we're done. @@ -829,16 +827,12 @@ FoldLogical(ExclusiveContext* cx, ParseNode** nodePtr, Parser& } } while (*elem); - // If the last node in the list was replaced, we need to update the - // tail pointer in the original and/or node. - node->pn_tail = elem; - - node->checkListConsistency(); + node->unsafeReplaceTail(elem); // If we removed nodes, we may have to replace a one-element list with // its element. - if (node->pn_count == 1) { - ParseNode* first = node->pn_head; + if (node->count() == 1) { + ParseNode* first = node->head(); ReplaceNode(nodePtr, first); node->setKind(PNK_NULL); @@ -999,7 +993,7 @@ FoldIf(ExclusiveContext* cx, ParseNode** nodePtr, Parser& pars parser.prepareNodeForMutation(node); node->setKind(PNK_STATEMENTLIST); node->setArity(PN_LIST); - node->makeEmpty(); + node->as().makeEmpty(); } else { // Replacement invalidates |nextNode|, so reset it (if the // replacement requires folding) or clear it (if |alternative| @@ -1013,9 +1007,9 @@ FoldIf(ExclusiveContext* cx, ParseNode** nodePtr, Parser& pars // any bugs in the preceding logic. node->setKind(PNK_STATEMENTLIST); node->setArity(PN_LIST); - node->makeEmpty(); + node->as().makeEmpty(); if (discarded) - node->append(discarded); + node->as().append(discarded); parser.freeTree(node); } } while (nextNode); @@ -1098,7 +1092,7 @@ FoldModule(ExclusiveContext* cx, ParseNode* node, Parser& pars } static bool -FoldBinaryArithmetic(ExclusiveContext* cx, ParseNode* node, Parser& parser, +FoldBinaryArithmetic(ExclusiveContext* cx, ListNode* node, Parser& parser, bool inGenexpLambda) { MOZ_ASSERT(node->isKind(PNK_SUB) || @@ -1108,11 +1102,10 @@ FoldBinaryArithmetic(ExclusiveContext* cx, ParseNode* node, ParserisKind(PNK_URSH) || node->isKind(PNK_DIV) || node->isKind(PNK_MOD)); - MOZ_ASSERT(node->isArity(PN_LIST)); - MOZ_ASSERT(node->pn_count >= 2); + MOZ_ASSERT(node->count() >= 2); // Fold each operand, ideally into a number. - ParseNode** listp = &node->pn_head; + ParseNode** listp = node->unsafeHeadReference(); for (; *listp; listp = &(*listp)->pn_next) { if (!Fold(cx, listp, parser, inGenexpLambda)) return false; @@ -1121,15 +1114,14 @@ FoldBinaryArithmetic(ExclusiveContext* cx, ParseNode* node, Parserpn_tail = listp; + node->unsafeReplaceTail(listp); // Now fold all leading numeric terms together into a single number. // (Trailing terms for the non-shift operations can't be folded together // due to floating point imprecision. For example, if |x === -2**53|, // |x - 1 - 1 === -2**53| but |x - 2 === -2**53 - 2|. Shifts could be // folded, but it doesn't seem worth the effort.) - ParseNode* elem = node->pn_head; + ParseNode* elem = node->head(); ParseNode* next = elem->pn_next; if (elem->isKind(PNK_NUMBER)) { ParseNodeKind kind = node->getKind(); @@ -1149,11 +1141,11 @@ FoldBinaryArithmetic(ExclusiveContext* cx, ParseNode* node, ParsersetArity(PN_NULLARY); elem->pn_dval = d; - node->pn_count--; + node->unsafeDecrementCount(); } - if (node->pn_count == 1) { - MOZ_ASSERT(node->pn_head == elem); + if (node->count() == 1) { + MOZ_ASSERT(node->head() == elem); MOZ_ASSERT(elem->isKind(PNK_NUMBER)); double d = elem->pn_dval; @@ -1170,15 +1162,14 @@ FoldBinaryArithmetic(ExclusiveContext* cx, ParseNode* node, Parser& parser, +FoldExponentiation(ExclusiveContext* cx, ListNode* node, Parser& parser, bool inGenexpLambda) { MOZ_ASSERT(node->isKind(PNK_POW)); - MOZ_ASSERT(node->isArity(PN_LIST)); - MOZ_ASSERT(node->pn_count >= 2); + MOZ_ASSERT(node->count() >= 2); // Fold each operand, ideally into a number. - ParseNode** listp = &node->pn_head; + ParseNode** listp = node->unsafeHeadReference(); for (; *listp; listp = &(*listp)->pn_next) { if (!Fold(cx, listp, parser, inGenexpLambda)) return false; @@ -1187,18 +1178,17 @@ FoldExponentiation(ExclusiveContext* cx, ParseNode* node, Parserpn_tail = listp; + node->unsafeReplaceTail(listp); // Unlike all other binary arithmetic operators, ** is right-associative: // 2**3**5 is 2**(3**5), not (2**3)**5. As list nodes singly-link their // children, full constant-folding requires either linear space or dodgy // in-place linked list reversal. So we only fold one exponentiation: it's // easy and addresses common cases like |2**32|. - if (node->pn_count > 2) + if (node->count() > 2) return true; - ParseNode* base = node->pn_head; + ParseNode* base = node->head(); ParseNode* exponent = base->pn_next; if (!base->isKind(PNK_NUMBER) || !exponent->isKind(PNK_NUMBER)) return true; @@ -1214,21 +1204,16 @@ FoldExponentiation(ExclusiveContext* cx, ParseNode* node, Parser& parser, +FoldList(ExclusiveContext* cx, ListNode* list, Parser& parser, bool inGenexpLambda) { - MOZ_ASSERT(list->isArity(PN_LIST)); - - ParseNode** elem = &list->pn_head; + ParseNode** elem = list->unsafeHeadReference(); for (; *elem; elem = &(*elem)->pn_next) { if (!Fold(cx, elem, parser, inGenexpLambda)) return false; } - // Repoint the list's tail pointer if the final element was replaced. - list->pn_tail = elem; - - list->checkListConsistency(); + list->unsafeReplaceTail(elem); return true; } @@ -1400,11 +1385,10 @@ static bool FoldAdd(ExclusiveContext* cx, ParseNode** nodePtr, Parser& parser, bool inGenexpLambda) { - ParseNode* node = *nodePtr; + ListNode* node = &(*nodePtr)->as(); MOZ_ASSERT(node->isKind(PNK_ADD)); - MOZ_ASSERT(node->isArity(PN_LIST)); - MOZ_ASSERT(node->pn_count >= 2); + MOZ_ASSERT(node->count() >= 2); // Generically fold all operands first. if (!FoldList(cx, node, parser, inGenexpLambda)) @@ -1416,7 +1400,7 @@ FoldAdd(ExclusiveContext* cx, ParseNode** nodePtr, Parser& par // // Don't go past the leading operands: additions after a string are // string concatenations, not additions: ("1" + 2 + 3 === "123"). - ParseNode* current = node->pn_head; + ParseNode* current = node->head(); ParseNode* next = current->pn_next; if (current->isKind(PNK_NUMBER)) { do { @@ -1428,8 +1412,7 @@ FoldAdd(ExclusiveContext* cx, ParseNode** nodePtr, Parser& par parser.freeTree(next); next = current->pn_next; - MOZ_ASSERT(node->pn_count > 1); - node->pn_count--; + node->unsafeDecrementCount(); } while (next); } @@ -1490,8 +1473,7 @@ FoldAdd(ExclusiveContext* cx, ParseNode** nodePtr, Parser& par parser.freeTree(next); next = current->pn_next; - MOZ_ASSERT(node->pn_count > 1); - node->pn_count--; + node->unsafeDecrementCount(); } while (next); // Replace |current|'s string with the entire combination. @@ -1529,10 +1511,9 @@ FoldAdd(ExclusiveContext* cx, ParseNode** nodePtr, Parser& par MOZ_ASSERT(!next, "must have considered all nodes here"); MOZ_ASSERT(!current->pn_next, "current node must be the last node"); - node->pn_tail = ¤t->pn_next; - node->checkListConsistency(); + node->unsafeReplaceTail(¤t->pn_next); - if (node->pn_count == 1) { + if (node->count() == 1) { // We reduced the list to a constant. Replace the PNK_ADD node // with that constant. ReplaceNode(nodePtr, current); @@ -1583,23 +1564,18 @@ FoldCall(ExclusiveContext* cx, ParseNode* node, Parser& parser } static bool -FoldArguments(ExclusiveContext* cx, ParseNode* node, Parser& parser, +FoldArguments(ExclusiveContext* cx, ListNode* node, Parser& parser, bool inGenexpLambda) { MOZ_ASSERT(node->isKind(PNK_ARGUMENTS)); - MOZ_ASSERT(node->isArity(PN_LIST)); - - ParseNode** listp = &node->pn_head; + ParseNode** listp = node->unsafeHeadReference(); for (; *listp; listp = &(*listp)->pn_next) { if (!Fold(cx, listp, parser, inGenexpLambda)) return false; } - // If the last node in the list was replaced, pn_tail points into the wrong node. - node->pn_tail = listp; - - node->checkListConsistency(); + node->unsafeReplaceTail(listp); return true; } @@ -1779,6 +1755,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_COALESCE: case PNK_AND: case PNK_OR: + MOZ_ASSERT((*pnp)->is()); return FoldLogical(cx, pnp, parser, inGenexpLambda); case PNK_FUNCTION: @@ -1794,10 +1771,10 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_URSH: case PNK_DIV: case PNK_MOD: - return FoldBinaryArithmetic(cx, pn, parser, inGenexpLambda); + return FoldBinaryArithmetic(cx, &pn->as(), parser, inGenexpLambda); case PNK_POW: - return FoldExponentiation(cx, pn, parser, inGenexpLambda); + return FoldExponentiation(cx, &pn->as(), parser, inGenexpLambda); // Various list nodes not requiring care to minimally fold. Some of // these could be further folded/optimized, but we don't make the effort. @@ -1829,7 +1806,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_CALLSITEOBJ: case PNK_EXPORT_SPEC_LIST: case PNK_IMPORT_SPEC_LIST: - return FoldList(cx, pn, parser, inGenexpLambda); + return FoldList(cx, &pn->as(), parser, inGenexpLambda); case PNK_INITIALYIELD: MOZ_ASSERT(pn->isArity(PN_UNARY)); @@ -1866,6 +1843,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return FoldElement(cx, pnp, parser, inGenexpLambda); case PNK_ADD: + MOZ_ASSERT((*pnp)->is()); return FoldAdd(cx, pnp, parser, inGenexpLambda); case PNK_CALL: @@ -1876,7 +1854,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return FoldCall(cx, pn, parser, inGenexpLambda); case PNK_ARGUMENTS: - return FoldArguments(cx, pn, parser, inGenexpLambda); + return FoldArguments(cx, &pn->as(), parser, inGenexpLambda); case PNK_SWITCH: case PNK_COLON: diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 87b4350308..249b0aa276 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -9,6 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/PodOperations.h" +#include // std::nullptr_t #include #include "frontend/ParseNode.h" @@ -68,7 +69,15 @@ class FullParseHandler /* new_ methods for creating parse nodes. These report OOM on context. */ JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline) - typedef ParseNode* Node; + // FIXME: Use ListNode instead of ListNodeType as an alias (bug 1489008). + using Node = ParseNode*; + +#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \ + using longTypeName = typeName*; +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + + using NullNode = std::nullptr_t; bool isPropertyAccess(ParseNode* node) { return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM); @@ -111,7 +120,14 @@ class FullParseHandler syntaxParser(syntaxParser) {} - static ParseNode* null() { return nullptr; } + static NullNode null() { return NullNode(); } + +#define DECLARE_AS(typeName, longTypeName, asMethodName) \ + static longTypeName asMethodName(Node node) { \ + return &node->as(); \ + } +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) +#undef DECLARE_AS ParseNode* freeTree(ParseNode* pn) { return allocator.freeTree(pn); } void prepareNodeForMutation(ParseNode* pn) { return allocator.prepareNodeForMutation(pn); } @@ -151,31 +167,32 @@ class FullParseHandler return new_(PNK_TEMPLATE_STRING, JSOP_NOP, pos, atom); } - ParseNode* newCallSiteObject(uint32_t begin) { - ParseNode* callSite = new_(begin); - if (!callSite) + CallSiteNodeType newCallSiteObject(uint32_t begin) { + CallSiteNode* callSiteObj = new_(begin); + if (!callSiteObj) return null(); - Node propExpr = newArrayLiteral(getPosition(callSite).begin); - if (!propExpr) + ListNode* rawNodes = newArrayLiteral(callSiteObj->pn_pos.begin); + if (!rawNodes) return null(); - addArrayElement(callSite, propExpr); + addArrayElement(callSiteObj, rawNodes); - return callSite; + return callSiteObj; } - void addToCallSiteObject(ParseNode* callSiteObj, ParseNode* rawNode, ParseNode* cookedNode) { + void addToCallSiteObject(CallSiteNodeType callSiteObj, ParseNode* rawNode, + ParseNode* cookedNode) { MOZ_ASSERT(callSiteObj->isKind(PNK_CALLSITEOBJ)); addArrayElement(callSiteObj, cookedNode); - addArrayElement(callSiteObj->pn_head, rawNode); + addArrayElement(callSiteObj->rawNodes(), rawNode); /* * We don't know when the last noSubstTemplate will come in, and we * don't want to deal with this outside this method */ - setEndPosition(callSiteObj, callSiteObj->pn_head); + setEndPosition(callSiteObj, callSiteObj->rawNodes()); } ParseNode* newThisLiteral(const TokenPos& pos, ParseNode* thisName) { @@ -289,45 +306,37 @@ class FullParseHandler // Expressions - ParseNode* newArrayComprehension(ParseNode* body, const TokenPos& pos) { - MOZ_ASSERT(pos.begin <= body->pn_pos.begin); - MOZ_ASSERT(body->pn_pos.end <= pos.end); - ParseNode* pn = new_(PNK_ARRAYCOMP, pos); - if (!pn) - return nullptr; - pn->append(body); - return pn; - } - - ParseNode* newArrayLiteral(uint32_t begin) { - ParseNode* literal = new_(PNK_ARRAY, TokenPos(begin, begin + 1)); + ListNodeType newArrayLiteral(uint32_t begin) { + ListNode* literal = new_(PNK_ARRAY, TokenPos(begin, begin + 1)); // Later in this stack: remove dependency on this opcode. if (literal) literal->setOp(JSOP_NEWINIT); return literal; } - MOZ_MUST_USE bool addElision(ParseNode* literal, const TokenPos& pos) { + MOZ_MUST_USE bool addElision(ListNodeType literal, const TokenPos& pos) { ParseNode* elision = new_(PNK_ELISION, pos); if (!elision) return false; literal->append(elision); - literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST; + literal->setHasArrayHoleOrSpread(); + literal->setHasNonConstInitializer(); return true; } - MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) { + MOZ_MUST_USE bool addSpreadElement(ListNodeType literal, uint32_t begin, Node inner) { ParseNode* spread = newSpread(begin, inner); if (!spread) return false; literal->append(spread); - literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST; + literal->setHasArrayHoleOrSpread(); + literal->setHasNonConstInitializer(); return true; } - void addArrayElement(ParseNode* literal, ParseNode* element) { + void addArrayElement(ListNodeType literal, Node element) { if (!element->isConstant()) - literal->pn_xflags |= PNX_NONCONST; + literal->setHasNonConstInitializer(); literal->append(element); } @@ -339,7 +348,7 @@ class FullParseHandler return new_(PNK_OPTCALL, JSOP_CALL, callee, args); } - ParseNode* newArguments(const TokenPos& pos) { + ListNodeType newArguments(const TokenPos& pos) { return new_(PNK_ARGUMENTS, JSOP_NOP, pos); } @@ -355,8 +364,8 @@ class FullParseHandler return new_(PNK_GENEXP, JSOP_CALL, callee, args); } - ParseNode* newObjectLiteral(uint32_t begin) { - ParseNode* literal = new_(PNK_OBJECT, TokenPos(begin, begin + 1)); + ListNodeType newObjectLiteral(uint32_t begin) { + ListNode* literal = new_(PNK_OBJECT, TokenPos(begin, begin + 1)); // Later in this stack: remove dependency on this opcode. if (literal) literal->setOp(JSOP_NEWINIT); @@ -368,7 +377,7 @@ class FullParseHandler { return new_(name, heritage, methodBlock, pos); } - ParseNode* newClassMethodList(uint32_t begin) { + ListNodeType newClassMethodList(uint32_t begin) { return new_(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1)); } ParseNode* newClassNames(ParseNode* outer, ParseNode* inner, const TokenPos& pos) { @@ -384,10 +393,10 @@ class FullParseHandler return new_(PNK_SUPERBASE, JSOP_NOP, pos, thisName); } - MOZ_MUST_USE bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) { + MOZ_MUST_USE bool addPrototypeMutation(ListNodeType literal, uint32_t begin, ParseNode* expr) { // Object literals with mutated [[Prototype]] are non-constant so that // singleton objects will have Object.prototype as their [[Prototype]]. - setListFlag(literal, PNX_NONCONST); + literal->setHasNonConstInitializer(); ParseNode* mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr); if (!mutation) @@ -396,9 +405,8 @@ class FullParseHandler return true; } - MOZ_MUST_USE bool addPropertyDefinition(ParseNode* literal, ParseNode* key, ParseNode* val) { + MOZ_MUST_USE bool addPropertyDefinition(ListNodeType literal, ParseNode* key, ParseNode* val) { MOZ_ASSERT(literal->isKind(PNK_OBJECT)); - MOZ_ASSERT(literal->isArity(PN_LIST)); MOZ_ASSERT(key->isKind(PNK_NUMBER) || key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING) || @@ -407,18 +415,21 @@ class FullParseHandler ParseNode* propdef = newBinary(PNK_COLON, key, val, JSOP_INITPROP); if (!propdef) return false; + + if (!val->isConstant()) { + literal->setHasNonConstInitializer(); + } literal->append(propdef); return true; } - MOZ_MUST_USE bool addShorthand(ParseNode* literal, ParseNode* name, ParseNode* expr) { + MOZ_MUST_USE bool addShorthand(ListNodeType literal, ParseNode* name, ParseNode* expr) { MOZ_ASSERT(literal->isKind(PNK_OBJECT)); - MOZ_ASSERT(literal->isArity(PN_LIST)); MOZ_ASSERT(name->isKind(PNK_OBJECT_PROPERTY_NAME)); MOZ_ASSERT(expr->isKind(PNK_NAME)); MOZ_ASSERT(name->pn_atom == expr->pn_atom); - setListFlag(literal, PNX_NONCONST); + literal->setHasNonConstInitializer(); ParseNode* propdef = newBinary(PNK_SHORTHAND, name, expr, JSOP_INITPROP); if (!propdef) return false; @@ -426,11 +437,10 @@ class FullParseHandler return true; } - MOZ_MUST_USE bool addSpreadProperty(ParseNode* literal, uint32_t begin, ParseNode* inner) { + MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin, ParseNode* inner) { MOZ_ASSERT(literal->isKind(PNK_OBJECT)); - MOZ_ASSERT(literal->isArity(PN_LIST)); - setListFlag(literal, PNX_NONCONST); + literal->setHasNonConstInitializer(); ParseNode* spread = newSpread(begin, inner); if (!spread) return false; @@ -438,15 +448,14 @@ class FullParseHandler return true; } - MOZ_MUST_USE bool addObjectMethodDefinition(ParseNode* literal, ParseNode* key, ParseNode* fn, + MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node key, Node fn, JSOp op) { - MOZ_ASSERT(literal->isArity(PN_LIST)); MOZ_ASSERT(key->isKind(PNK_NUMBER) || key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING) || key->isKind(PNK_COMPUTED_NAME)); - literal->pn_xflags |= PNX_NONCONST; + literal->setHasNonConstInitializer(); ParseNode* propdef = newBinary(PNK_COLON, key, fn, op); if (!propdef) @@ -455,7 +464,7 @@ class FullParseHandler return true; } - MOZ_MUST_USE bool addClassMethodDefinition(ParseNode* methodList, ParseNode* key, ParseNode* fn, + MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType methodList, Node key, Node fn, JSOp op, bool isStatic) { MOZ_ASSERT(methodList->isKind(PNK_CLASSMETHODLIST)); @@ -498,7 +507,7 @@ class FullParseHandler // Statements - ParseNode* newStatementList(const TokenPos& pos) { + ListNodeType newStatementList(const TokenPos& pos) { return new_(PNK_STATEMENTLIST, pos); } @@ -508,31 +517,30 @@ class FullParseHandler return stmt->isKind(PNK_FUNCTION); } - void addStatementToList(ParseNode* list, ParseNode* stmt) { + void addStatementToList(ListNodeType list, ParseNode* stmt) { MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST)); list->append(stmt); if (isFunctionStmt(stmt)) { - // PNX_FUNCDEFS notifies the emitter that the block contains - // body-level function definitions that should be processed - // before the rest of nodes. - list->pn_xflags |= PNX_FUNCDEFS; + // Notify the emitter that the block contains body-level function + // definitions that should be processed before the rest of nodes. + list->setHasTopLevelFunctionDeclarations(); } } - void addCaseStatementToList(ParseNode* list, ParseNode* casepn) { + void addCaseStatementToList(ListNodeType list, ParseNode* caseClause) { MOZ_ASSERT(list->isKind(PNK_STATEMENTLIST)); - MOZ_ASSERT(casepn->isKind(PNK_CASE)); - MOZ_ASSERT(casepn->pn_right->isKind(PNK_STATEMENTLIST)); + MOZ_ASSERT(caseClause->isKind(PNK_CASE)); + MOZ_ASSERT(caseClause->pn_right->isKind(PNK_STATEMENTLIST)); - list->append(casepn); + list->append(caseClause); - if (casepn->pn_right->pn_xflags & PNX_FUNCDEFS) - list->pn_xflags |= PNX_FUNCDEFS; + if (caseClause->pn_right->as().hasTopLevelFunctionDeclarations()) + list->setHasTopLevelFunctionDeclarations(); } - MOZ_MUST_USE bool prependInitialYield(ParseNode* stmtList, ParseNode* genName) { + MOZ_MUST_USE bool prependInitialYield(ListNodeType stmtList, Node genName) { MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST)); TokenPos yieldPos(stmtList->pn_pos.begin, stmtList->pn_pos.begin + 1); @@ -699,7 +707,7 @@ class FullParseHandler return new_(PNK_THROW, JSOP_THROW, pos, expr); } - ParseNode* newTryStatement(uint32_t begin, ParseNode* body, ParseNode* catchList, + ParseNode* newTryStatement(uint32_t begin, ParseNode* body, ListNodeType catchList, ParseNode* finallyBlock) { TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); return new_(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos); @@ -729,7 +737,7 @@ class FullParseHandler return new_(lhs, index, lhs->pn_pos.begin, end); } - inline MOZ_MUST_USE bool addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope, + inline MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, ParseNode* lexicalScope, ParseNode* catchName, ParseNode* catchGuard, ParseNode* catchBody); @@ -772,11 +780,11 @@ class FullParseHandler funbox->functionNode = pn; } void addFunctionFormalParameter(ParseNode* pn, ParseNode* argpn) { - pn->pn_body->append(argpn); + addList(/* list = */ &pn->pn_body->as(), /* child = */ argpn); } void setFunctionBody(ParseNode* fn, ParseNode* body) { MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY)); - fn->pn_body->append(body); + addList(/* list = */ &fn->pn_body->as(), /* child = */ body); } ParseNode* newModule() { @@ -869,27 +877,27 @@ class FullParseHandler return kind == PNK_VAR || kind == PNK_LET || kind == PNK_CONST; } - ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, JSOp op = JSOP_NOP) { MOZ_ASSERT(!isDeclarationKind(kind)); return new_(kind, op, pos()); } - ParseNode* newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) { MOZ_ASSERT(!isDeclarationKind(kind)); return new_(kind, op, TokenPos(begin, begin + 1)); } - ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) { MOZ_ASSERT(!isDeclarationKind(kind)); return new_(kind, op, kid); } - ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { + ListNodeType newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { MOZ_ASSERT(isDeclarationKind(kind)); return new_(kind, op, pos()); } - ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) { + ListNodeType newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) { MOZ_ASSERT(isDeclarationKind(kind)); return new_(kind, op, kid); } @@ -898,30 +906,29 @@ class FullParseHandler return isDeclarationKind(node->getKind()); } - ParseNode* singleBindingFromDeclaration(ParseNode* decl) { + Node singleBindingFromDeclaration(ListNodeType decl) { MOZ_ASSERT(isDeclarationList(decl)); - MOZ_ASSERT(decl->pn_count == 1); - return decl->pn_head; + MOZ_ASSERT(decl->count() == 1); + return decl->head(); } - ParseNode* newCatchList() { + ListNodeType newCatchList() { return new_(PNK_CATCHLIST, JSOP_NOP, pos()); } - ParseNode* newCommaExpressionList(ParseNode* kid) { + ListNodeType newCommaExpressionList(Node kid) { return newList(PNK_COMMA, kid, JSOP_NOP); } - void addList(ParseNode* list, ParseNode* kid) { + void addList(ListNodeType list, Node kid) { list->append(kid); } void setOp(ParseNode* pn, JSOp op) { pn->setOp(op); } - void setListFlag(ParseNode* pn, unsigned flag) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - pn->pn_xflags |= flag; + void setListHasNonConstInitializer(ListNodeType literal) { + literal->setHasNonConstInitializer(); } MOZ_MUST_USE ParseNode* parenthesize(ParseNode* pn) { pn->setInParens(true); @@ -1015,7 +1022,7 @@ class FullParseHandler }; inline bool -FullParseHandler::addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope, +FullParseHandler::addCatchBlock(ListNodeType catchList, ParseNode* lexicalScope, ParseNode* catchName, ParseNode* catchGuard, ParseNode* catchBody) { ParseNode* catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody); @@ -1029,27 +1036,15 @@ FullParseHandler::addCatchBlock(ParseNode* catchList, ParseNode* lexicalScope, inline bool FullParseHandler::setLastFunctionFormalParameterDefault(ParseNode* funcpn, ParseNode* defaultValue) { - ParseNode* arg = funcpn->pn_body->last(); + ListNode* body = &funcpn->pn_body->as(); + ParseNode* arg = body->last(); ParseNode* pn = newBinary(PNK_ASSIGN, arg, defaultValue, JSOP_NOP); if (!pn) return false; checkAndSetIsDirectRHSAnonFunction(defaultValue); - funcpn->pn_body->pn_pos.end = pn->pn_pos.end; - ParseNode* pnchild = funcpn->pn_body->pn_head; - ParseNode* pnlast = funcpn->pn_body->last(); - MOZ_ASSERT(pnchild); - if (pnchild == pnlast) { - funcpn->pn_body->pn_head = pn; - } else { - while (pnchild->pn_next != pnlast) { - MOZ_ASSERT(pnchild->pn_next); - pnchild = pnchild->pn_next; - } - pnchild->pn_next = pn; - } - funcpn->pn_body->pn_tail = &pn->pn_next; + body->replaceLast(pn); return true; } diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 76433fcc80..1b981876c2 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -284,12 +284,12 @@ class NameResolver * for new variables and then return an anonymous function using this scope. */ bool isDirectCall(int pos, ParseNode* cur) { - return pos >= 0 && call(parents[pos]) && parents[pos]->pn_head == cur; + return pos >= 0 && call(parents[pos]) && parents[pos]->pn_left == cur; } - bool resolveTemplateLiteral(ParseNode* node, HandleAtom prefix) { + bool resolveTemplateLiteral(ListNode* node, HandleAtom prefix) { MOZ_ASSERT(node->isKind(PNK_TEMPLATE_STRING_LIST)); - ParseNode* element = node->pn_head; + ParseNode* element = node->head(); while (true) { MOZ_ASSERT(element->isKind(PNK_TEMPLATE_STRING)); @@ -317,16 +317,18 @@ class NameResolver // The callsite object node is first. This node only contains // internal strings or undefined and an array -- no user-controlled // expressions. - ParseNode* element = node->pn_right->pn_head; + CallSiteNode* element = &node->pn_right->as().head()->as(); #ifdef DEBUG { - MOZ_ASSERT(element->isKind(PNK_CALLSITEOBJ)); - ParseNode* array = element->pn_head; - MOZ_ASSERT(array->isKind(PNK_ARRAY)); - for (ParseNode* kid = array->pn_head; kid; kid = kid->pn_next) - MOZ_ASSERT(kid->isKind(PNK_TEMPLATE_STRING)); - for (ParseNode* next = array->pn_next; next; next = next->pn_next) - MOZ_ASSERT(next->isKind(PNK_TEMPLATE_STRING) || next->isKind(PNK_RAW_UNDEFINED)); + ListNode* rawNodes = &element->head()->as(); + MOZ_ASSERT(rawNodes->isKind(PNK_ARRAY)); + for (ParseNode* raw : rawNodes->contents()) { + MOZ_ASSERT(raw->isKind(PNK_TEMPLATE_STRING)); + } + for (ParseNode* cooked : element->contentsFrom(rawNodes->pn_next)) { + MOZ_ASSERT(cooked->isKind(PNK_TEMPLATE_STRING) || + cooked->isKind(PNK_RAW_UNDEFINED)); + } } #endif @@ -697,8 +699,7 @@ class NameResolver case PNK_VAR: case PNK_CONST: case PNK_LET: - MOZ_ASSERT(cur->isArity(PN_LIST)); - for (ParseNode* element = cur->pn_head; element; element = element->pn_next) { + for (ParseNode* element : cur->as().contents()) { if (!resolve(element, prefix)) return false; } @@ -708,19 +709,19 @@ class NameResolver // PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for // legacy comprehensions. Probably this should be a non-list // eventually. - case PNK_ARRAYCOMP: - MOZ_ASSERT(cur->isArity(PN_LIST)); - MOZ_ASSERT(cur->pn_count == 1); - MOZ_ASSERT(cur->pn_head->isKind(PNK_LEXICALSCOPE) || - cur->pn_head->isKind(PNK_COMPREHENSIONFOR)); - if (!resolve(cur->pn_head, prefix)) + case PNK_ARRAYCOMP: { + ListNode* literal = &cur->as(); + MOZ_ASSERT(literal->count() == 1); + MOZ_ASSERT(literal->head()->isKind(PNK_LEXICALSCOPE) || + literal->head()->isKind(PNK_COMPREHENSIONFOR)); + if (!resolve(literal->head(), prefix)) return false; break; + } case PNK_OBJECT: case PNK_CLASSMETHODLIST: - MOZ_ASSERT(cur->isArity(PN_LIST)); - for (ParseNode* element = cur->pn_head; element; element = element->pn_next) { + for (ParseNode* element : cur->as().contents()) { if (!resolve(element, prefix)) return false; } @@ -729,8 +730,7 @@ class NameResolver // A template string list's contents alternate raw template string // contents with expressions interpolated into the overall literal. case PNK_TEMPLATE_STRING_LIST: - MOZ_ASSERT(cur->isArity(PN_LIST)); - if (!resolveTemplateLiteral(cur, prefix)) + if (!resolveTemplateLiteral(&cur->as(), prefix)) return false; break; @@ -755,8 +755,7 @@ class NameResolver // the Arguments node used by tagged template literals, since that is // special-cased inside of resolveTaggedTemplate. case PNK_ARGUMENTS: - MOZ_ASSERT(cur->isArity(PN_LIST)); - for (ParseNode* element = cur->pn_head; element; element = element->pn_next) { + for (ParseNode* element : cur->as().contents()) { if (!resolve(element, prefix)) return false; } @@ -767,15 +766,15 @@ class NameResolver // contain a single export batch specifier. case PNK_EXPORT_SPEC_LIST: case PNK_IMPORT_SPEC_LIST: { - MOZ_ASSERT(cur->isArity(PN_LIST)); #ifdef DEBUG bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST); - ParseNode* item = cur->pn_head; + ListNode* list = &cur->as(); + ParseNode* item = list->head(); if (!isImport && item && item->isKind(PNK_EXPORT_BATCH_SPEC)) { MOZ_ASSERT(item->isArity(PN_NULLARY)); break; } - for (; item; item = item->pn_next) { + for (ParseNode* item : list->contents()) { MOZ_ASSERT(item->isKind(isImport ? PNK_IMPORT_SPEC : PNK_EXPORT_SPEC)); MOZ_ASSERT(item->isArity(PN_BINARY)); MOZ_ASSERT(item->pn_left->isKind(PNK_NAME)); @@ -788,8 +787,8 @@ class NameResolver } case PNK_CATCHLIST: { - MOZ_ASSERT(cur->isArity(PN_LIST)); - for (ParseNode* catchNode = cur->pn_head; catchNode; catchNode = catchNode->pn_next) { + ListNode* catchList = &cur->as(); + 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)); diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 5de58b9a29..218b08ef48 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -17,26 +17,24 @@ using mozilla::IsFinite; #ifdef DEBUG void -ParseNode::checkListConsistency() +ListNode::checkConsistency() const { - MOZ_ASSERT(isArity(PN_LIST)); - ParseNode** tail; - uint32_t count = 0; - if (pn_head) { - ParseNode* last = pn_head; - ParseNode* pn = last; + ParseNode* const* tailNode; + uint32_t actualCount = 0; + if (const ParseNode* last = head()) { + const ParseNode* pn = last; while (pn) { last = pn; pn = pn->pn_next; - count++; + actualCount++; } - tail = &last->pn_next; + tailNode = &last->pn_next; } else { - tail = &pn_head; + tailNode = &pn_u.list.head; } - MOZ_ASSERT(pn_tail == tail); - MOZ_ASSERT(pn_count == count); + MOZ_ASSERT(tail() == tailNode); + MOZ_ASSERT(count() == actualCount); } #endif @@ -76,10 +74,10 @@ class NodeStack { top = pn; } /* Push the children of the PN_LIST node |pn| on the stack. */ - void pushList(ParseNode* pn) { + void pushList(ListNode* pn) { /* This clobbers pn->pn_head if the list is empty; should be okay. */ - *pn->pn_tail = top; - top = pn->pn_head; + pn->unsafeSetTail(top); + top = pn->head(); } ParseNode* pop() { MOZ_ASSERT(!empty()); @@ -148,10 +146,10 @@ PushScopeNodeChildren(ParseNode* node, NodeStack* stack) } static PushResult -PushListNodeChildren(ParseNode* node, NodeStack* stack) +PushListNodeChildren(ListNode* node, NodeStack* stack) { MOZ_ASSERT(node->isArity(PN_LIST)); - node->checkListConsistency(); + node->checkConsistency(); stack->pushList(node); @@ -335,7 +333,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_left->isKind(PNK_EXPORT_SPEC_LIST)); MOZ_ASSERT(pn->pn_left->isArity(PN_LIST)); MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING)); - stack->pushList(pn->pn_left); + stack->pushList(&pn->pn_left->as()); stack->push(pn->pn_right); return PushResult::Recyclable; } @@ -474,20 +472,17 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_EXPORT_SPEC_LIST: case PNK_PARAMSBODY: case PNK_CLASSMETHODLIST: - return PushListNodeChildren(pn, stack); + return PushListNodeChildren(&pn->as(), stack); // Array comprehension nodes are lists with a single child: // PNK_COMPREHENSIONFOR for comprehensions, PNK_LEXICALSCOPE for legacy // comprehensions. Probably this should be a non-list eventually. case PNK_ARRAYCOMP: { -#ifdef DEBUG - MOZ_ASSERT(pn->isKind(PNK_ARRAYCOMP)); - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count == 1); - MOZ_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE) || - pn->pn_head->isKind(PNK_COMPREHENSIONFOR)); -#endif - return PushListNodeChildren(pn, stack); + ListNode* literal = &pn->as(); + MOZ_ASSERT(literal->count() == 1); + MOZ_ASSERT(literal->head()->isKind(PNK_LEXICALSCOPE) || + literal->head()->isKind(PNK_COMPREHENSIONFOR)); + return PushListNodeChildren(literal, stack); } case PNK_LABEL: @@ -614,7 +609,7 @@ ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, Pars } } - ParseNode* list = handler->new_(kind, op, left); + ListNode* list = handler->new_(kind, op, left); if (!list) return nullptr; @@ -674,7 +669,7 @@ ParseNode::dump(int indent) ((CodeNode*) this)->dump(indent); break; case PN_LIST: - ((ListNode*) this)->dump(indent); + as().dump(indent); break; case PN_NAME: ((NameNode*) this)->dump(indent); @@ -785,14 +780,12 @@ ListNode::dump(int indent) { const char* name = parseNodeNames[getKind()]; fprintf(stderr, "(%s [", name); - if (pn_head != nullptr) { + if (ParseNode* listHead = head()) { indent += strlen(name) + 3; - DumpParseTree(pn_head, indent); - ParseNode* pn = pn_head->pn_next; - while (pn != nullptr) { + DumpParseTree(listHead, indent); + for (ParseNode* item : contentsFrom(listHead->pn_next)) { IndentNewLine(indent); - DumpParseTree(pn, indent); - pn = pn->pn_next; + DumpParseTree(item, indent); } } fprintf(stderr, "])"); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 51d43a36a1..a19e4c3389 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -220,8 +220,6 @@ IsTypeofKind(ParseNodeKind kind) } /* - * Label Variant Members - * ----- ------- ------- * * PNK_FUNCTION name pn_funbox: ptr to js::FunctionBox holding function * object containing arg and var properties. We @@ -229,27 +227,25 @@ IsTypeofKind(ParseNodeKind kind) * time to specialize arg and var bytecodes early. * pn_body: PNK_PARAMSBODY, ordinarily; * PNK_LEXICALSCOPE for implicit function in genexpr - * PNK_PARAMSBODY list list of formal parameters with - * PNK_NAME node with non-empty name for - * SingleNameBinding without Initializer - * PNK_ASSIGN node for SingleNameBinding with - * Initializer - * PNK_NAME node with empty name for destructuring - * pn_expr: PNK_ARRAY, PNK_OBJECT, or PNK_ASSIGN - * PNK_ARRAY or PNK_OBJECT for BindingPattern - * without Initializer - * PNK_ASSIGN for BindingPattern with - * Initializer - * followed by: - * PNK_STATEMENTLIST node for function body - * statements, - * PNK_RETURN for expression closure - * pn_count: 1 + number of formal parameters - * pn_tree: PNK_PARAMSBODY or PNK_STATEMENTLIST node + * PNK_PARAMSBODY (ListNode) + * head: list of formal parameters with + * * Name node with non-empty name for SingleNameBinding without + * Initializer + * * Assign node for SingleNameBinding with Initializer + * * Name node with empty name for destructuring + * pn_expr: Array or Object for BindingPattern without + * Initializer, Assign for BindingPattern with + * Initializer + * followed by either: + * * StatementList node for function body statements + * * Return for expression closure + * count: number of formal parameters + 1 * PNK_SPREAD unary pn_kid: expression being spread * * - * PNK_STATEMENTLIST list pn_head: list of pn_count statements + * PNK_STATEMENTLIST (ListNode) + * head: list of N statements + * count: N >= 0 * PNK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null. * In body of a comprehension or desugared generator * expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH, @@ -293,19 +289,21 @@ IsTypeofKind(ParseNodeKind kind) * PNK_BREAK name pn_atom: label or null * PNK_CONTINUE name pn_atom: label or null * PNK_WITH binary pn_left: head expr; pn_right: body; - * PNK_VAR, list pn_head: list of PNK_NAME or PNK_ASSIGN nodes - * PNK_LET, each name node has either - * PNK_CONST pn_used: false - * pn_atom: variable name - * pn_expr: initializer or null - * or - * pn_used: true - * pn_atom: variable name - * pn_lexdef: def node - * each assignment node has - * pn_left: PNK_NAME with pn_used true and - * pn_lexdef (NOT pn_expr) set - * pn_right: initializer + * PNK_VAR, PNK_LET, PNK_CONST (ListNode) + * head: list of N Name or Assign nodes + * each name node has either + * pn_used: false + * pn_atom: variable name + * pn_expr: initializer or null + * or + * pn_used: true + * pn_atom: variable name + * pn_lexdef: def node + * each assignment node has + * pn_left: Name with pn_used true and + * pn_lexdef (NOT pn_expr) set + * pn_right: initializer + * count: N > 0 * PNK_RETURN unary pn_kid: return expr or null * PNK_SEMI unary pn_kid: expr or null statement * pn_prologue: true if Directive Prologue member @@ -314,15 +312,23 @@ IsTypeofKind(ParseNodeKind kind) * PNK_LABEL name pn_atom: label, pn_expr: labeled statement * PNK_IMPORT binary pn_left: PNK_IMPORT_SPEC_LIST import specifiers * pn_right: PNK_STRING module specifier + * PNK_IMPORT_SPEC_LIST (ListNode) + * head: list of N ImportSpec nodes + * count: N >= 0 (N = 0 for `import {} from ...`) * PNK_EXPORT unary pn_kid: declaration expression * PNK_EXPORT_FROM binary pn_left: PNK_EXPORT_SPEC_LIST export specifiers * pn_right: PNK_STRING module specifier + * PNK_EXPORT_SPEC_LIST (ListNode) + * head: list of N ExportSpec nodes + * count: N >= 0 (N = 0 for `export {}`) * PNK_EXPORT_DEFAULT unary pn_kid: export default declaration or expression * * * All left-associated binary trees of the same type are optimized into lists * to avoid recursion when processing expression chains. - * PNK_COMMA list pn_head: list of pn_count comma-separated exprs + * PNK_COMMA (ListNode) + * head: list of N comma-separated exprs + * count: N >= 2 * PNK_ASSIGN binary pn_left: lvalue, pn_right: rvalue * PNK_ADDASSIGN, binary pn_left: lvalue, pn_right: rvalue * PNK_SUBASSIGN, pn_op: JSOP_ADD for +=, etc. @@ -339,29 +345,18 @@ IsTypeofKind(ParseNodeKind kind) * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr) * pn_kid1: cond, pn_kid2: then, pn_kid3: else * PNK_COALESCE, list pn_head; list of pn_count subexpressions - * PNK_OR, All of these operators are left-associative except (**). - * PNK_AND - * PNK_BITOR, - * PNK_BITXOR, - * PNK_BITAND, - * PNK_EQ, - * PNK_NE, - * PNK_STRICTEQ, - * PNK_STRICTNE, - * PNK_LT, - * PNK_LE, - * PNK_GT, - * PNK_GE, - * PNK_LSH, - * PNK_RSH, - * PNK_URSH, - * PNK_ADD, - * PNK_SUB, - * PNK_STAR, - * PNK_DIV, - * PNK_MOD, - * PNK_POW (**) is right-associative, but forms a list - * nonetheless. Special hacks everywhere. + * PNK_OR, PNK_AND, PNK_BITOR, + * PNK_BITXOR, PNK_BITAND, PNK_EQ, + * PNK_NE, PNK_STRICTEQ, PNK_STRICTNE, + * PNK_LT, PNK_LE, PNK_GT, PNK_GE, + * PNK_LSH, PNK_RSH, PNK_URSH, + * PNK_ADD, PNK_SUB, PNK_STAR, + * PNK_DIV, PNK_MOD, PNK_POW (ListNode) + * head: list of N subexpressions + * All of these operators are left-associative except Pow which is + * right-associative, but still forms a list (see comments in + * ParseNode::appendOrCreateList). + * count: N >= 2 * * PNK_POS, unary pn_kid: UNARY expr * PNK_NEG @@ -420,10 +415,21 @@ IsTypeofKind(ParseNodeKind kind) * pn_count: N (where N is number of args) * PNK_GENEXP binary Exactly like PNK_CALL, used for the implicit call * in the desugaring of a generator-expression. - * PNK_ARRAY list pn_head: list of pn_count array element exprs - * [,,] holes are represented by PNK_ELISION nodes - * pn_xflags: PN_ENDCOMMA if extra comma at end - * PNK_OBJECT list pn_head: list of pn_count binary PNK_COLON nodes + * PNK_ARGUMENTS (ListNode) + * head: list of arg1, arg2, ... argN + * count: N >= 0 + * PNK_ARRAY (ListNode) + * head: list of N array element expressions + * holes ([,,]) are represented by Elision nodes, + * spread elements ([...X]) are represented by Spread nodes + * count: N >= 0 + * PNK_OBJECT (ListNode) + * head: list of N nodes, each item is one of: + * * MutateProto + * * Colon + * * Shorthand + * * Spread + * count: N >= 0 * PNK_COLON binary key-value pair in object initializer or * destructuring lhs * pn_left: property id, pn_right: value @@ -435,14 +441,21 @@ IsTypeofKind(ParseNodeKind kind) * PNK_STRING pn_op: JSOP_GETNAME, JSOP_STRING, or JSOP_OBJECT * If JSOP_GETNAME, pn_op may be JSOP_*ARG or JSOP_*VAR * telling const-ness and static analysis results - * PNK_TEMPLATE_STRING_LIST pn_head: list of alternating expr and template strings - * list + * PNK_TEMPLATE_STRING_LIST (ListNode) + * head: list of alternating expr and template strings + * TemplateString [, expression, TemplateString]+ + * there's at least one expression. If the template literal contains + * no ${}-delimited expression, it's parsed as a single TemplateString * PNK_TEMPLATE_STRING pn_atom: template string atom nullary pn_op: JSOP_NOP * PNK_TAGGED_TEMPLATE pn_left: tag expression * binary pn_right: Arguments, with the first being the call site object, then arg1, arg2, ... argN - * PNK_CALLSITEOBJ list pn_head: a PNK_ARRAY node followed by - * list of pn_count - 1 PNK_TEMPLATE_STRING nodes + * PNK_CALLSITEOBJ (CallSiteNode) + * head: an Array of raw TemplateString, then corresponding cooked + * TemplateString nodes + * Array [, cooked TemplateString]+ + * where the Array is + * [raw TemplateString]+ * PNK_REGEXP nullary pn_objbox: RegExp model object * PNK_NUMBER dval pn_dval: double value of numeric literal * PNK_TRUE, nullary pn_op: JSOp bytecode @@ -483,12 +496,21 @@ enum ParseNodeArity PN_SCOPE /* lexical scope */ }; +#define FOR_EACH_PARSENODE_SUBCLASS(macro) \ + macro(ListNode, ListNodeType, asList) \ + macro(CallSiteNode, CallSiteNodeType, asCallSite) + class LoopControlStatement; class BreakStatement; class ContinueStatement; class ConditionalExpression; class PropertyAccess; +#define DECLARE_CLASS(typeName, longTypeName, asMethodName) \ +class typeName; +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_CLASS) +#undef DECLARE_CLASS + class ParseNode { uint16_t pn_type; /* PNK_* type */ @@ -574,10 +596,12 @@ class ParseNode union { struct { /* list of next-linked nodes */ + private: + friend class ListNode; ParseNode* head; /* first node in list */ - ParseNode** tail; /* ptr to ptr to last node in list */ + ParseNode** tail; /* ptr to last node's pn_next in list */ uint32_t count; /* number of nodes in list */ - uint32_t xflags; /* see PNX_* below */ + uint32_t xflags; /* see ListNode class */ } list; struct { /* ternary: if, for(;;), ?: */ ParseNode* kid1; /* condition, discriminant, etc. */ @@ -624,10 +648,6 @@ class ParseNode #define pn_objbox pn_u.name.objbox #define pn_funbox pn_u.name.funbox #define pn_body pn_u.name.expr -#define pn_head pn_u.list.head -#define pn_tail pn_u.list.tail -#define pn_count pn_u.list.count -#define pn_xflags pn_u.list.xflags #define pn_kid1 pn_u.ternary.kid1 #define pn_kid2 pn_u.ternary.kid2 #define pn_kid3 pn_u.ternary.kid3 @@ -682,13 +702,6 @@ class ParseNode pn_u.scope.body = body; } -/* PN_LIST pn_xflags bits. */ -#define PNX_FUNCDEFS 0x01 /* contains top-level function statements */ -#define PNX_ARRAYHOLESPREAD 0x02 /* one or more of - 1. array initialiser has holes - 2. array initializer has spread node */ -#define PNX_NONCONST 0x04 /* initialiser has non-constants */ - bool functionIsHoisted() const { MOZ_ASSERT(pn_arity == PN_CODE && getKind() == PNK_FUNCTION); MOZ_ASSERT(isOp(JSOP_LAMBDA) || // lambda, genexpr @@ -738,41 +751,7 @@ class ParseNode bool isDirectivePrologueMember() const { return pn_prologue; } // True iff this is a for-in/of loop variable declaration (var/let/const). - bool isForLoopDeclaration() const { - if (isKind(PNK_VAR) || isKind(PNK_LET) || isKind(PNK_CONST)) { - MOZ_ASSERT(isArity(PN_LIST)); - MOZ_ASSERT(pn_count > 0); - return true; - } - - return false; - } - - ParseNode* generatorExpr() const { - MOZ_ASSERT(isKind(PNK_GENEXP)); - - ParseNode* callee = this->pn_left; - MOZ_ASSERT(callee->isKind(PNK_FUNCTION)); - - ParseNode* paramsBody = callee->pn_body; - MOZ_ASSERT(paramsBody->isKind(PNK_PARAMSBODY)); - - ParseNode* body = paramsBody->last(); - MOZ_ASSERT(body->isKind(PNK_STATEMENTLIST)); - MOZ_ASSERT(body->last()->isKind(PNK_LEXICALSCOPE) || - body->last()->isKind(PNK_COMPREHENSIONFOR)); - return body->last(); - } - - /* - * Compute a pointer to the last element in a singly-linked list. NB: list - * must be non-empty for correct PN_LAST usage -- this is asserted! - */ - ParseNode* last() const { - MOZ_ASSERT(pn_arity == PN_LIST); - MOZ_ASSERT(pn_count != 0); - return (ParseNode*)(uintptr_t(pn_tail) - offsetof(ParseNode, pn_next)); - } + bool isForLoopDeclaration() const; void initNumber(double value, DecimalPoint decimalPoint) { MOZ_ASSERT(pn_arity == PN_NULLARY); @@ -781,49 +760,6 @@ class ParseNode pn_u.number.decimalPoint = decimalPoint; } - void makeEmpty() { - MOZ_ASSERT(pn_arity == PN_LIST); - pn_head = nullptr; - pn_tail = &pn_head; - pn_count = 0; - pn_xflags = 0; - } - - void initList(ParseNode* pn) { - MOZ_ASSERT(pn_arity == PN_LIST); - if (pn->pn_pos.begin < pn_pos.begin) - pn_pos.begin = pn->pn_pos.begin; - pn_pos.end = pn->pn_pos.end; - pn_head = pn; - pn_tail = &pn->pn_next; - pn_count = 1; - pn_xflags = 0; - } - - void append(ParseNode* pn) { - MOZ_ASSERT(pn_arity == PN_LIST); - MOZ_ASSERT(pn->pn_pos.begin >= pn_pos.begin); - pn_pos.end = pn->pn_pos.end; - *pn_tail = pn; - pn_tail = &pn->pn_next; - pn_count++; - } - - void prepend(ParseNode* pn) { - MOZ_ASSERT(pn_arity == PN_LIST); - pn->pn_next = pn_head; - pn_head = pn; - if (pn_tail == &pn_head) - pn_tail = &pn->pn_next; - pn_count++; - } - - void checkListConsistency() -#ifndef DEBUG - {} -#endif - ; - enum AllowConstantObjects { DontAllowObjects = 0, AllowObjects, @@ -944,8 +880,33 @@ struct TernaryNode : public ParseNode #endif }; -struct ListNode : public ParseNode +class ListNode : public ParseNode { + private: + // xflags bits. + + // Statement list has top-level function statements. + static constexpr uint32_t hasTopLevelFunctionDeclarationsBit = 0x01; + + // One or more of + // * array has holes + // * array has spread node + static constexpr uint32_t hasArrayHoleOrSpreadBit = 0x02; + + // Array/Object/Class initializer has non-constants. + // * array has holes + // * array has spread node + // * array has element which is known not to be constant + // * array has no element + // * object/class has __proto__ + // * object/class has property which is known not to be constant + // * object/class shorthand property + // * object/class spread property + // * object/class has method + // * object/class has computed property + static constexpr uint32_t hasNonConstInitializerBit = 0x04; + + public: ListNode(ParseNodeKind kind, const TokenPos& pos) : ParseNode(kind, JSOP_NOP, PN_LIST, pos) { @@ -961,7 +922,15 @@ struct ListNode : public ParseNode ListNode(ParseNodeKind kind, JSOp op, ParseNode* kid) : ParseNode(kind, op, PN_LIST, kid->pn_pos) { - initList(kid); + if (kid->pn_pos.begin < pn_pos.begin) { + pn_pos.begin = kid->pn_pos.begin; + } + pn_pos.end = kid->pn_pos.end; + + pn_u.list.head = kid; + pn_u.list.tail = &kid->pn_next; + pn_u.list.count = 1; + pn_u.list.xflags = 0; } static bool test(const ParseNode& node) { @@ -971,8 +940,278 @@ struct ListNode : public ParseNode #ifdef DEBUG void dump(int indent); #endif + + ParseNode* head() const { + return pn_u.list.head; + } + + ParseNode** tail() const { + return pn_u.list.tail; + } + + uint32_t count() const { + return pn_u.list.count; + } + + bool empty() const { + return count() == 0; + } + + MOZ_MUST_USE bool hasTopLevelFunctionDeclarations() const { + MOZ_ASSERT(isKind(PNK_STATEMENTLIST)); + return pn_u.list.xflags & hasTopLevelFunctionDeclarationsBit; + } + + MOZ_MUST_USE bool hasArrayHoleOrSpread() const { + MOZ_ASSERT(isKind(PNK_ARRAY)); + return pn_u.list.xflags & hasArrayHoleOrSpreadBit; + } + + MOZ_MUST_USE bool hasNonConstInitializer() const { + MOZ_ASSERT(isKind(PNK_ARRAY) || + isKind(PNK_OBJECT) || + isKind(PNK_CLASSMETHODLIST)); + return pn_u.list.xflags & hasNonConstInitializerBit; + } + + void setHasTopLevelFunctionDeclarations() { + MOZ_ASSERT(isKind(PNK_STATEMENTLIST)); + pn_u.list.xflags |= hasTopLevelFunctionDeclarationsBit; + } + + void setHasArrayHoleOrSpread() { + MOZ_ASSERT(isKind(PNK_ARRAY)); + pn_u.list.xflags |= hasArrayHoleOrSpreadBit; + } + + void setHasNonConstInitializer() { + MOZ_ASSERT(isKind(PNK_ARRAY) || + isKind(PNK_OBJECT) || + isKind(PNK_CLASSMETHODLIST)); + pn_u.list.xflags |= hasNonConstInitializerBit; + } + + void checkConsistency() const +#ifndef DEBUG + {} +#endif + ; + + /* + * Compute a pointer to the last element in a singly-linked list. NB: list + * must be non-empty -- this is asserted! + */ + ParseNode* last() const { + MOZ_ASSERT(!empty()); + // + // ParseNode ParseNode + // +-----+---------+-----+ +-----+---------+-----+ + // | ... | pn_next | ... | +-...->| ... | pn_next | ... | + // +-----+---------+-----+ | +-----+---------+-----+ + // ^ | | ^ ^ + // | +---------------+ | | + // | | tail() + // | | + // head() last() + // + return (ParseNode*)(uintptr_t(tail()) - offsetof(ParseNode, pn_next)); + } + + void replaceLast(ParseNode* node) { + MOZ_ASSERT(!empty()); + pn_pos.end = node->pn_pos.end; + + ParseNode* item = head(); + ParseNode* lastNode = last(); + MOZ_ASSERT(item); + if (item == lastNode) { + pn_u.list.head = node; + } else { + while (item->pn_next != lastNode) { + MOZ_ASSERT(item->pn_next); + item = item->pn_next; + } + item->pn_next = node; + } + pn_u.list.tail = &node->pn_next; + } + + void makeEmpty() { + pn_u.list.head = nullptr; + pn_u.list.tail = &pn_u.list.head; + pn_u.list.count = 0; + pn_u.list.xflags = 0; + } + + void append(ParseNode* item) { + MOZ_ASSERT(item->pn_pos.begin >= pn_pos.begin); + pn_pos.end = item->pn_pos.end; + *pn_u.list.tail = item; + pn_u.list.tail = &item->pn_next; + pn_u.list.count++; + } + + void prepend(ParseNode* item) { + item->pn_next = pn_u.list.head; + pn_u.list.head = item; + if (pn_u.list.tail == &pn_u.list.head) { + pn_u.list.tail = &item->pn_next; + } + pn_u.list.count++; + } + + // Methods used by FoldConstants.cpp. + // Caller is responsible for keeping the list consistent. + ParseNode** unsafeHeadReference() { + return &pn_u.list.head; + } + + void unsafeReplaceTail(ParseNode** newTail) { + pn_u.list.tail = newTail; + checkConsistency(); + } + + void unsafeSetTail(ParseNode* newTail) { + *pn_u.list.tail = newTail; + } + + void unsafeDecrementCount() { + MOZ_ASSERT(count() > 1); + pn_u.list.count--; + } + + private: + // Classes to iterate over ListNode contents: + // + // Usage: + // ListNode* list; + // for (ParseNode* item : list->contents()) { + // // item is ParseNode* typed. + // } + class iterator + { + private: + ParseNode* node_; + + friend class ListNode; + explicit iterator(ParseNode* node) + : node_(node) + {} + + public: + bool operator==(const iterator& other) const { + return node_ == other.node_; + } + + bool operator!=(const iterator& other) const { + return !(*this == other); + } + + iterator& operator++() { + node_ = node_->pn_next; + return *this; + } + + ParseNode* operator*() { + return node_; + } + + const ParseNode* operator*() const { + return node_; + } + }; + + class range + { + private: + ParseNode* begin_; + ParseNode* end_; + + friend class ListNode; + range(ParseNode* begin, ParseNode* end) + : begin_(begin), + end_(end) + {} + + public: + iterator begin() { + return iterator(begin_); + } + + iterator end() { + return iterator(end_); + } + + const iterator begin() const { + return iterator(begin_); + } + + const iterator end() const { + return iterator(end_); + } + + const iterator cbegin() const { + return begin(); + } + + const iterator cend() const { + return end(); + } + }; + +#ifdef DEBUG + MOZ_MUST_USE bool contains(ParseNode* target) const { + MOZ_ASSERT(target); + for (ParseNode* node : contents()) { + if (target == node) { + return true; + } + } + return false; + } +#endif + + public: + range contents() { + return range(head(), nullptr); + } + + const range contents() const { + return range(head(), nullptr); + } + + range contentsFrom(ParseNode* begin) { + MOZ_ASSERT_IF(begin, contains(begin)); + return range(begin, nullptr); + } + + const range contentsFrom(ParseNode* begin) const { + MOZ_ASSERT_IF(begin, contains(begin)); + return range(begin, nullptr); + } + + range contentsTo(ParseNode* end) { + MOZ_ASSERT_IF(end, contains(end)); + return range(head(), end); + } + + const range contentsTo(ParseNode* end) const { + MOZ_ASSERT_IF(end, contains(end)); + return range(head(), end); + } }; +inline bool +ParseNode::isForLoopDeclaration() const +{ + if (isKind(PNK_VAR) || isKind(PNK_LET) || isKind(PNK_CONST)) { + MOZ_ASSERT(!as().empty()); + return true; + } + + return false; +} + struct CodeNode : public ParseNode { CodeNode(ParseNodeKind kind, JSOp op, const TokenPos& pos) @@ -1066,10 +1305,7 @@ class CaseClause : public BinaryNode ParseNode* caseExpression() const { return pn_left; } bool isDefault() const { return !caseExpression(); } - ParseNode* statementList() const { return pn_right; } - - // The next CaseClause in the same switch statement. - CaseClause* next() const { return pn_next ? &pn_next->as() : nullptr; } + ListNode* statementList() const { return &pn_right->as(); } static bool test(const ParseNode& node) { bool match = node.isKind(PNK_CASE); @@ -1363,15 +1599,24 @@ class OptionalPropertyByValue : public PropertyByValueBase { /* * A CallSiteNode represents the implicit call site object argument in a TaggedTemplate. */ -struct CallSiteNode : public ListNode { +class CallSiteNode : public ListNode +{ + public: explicit CallSiteNode(uint32_t begin): ListNode(PNK_CALLSITEOBJ, TokenPos(begin, begin + 1)) {} static bool test(const ParseNode& node) { - return node.isKind(PNK_CALLSITEOBJ); + bool match = node.isKind(PNK_CALLSITEOBJ); + MOZ_ASSERT_IF(match, node.is()); + return match; } MOZ_MUST_USE bool getRawArrayValue(ExclusiveContext* cx, MutableHandleValue vp) { - return pn_head->getConstantValue(cx, AllowObjects, vp); + return head()->getConstantValue(cx, AllowObjects, vp); + } + + ListNode* rawNodes() const { + MOZ_ASSERT(head()); + return &head()->as(); } }; @@ -1412,11 +1657,11 @@ struct SwitchStatement : public BinaryNode { { #ifdef DEBUG MOZ_ASSERT(lexicalForCaseList->isKind(PNK_LEXICALSCOPE)); - ParseNode* cases = lexicalForCaseList->scopeBody(); + ListNode* cases = &lexicalForCaseList->scopeBody()->as(); MOZ_ASSERT(cases->isKind(PNK_STATEMENTLIST)); bool found = false; - CaseClause* firstCase = cases->pn_head ? &cases->pn_head->as() : nullptr; - for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) { + for (ParseNode* item : cases->contents()) { + CaseClause* caseNode = &item->as(); if (caseNode->isDefault()) { found = true; break; @@ -1498,12 +1743,12 @@ struct ClassNode : public TernaryNode { ParseNode* heritage() const { return pn_kid2; } - ParseNode* methodList() const { + ListNode* methodList() const { if (pn_kid3->isKind(PNK_CLASSMETHODLIST)) - return pn_kid3; + return &pn_kid3->as(); MOZ_ASSERT(pn_kid3->is()); - ParseNode* list = pn_kid3->scopeBody(); + ListNode* list = &pn_kid3->scopeBody()->as(); MOZ_ASSERT(list->isKind(PNK_CLASSMETHODLIST)); return list; } @@ -1550,7 +1795,7 @@ ParseNode::isConstant() case PNK_ARRAY: case PNK_OBJECT: MOZ_ASSERT(isOp(JSOP_NEWINIT)); - return !(pn_xflags & PNX_NONCONST); + return !as().hasNonConstInitializer(); default: return false; } @@ -1628,17 +1873,16 @@ static inline ParseNode* FunctionFormalParametersList(ParseNode* fn, unsigned* numFormals) { MOZ_ASSERT(fn->isKind(PNK_FUNCTION)); - ParseNode* argsBody = fn->pn_body; + ListNode* argsBody = &fn->pn_body->as(); MOZ_ASSERT(argsBody->isKind(PNK_PARAMSBODY)); - *numFormals = argsBody->pn_count; + *numFormals = argsBody->count(); if (*numFormals > 0 && argsBody->last()->isKind(PNK_LEXICALSCOPE) && argsBody->last()->scopeBody()->isKind(PNK_STATEMENTLIST)) { (*numFormals)--; } - MOZ_ASSERT(argsBody->isArity(PN_LIST)); - return argsBody->pn_head; + return argsBody->head(); } bool diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c87d3baf3c..b6f834c876 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -969,7 +969,7 @@ MarkParser(JSTracer* trc, AutoGCRooter* parser) * Parse a top-level JS script. */ template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::parse() { MOZ_ASSERT(checkOptionsCalled); @@ -985,8 +985,8 @@ Parser::parse() if (!varScope.init(pc)) return null(); - Node pn = statementList(YieldIsName); - if (!pn) + ListNodeType stmtList = statementList(YieldIsName); + if (!stmtList) return null(); TokenKind tt; @@ -997,11 +997,14 @@ Parser::parse() return null(); } if (foldConstants) { - if (!FoldConstants(context, &pn, this)) + Node node = stmtList; + if (!FoldConstants(context, &node, this)) { return null(); + } + stmtList = handler.asList(node); } - return pn; + return stmtList; } /* @@ -2179,7 +2182,7 @@ Parser::evalBody(EvalSharedContext* evalsc) } template <> -ParseNode* +ListNode* Parser::globalBody(GlobalSharedContext* globalsc) { ParseContext globalpc(this, globalsc, /* newDirectives = */ nullptr); @@ -2190,15 +2193,18 @@ Parser::globalBody(GlobalSharedContext* globalsc) if (!varScope.init(pc)) return nullptr; - ParseNode* body = statementList(YieldIsName); + ListNode* body = statementList(YieldIsName); if (!body) return nullptr; if (!checkStatementsEOF()) return nullptr; - if (!FoldConstants(context, &body, this)) - return nullptr; + ParseNode* node = body; + if (!FoldConstants(context, &node, this)) { + return null(); + } + body = &node->as(); Maybe bindings = newGlobalScopeData(pc->varScope()); if (!bindings) @@ -2227,12 +2233,13 @@ Parser::moduleBody(ModuleSharedContext* modulesc) return null(); AutoAwaitIsKeyword awaitIsKeyword(this, true); - ParseNode* pn = statementList(YieldIsKeyword); - if (!pn) + ListNode* stmtList = statementList(YieldIsName); + if (!stmtList) { return null(); + } - MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST)); - mn->pn_body = pn; + MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST)); + mn->pn_body = stmtList; TokenKind tt; if (!tokenStream.getToken(&tt, TokenStream::Operand)) @@ -2264,8 +2271,11 @@ Parser::moduleBody(ModuleSharedContext* modulesc) p->value()->setClosedOver(); } - if (!FoldConstants(context, &pn, this)) + ParseNode* node = stmtList; + if (!FoldConstants(context, &node, this)) { return null(); + } + stmtList = &node->as(); if (!propagateFreeNamesAndMarkClosedOverBindings(modulepc.varScope())) return null(); @@ -2536,7 +2546,7 @@ Parser::standaloneFunction(HandleFunction fun, if (!fn) return null(); - ParseNode* argsbody = handler.newList(PNK_PARAMSBODY); + ListNodeType argsbody = handler.newList(PNK_PARAMSBODY); if (!argsbody) return null(); fn->pn_body = argsbody; @@ -2662,11 +2672,11 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan uint32_t startYieldOffset = pc->lastYieldOffset; #endif - Node pn; + Node body; if (type == StatementListBody) { bool inheritedStrict = pc->sc()->strict(); - pn = statementList(yieldHandling); - if (!pn) + body = statementList(yieldHandling); + if (!body) return null(); // When we transitioned from non-strict to strict mode, we need to @@ -2687,7 +2697,7 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan // Async functions are implemented as star generators, and star // generators are assumed to be statement lists, to prepend initial // `yield`. - Node stmtList = null(); + ListNodeType stmtList = null(); if (pc->isAsync()) { stmtList = handler.newStatementList(pos()); if (!stmtList) @@ -2698,13 +2708,13 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan if (!kid) return null(); - pn = handler.newReturnStatement(kid, handler.getPosition(kid)); - if (!pn) + body = handler.newReturnStatement(kid, handler.getPosition(kid)); + if (!body) return null(); if (pc->isAsync()) { - handler.addStatementToList(stmtList, pn); - pn = stmtList; + handler.addStatementToList(stmtList, body); + body = stmtList; } } @@ -2738,7 +2748,7 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan Node generator = newDotGeneratorName(); if (!generator) return null(); - if (!handler.prependInitialYield(pn, generator)) + if (!handler.prependInitialYield(handler.asList(body), generator)) return null(); } @@ -2752,7 +2762,7 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan return null(); } - return finishLexicalScope(pc->varScope(), pn); + return finishLexicalScope(pc->varScope(), body); } template @@ -3000,7 +3010,7 @@ Parser::functionArguments(YieldHandling yieldHandling, FunctionSyn funbox->setStart(tokenStream); } - Node argsbody = handler.newList(PNK_PARAMSBODY); + ListNodeType argsbody = handler.newList(PNK_PARAMSBODY); if (!argsbody) return false; handler.setFunctionFormalParametersAndBody(funcpn, argsbody); @@ -3259,7 +3269,7 @@ Parser::skipLazyInnerFunction(Node pn, uint32_t toStringStar template bool -Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList, +Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, ListNodeType nodeList, TokenKind* ttp) { Node pn = expr(InAllowed, yieldHandling, TripledotProhibited); @@ -3280,9 +3290,9 @@ Parser::addExprAndGetNextTemplStrToken(YieldHandling yieldHandling template bool -Parser::taggedTemplate(YieldHandling yieldHandling, Node tagArgsList, TokenKind tt) +Parser::taggedTemplate(YieldHandling yieldHandling, ListNodeType tagArgsList, TokenKind tt) { - Node callSiteObjNode = handler.newCallSiteObject(pos().begin); + CallSiteNodeType callSiteObjNode = handler.newCallSiteObject(pos().begin); if (!callSiteObjNode) return false; handler.addList(tagArgsList, callSiteObjNode); @@ -3301,14 +3311,14 @@ Parser::taggedTemplate(YieldHandling yieldHandling, Node tagArgsLi } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::templateLiteral(YieldHandling yieldHandling) { Node pn = noSubstitutionUntaggedTemplate(); if (!pn) return null(); - Node nodeList = handler.newList(PNK_TEMPLATE_STRING_LIST, pn); + ListNodeType nodeList = handler.newList(PNK_TEMPLATE_STRING_LIST, pn); if (!nodeList) return null(); @@ -3543,7 +3553,7 @@ Parser::innerFunction(Node pn, ParseContext* outerpc, HandleFuncti template bool -Parser::appendToCallSiteObj(Node callSiteObj) +Parser::appendToCallSiteObj(CallSiteNodeType callSiteObj) { Node cookedNode = noSubstitutionTaggedTemplate(); if (!cookedNode) @@ -3914,7 +3924,7 @@ IsEscapeFreeStringLiteral(const TokenPos& pos, JSAtom* str) template <> bool -Parser::asmJS(Node list) +Parser::asmJS(ListNodeType list) { // While asm.js could technically be validated and compiled during syntax // parsing, we have no guarantee that some later JS wouldn't abort the @@ -3928,7 +3938,7 @@ Parser::asmJS(Node list) template <> bool -Parser::asmJS(Node list) +Parser::asmJS(ListNodeType list) { // Disable syntax parsing in anything nested inside the asm.js module. handler.disableSyntaxParser(); @@ -3984,7 +3994,7 @@ Parser::asmJS(Node list) */ template bool -Parser::maybeParseDirective(Node list, Node possibleDirective, bool* cont) +Parser::maybeParseDirective(ListNodeType list, Node possibleDirective, bool* cont) { TokenPos directivePos; JSAtom* directive = handler.isStringExprStatement(possibleDirective, &directivePos); @@ -4046,13 +4056,13 @@ Parser::maybeParseDirective(Node list, Node possibleDirective, boo } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::statementList(YieldHandling yieldHandling) { JS_CHECK_RECURSION(context, return null()); - Node pn = handler.newStatementList(pos()); - if (!pn) + ListNodeType stmtList = handler.newStatementList(pos()); + if (!stmtList) return null(); bool canHaveDirectives = pc->atBodyLevel(); @@ -4094,14 +4104,14 @@ Parser::statementList(YieldHandling yieldHandling) } if (canHaveDirectives) { - if (!maybeParseDirective(pn, next, &canHaveDirectives)) + if (!maybeParseDirective(stmtList, next, &canHaveDirectives)) return null(); } - handler.addStatementToList(pn, next); + handler.addStatementToList(stmtList, next); } - return pn; + return stmtList; } template @@ -4357,7 +4367,7 @@ Parser::bindingIdentifierOrPattern(DeclarationKind kind, YieldHand } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); @@ -4365,7 +4375,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y JS_CHECK_RECURSION(context, return null()); uint32_t begin = pos().begin; - Node literal = handler.newObjectLiteral(begin); + ListNodeType literal = handler.newObjectLiteral(begin); if (!literal) return null(); @@ -4477,7 +4487,7 @@ Parser::objectBindingPattern(DeclarationKind kind, YieldHandling y } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB)); @@ -4485,7 +4495,7 @@ Parser::arrayBindingPattern(DeclarationKind kind, YieldHandling yi JS_CHECK_RECURSION(context, return null()); uint32_t begin = pos().begin; - Node literal = handler.newArrayLiteral(begin); + ListNodeType literal = handler.newArrayLiteral(begin); if (!literal) return null(); @@ -4611,7 +4621,7 @@ Parser::blockStatement(YieldHandling yieldHandling, unsigned error if (!scope.init(pc)) return null(); - Node list = statementList(yieldHandling); + ListNodeType list = statementList(yieldHandling); if (!list) return null(); @@ -4871,7 +4881,7 @@ Parser::declarationName(Node decl, DeclarationKind declKind, Token } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::declarationList(YieldHandling yieldHandling, ParseNodeKind kind, ParseNodeKind* forHeadKind /* = nullptr */, @@ -4898,7 +4908,7 @@ Parser::declarationList(YieldHandling yieldHandling, MOZ_CRASH("Unknown declaration kind"); } - Node decl = handler.newDeclarationList(kind, op); + ListNodeType decl = handler.newDeclarationList(kind, op); if (!decl) return null(); @@ -4935,7 +4945,7 @@ Parser::declarationList(YieldHandling yieldHandling, } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind) { MOZ_ASSERT(kind == DeclarationKind::Const || kind == DeclarationKind::Let); @@ -4951,8 +4961,8 @@ Parser::lexicalDeclaration(YieldHandling yieldHandling, Declaratio * * See 8.1.1.1.6 and the note in 13.2.1. */ - Node decl = declarationList(yieldHandling, - kind == DeclarationKind::Const ? PNK_CONST : PNK_LET); + ListNodeType decl = declarationList(yieldHandling, + kind == DeclarationKind::Const ? PNK_CONST : PNK_LET); if (!decl || !matchOrInsertSemicolonAfterExpression()) return null(); @@ -4961,7 +4971,7 @@ Parser::lexicalDeclaration(YieldHandling yieldHandling, Declaratio template <> bool -Parser::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet) +Parser::namedImportsOrNamespaceImport(TokenKind tt, ListNodeType importSpecSet) { if (tt == TOK_LC) { while (true) { @@ -5092,7 +5102,7 @@ Parser::importDeclaration() if (!tokenStream.getToken(&tt)) return null(); - Node importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST); + ListNodeType importSpecSet = handler.newList(PNK_IMPORT_SPEC_LIST); if (!importSpecSet) return null(); @@ -5204,12 +5214,11 @@ Parser::checkExportedName(JSAtom* exportName) template<> bool -Parser::checkExportedNamesForArrayBinding(ParseNode* pn) +Parser::checkExportedNamesForArrayBinding(ListNode* array) { - MOZ_ASSERT(pn->isKind(PNK_ARRAY)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(array->isKind(PNK_ARRAY)); - for (ParseNode* node = pn->pn_head; node; node = node->pn_next) { + for (ParseNode* node : array->contents()) { if (node->isKind(PNK_ELISION)) continue; @@ -5230,7 +5239,7 @@ Parser::checkExportedNamesForArrayBinding(ParseNode* pn) template<> inline bool -Parser::checkExportedNamesForArrayBinding(Node node) +Parser::checkExportedNamesForArrayBinding(ListNodeType array) { MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); return false; @@ -5238,12 +5247,11 @@ Parser::checkExportedNamesForArrayBinding(Node node) template<> bool -Parser::checkExportedNamesForObjectBinding(ParseNode* pn) +Parser::checkExportedNamesForObjectBinding(ListNode* obj) { - MOZ_ASSERT(pn->isKind(PNK_OBJECT)); - MOZ_ASSERT(pn->isArity(PN_LIST)); + MOZ_ASSERT(obj->isKind(PNK_OBJECT)); - for (ParseNode* node = pn->pn_head; node; node = node->pn_next) { + for (ParseNode* node : obj->contents()) { MOZ_ASSERT(node->isKind(PNK_MUTATEPROTO) || node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND) || @@ -5271,7 +5279,7 @@ Parser::checkExportedNamesForObjectBinding(ParseNode* pn) template<> inline bool -Parser::checkExportedNamesForObjectBinding(Node node) +Parser::checkExportedNamesForObjectBinding(ListNodeType obj) { MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); return false; @@ -5285,11 +5293,11 @@ Parser::checkExportedNamesForDeclaration(ParseNode* node) if (!checkExportedName(node->pn_atom)) return false; } else if (node->isKind(PNK_ARRAY)) { - if (!checkExportedNamesForArrayBinding(node)) + if (!checkExportedNamesForArrayBinding(&node->as())) return false; } else { MOZ_ASSERT(node->isKind(PNK_OBJECT)); - if (!checkExportedNamesForObjectBinding(node)) + if (!checkExportedNamesForObjectBinding(&node->as())) return false; } @@ -5306,10 +5314,9 @@ Parser::checkExportedNamesForDeclaration(Node node) template<> bool -Parser::checkExportedNamesForDeclarationList(ParseNode* node) +Parser::checkExportedNamesForDeclarationList(ListNode* node) { - MOZ_ASSERT(node->isArity(PN_LIST)); - for (ParseNode* binding = node->pn_head; binding; binding = binding->pn_next) { + for (ParseNode* binding : node->contents()) { if (binding->isKind(PNK_ASSIGN)) binding = binding->pn_left; else @@ -5324,7 +5331,7 @@ Parser::checkExportedNamesForDeclarationList(ParseNode* node) template<> bool -Parser::checkExportedNamesForDeclarationList(Node node) +Parser::checkExportedNamesForDeclarationList(ListNodeType node) { MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); return false; @@ -5447,7 +5454,7 @@ Parser::exportBatch(uint32_t begin) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_MUL)); - Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + ListNodeType kid = handler.newList(PNK_EXPORT_SPEC_LIST); if (!kid) return null(); @@ -5466,10 +5473,10 @@ Parser::exportBatch(uint32_t begin) template<> bool -Parser::checkLocalExportNames(ParseNode* node) +Parser::checkLocalExportNames(ListNode* node) { // ES 2017 draft 15.2.3.1. - for (ParseNode* next = node->pn_head; next; next = next->pn_next) { + for (ParseNode* next : node->contents()) { ParseNode* name = next->pn_left; MOZ_ASSERT(name->isKind(PNK_NAME)); @@ -5483,7 +5490,7 @@ Parser::checkLocalExportNames(ParseNode* node) template<> bool -Parser::checkLocalExportNames(Node node) +Parser::checkLocalExportNames(ListNodeType node) { MOZ_ALWAYS_FALSE(abortIfSyntaxParser()); return false; @@ -5498,7 +5505,7 @@ Parser::exportClause(uint32_t begin) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); - Node kid = handler.newList(PNK_EXPORT_SPEC_LIST); + ListNodeType kid = handler.newList(PNK_EXPORT_SPEC_LIST); if (!kid) return null(); @@ -5598,7 +5605,7 @@ Parser::exportVariableStatement(uint32_t begin) MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_VAR)); - Node kid = declarationList(YieldIsName, PNK_VAR); + ListNodeType kid = declarationList(YieldIsName, PNK_VAR); if (!kid) return null(); if (!matchOrInsertSemicolonAfterExpression()) @@ -5679,7 +5686,7 @@ Parser::exportLexicalDeclaration(uint32_t begin, DeclarationKind k MOZ_ASSERT_IF(kind == DeclarationKind::Const, tokenStream.isCurrentTokenType(TOK_CONST)); MOZ_ASSERT_IF(kind == DeclarationKind::Let, tokenStream.isCurrentTokenType(TOK_LET)); - Node kid = lexicalDeclaration(YieldIsName, kind); + ListNodeType kid = lexicalDeclaration(YieldIsName, kind); if (!kid) return null(); if (!checkExportedNamesForDeclarationList(kid)) @@ -5947,7 +5954,7 @@ Parser::consequentOrAlternative(YieldHandling yieldHandling) if (!fun) return null(); - Node block = handler.newStatementList(funcPos); + ListNodeType block = handler.newStatementList(funcPos); if (!block) return null(); @@ -6436,7 +6443,7 @@ Parser::switchStatement(YieldHandling yieldHandling) if (!scope.init(pc)) return null(); - Node caseList = handler.newStatementList(pos()); + ListNodeType caseList = handler.newStatementList(pos()); if (!caseList) return null(); @@ -6473,7 +6480,7 @@ Parser::switchStatement(YieldHandling yieldHandling) MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE); - Node body = handler.newStatementList(pos()); + ListNodeType body = handler.newStatementList(pos()); if (!body) return null(); @@ -6513,13 +6520,13 @@ Parser::switchStatement(YieldHandling yieldHandling) handler.addCaseStatementToList(caseList, casepn); } - caseList = finishLexicalScope(scope, caseList); - if (!caseList) + Node lexicalForCaseList = finishLexicalScope(scope, caseList); + if (!lexicalForCaseList) return null(); - handler.setEndPosition(caseList, pos().end); + handler.setEndPosition(lexicalForCaseList, pos().end); - return handler.newSwitchStatement(begin, discriminant, caseList, seenDefault); + return handler.newSwitchStatement(begin, discriminant, lexicalForCaseList, seenDefault); } template @@ -6989,7 +6996,7 @@ Parser::tryStatement(YieldHandling yieldHandling) } bool hasUnconditionalCatch = false; - Node catchList = null(); + ListNodeType catchList = null(); TokenKind tt; if (!tokenStream.getToken(&tt)) return null(); @@ -7158,7 +7165,7 @@ Parser::catchBlockStatement(YieldHandling yieldHandling, if (!scope.addCatchParameters(pc, catchParamScope)) return null(); - Node list = statementList(yieldHandling); + ListNodeType list = statementList(yieldHandling); if (!list) return null(); @@ -7281,7 +7288,7 @@ Parser::classDefinition(YieldHandling yieldHandling, MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS); - Node classMethods = handler.newClassMethodList(pos().begin); + ListNodeType classMethods = handler.newClassMethodList(pos().begin); if (!classMethods) return null(); @@ -7494,7 +7501,7 @@ template typename ParseHandler::Node Parser::variableStatement(YieldHandling yieldHandling) { - Node vars = declarationList(yieldHandling, PNK_VAR); + ListNodeType vars = declarationList(yieldHandling, PNK_VAR); if (!vars) return null(); if (!matchOrInsertSemicolonAfterExpression()) @@ -7909,7 +7916,7 @@ Parser::expr(InHandling inHandling, YieldHandling yieldHandling, if (!matched) return pn; - Node seq = handler.newCommaExpressionList(pn); + ListNodeType seq = handler.newCommaExpressionList(pn); if (!seq) return null(); while (true) { @@ -8815,7 +8822,7 @@ Parser::generatorComprehensionLambda(unsigned begin) if (!declareDotGeneratorName()) return null(); - Node body = handler.newStatementList(TokenPos(begin, pos().end)); + ListNodeType body = handler.newStatementList(TokenPos(begin, pos().end)); if (!body) return null(); @@ -9014,7 +9021,7 @@ Parser::comprehension(GeneratorKind comprehensionKind) } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::arrayComprehension(uint32_t begin) { Node inner = comprehension(NotGenerator); @@ -9023,7 +9030,7 @@ Parser::arrayComprehension(uint32_t begin) MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION); - Node comp = handler.newList(PNK_ARRAYCOMP, inner); + ListNodeType comp = handler.newList(PNK_ARRAYCOMP, inner); if (!comp) return null(); @@ -9086,11 +9093,11 @@ Parser::assignExprWithoutYieldOrAwait(YieldHandling yieldHandling) } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::argumentList(YieldHandling yieldHandling, bool* isSpread, PossibleError* possibleError /* = nullptr */) { - Node argsList = handler.newArguments(pos()); + ListNodeType argsList = handler.newArguments(pos()); if (!argsList) return null(); @@ -9473,7 +9480,7 @@ Parser::memberCall( if (!nextMember) return null(); } else { - Node args = handler.newArguments(pos()); + ListNodeType args = handler.newArguments(pos()); if (!args) return null(); @@ -9752,13 +9759,13 @@ Parser::checkDestructuringAssignmentElement(Node expr, TokenPos ex } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LB)); uint32_t begin = pos().begin; - Node literal = handler.newArrayLiteral(begin); + ListNodeType literal = handler.newArrayLiteral(begin); if (!literal) return null(); @@ -9775,7 +9782,7 @@ Parser::arrayInitializer(YieldHandling yieldHandling, PossibleErro * Mark empty arrays as non-constant, since we cannot easily * determine their type. */ - handler.setListFlag(literal, PNX_NONCONST); + handler.setListHasNonConstInitializer(literal); } else { tokenStream.ungetToken(); @@ -9861,7 +9868,7 @@ DoubleToAtom(ExclusiveContext* cx, double value) template typename ParseHandler::Node Parser::propertyName(YieldHandling yieldHandling, - const Maybe& maybeDecl, Node propList, + const Maybe& maybeDecl, ListNodeType propList, PropertyType* propType, MutableHandleAtom propAtom) { TokenKind ltok; @@ -10054,7 +10061,7 @@ template typename ParseHandler::Node Parser::computedPropertyName(YieldHandling yieldHandling, const Maybe& maybeDecl, - Node literal) + ListNodeType literal) { uint32_t begin = pos().begin; @@ -10062,7 +10069,7 @@ Parser::computedPropertyName(YieldHandling yieldHandling, if (*maybeDecl == DeclarationKind::FormalParameter) pc->functionBox()->hasParameterExprs = true; } else { - handler.setListFlag(literal, PNX_NONCONST); + handler.setListHasNonConstInitializer(literal); } Node assignNode = assignExpr(InAllowed, yieldHandling, TripledotProhibited); @@ -10074,14 +10081,14 @@ Parser::computedPropertyName(YieldHandling yieldHandling, } template -typename ParseHandler::Node +typename ParseHandler::ListNodeType Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC)); uint32_t openedPos = pos().begin; - Node literal = handler.newObjectLiteral(pos().begin); + ListNodeType literal = handler.newObjectLiteral(pos().begin); if (!literal) return null(); @@ -10164,7 +10171,7 @@ Parser::objectLiteral(YieldHandling yieldHandling, PossibleError* return null(); } else { if (!handler.isConstant(propExpr)) - handler.setListFlag(literal, PNX_NONCONST); + handler.setListHasNonConstInitializer(literal); if (!handler.addPropertyDefinition(literal, propName, propExpr)) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index ad5e079674..59ce925464 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -903,6 +903,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter private: using Node = typename ParseHandler::Node; +#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \ + using longTypeName = typename ParseHandler::longTypeName; +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + /* * A class for temporarily stashing errors while parsing continues. * @@ -1073,7 +1078,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter /* * Parse a top-level JS script. */ - Node parse(); + ListNodeType parse(); /* * Allocate a new parsed object or function container from @@ -1103,10 +1108,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node stringLiteral(); Node noSubstitutionTaggedTemplate(); Node noSubstitutionUntaggedTemplate(); - Node templateLiteral(YieldHandling yieldHandling); - bool taggedTemplate(YieldHandling yieldHandling, Node nodeList, TokenKind tt); - bool appendToCallSiteObj(Node callSiteObj); - bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList, + ListNodeType templateLiteral(YieldHandling yieldHandling); + bool taggedTemplate(YieldHandling yieldHandling, ListNodeType tagArgsList, TokenKind tt); + bool appendToCallSiteObj(CallSiteNodeType callSiteObj); + bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, ListNodeType nodeList, TokenKind* ttp); bool checkStatementsEOF(); @@ -1120,7 +1125,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node statement(YieldHandling yieldHandling); Node statementListItem(YieldHandling yieldHandling, bool canHaveDirectives = false); - bool maybeParseDirective(Node list, Node pn, bool* cont); + bool maybeParseDirective(ListNodeType list, Node pn, bool* cont); // Parse the body of an eval. // @@ -1130,7 +1135,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node evalBody(EvalSharedContext* evalsc); // Parse the body of a global script. - Node globalBody(GlobalSharedContext* globalsc); + ListNodeType globalBody(GlobalSharedContext* globalsc); // Parse a module. Node moduleBody(ModuleSharedContext* modulesc); @@ -1189,7 +1194,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node functionExpr(uint32_t toStringStart, InvokedPrediction invoked = PredictUninvoked, FunctionAsyncKind asyncKind = SyncFunction); - Node statementList(YieldHandling yieldHandling); + ListNodeType statementList(YieldHandling yieldHandling); Node blockStatement(YieldHandling yieldHandling, unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND); @@ -1228,7 +1233,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter // continues a LexicalDeclaration. bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling); - Node lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind); + ListNodeType lexicalDeclaration(YieldHandling yieldHandling, DeclarationKind kind); Node importDeclaration(); @@ -1237,7 +1242,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node exportFrom(uint32_t begin, Node specList); Node exportBatch(uint32_t begin); - bool checkLocalExportNames(Node node); + bool checkLocalExportNames(ListNodeType node); Node exportClause(uint32_t begin); Node exportFunctionDeclaration(uint32_t begin); Node exportVariableStatement(uint32_t begin); @@ -1273,10 +1278,10 @@ class Parser final : public ParserBase, private JS::AutoGCRooter // Otherwise, for for-in/of loops, the next token is the ')' ending the // loop-head. Additionally, the expression that the loop iterates over was // parsed into |*forInOrOfExpression|. - Node declarationList(YieldHandling yieldHandling, - ParseNodeKind kind, - ParseNodeKind* forHeadKind = nullptr, - Node* forInOrOfExpression = nullptr); + ListNodeType declarationList(YieldHandling yieldHandling, + ParseNodeKind kind, + ParseNodeKind* forHeadKind = nullptr, + Node* forInOrOfExpression = nullptr); // The items in a declaration list are either patterns or names, with or // without initializers. These two methods parse a single pattern/name and @@ -1371,22 +1376,22 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node comprehensionIf(GeneratorKind comprehensionKind); Node comprehensionTail(GeneratorKind comprehensionKind); Node comprehension(GeneratorKind comprehensionKind); - Node arrayComprehension(uint32_t begin); + ListNodeType arrayComprehension(uint32_t begin); Node generatorComprehension(uint32_t begin); - Node argumentList(YieldHandling yieldHandling, bool* isSpread, - PossibleError* possibleError = nullptr); + ListNodeType argumentList(YieldHandling yieldHandling, bool* isSpread, + PossibleError* possibleError = nullptr); Node destructuringDeclaration(DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt); Node destructuringDeclarationWithoutYieldOrAwait(DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt); - bool namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet); + bool namedImportsOrNamespaceImport(TokenKind tt, ListNodeType importSpecSet); bool checkExportedName(JSAtom* exportName); - bool checkExportedNamesForArrayBinding(Node node); - bool checkExportedNamesForObjectBinding(Node node); + bool checkExportedNamesForArrayBinding(ListNodeType array); + bool checkExportedNamesForObjectBinding(ListNodeType obj); bool checkExportedNamesForDeclaration(Node node); - bool checkExportedNamesForDeclarationList(Node node); + bool checkExportedNamesForDeclarationList(ListNodeType node); bool checkExportedNameForClause(Node node); bool checkExportedNameForFunction(Node node); @@ -1512,21 +1517,21 @@ class Parser final : public ParserBase, private JS::AutoGCRooter Node finishLexicalScope(ParseContext::Scope& scope, Node body); Node propertyName(YieldHandling yieldHandling, - const mozilla::Maybe& maybeDecl, Node propList, + const mozilla::Maybe& maybeDecl, ListNodeType propList, PropertyType* propType, MutableHandleAtom propAtom); Node computedPropertyName(YieldHandling yieldHandling, - const mozilla::Maybe& maybeDecl, Node literal); - Node arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError); + const mozilla::Maybe& maybeDecl, ListNodeType literal); + ListNodeType arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError); Node newRegExp(); - Node objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError); + ListNodeType objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError); Node bindingInitializer(Node lhs, DeclarationKind kind, YieldHandling yieldHandling); Node bindingIdentifier(DeclarationKind kind, YieldHandling yieldHandling); Node bindingIdentifierOrPattern(DeclarationKind kind, YieldHandling yieldHandling, TokenKind tt); - Node objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); - Node arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); + ListNodeType objectBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); + ListNodeType arrayBindingPattern(DeclarationKind kind, YieldHandling yieldHandling); void checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, PossibleError* possibleError); @@ -1537,11 +1542,11 @@ class Parser final : public ParserBase, private JS::AutoGCRooter return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos); } - static Node null() { return ParseHandler::null(); } + static typename ParseHandler::NullNode null() { return ParseHandler::null(); } JSAtom* prefixAccessorName(PropertyType propType, HandleAtom propAtom); - bool asmJS(Node list); + bool asmJS(ListNodeType list); enum class OptionalKind { NonOptional = 0, diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index c2abffbd06..0f4c66e8e7 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -145,6 +145,13 @@ class SyntaxParseHandler NodeSuperBase }; +#define DECLARE_TYPE(typeName, longTypeName, asMethodName) \ + using longTypeName = Node; +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) +#undef DECLARE_TYPE + + using NullNode = Node; + bool isPropertyAccess(Node node) { return node == NodeDottedProperty || node == NodeElement; } @@ -183,7 +190,14 @@ class SyntaxParseHandler tokenStream(tokenStream) {} - static Node null() { return NodeFailure; } + static NullNode null() { return NodeFailure; } + +#define DECLARE_AS(typeName, longTypeName, asMethodName) \ + static longTypeName asMethodName(Node node) { \ + return node; \ + } +FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) +#undef DECLARE_AS void prepareNodeForMutation(Node node) {} void freeTree(Node node) {} @@ -222,11 +236,11 @@ class SyntaxParseHandler return NodeGeneric; } - Node newCallSiteObject(uint32_t begin) { + CallSiteNodeType newCallSiteObject(uint32_t begin) { return NodeGeneric; } - void addToCallSiteObject(Node callSiteObj, Node rawNode, Node cookedNode) {} + void addToCallSiteObject(CallSiteNodeType callSiteObj, Node rawNode, Node cookedNode) {} Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; } Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; } @@ -283,21 +297,20 @@ class SyntaxParseHandler // Expressions - Node newArrayComprehension(Node body, const TokenPos& pos) { return NodeGeneric; } - Node newArrayLiteral(uint32_t begin) { return NodeUnparenthesizedArray; } - MOZ_MUST_USE bool addElision(Node literal, const TokenPos& pos) { return true; } - MOZ_MUST_USE bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } - void addArrayElement(Node literal, Node element) { } + ListNodeType newArrayLiteral(uint32_t begin) { return NodeUnparenthesizedArray; } + MOZ_MUST_USE bool addElision(ListNodeType literal, const TokenPos& pos) { return true; } + MOZ_MUST_USE bool addSpreadElement(ListNodeType literal, uint32_t begin, Node inner) { return true; } + void addArrayElement(ListNodeType literal, Node element) { } Node newCall(Node callee, Node args) { return NodeFunctionCall; } Node newOptionalCall(Node callee, Node args) { return NodeOptionalFunctionCall; } - Node newArguments(const TokenPos& pos) { return NodeGeneric; } + ListNodeType newArguments(const TokenPos& pos) { return NodeGeneric; } Node newSuperCall(Node callee, Node args) { return NodeGeneric; } Node newTaggedTemplate(Node callee, Node args) { return NodeGeneric; } Node newGenExp(Node callee, Node args) { return NodeGeneric; } - Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } - Node newClassMethodList(uint32_t begin) { return NodeGeneric; } + ListNodeType newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } + ListNodeType newClassMethodList(uint32_t begin) { return NodeGeneric; } Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; } Node newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) { return NodeGeneric; } @@ -305,12 +318,12 @@ class SyntaxParseHandler Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } Node newSuperBase(Node thisName, const TokenPos& pos) { return NodeSuperBase; } - MOZ_MUST_USE bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } - MOZ_MUST_USE bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } - MOZ_MUST_USE bool addShorthand(Node literal, Node name, Node expr) { return true; } - MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; } - MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } - MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } + MOZ_MUST_USE bool addPrototypeMutation(ListNodeType literal, uint32_t begin, Node expr) { return true; } + MOZ_MUST_USE bool addPropertyDefinition(ListNodeType literal, Node name, Node expr) { return true; } + MOZ_MUST_USE bool addShorthand(ListNodeType literal, Node name, Node expr) { return true; } + MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin, Node inner) { return true; } + MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node name, Node fn, JSOp op) { return true; } + MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; } Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; } Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; } @@ -318,10 +331,10 @@ class SyntaxParseHandler // Statements - Node newStatementList(const TokenPos& pos) { return NodeGeneric; } - void addStatementToList(Node list, Node stmt) {} - void addCaseStatementToList(Node list, Node stmt) {} - MOZ_MUST_USE bool prependInitialYield(Node stmtList, Node gen) { return true; } + ListNodeType newStatementList(const TokenPos& pos) { return NodeGeneric; } + void addStatementToList(ListNodeType list, Node stmt) {} + void addCaseStatementToList(ListNodeType list, Node caseClause) {} + MOZ_MUST_USE bool prependInitialYield(ListNodeType stmtList, Node genName) { return true; } Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; } Node newExportDeclaration(Node kid, const TokenPos& pos) { @@ -358,7 +371,7 @@ class SyntaxParseHandler } Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; } - Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) { + Node newTryStatement(uint32_t begin, Node body, ListNodeType catchList, Node finallyBlock) { return NodeGeneric; } Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; } @@ -380,7 +393,7 @@ class SyntaxParseHandler Node newOptionalPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeOptionalElement; } - MOZ_MUST_USE bool addCatchBlock(Node catchList, Node letBlock, Node catchName, + MOZ_MUST_USE bool addCatchBlock(ListNodeType catchList, Node letBlock, Node catchName, Node catchGuard, Node catchBody) { return true; } MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(Node funcpn, Node pn) { return true; } @@ -434,26 +447,26 @@ class SyntaxParseHandler return tokenStream.currentToken().pos; } - Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, JSOp op = JSOP_NOP) { MOZ_ASSERT(kind != PNK_VAR); MOZ_ASSERT(kind != PNK_LET); MOZ_ASSERT(kind != PNK_CONST); return NodeGeneric; } - Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) { return newList(kind, op); } - Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { + ListNodeType newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { return newList(kind, op); } - Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { + ListNodeType newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { if (kind == PNK_VAR) return NodeVarDeclaration; MOZ_ASSERT(kind == PNK_LET || kind == PNK_CONST); return NodeLexicalDeclaration; } - Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { + ListNodeType newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { return newDeclarationList(kind, op); } @@ -461,7 +474,7 @@ class SyntaxParseHandler return node == NodeVarDeclaration || node == NodeLexicalDeclaration; } - Node singleBindingFromDeclaration(Node decl) { + Node singleBindingFromDeclaration(ListNodeType decl) { MOZ_ASSERT(isDeclarationList(decl)); // This is, unfortunately, very dodgy. Obviously NodeVarDeclaration @@ -485,11 +498,11 @@ class SyntaxParseHandler return newList(PNK_CATCHLIST, JSOP_NOP); } - Node newCommaExpressionList(Node kid) { + ListNodeType newCommaExpressionList(Node kid) { return NodeUnparenthesizedCommaExpr; } - void addList(Node list, Node kid) { + void addList(ListNodeType list, Node kid) { MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedArray || list == NodeUnparenthesizedObject || @@ -539,7 +552,7 @@ class SyntaxParseHandler } void setOp(Node pn, JSOp op) {} - void setListFlag(Node pn, unsigned flag) {} + void setListHasNonConstInitializer(ListNodeType literal) {} MOZ_MUST_USE Node parenthesize(Node node) { // A number of nodes have different behavior upon parenthesization, but // only in some circumstances. Convert these nodes to special diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index 202d271398..84ba5d75ee 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -450,15 +450,13 @@ TernaryKid3(ParseNode* pn) static inline ParseNode* ListHead(ParseNode* pn) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - return pn->pn_head; + return pn->as().head(); } static inline unsigned ListLength(ParseNode* pn) { - MOZ_ASSERT(pn->isArity(PN_LIST)); - return pn->pn_count; + return pn->as().count(); } static inline ParseNode* @@ -511,8 +509,7 @@ static inline ParseNode* BinaryOpLeft(ParseNode* pn) { MOZ_ASSERT(pn->isBinaryOperation()); - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count == 2); + MOZ_ASSERT(pn->as().count() == 2); return ListHead(pn); } @@ -520,8 +517,7 @@ static inline ParseNode* BinaryOpRight(ParseNode* pn) { MOZ_ASSERT(pn->isBinaryOperation()); - MOZ_ASSERT(pn->isArity(PN_LIST)); - MOZ_ASSERT(pn->pn_count == 2); + MOZ_ASSERT(pn->as().count() == 2); return NextNode(ListHead(pn)); } @@ -688,7 +684,7 @@ static inline ParseNode* FunctionStatementList(ParseNode* fn) { MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY)); - ParseNode* last = fn->pn_body->last(); + ParseNode* last = fn->pn_body->as().last(); MOZ_ASSERT(last->isKind(PNK_LEXICALSCOPE)); MOZ_ASSERT(last->isEmptyScope()); ParseNode* body = last->scopeBody();