Issue #2173 - Add TryNode

This is adjusted from upstream to follow our data structure with PNK_CATCHLIST

Based-on: m-c 1479659/8
This commit is contained in:
Martok 2023-04-02 01:29:38 +02:00 • committed by roytam1
commit d4103253dd
7 changed files with 64 additions and 37 deletions

View file

@ -1825,7 +1825,7 @@ class ASTSerializer
bool blockStatement(ListNode* node, MutableHandleValue dst); bool blockStatement(ListNode* node, MutableHandleValue dst);
bool switchStatement(SwitchStatement* switchStmt, MutableHandleValue dst); bool switchStatement(SwitchStatement* switchStmt, MutableHandleValue dst);
bool switchCase(CaseClause* caseClause, 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 catchClause(TernaryNode* clauseNode, bool* isGuarded, MutableHandleValue dst);
bool optExpression(ParseNode* pn, MutableHandleValue dst) { bool optExpression(ParseNode* pn, MutableHandleValue dst) {
@ -2358,15 +2358,15 @@ ASTSerializer::catchClause(TernaryNode* clauseNode, bool* isGuarded, MutableHand
} }
bool 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)); MOZ_ASSERT(tryNode->pn_pos.encloses(bodyNode->pn_pos));
ParseNode* catchNode = tryNode->kid2(); ListNode* catchList = tryNode->catchList();
MOZ_ASSERT_IF(catchNode, tryNode->pn_pos.encloses(catchNode->pn_pos)); 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)); MOZ_ASSERT_IF(finallyNode, tryNode->pn_pos.encloses(finallyNode->pn_pos));
RootedValue body(cx); RootedValue body(cx);
@ -2376,7 +2376,7 @@ ASTSerializer::tryStatement(TernaryNode* tryNode, MutableHandleValue dst)
NodeVector guarded(cx); NodeVector guarded(cx);
RootedValue unguarded(cx, NullValue()); RootedValue unguarded(cx, NullValue());
if (ListNode* catchList = &catchNode->as<ListNode>()) { if (catchList) {
if (!guarded.reserve(catchList->count())) if (!guarded.reserve(catchList->count()))
return false; return false;
@ -2513,7 +2513,7 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
return switchStatement(&pn->as<SwitchStatement>(), dst); return switchStatement(&pn->as<SwitchStatement>(), dst);
case PNK_TRY: case PNK_TRY:
return tryStatement(&pn->as<TernaryNode>(), dst); return tryStatement(&pn->as<TryNode>(), dst);
case PNK_WITH: case PNK_WITH:
case PNK_WHILE: case PNK_WHILE:

View file

@ -1438,19 +1438,18 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_TRY: case PNK_TRY:
{ {
TernaryNode* tryNode = &pn->as<TernaryNode>(); TryNode* tryNode = &pn->as<TryNode>();
if (!checkSideEffects(tryNode->kid1(), answer)) if (!checkSideEffects(tryNode->body(), answer))
return false; return false;
if (*answer) if (*answer)
return true; return true;
if (ParseNode* catchList = tryNode->kid2()) { if (ListNode* catchList = tryNode->catchList()) {
MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
if (!checkSideEffects(catchList, answer)) if (!checkSideEffects(catchList, answer))
return false; return false;
if (*answer) if (*answer)
return true; return true;
} }
if (ParseNode* finallyBlock = tryNode->kid3()) { if (ParseNode* finallyBlock = tryNode->finallyBlock()) {
if (!checkSideEffects(finallyBlock, answer)) if (!checkSideEffects(finallyBlock, answer))
return false; 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 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See the
// comment on EmitSwitch. // comment on EmitSwitch.
MOZ_NEVER_INLINE bool MOZ_NEVER_INLINE bool
BytecodeEmitter::emitTry(TernaryNode* tryNode) BytecodeEmitter::emitTry(TryNode* tryNode)
{ {
ParseNode* catchList = tryNode->kid2(); ListNode* catchList = tryNode->catchList();
ParseNode* finallyNode = tryNode->kid3(); ParseNode* finallyNode = tryNode->finallyBlock();
TryEmitter::Kind kind; TryEmitter::Kind kind;
if (catchList) { if (catchList) {
@ -4240,13 +4239,11 @@ BytecodeEmitter::emitTry(TernaryNode* tryNode)
if (!tryCatch.emitTry()) if (!tryCatch.emitTry())
return false; return false;
if (!emitTree(tryNode->kid1())) if (!emitTree(tryNode->body()))
return false; return false;
// If this try has a catch block, emit it. // If this try has a catch block, emit it.
if (catchList) { if (catchList) {
MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
// The emitted code for a catch block looks like: // The emitted code for a catch block looks like:
// //
// [pushlexicalenv] only if any local aliased // [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 // code if appropriate, and is also used for the catch-all trynote for
// capturing exceptions thrown from catch{} blocks. // capturing exceptions thrown from catch{} blocks.
// //
for (ParseNode* scopeNode : catchList->as<ListNode>().contents()) { for (ParseNode* scopeNode : catchList->contents()) {
LexicalScopeNode* catchScope = &scopeNode->as<LexicalScopeNode>(); LexicalScopeNode* catchScope = &scopeNode->as<LexicalScopeNode>();
if (!tryCatch.emitCatch()) if (!tryCatch.emitCatch())
return false; return false;
@ -8703,7 +8700,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break; break;
case PNK_TRY: case PNK_TRY:
if (!emitTry(&pn->as<TernaryNode>())) if (!emitTry(&pn->as<TryNode>()))
return false; return false;
break; break;

View file

@ -592,7 +592,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body, MOZ_MUST_USE bool emitLexicalScopeBody(ParseNode* body,
EmitLineNumberNote emitLineNote = EMIT_LINENOTE); EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt);
MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TernaryNode* tryNode); MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TryNode* tryNode);
enum DestructuringFlavor { enum DestructuringFlavor {
// Destructuring into a declaration. // Destructuring into a declaration.

View file

@ -1230,10 +1230,9 @@ FoldReturn(ExclusiveContext* cx, UnaryNode* node, Parser<FullParseHandler>& pars
} }
static bool static bool
FoldTry(ExclusiveContext* cx, TernaryNode* node, Parser<FullParseHandler>& parser, FoldTry(ExclusiveContext* cx, TryNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda) bool inGenexpLambda)
{ {
MOZ_ASSERT(node->isKind(PNK_TRY));
ParseNode** statements = node->unsafeKid1Reference(); ParseNode** statements = node->unsafeKid1Reference();
if (!Fold(cx, statements, parser, inGenexpLambda)) if (!Fold(cx, statements, parser, inGenexpLambda))
return false; return false;
@ -1845,7 +1844,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldReturn(cx, &pn->as<UnaryNode>(), parser, inGenexpLambda); return FoldReturn(cx, &pn->as<UnaryNode>(), parser, inGenexpLambda);
case PNK_TRY: case PNK_TRY:
return FoldTry(cx, &pn->as<TernaryNode>(), parser, inGenexpLambda); return FoldTry(cx, &pn->as<TryNode>(), parser, inGenexpLambda);
case PNK_CATCH: case PNK_CATCH:
return FoldCatch(cx, &pn->as<TernaryNode>(), parser, inGenexpLambda); return FoldCatch(cx, &pn->as<TernaryNode>(), parser, inGenexpLambda);

View file

@ -686,8 +686,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
TernaryNodeType newTryStatement(uint32_t begin, Node body, ListNodeType catchList, TernaryNodeType newTryStatement(uint32_t begin, Node body, ListNodeType catchList,
Node finallyBlock) { Node finallyBlock) {
TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); return new_<TryNode>(begin, body, catchList, finallyBlock);
return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos);
} }
DebuggerStatementType newDebuggerStatement(const TokenPos& pos) { DebuggerStatementType newDebuggerStatement(const TokenPos& pos) {

View file

@ -668,16 +668,15 @@ class NameResolver
// and finally block are optional (but at least one or the other must // and finally block are optional (but at least one or the other must
// be present). // be present).
case PNK_TRY: { case PNK_TRY: {
TernaryNode* tryNode = &cur->as<TernaryNode>(); TryNode* tryNode = &cur->as<TryNode>();
if (!resolve(tryNode->kid1(), prefix)) if (!resolve(tryNode->body(), prefix))
return false; return false;
MOZ_ASSERT(tryNode->kid2() || tryNode->kid3()); MOZ_ASSERT(tryNode->catchList() || tryNode->finallyBlock());
if (ParseNode* catchList = tryNode->kid2()) { if (ListNode* catchList = tryNode->catchList()) {
MOZ_ASSERT(catchList->isKind(PNK_CATCHLIST));
if (!resolve(catchList, prefix)) if (!resolve(catchList, prefix))
return false; return false;
} }
if (ParseNode* finallyBlock = tryNode->kid3()) { if (ParseNode* finallyBlock = tryNode->finallyBlock()) {
if (!resolve(finallyBlock, prefix)) if (!resolve(finallyBlock, prefix))
return false; return false;
} }

View file

@ -308,10 +308,10 @@ IsTypeofKind(ParseNodeKind kind)
* kid3: update expr after second ';' or nullptr * kid3: update expr after second ';' or nullptr
* PNK_THROW (UnaryNode) * PNK_THROW (UnaryNode)
* kid: thrown exception * kid: thrown exception
* PNK_TRY (TernaryNode) * PNK_TRY (TryNode)
* kid1: try block * body: try block
* kid2: null or PNK_CATCHLIST list * catchList: null or PNK_CATCHLIST list
* kid3: null or finally block * finallyBlock: null or finally block
* PNK_CATCHLIST (ListNode) * PNK_CATCHLIST (ListNode)
* head: list of PNK_LEXICALSCOPE nodes, one per catch-block, * head: list of PNK_LEXICALSCOPE nodes, one per catch-block,
* each with scopeBody pointing to a PNK_CATCH node * each with scopeBody pointing to a PNK_CATCH node
@ -593,6 +593,8 @@ enum ParseNodeArity
macro(TernaryNode, TernaryNodeType, asTernary) \ macro(TernaryNode, TernaryNodeType, asTernary) \
macro(ClassNode, ClassNodeType, asClass) \ macro(ClassNode, ClassNodeType, asClass) \
macro(ConditionalExpression, ConditionalExpressionType, asConditionalExpression) \ macro(ConditionalExpression, ConditionalExpressionType, asConditionalExpression) \
macro(TryNode, TryNodeType, asTry) \
\
macro(UnaryNode, UnaryNodeType, asUnary) \ macro(UnaryNode, UnaryNodeType, asUnary) \
macro(ThisLiteral, ThisLiteralType, asThisLiteral) 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<TernaryNode>());
return match;
}
ParseNode* body() const {
return kid1();
}
ListNode* catchList() const {
return kid2() ? &kid2()->as<ListNode>() : nullptr;
}
ParseNode* finallyBlock() const {
return kid3();
}
};
class ThisLiteral : public UnaryNode class ThisLiteral : public UnaryNode
{ {
public: public: