diff options
author | Martok <martok@martoks-place.de> | 2023-03-23 18:53:27 +0100 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-04-03 16:50:21 +0200 |
commit | 33d29efe43993cd5b5ac63f898430f0cca30f4a5 (patch) | |
tree | 40ad8075f9fb82bf2125e12394b3fb21b1f87f56 /js | |
parent | 416d9683fec34fcd73a1755493a4f44006687270 (diff) | |
download | uxp-33d29efe43993cd5b5ac63f898430f0cca30f4a5.tar.gz |
Issue #2173 - Add a new PNK_PROPERTYNAME to hold location information about property access name
Based-on: m-c 1378808/2
Diffstat (limited to 'js')
-rw-r--r-- | js/src/builtin/ReflectParse.cpp | 8 | ||||
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 26 | ||||
-rw-r--r-- | js/src/frontend/FoldConstants.cpp | 19 | ||||
-rw-r--r-- | js/src/frontend/FullParseHandler.h | 12 | ||||
-rw-r--r-- | js/src/frontend/NameFunctions.cpp | 9 | ||||
-rw-r--r-- | js/src/frontend/ParseNode.cpp | 34 | ||||
-rw-r--r-- | js/src/frontend/ParseNode.h | 48 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 7 | ||||
-rw-r--r-- | js/src/frontend/SyntaxParseHandler.h | 9 | ||||
-rw-r--r-- | js/src/wasm/AsmJS.cpp | 8 |
10 files changed, 104 insertions, 76 deletions
diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index a9c354fa7c..d63c1dd493 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -3066,20 +3066,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) case PNK_OPTDOT: case PNK_DOT: { - MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos)); + MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); RootedValue expr(cx); RootedValue propname(cx); - RootedAtom pnAtom(cx, pn->pn_atom); + RootedAtom pnAtom(cx, pn->pn_right->pn_atom); bool isSuper = pn->is<PropertyAccess>() && pn->as<PropertyAccess>().isSuper(); if (isSuper) { - if (!builder.super(&pn->pn_expr->pn_pos, &expr)) + if (!builder.super(&pn->pn_left->pn_pos, &expr)) return false; } else { - if (!expression(pn->pn_expr, &expr)) + if (!expression(pn->pn_left, &expr)) return false; } diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8c3e74155e..3997d1cf3e 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1090,7 +1090,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) // Watch out for getters! case PNK_DOT: case PNK_OPTDOT: - MOZ_ASSERT(pn->isArity(PN_NAME)); + MOZ_ASSERT(pn->isArity(PN_BINARY)); *answer = true; return true; @@ -1497,6 +1497,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE case PNK_POSHOLDER: // by PNK_NEWTARGET case PNK_SUPERBASE: // by PNK_ELEM and others + case PNK_PROPERTYNAME: // by PNK_DOT MOZ_CRASH("handled by parent nodes"); case PNK_LIMIT: // invalid sentinel value @@ -1813,11 +1814,11 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn) MOZ_ASSERT(pn->isKind(PNK_DOT)); MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper()); - ParseNode* pn2 = pn->pn_expr; + ParseNode* pn2 = pn->pn_left; /* * If the object operand is also a dotted property reference, reverse the - * list linked via pn_expr temporarily so we can iterate over it from the + * list linked via pn_left temporarily so we can iterate over it from the * bottom up (reversing again as we go), to avoid excessive recursion. */ if (pn2->isKind(PNK_DOT) && !pn2->as<PropertyAccess>().isSuper()) { @@ -1825,9 +1826,9 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn) ParseNode* pnup = nullptr; ParseNode* pndown; for (;;) { - /* Reverse pndot->pn_expr to point up, not down. */ - pndown = pndot->pn_expr; - pndot->pn_expr = pnup; + /* Reverse pndot->pn_left to point up, not down. */ + pndown = pndot->pn_left; + pndot->pn_left = pnup; if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper()) break; pnup = pndot; @@ -1840,12 +1841,12 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn) do { /* Walk back up the list, emitting annotated name ops. */ - if (!emitAtomOp(pndot->pn_atom, JSOP_GETPROP)) + if (!emitAtomOp(pndot->pn_right->pn_atom, JSOP_GETPROP)) return false; - /* Reverse the pn_expr link again. */ - pnup = pndot->pn_expr; - pndot->pn_expr = pndown; + /* Reverse the pn_left link again. */ + pnup = pndot->pn_left; + pndot->pn_left = pndown; pndown = pndot; } while ((pndot = pnup) != nullptr); return true; @@ -2505,7 +2506,7 @@ BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted) // SUPERBASE is pushed onto THIS in poe.prepareForRhs below. *emitted = 2; } else { - if (!emitTree(target->pn_expr)) // OBJ + if (!emitTree(target->pn_left)) // OBJ return false; *emitted = 1; } @@ -9080,8 +9081,9 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage:: return false; break; + case PNK_PROPERTYNAME: case PNK_POSHOLDER: - MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER"); + MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER or PNK_PROPERTYNAME"); default: MOZ_ASSERT(0); diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index abeebadddf..3b11e8de37 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -367,6 +367,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_COMMA: case PNK_ARRAY: case PNK_OBJECT: + case PNK_PROPERTYNAME: case PNK_DOT: case PNK_ELEM: case PNK_ARGUMENTS: @@ -1367,11 +1368,14 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>& // Optimization 3: We have expr["foo"] where foo is not an index. Convert // to a property access (like expr.foo) that optimizes better downstream. + ParseNode* nameNode = parser.handler.newPropertyName(name, key->pn_pos); + if (!nameNode) + return false; ParseNode* dottedAccess; if (node->isKind(PNK_OPTELEM)) { - dottedAccess = parser.handler.newOptionalPropertyAccess(expr, name, node->pn_pos.end); + dottedAccess = parser.handler.newOptionalPropertyAccess(expr, nameNode); } else { - dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end); + dottedAccess = parser.handler.newPropertyAccess(expr, nameNode); } if (!dottedAccess) { return false; @@ -1646,14 +1650,14 @@ FoldDottedProperty(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandle bool inGenexpLambda) { MOZ_ASSERT(node->isKind(PNK_DOT) || node->isKind(PNK_OPTDOT)); - MOZ_ASSERT(node->isArity(PN_NAME)); + MOZ_ASSERT(node->isArity(PN_BINARY)); // Iterate through a long chain of dotted property accesses to find the // most-nested non-dotted property node, then fold that. - ParseNode** nested = &node->pn_expr; + ParseNode** nested = &node->pn_left; while ((*nested)->isKind(PNK_DOT) || (*nested)->isKind(PNK_OPTDOT)) { - MOZ_ASSERT((*nested)->isArity(PN_NAME)); - nested = &(*nested)->pn_expr; + MOZ_ASSERT((*nested)->isArity(PN_BINARY)); + nested = &(*nested)->pn_left; } return Fold(cx, nested, parser, inGenexpLambda); @@ -1953,6 +1957,9 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo MOZ_ASSERT(pn->isArity(PN_NAME)); return Fold(cx, &pn->pn_expr, parser, inGenexpLambda); + case PNK_PROPERTYNAME: + MOZ_CRASH("unreachable, handled by ::Dot"); + case PNK_OPTDOT: case PNK_DOT: return FoldDottedProperty(cx, pn, parser, inGenexpLambda); diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 786a5c32dd..d5a8c1ab4e 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -707,16 +707,20 @@ class FullParseHandler return new_<DebuggerStatement>(pos); } - ParseNode* newPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) { - return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end); + ParseNode* newPropertyName(PropertyName* name, const TokenPos& pos) { + return new_<NameNode>(PNK_PROPERTYNAME, JSOP_NOP, name, pos); + } + + ParseNode* newPropertyAccess(ParseNode* expr, ParseNode* key) { + return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end); } ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) { return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end); } - ParseNode* newOptionalPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) { - return new_<OptionalPropertyAccess>(pn, name, pn->pn_pos.begin, end); + ParseNode* newOptionalPropertyAccess(ParseNode* expr, ParseNode* key) { + return new_<OptionalPropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end); } ParseNode* newOptionalPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) { diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index e82775b884..76433fcc80 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -74,11 +74,11 @@ class NameResolver bool nameExpression(ParseNode* n, bool* foundName) { switch (n->getKind()) { case PNK_DOT: - if (!nameExpression(n->expr(), foundName)) + if (!nameExpression(n->pn_left, foundName)) return false; if (!*foundName) return true; - return appendPropertyReference(n->pn_atom); + return appendPropertyReference(n->pn_right->pn_atom); case PNK_NAME: *foundName = true; @@ -800,12 +800,12 @@ class NameResolver } case PNK_DOT: - MOZ_ASSERT(cur->isArity(PN_NAME)); + MOZ_ASSERT(cur->isArity(PN_BINARY)); // Super prop nodes do not have a meaningful LHS if (cur->as<PropertyAccess>().isSuper()) break; - if (!resolve(cur->expr(), prefix)) + if (!resolve(cur->pn_left, prefix)) return false; break; @@ -840,6 +840,7 @@ class NameResolver case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE case PNK_CLASSNAMES: // by PNK_CLASS + case PNK_PROPERTYNAME: // by PNK_DOT MOZ_CRASH("should have been handled by a parent node"); case PNK_LIMIT: // invalid sentinel value diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 71b57910c7..5de58b9a29 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -265,6 +265,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_WHILE: case PNK_SWITCH: case PNK_NEW: + case PNK_OPTDOT: + case PNK_DOT: case PNK_OPTCALL: case PNK_CALL: case PNK_SUPERCALL: @@ -489,9 +491,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) } case PNK_LABEL: - case PNK_OPTDOT: - case PNK_DOT: case PNK_NAME: + case PNK_PROPERTYNAME: return PushNameNodeChildren(pn, stack); case PNK_LEXICALSCOPE: @@ -731,6 +732,21 @@ UnaryNode::dump(int indent) void BinaryNode::dump(int indent) { + if (isKind(PNK_DOT)) { + fprintf(stderr, "(."); + + DumpParseTree(pn_right, indent + 2); + + fprintf(stderr, " "); + if (as<PropertyAccess>().isSuper()) + fprintf(stderr, "super"); + else + DumpParseTree(pn_left, indent + 2); + + fprintf(stderr, ")"); + return; + } + const char* name = parseNodeNames[getKind()]; fprintf(stderr, "(%s ", name); indent += strlen(name) + 2; @@ -803,10 +819,7 @@ DumpName(const CharT* s, size_t len) void NameNode::dump(int indent) { - if (isKind(PNK_NAME) || isKind(PNK_DOT)) { - if (isKind(PNK_DOT)) - fprintf(stderr, "(."); - + if (isKind(PNK_NAME) || isKind(PNK_PROPERTYNAME)) { if (!pn_atom) { fprintf(stderr, "#<null name>"); } else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) { @@ -821,15 +834,6 @@ NameNode::dump(int indent) else DumpName(pn_atom->twoByteChars(nogc), pn_atom->length()); } - - if (isKind(PNK_DOT)) { - fputc(' ', stderr); - if (as<PropertyAccess>().isSuper()) - fprintf(stderr, "super"); - else - DumpParseTree(expr(), indent + 2); - fputc(')', stderr); - } return; } diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 68bdfdc200..7f42b57eeb 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -32,6 +32,7 @@ class ObjectBox; F(POSTINCREMENT) \ F(PREDECREMENT) \ F(POSTDECREMENT) \ + F(PROPERTYNAME) \ F(DOT) \ F(ELEM) \ F(OPTDOT) \ @@ -396,9 +397,9 @@ IsTypeofKind(ParseNodeKind kind) * contains are nullish. An optional chain can also * contain nodes such as PNK_DOT, PNK_ELEM, PNK_NAME, * PNK_CALL, etc. These are evaluated normally. - * PNK_OPTDOT name pn_expr: MEMBER expr to left of . + * PNK_OPTDOT binary pn_left: MEMBER expr to left of . * short circuits back to PNK_OPTCHAIN if nullish. - * pn_atom: name to right of . + * pn_right: PropertyName to right of . * PNK_OPTELEM binary pn_left: MEMBER expr to left of [ * short circuits back to PNK_OPTCHAIN if nullish. * pn_right: expr between [ and ] @@ -406,8 +407,10 @@ IsTypeofKind(ParseNodeKind kind) * pn_count: 1 + N (where N is number of args) * call is a MEMBER expr naming a callable object, * short circuits back to PNK_OPTCHAIN if nullish. - * PNK_DOT name pn_expr: MEMBER expr to left of . - * pn_atom: name to right of . + * PNK_PROPERTYNAME pn_atom: property being accessed + * name + * PNK_DOT binary pn_left: MEMBER expr to left of . + * pn_right: PropertyName to right of . * PNK_ELEM binary pn_left: MEMBER expr to left of [ * pn_right: expr between [ and ] * PNK_CALL binary pn_left: callee expression on the left of the ( @@ -600,8 +603,7 @@ class ParseNode FunctionBox* funbox; /* function object */ }; ParseNode* expr; /* module or function body, var - initializer, argument default, or - base object of PNK_DOT */ + initializer, or argument default */ } name; struct { LexicalScope::Data* bindings; @@ -1223,44 +1225,45 @@ class RegExpLiteral : public NullaryNode } }; -class PropertyAccessBase : public ParseNode +class PropertyAccessBase : public BinaryNode { public: - PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, PropertyName* name, - uint32_t begin, uint32_t end) - : ParseNode(kind, JSOP_NOP, PN_NAME, TokenPos(begin, end)) + /* + * PropertyAccess nodes can have any expression/'super' as left-hand + * side, but the name must be a ParseNodeKind::PropertyName node. + */ + PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end) + : BinaryNode(kind, JSOP_NOP, TokenPos(begin, end), lhs, name) { MOZ_ASSERT(lhs != nullptr); MOZ_ASSERT(name != nullptr); - pn_u.name.expr = lhs; - pn_u.name.atom = name; } static bool test(const ParseNode& node) { bool match = node.isKind(PNK_DOT) || node.isKind(PNK_OPTDOT); - MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); + MOZ_ASSERT_IF(match, node.isArity(PN_BINARY)); + MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME)); return match; } ParseNode& expression() const { - return *pn_u.name.expr; + return *pn_u.binary.left; } PropertyName& name() const { - return *pn_u.name.atom->asPropertyName(); + return *pn_u.binary.right->pn_atom->asPropertyName(); } JSAtom* nameAtom() const { - return pn_u.name.atom; + return pn_u.binary.right->pn_atom; } }; class PropertyAccess : public PropertyAccessBase { public: - PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, - uint32_t end) + PropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end) : PropertyAccessBase(PNK_DOT, lhs, name, begin, end) { MOZ_ASSERT(lhs != nullptr); @@ -1269,7 +1272,8 @@ class PropertyAccess : public PropertyAccessBase static bool test(const ParseNode& node) { bool match = node.isKind(PNK_DOT); - MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); + MOZ_ASSERT_IF(match, node.isArity(PN_BINARY)); + MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME)); return match; } @@ -1282,8 +1286,7 @@ class PropertyAccess : public PropertyAccessBase class OptionalPropertyAccess : public PropertyAccessBase { public: - OptionalPropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, - uint32_t end) + OptionalPropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end) : PropertyAccessBase(PNK_OPTDOT, lhs, name, begin, end) { MOZ_ASSERT(lhs != nullptr); @@ -1292,7 +1295,8 @@ class OptionalPropertyAccess : public PropertyAccessBase static bool test(const ParseNode& node) { bool match = node.isKind(PNK_OPTDOT); - MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); + MOZ_ASSERT_IF(match, node.isArity(PN_BINARY)); + MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME)); return match; } }; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 08812741af..779cd692c6 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9333,11 +9333,14 @@ Parser<ParseHandler>::memberPropertyAccess( error(JSMSG_BAD_SUPERPROP, "property"); return null(); } + Node name = handler.newPropertyName(field, pos()); + if (!name) + return null(); if (optionalKind == OptionalKind::Optional) { MOZ_ASSERT(!handler.isSuperBase(lhs)); - return handler.newOptionalPropertyAccess(lhs, field, pos().end); + return handler.newOptionalPropertyAccess(lhs, name); } - return handler.newPropertyAccess(lhs, field, pos().end); + return handler.newPropertyAccess(lhs, name); } template <class ParseHandler> diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 2ada163938..bca7400e55 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -360,13 +360,16 @@ class SyntaxParseHandler } Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; } - Node newPropertyAccess(Node pn, PropertyName* name, uint32_t end) { + Node newPropertyName(PropertyName* name, const TokenPos& pos) { lastAtom = name; + return NodeGeneric; + } + + Node newPropertyAccess(Node expr, Node key) { return NodeDottedProperty; } - Node newOptionalPropertyAccess(Node pn, PropertyName* name, uint32_t end) { - lastAtom = name; + Node newOptionalPropertyAccess(Node expr, Node key) { return NodeOptionalDottedProperty; } diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index be7db1a0a3..f359d19c2a 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -643,16 +643,16 @@ static ParseNode* DotBase(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_DOT)); - MOZ_ASSERT(pn->isArity(PN_NAME)); - return pn->expr(); + MOZ_ASSERT(pn->isArity(PN_BINARY)); + return pn->pn_left; } static PropertyName* DotMember(ParseNode* pn) { MOZ_ASSERT(pn->isKind(PNK_DOT)); - MOZ_ASSERT(pn->isArity(PN_NAME)); - return pn->pn_atom->asPropertyName(); + MOZ_ASSERT(pn->isArity(PN_BINARY)); + return pn->pn_right->pn_atom->asPropertyName(); } static ParseNode* |