summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorMartok <martok@martoks-place.de>2023-03-23 18:53:27 +0100
committerMartok <martok@martoks-place.de>2023-04-03 16:50:21 +0200
commit33d29efe43993cd5b5ac63f898430f0cca30f4a5 (patch)
tree40ad8075f9fb82bf2125e12394b3fb21b1f87f56 /js
parent416d9683fec34fcd73a1755493a4f44006687270 (diff)
downloaduxp-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.cpp8
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp26
-rw-r--r--js/src/frontend/FoldConstants.cpp19
-rw-r--r--js/src/frontend/FullParseHandler.h12
-rw-r--r--js/src/frontend/NameFunctions.cpp9
-rw-r--r--js/src/frontend/ParseNode.cpp34
-rw-r--r--js/src/frontend/ParseNode.h48
-rw-r--r--js/src/frontend/Parser.cpp7
-rw-r--r--js/src/frontend/SyntaxParseHandler.h9
-rw-r--r--js/src/wasm/AsmJS.cpp8
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*