--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2736,27 +2736,27 @@ ASTSerializer::expression(ParseNode* pn,
return pn->isKind(ParseNodeKind::New)
? builder.newExpression(callee, args, &pn->pn_pos, dst)
: builder.callExpression(callee, args, &pn->pn_pos, dst);
}
case ParseNodeKind::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);
if (pn->as<PropertyAccess>().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;
}
return identifier(pnAtom, nullptr, &propname) &&
builder.memberExpression(false, expr, propname, &pn->pn_pos, dst);
}
case ParseNodeKind::Elem:
--- a/js/src/frontend/BinSource-auto.cpp
+++ b/js/src/frontend/BinSource-auto.cpp
@@ -6188,23 +6188,28 @@ BinASTParser<Tok>::parseInterfaceStaticM
{
MOZ_ASSERT(kind == BinKind::StaticMemberAssignmentTarget);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinField expected_fields[2] = { BinField::Object, BinField::Property };
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
+ size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
-
RootedAtom property(cx_);
- MOZ_TRY_VAR(property, tokenizer_->readAtom());
-
- BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
+ {
+ nameStart = tokenizer_->offset();
+ MOZ_TRY_VAR(property, tokenizer_->readAtom());
+
+ }
+
+ BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
+ BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
return result;
}
/*
interface StaticMemberExpression : Node {
(Expression or Super) object;
IdentifierName property;
@@ -6233,23 +6238,28 @@ BinASTParser<Tok>::parseInterfaceStaticM
{
MOZ_ASSERT(kind == BinKind::StaticMemberExpression);
BINJS_TRY(CheckRecursionLimit(cx_));
#if defined(DEBUG)
const BinField expected_fields[2] = { BinField::Object, BinField::Property };
MOZ_TRY(tokenizer_->checkFields(kind, fields, expected_fields));
#endif // defined(DEBUG)
+ size_t nameStart;
BINJS_MOZ_TRY_DECL(object, parseExpressionOrSuper());
-
RootedAtom property(cx_);
- MOZ_TRY_VAR(property, tokenizer_->readAtom());
-
- BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
+ {
+ nameStart = tokenizer_->offset();
+ MOZ_TRY_VAR(property, tokenizer_->readAtom());
+
+ }
+
+ BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
+ BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
return result;
}
/*
interface Super : Node {
}
*/
--- a/js/src/frontend/BinSource.yaml
+++ b/js/src/frontend/BinSource.yaml
@@ -900,22 +900,38 @@ SwitchStatementWithDefault:
ParseNode* next = iter->pn_next;
factory_.addList(cases, iter);
iter = next;
}
BINJS_TRY_DECL(scope, factory_.newLexicalScope(nullptr, cases));
BINJS_TRY_DECL(result, factory_.newSwitchStatement(start, discriminant, scope));
StaticMemberAssignmentTarget:
+ init:
+ size_t nameStart;
+ fields:
+ property:
+ block:
+ before: |
+ nameStart = tokenizer_->offset();
build: |
- BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
+ BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
+ BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
StaticMemberExpression:
+ init:
+ size_t nameStart;
+ fields:
+ property:
+ block:
+ before: |
+ nameStart = tokenizer_->offset();
build: |
- BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, property->asPropertyName(), tokenizer_->offset()));
+ BINJS_TRY_DECL(name, factory_.newPropertyName(property->asPropertyName(), tokenizer_->pos(nameStart)));
+ BINJS_TRY_DECL(result, factory_.newPropertyAccess(object, name));
ThisExpression:
build: |
if (parseContext_->isFunctionBox())
parseContext_->functionBox()->usesThis = true;
TokenPos pos = tokenizer_->pos(start);
ParseNode* thisName(nullptr);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3480,17 +3480,17 @@ BytecodeEmitter::checkSideEffects(ParseN
case ParseNodeKind::Continue:
case ParseNodeKind::Debugger:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
*answer = true;
return true;
// Watch out for getters!
case ParseNodeKind::Dot:
- MOZ_ASSERT(pn->isArity(PN_NAME));
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true;
return true;
// Unary cases with side effects only if the child has them.
case ParseNodeKind::TypeOfExpr:
case ParseNodeKind::Void:
case ParseNodeKind::Not:
MOZ_ASSERT(pn->isArity(PN_UNARY));
@@ -3860,16 +3860,17 @@ BytecodeEmitter::checkSideEffects(ParseN
case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
case ParseNodeKind::ExportBatchSpec:// by ParseNodeKind::Export
case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
+ case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
MOZ_CRASH("handled by parent nodes");
case ParseNodeKind::Limit: // invalid sentinel value
MOZ_CRASH("invalid node kind");
}
MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
"BytecodeEmitter::checkSideEffects");
@@ -4301,49 +4302,49 @@ BytecodeEmitter::emitTDZCheckIfNeeded(JS
}
bool
BytecodeEmitter::emitPropLHS(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(ParseNodeKind::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(ParseNodeKind::Dot) && !pn2->as<PropertyAccess>().isSuper()) {
ParseNode* pndot = pn2;
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(ParseNodeKind::Dot) || pndown->as<PropertyAccess>().isSuper())
break;
pnup = pndot;
pndot = pndown;
}
/* pndown is a primary expression, not a dotted property reference. */
if (!emitTree(pndown))
return false;
do {
/* Walk back up the list, emitting annotated name ops. */
- if (!emitAtomOp(pndot, JSOP_GETPROP))
- return false;
-
- /* Reverse the pn_expr link again. */
- pnup = pndot->pn_expr;
- pndot->pn_expr = pndown;
+ if (!emitAtomOp(pndot->pn_right, JSOP_GETPROP))
+ return false;
+
+ /* Reverse the pn_left link again. */
+ pnup = pndot->pn_left;
+ pndot->pn_left = pndown;
pndown = pndot;
} while ((pndot = pnup) != nullptr);
return true;
}
// The non-optimized case.
return emitTree(pn2);
}
@@ -4358,41 +4359,41 @@ BytecodeEmitter::emitSuperPropLHS(ParseN
if (!emit1(JSOP_SUPERBASE))
return false;
return true;
}
bool
BytecodeEmitter::emitPropOp(ParseNode* pn, JSOp op)
{
- MOZ_ASSERT(pn->isArity(PN_NAME));
+ MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!emitPropLHS(pn))
return false;
if (op == JSOP_CALLPROP && !emit1(JSOP_DUP))
return false;
- if (!emitAtomOp(pn, op))
+ if (!emitAtomOp(pn->pn_right, op))
return false;
if (op == JSOP_CALLPROP && !emit1(JSOP_SWAP))
return false;
return true;
}
bool
BytecodeEmitter::emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall)
{
ParseNode* base = &pn->as<PropertyAccess>().expression();
if (!emitSuperPropLHS(base, isCall))
return false;
- if (!emitAtomOp(pn, op))
+ if (!emitAtomOp(pn->pn_right, op))
return false;
if (isCall && !emit1(JSOP_SWAP))
return false;
return true;
}
@@ -4412,17 +4413,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
if (!emit1(JSOP_DUP2)) // THIS OBJ THIS OBJ
return false;
} else {
if (!emitPropLHS(pn->pn_kid)) // OBJ
return false;
if (!emit1(JSOP_DUP)) // OBJ OBJ
return false;
}
- if (!emitAtomOp(pn->pn_kid, isSuper? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
+ if (!emitAtomOp(pn->pn_kid->pn_right, isSuper ? JSOP_GETPROP_SUPER : JSOP_GETPROP)) // OBJ V
return false;
if (!emit1(JSOP_POS)) // OBJ N
return false;
if (post && !emit1(JSOP_DUP)) // OBJ N? N
return false;
if (!emit1(JSOP_ONE)) // OBJ N? N 1
return false;
if (!emit1(binop)) // OBJ N? N+1
@@ -4438,17 +4439,17 @@ BytecodeEmitter::emitPropIncDec(ParseNod
return false;
if (!emit1(JSOP_SWAP)) // N THIS OBJ N+1
return false;
}
}
JSOp setOp = isSuper ? sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER
: sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
- if (!emitAtomOp(pn->pn_kid, setOp)) // N? N+1
+ if (!emitAtomOp(pn->pn_kid->pn_right, setOp)) // N? N+1
return false;
if (post && !emit1(JSOP_POP)) // RESULT
return false;
return true;
}
bool
@@ -5364,17 +5365,17 @@ BytecodeEmitter::emitDestructuringLHSRef
switch (target->getKind()) {
case ParseNodeKind::Dot: {
if (target->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropLHS(&target->as<PropertyAccess>().expression()))
return false;
*emitted = 2;
} else {
- if (!emitTree(target->pn_expr))
+ if (!emitTree(target->pn_left))
return false;
*emitted = 1;
}
break;
}
case ParseNodeKind::Elem: {
if (target->as<PropertyByValue>().isSuper()) {
@@ -5482,17 +5483,17 @@ BytecodeEmitter::emitSetOrInitializeDest
case ParseNodeKind::Dot: {
// The reference is already pushed by emitDestructuringLHSRef.
JSOp setOp;
if (target->as<PropertyAccess>().isSuper())
setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
else
setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
- if (!emitAtomOp(target, setOp))
+ if (!emitAtomOp(target->pn_right, setOp))
return false;
break;
}
case ParseNodeKind::Elem: {
// The reference is already pushed by emitDestructuringLHSRef.
if (target->as<PropertyByValue>().isSuper()) {
JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
@@ -6594,21 +6595,21 @@ BytecodeEmitter::emitAssignment(ParseNod
switch (lhs->getKind()) {
case ParseNodeKind::Dot:
if (lhs->as<PropertyAccess>().isSuper()) {
if (!emitSuperPropLHS(&lhs->as<PropertyAccess>().expression()))
return false;
offset += 2;
} else {
- if (!emitTree(lhs->expr()))
+ if (!emitTree(lhs->pn_left))
return false;
offset += 1;
}
- if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
+ if (!makeAtomIndex(lhs->pn_right->pn_atom, &atomIndex))
return false;
break;
case ParseNodeKind::Elem: {
MOZ_ASSERT(lhs->isArity(PN_BINARY));
EmitElemOption opt = op == JSOP_NOP ? EmitElemOption::Get : EmitElemOption::CompoundAssign;
if (lhs->as<PropertyByValue>().isSuper()) {
if (!emitSuperElemOperands(lhs, opt))
return false;
@@ -6647,17 +6648,17 @@ BytecodeEmitter::emitAssignment(ParseNod
JSOp getOp;
if (lhs->as<PropertyAccess>().isSuper()) {
if (!emit1(JSOP_DUP2))
return false;
getOp = JSOP_GETPROP_SUPER;
} else {
if (!emit1(JSOP_DUP))
return false;
- bool isLength = (lhs->pn_atom == cx->names().length);
+ bool isLength = (lhs->pn_right->pn_atom == cx->names().length);
getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
}
if (!emitIndex32(getOp, atomIndex))
return false;
break;
}
case ParseNodeKind::Elem: {
JSOp elemOp;
@@ -11316,18 +11317,19 @@ BytecodeEmitter::emitTree(ParseNode* pn,
return false;
break;
case ParseNodeKind::SetThis:
if (!emitSetThis(pn))
return false;
break;
+ case ParseNodeKind::PropertyName:
case ParseNodeKind::PosHolder:
- MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder");
+ MOZ_FALLTHROUGH_ASSERT("Should never try to emit ParseNodeKind::PosHolder or ::Property");
default:
MOZ_ASSERT(0);
}
/* bce->emitLevel == 1 means we're last on the stack, so finish up. */
if (emitLevel == 1) {
if (!updateSourceCoordNotes(pn->pn_pos.end))
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -342,16 +342,17 @@ ContainsHoistedDeclaration(JSContext* cx
case ParseNodeKind::UrshAssign:
case ParseNodeKind::MulAssign:
case ParseNodeKind::DivAssign:
case ParseNodeKind::ModAssign:
case ParseNodeKind::PowAssign:
case ParseNodeKind::Comma:
case ParseNodeKind::Array:
case ParseNodeKind::Object:
+ case ParseNodeKind::PropertyName:
case ParseNodeKind::Dot:
case ParseNodeKind::Elem:
case ParseNodeKind::Arguments:
case ParseNodeKind::Call:
case ParseNodeKind::Name:
case ParseNodeKind::TemplateString:
case ParseNodeKind::TemplateStringList:
case ParseNodeKind::TaggedTemplate:
@@ -1249,17 +1250,18 @@ FoldElement(JSContext* cx, ParseNode** n
}
// If we don't have a name, we can't optimize to getprop.
if (!name)
return true;
// 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* dottedAccess = parser.newPropertyAccess(expr, name, node->pn_pos.end);
+ ParseNode* nameNode = parser.newPropertyName(name, key->pn_pos);
+ ParseNode* dottedAccess = parser.newPropertyAccess(expr, nameNode);
if (!dottedAccess)
return false;
dottedAccess->setInParens(node->isInParens());
ReplaceNode(nodePtr, dottedAccess);
return true;
}
@@ -1495,24 +1497,24 @@ FoldForHead(JSContext* cx, ParseNode* no
return true;
}
static bool
FoldDottedProperty(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
{
MOZ_ASSERT(node->isKind(ParseNodeKind::Dot));
- 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(ParseNodeKind::Dot)) {
- 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);
}
static bool
FoldName(JSContext* cx, ParseNode* node, PerHandlerParser<FullParseHandler>& parser)
{
@@ -1793,16 +1795,19 @@ Fold(JSContext* cx, ParseNode** pnp, Per
case ParseNodeKind::ForHead:
return FoldForHead(cx, pn, parser);
case ParseNodeKind::Label:
MOZ_ASSERT(pn->isArity(PN_NAME));
return Fold(cx, &pn->pn_expr, parser);
+ case ParseNodeKind::PropertyName:
+ MOZ_CRASH("unreachable, handled by ::Dot");
+
case ParseNodeKind::Dot:
return FoldDottedProperty(cx, pn, parser);
case ParseNodeKind::LexicalScope:
MOZ_ASSERT(pn->isArity(PN_SCOPE));
if (!pn->scopeBody())
return true;
return Fold(cx, &pn->pn_u.scope.body, parser);
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -658,18 +658,22 @@ class FullParseHandler
TokenPos pos(begin, (finallyBlock ? finallyBlock : catchScope)->pn_pos.end);
return new_<TernaryNode>(ParseNodeKind::Try, body, catchScope, finallyBlock, pos);
}
ParseNode* newDebuggerStatement(const TokenPos& pos) {
return new_<DebuggerStatement>(pos);
}
- ParseNode* newPropertyAccess(ParseNode* expr, PropertyName* key, uint32_t end) {
- return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, end);
+ ParseNode* newPropertyName(PropertyName* name, const TokenPos& pos) {
+ return new_<NameNode>(ParseNodeKind::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);
}
bool setupCatchScope(ParseNode* lexicalScope, ParseNode* catchName, ParseNode* catchBody) {
ParseNode* catchpn;
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -70,21 +70,21 @@ class NameResolver
* Walk over the given ParseNode, attempting to convert it to a stringified
* name that respresents where the function is being assigned to.
*
* |*foundName| is set to true if a name is found for the expression.
*/
bool nameExpression(ParseNode* n, bool* foundName) {
switch (n->getKind()) {
case ParseNodeKind::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 ParseNodeKind::Name:
*foundName = true;
return buf->append(n->pn_atom);
case ParseNodeKind::This:
*foundName = true;
return buf->append("this");
@@ -779,22 +779,22 @@ class NameResolver
MOZ_ASSERT(item->pn_right->isKind(ParseNodeKind::Name));
MOZ_ASSERT(!item->pn_right->expr());
}
#endif
break;
}
case ParseNodeKind::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;
case ParseNodeKind::Label:
MOZ_ASSERT(cur->isArity(PN_NAME));
if (!resolve(cur->expr(), prefix))
return false;
break;
@@ -823,16 +823,17 @@ class NameResolver
break;
// Kinds that should be handled by parent node resolution.
case ParseNodeKind::ImportSpec: // by ParseNodeKind::ImportSpecList
case ParseNodeKind::ExportSpec: // by ParseNodeKind::ExportSpecList
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
+ case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
MOZ_CRASH("should have been handled by a parent node");
case ParseNodeKind::Limit: // invalid sentinel value
MOZ_CRASH("invalid node kind");
}
nparents--;
MOZ_ASSERT(initialParents == nparents, "nparents imbalance detected");
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -211,16 +211,31 @@ UnaryNode::dump(GenericPrinter& out, int
indent += strlen(name) + 2;
DumpParseTree(pn_kid, out, indent);
out.printf(")");
}
void
BinaryNode::dump(GenericPrinter& out, int indent)
{
+ if (isKind(ParseNodeKind::Dot)) {
+ out.put("(.");
+
+ DumpParseTree(pn_right, out, indent + 2);
+
+ out.putChar(' ');
+ if (as<PropertyAccess>().isSuper())
+ out.put("super");
+ else
+ DumpParseTree(pn_left, out, indent + 2);
+
+ out.printf(")");
+ return;
+ }
+
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
indent += strlen(name) + 2;
DumpParseTree(pn_left, out, indent);
IndentNewLine(out, indent);
DumpParseTree(pn_right, out, indent);
out.printf(")");
}
@@ -283,43 +298,31 @@ DumpName(GenericPrinter& out, const Char
else
out.printf("\\u%04x", unsigned(c));
}
}
void
NameNode::dump(GenericPrinter& out, int indent)
{
- if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::Dot)) {
- if (isKind(ParseNodeKind::Dot))
- out.put("(.");
-
+ if (isKind(ParseNodeKind::Name) || isKind(ParseNodeKind::PropertyName)) {
if (!pn_atom) {
out.put("#<null name>");
} else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
// Dump destructuring parameter.
out.put("(#<zero-length name> ");
DumpParseTree(expr(), out, indent + 21);
out.printf(")");
} else {
JS::AutoCheckCannotGC nogc;
if (pn_atom->hasLatin1Chars())
DumpName(out, pn_atom->latin1Chars(nogc), pn_atom->length());
else
DumpName(out, pn_atom->twoByteChars(nogc), pn_atom->length());
}
-
- if (isKind(ParseNodeKind::Dot)) {
- out.putChar(' ');
- if (as<PropertyAccess>().isSuper())
- out.put("super");
- else
- DumpParseTree(expr(), out, indent + 2);
- out.printf(")");
- }
return;
}
const char* name = parseNodeNames[size_t(getKind())];
out.printf("(%s ", name);
indent += strlen(name) + 2;
DumpParseTree(expr(), out, indent);
out.printf(")");
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -50,16 +50,17 @@ class ObjectBox;
F(Colon) \
F(Shorthand) \
F(Pos) \
F(Neg) \
F(PreIncrement) \
F(PostIncrement) \
F(PreDecrement) \
F(PostDecrement) \
+ F(PropertyName) \
F(Dot) \
F(Elem) \
F(Array) \
F(Elision) \
F(StatementList) \
F(Label) \
F(Object) \
F(Call) \
@@ -379,18 +380,19 @@ IsTypeofKind(ParseNodeKind kind)
* DeleteName unary pn_kid: Name expr
* DeleteProp unary pn_kid: Dot expr
* DeleteElem unary pn_kid: Elem expr
* DeleteExpr unary pn_kid: MEMBER expr that's evaluated, then the
* overall delete evaluates to true; can't be a kind
* for a more-specific PNK_DELETE* unless constant
* folding (or a similar parse tree manipulation) has
* occurred
- * Dot name pn_expr: MEMBER expr to left of .
- * pn_atom: name to right of .
+ * PropertyName name pn_atom: property name being accessed
+ * Dot binary pn_left: MEMBER expr to left of .
+ * pn_right: PropertyName to right of .
* Elem binary pn_left: MEMBER expr to left of [
* pn_right: expr between [ and ]
* Call binary pn_left: callee expression on the left of the (
* pn_right: Arguments
* Arguments list pn_head: list of arg1, arg2, ... argN
* pn_count: N (where N is number of args)
* Array list pn_head: list of pn_count array element exprs
* [,,] holes are represented by Elision nodes
@@ -570,18 +572,17 @@ class ParseNode
} unary;
struct { /* name, labeled statement, etc. */
union {
JSAtom* atom; /* lexical name or label atom */
ObjectBox* objbox; /* regexp object */
FunctionBox* funbox; /* function object */
};
ParseNode* expr; /* module or function body, var
- initializer, argument default, or
- base object of ParseNodeKind::Dot */
+ initializer, or argument default */
} name;
struct {
LexicalScope::Data* bindings;
ParseNode* body;
} scope;
struct {
double value; /* aligned numeric literal value */
DecimalPoint decimalPoint; /* Whether the number has a decimal point */
@@ -1179,40 +1180,43 @@ class RegExpLiteral : public NullaryNode
static bool test(const ParseNode& node) {
bool match = node.isKind(ParseNodeKind::RegExp);
MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
MOZ_ASSERT_IF(match, node.isOp(JSOP_REGEXP));
return match;
}
};
-class PropertyAccess : public ParseNode
+class PropertyAccess : public BinaryNode
{
public:
- PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, uint32_t end)
- : ParseNode(ParseNodeKind::Dot, 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.
+ */
+ PropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end)
+ : BinaryNode(ParseNodeKind::Dot, 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(ParseNodeKind::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(ParseNodeKind::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();
}
bool isSuper() const {
// ParseNodeKind::SuperBase cannot result from any expression syntax.
return expression().isKind(ParseNodeKind::SuperBase);
}
};
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -8755,17 +8755,22 @@ GeneralParser<ParseHandler, CharT>::memb
if (!tokenStream.getToken(&tt))
return null();
if (TokenKindIsPossibleIdentifierName(tt)) {
PropertyName* field = anyChars.currentName();
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
error(JSMSG_BAD_SUPERPROP, "property");
return null();
}
- nextMember = handler.newPropertyAccess(lhs, field, pos().end);
+
+ Node name = handler.newPropertyName(field, pos());
+ if (!name)
+ return null();
+
+ nextMember = handler.newPropertyAccess(lhs, name);
if (!nextMember)
return null();
} else {
error(JSMSG_NAME_AFTER_DOT);
return null();
}
} else if (tt == TokenKind::Lb) {
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -564,18 +564,22 @@ class MOZ_STACK_CLASS PerHandlerParser
// If ParseHandler is FullParseHandler:
// Do nothing.
inline void clearAbortedSyntaxParse();
public:
bool isValidSimpleAssignmentTarget(Node node,
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
- Node newPropertyAccess(Node expr, PropertyName* key, uint32_t end) {
- return handler.newPropertyAccess(expr, key, end);
+ Node newPropertyName(PropertyName* key, const TokenPos& pos) {
+ return handler.newPropertyName(key, pos);
+ }
+
+ Node newPropertyAccess(Node expr, Node key) {
+ return handler.newPropertyAccess(expr, key);
}
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, uint32_t toStringStart,
Directives directives, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind);
};
#define ABORTED_SYNTAX_PARSE_SENTINEL reinterpret_cast<void*>(0x1)
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -325,18 +325,22 @@ class SyntaxParseHandler
}
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; }
Node newTryStatement(uint32_t begin, Node body, Node catchScope, Node finallyBlock) {
return NodeGeneric;
}
Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; }
- Node newPropertyAccess(Node expr, PropertyName* key, uint32_t end) {
- lastAtom = key;
+ Node newPropertyName(PropertyName* name, const TokenPos& pos) {
+ lastAtom = name;
+ return NodeGeneric;
+ }
+
+ Node newPropertyAccess(Node expr, Node key) {
return NodeDottedProperty;
}
Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeElement; }
MOZ_MUST_USE bool setupCatchScope(Node letBlock, Node catchName, Node catchBody) {
return true;
}
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -629,26 +629,26 @@ NumberNodeHasFrac(ParseNode* pn)
MOZ_ASSERT(pn->isKind(ParseNodeKind::Number));
return pn->pn_u.number.decimalPoint == HasDecimal;
}
static ParseNode*
DotBase(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(ParseNodeKind::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(ParseNodeKind::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*
ElemBase(ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(ParseNodeKind::Elem));
return BinaryLeft(pn);
}