From d4103253dd18e9798cfc4674d2d0f7183af57a10 Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 2 Apr 2023 01:29:38 +0200 Subject: [PATCH] Issue #2173 - Add TryNode This is adjusted from upstream to follow our data structure with PNK_CATCHLIST Based-on: m-c 1479659/8 --- js/src/builtin/ReflectParse.cpp | 16 +++++------ js/src/frontend/BytecodeEmitter.cpp | 23 +++++++--------- js/src/frontend/BytecodeEmitter.h | 2 +- js/src/frontend/FoldConstants.cpp | 5 ++-- js/src/frontend/FullParseHandler.h | 3 +-- js/src/frontend/NameFunctions.cpp | 11 ++++---- js/src/frontend/ParseNode.h | 41 ++++++++++++++++++++++++++--- 7 files changed, 64 insertions(+), 37 deletions(-) diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 5dd170b3eb..fd38352dad 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -1825,7 +1825,7 @@ class ASTSerializer bool blockStatement(ListNode* node, MutableHandleValue dst); bool switchStatement(SwitchStatement* switchStmt, MutableHandleValue dst); bool switchCase(CaseClause* caseClause, MutableHandleValue dst); - bool tryStatement(TernaryNode* tryNode, MutableHandleValue dst); + bool tryStatement(TryNode* tryNode, MutableHandleValue dst); bool catchClause(TernaryNode* clauseNode, bool* isGuarded, MutableHandleValue dst); bool optExpression(ParseNode* pn, MutableHandleValue dst) { @@ -2358,15 +2358,15 @@ ASTSerializer::catchClause(TernaryNode* clauseNode, bool* isGuarded, MutableHand } bool -ASTSerializer::tryStatement(TernaryNode* tryNode, MutableHandleValue dst) +ASTSerializer::tryStatement(TryNode* tryNode, MutableHandleValue dst) { - ParseNode* bodyNode = tryNode->kid1(); + ParseNode* bodyNode = tryNode->body(); MOZ_ASSERT(tryNode->pn_pos.encloses(bodyNode->pn_pos)); - ParseNode* catchNode = tryNode->kid2(); - MOZ_ASSERT_IF(catchNode, tryNode->pn_pos.encloses(catchNode->pn_pos)); + ListNode* catchList = tryNode->catchList(); + MOZ_ASSERT_IF(catchList, tryNode->pn_pos.encloses(catchList->pn_pos)); - ParseNode* finallyNode = tryNode->kid3(); + ParseNode* finallyNode = tryNode->finallyBlock(); MOZ_ASSERT_IF(finallyNode, tryNode->pn_pos.encloses(finallyNode->pn_pos)); RootedValue body(cx); @@ -2376,7 +2376,7 @@ ASTSerializer::tryStatement(TernaryNode* tryNode, MutableHandleValue dst) NodeVector guarded(cx); RootedValue unguarded(cx, NullValue()); - if (ListNode* catchList = &catchNode->as()) { + if (catchList) { if (!guarded.reserve(catchList->count())) return false; @@ -2513,7 +2513,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) return switchStatement(&pn->as(), dst); case PNK_TRY: - return tryStatement(&pn->as(), dst); + return tryStatement(&pn->as(), dst); case PNK_WITH: case PNK_WHILE: diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index b8f085b152..e871505c21 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1438,19 +1438,18 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_TRY: { - TernaryNode* tryNode = &pn->as(); - if (!checkSideEffects(tryNode->kid1(), answer)) + TryNode* tryNode = &pn->as(); + if (!checkSideEffects(tryNode->body(), answer)) return false; if (*answer) return true; - if (ParseNode* catchList = tryNode->kid2()) { - MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST)); + if (ListNode* catchList = tryNode->catchList()) { if (!checkSideEffects(catchList, answer)) return false; if (*answer) return true; } - if (ParseNode* finallyBlock = tryNode->kid3()) { + if (ParseNode* finallyBlock = tryNode->finallyBlock()) { if (!checkSideEffects(finallyBlock, answer)) return false; } @@ -4220,10 +4219,10 @@ BytecodeEmitter::emitCatch(TernaryNode* catchNode) // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the // comment on EmitSwitch. MOZ_NEVER_INLINE bool -BytecodeEmitter::emitTry(TernaryNode* tryNode) +BytecodeEmitter::emitTry(TryNode* tryNode) { - ParseNode* catchList = tryNode->kid2(); - ParseNode* finallyNode = tryNode->kid3(); + ListNode* catchList = tryNode->catchList(); + ParseNode* finallyNode = tryNode->finallyBlock(); TryEmitter::Kind kind; if (catchList) { @@ -4240,13 +4239,11 @@ BytecodeEmitter::emitTry(TernaryNode* tryNode) if (!tryCatch.emitTry()) return false; - if (!emitTree(tryNode->kid1())) + if (!emitTree(tryNode->body())) return false; // If this try has a catch block, emit it. if (catchList) { - MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST)); - // The emitted code for a catch block looks like: // // [pushlexicalenv] only if any local aliased @@ -4272,7 +4269,7 @@ BytecodeEmitter::emitTry(TernaryNode* tryNode) // code if appropriate, and is also used for the catch-all trynote for // capturing exceptions thrown from catch{} blocks. // - for (ParseNode* scopeNode : catchList->as().contents()) { + for (ParseNode* scopeNode : catchList->contents()) { LexicalScopeNode* catchScope = &scopeNode->as(); if (!tryCatch.emitCatch()) return false; @@ -8703,7 +8700,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: break; case PNK_TRY: - if (!emitTry(&pn->as())) + if (!emitTry(&pn->as())) return false; break; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index d9334d3445..379f2060ab 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -592,7 +592,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body, EmitLineNumberNote emitLineNote = EMIT_LINENOTE); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt); - MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TernaryNode* tryNode); + MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TryNode* tryNode); enum DestructuringFlavor { // Destructuring into a declaration. diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index 5a3f6e8c9d..ed176a27d4 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -1230,10 +1230,9 @@ FoldReturn(ExclusiveContext* cx, UnaryNode* node, Parser& pars } static bool -FoldTry(ExclusiveContext* cx, TernaryNode* node, Parser& parser, +FoldTry(ExclusiveContext* cx, TryNode* node, Parser& parser, bool inGenexpLambda) { - MOZ_ASSERT(node->isKind(PNK_TRY)); ParseNode** statements = node->unsafeKid1Reference(); if (!Fold(cx, statements, parser, inGenexpLambda)) return false; @@ -1845,7 +1844,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return FoldReturn(cx, &pn->as(), parser, inGenexpLambda); case PNK_TRY: - return FoldTry(cx, &pn->as(), parser, inGenexpLambda); + return FoldTry(cx, &pn->as(), parser, inGenexpLambda); case PNK_CATCH: return FoldCatch(cx, &pn->as(), parser, inGenexpLambda); diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index e0fc057530..179f63fc97 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -686,8 +686,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) TernaryNodeType newTryStatement(uint32_t begin, Node body, ListNodeType catchList, Node finallyBlock) { - TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); - return new_(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos); + return new_(begin, body, catchList, finallyBlock); } DebuggerStatementType newDebuggerStatement(const TokenPos& pos) { diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index c3e709699f..7d17c51bbb 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -668,16 +668,15 @@ class NameResolver // and finally block are optional (but at least one or the other must // be present). case PNK_TRY: { - TernaryNode* tryNode = &cur->as(); - if (!resolve(tryNode->kid1(), prefix)) + TryNode* tryNode = &cur->as(); + if (!resolve(tryNode->body(), prefix)) return false; - MOZ_ASSERT(tryNode->kid2() || tryNode->kid3()); - if (ParseNode* catchList = tryNode->kid2()) { - MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST)); + MOZ_ASSERT(tryNode->catchList() || tryNode->finallyBlock()); + if (ListNode* catchList = tryNode->catchList()) { if (!resolve(catchList, prefix)) return false; } - if (ParseNode* finallyBlock = tryNode->kid3()) { + if (ParseNode* finallyBlock = tryNode->finallyBlock()) { if (!resolve(finallyBlock, prefix)) return false; } diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index fffd28edd3..3779426adf 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -308,10 +308,10 @@ IsTypeofKind(ParseNodeKind kind) * kid3: update expr after second ';' or nullptr * PNK_THROW (UnaryNode) * kid: thrown exception - * PNK_TRY (TernaryNode) - * kid1: try block - * kid2: null or PNK_CATCHLIST list - * kid3: null or finally block + * PNK_TRY (TryNode) + * body: try block + * catchList: null or PNK_CATCHLIST list + * finallyBlock: null or finally block * PNK_CATCHLIST (ListNode) * head: list of PNK_LEXICALSCOPE nodes, one per catch-block, * each with scopeBody pointing to a PNK_CATCH node @@ -593,6 +593,8 @@ enum ParseNodeArity macro(TernaryNode, TernaryNodeType, asTernary) \ macro(ClassNode, ClassNodeType, asClass) \ macro(ConditionalExpression, ConditionalExpressionType, asConditionalExpression) \ + macro(TryNode, TryNodeType, asTry) \ + \ macro(UnaryNode, UnaryNodeType, asUnary) \ macro(ThisLiteral, ThisLiteralType, asThisLiteral) @@ -1711,6 +1713,37 @@ class ConditionalExpression : public TernaryNode } }; +class TryNode : public TernaryNode +{ + public: + TryNode(uint32_t begin, ParseNode* body, ListNode* catchList, ParseNode* finallyBlock) + : TernaryNode(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, + TokenPos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end)) + { + MOZ_ASSERT(body); + MOZ_ASSERT(catchList || finallyBlock); + MOZ_ASSERT_IF(catchList, catchList->isKind(PNK_CATCHLIST)); + } + + static bool test(const ParseNode& node) { + bool match = node.isKind(PNK_TRY); + MOZ_ASSERT_IF(match, node.is()); + return match; + } + + ParseNode* body() const { + return kid1(); + } + + ListNode* catchList() const { + return kid2() ? &kid2()->as() : nullptr; + } + + ParseNode* finallyBlock() const { + return kid3(); + } +}; + class ThisLiteral : public UnaryNode { public: