From 371c557f9730a1ec8162755a3460e11dff8b98ae Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Wed, 2 Sep 2015 15:09:03 -0700 Subject: [PATCH] Bug 1168992 - Part 2: Fix reflection of new.target. (r=Waldo) --- js/src/builtin/ReflectParse.cpp | 30 +++++++++++++++---- js/src/frontend/BytecodeEmitter.cpp | 13 +++++++- js/src/frontend/FoldConstants.cpp | 9 +++++- js/src/frontend/FullParseHandler.h | 7 +++-- js/src/frontend/NameFunctions.cpp | 8 ++++- js/src/frontend/ParseNode.cpp | 3 +- js/src/frontend/ParseNode.h | 1 + js/src/frontend/Parser.cpp | 13 ++++++-- js/src/frontend/SyntaxParseHandler.h | 3 +- js/src/jsast.tbl | 2 +- js/src/jsatom.cpp | 1 - js/src/jsatom.h | 1 - .../js1_8_5/reflect-parse/PatternBuilders.js | 10 +++++-- js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/Opcodes.h | 2 +- 15 files changed, 83 insertions(+), 21 deletions(-) diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index dc39a69e0ecf..7245cfc4ef0a 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -756,7 +756,7 @@ class NodeBuilder bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter, bool isLegacy, TokenPos* pos, MutableHandleValue dst); - bool newTargetExpression(TokenPos* pos, MutableHandleValue dst); + bool metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst); /* * declarations @@ -1826,13 +1826,16 @@ NodeBuilder::classDefinition(bool expr, HandleValue name, HandleValue heritage, } bool -NodeBuilder::newTargetExpression(TokenPos* pos, MutableHandleValue dst) +NodeBuilder::metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst) { - RootedValue cb(cx, callbacks[AST_NEWTARGET_EXPR]); + RootedValue cb(cx, callbacks[AST_METAPROPERTY]); if (!cb.isNull()) - return callback(cb, pos, dst); + return callback(cb, meta, property, pos, dst); - return newNode(AST_NEWTARGET_EXPR, pos, dst); + return newNode(AST_METAPROPERTY, pos, + "meta", meta, + "property", property, + dst); } namespace { @@ -3312,7 +3315,22 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) return classDefinition(pn, true, dst); case PNK_NEWTARGET: - return builder.newTargetExpression(&pn->pn_pos, dst); + { + MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER)); + MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); + MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER)); + MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos)); + + RootedValue newIdent(cx); + RootedValue targetIdent(cx); + + RootedAtom newStr(cx, cx->names().new_); + RootedAtom targetStr(cx, cx->names().target); + + return identifier(newStr, &pn->pn_left->pn_pos, &newIdent) && + identifier(targetStr, &pn->pn_right->pn_pos, &targetIdent) && + builder.metaProperty(newIdent, targetIdent, &pn->pn_pos, dst); + } default: LOCAL_NOT_REACHED("unexpected expression type"); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 24593e5283f0..d75a45e3fbd0 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1915,7 +1915,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) switch (pn->getKind()) { // Trivial cases with no side effects. - case PNK_NEWTARGET: case PNK_NOP: case PNK_STRING: case PNK_TEMPLATE_STRING: @@ -1932,6 +1931,14 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) *answer = false; return true; + // Trivial binary nodes with more token pos holders. + case PNK_NEWTARGET: + MOZ_ASSERT(pn->isArity(PN_BINARY)); + MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER)); + MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER)); + *answer = false; + return true; + case PNK_BREAK: case PNK_CONTINUE: case PNK_DEBUGGER: @@ -2320,6 +2327,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer) case PNK_EXPORT_SPEC_LIST: // by PNK_EXPORT case PNK_EXPORT_SPEC: // by PNK_EXPORT case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE + case PNK_POSHOLDER: // by PNK_NEWTARGET MOZ_CRASH("handled by parent nodes"); case PNK_LIMIT: // invalid sentinel value @@ -8088,6 +8096,9 @@ BytecodeEmitter::emitTree(ParseNode* pn) return false; break; + case PNK_POSHOLDER: + MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER"); + default: MOZ_ASSERT(0); } diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp index d7efc8b99a46..b64e766df268 100644 --- a/js/src/frontend/FoldConstants.cpp +++ b/js/src/frontend/FoldConstants.cpp @@ -417,6 +417,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result) case PNK_SUPERPROP: case PNK_SUPERELEM: case PNK_NEWTARGET: + case PNK_POSHOLDER: MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on " "some parent node without recurring to test this node"); @@ -1709,7 +1710,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo ParseNode* pn = *pnp; switch (pn->getKind()) { - case PNK_NEWTARGET: case PNK_NOP: case PNK_REGEXP: case PNK_STRING: @@ -1728,6 +1728,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo case PNK_OBJECT_PROPERTY_NAME: case PNK_SUPERPROP: case PNK_FRESHENBLOCK: + case PNK_POSHOLDER: MOZ_ASSERT(pn->isArity(PN_NULLARY)); return true; @@ -1918,6 +1919,12 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser& parser, bo return Fold(cx, &pn->pn_left, parser, inGenexpLambda) && Fold(cx, &pn->pn_right, parser, inGenexpLambda); + case PNK_NEWTARGET: + MOZ_ASSERT(pn->isArity(PN_BINARY)); + MOZ_ASSERT(pn->pn_left->isKind(PNK_POSHOLDER)); + MOZ_ASSERT(pn->pn_right->isKind(PNK_POSHOLDER)); + return true; + case PNK_CLASSNAMES: MOZ_ASSERT(pn->isArity(PN_BINARY)); if (ParseNode*& outerBinding = pn->pn_left) { diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 7387f41df3b9..09d0a6e38722 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -352,8 +352,11 @@ class FullParseHandler ParseNode* newSuperElement(ParseNode* expr, const TokenPos& pos) { return new_(expr, pos); } - ParseNode* newNewTarget(const TokenPos& pos) { - return new_(PNK_NEWTARGET, pos); + ParseNode* newNewTarget(ParseNode* newHolder, ParseNode* targetHolder) { + return new_(PNK_NEWTARGET, JSOP_NOP, newHolder, targetHolder); + } + ParseNode* newPosHolder(const TokenPos& pos) { + return new_(PNK_POSHOLDER, pos); } bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) { diff --git a/js/src/frontend/NameFunctions.cpp b/js/src/frontend/NameFunctions.cpp index 352f2291dae2..6fa9a17e1204 100644 --- a/js/src/frontend/NameFunctions.cpp +++ b/js/src/frontend/NameFunctions.cpp @@ -377,7 +377,6 @@ class NameResolver case PNK_FRESHENBLOCK: case PNK_SUPERPROP: case PNK_OBJECT_PROPERTY_NAME: - case PNK_NEWTARGET: MOZ_ASSERT(cur->isArity(PN_NULLARY)); break; @@ -387,6 +386,12 @@ class NameResolver MOZ_ASSERT(!cur->pn_kid->maybeExpr()); break; + case PNK_NEWTARGET: + MOZ_ASSERT(cur->isArity(PN_BINARY)); + MOZ_ASSERT(cur->pn_left->isKind(PNK_POSHOLDER)); + MOZ_ASSERT(cur->pn_right->isKind(PNK_POSHOLDER)); + break; + // Nodes with a single non-null child requiring name resolution. case PNK_TYPEOFEXPR: case PNK_VOID: @@ -779,6 +784,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_POSHOLDER: // by PNK_NEWTARGET 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 12180d7a3de5..22aee6cf949c 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -215,7 +215,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_OBJECT_PROPERTY_NAME: case PNK_FRESHENBLOCK: case PNK_SUPERPROP: - case PNK_NEWTARGET: + case PNK_POSHOLDER: MOZ_ASSERT(pn->isArity(PN_NULLARY)); MOZ_ASSERT(!pn->isUsed(), "handle non-trivial cases separately"); MOZ_ASSERT(!pn->isDefn(), "handle non-trivial cases separately"); @@ -285,6 +285,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack) case PNK_SWITCH: case PNK_LETBLOCK: case PNK_CLASSMETHOD: + case PNK_NEWTARGET: case PNK_FOR: { MOZ_ASSERT(pn->isArity(PN_BINARY)); stack->push(pn->pn_left); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 56914017beab..21e151d30ac3 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -179,6 +179,7 @@ class PackedScopeCoordinate F(SUPERPROP) \ F(SUPERELEM) \ F(NEWTARGET) \ + F(POSHOLDER) \ \ /* Unary operators. */ \ F(TYPEOFNAME) \ diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 1c9cd1dea94b..f3bf9826e045 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -8949,9 +8949,14 @@ Parser::tryNewTarget(Node &newTarget) { MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NEW)); - uint32_t begin = pos().begin; newTarget = null(); + Node newHolder = handler.newPosHolder(pos()); + if (!newHolder) + return false; + + uint32_t begin = pos().begin; + // |new| expects to look for an operand, so we will honor that. TokenKind next; if (!tokenStream.getToken(&next, TokenStream::Operand)) @@ -8975,7 +8980,11 @@ Parser::tryNewTarget(Node &newTarget) return false; } - newTarget = handler.newNewTarget(TokenPos(begin, pos().end)); + Node targetHolder = handler.newPosHolder(pos()); + if (!targetHolder) + return false; + + newTarget = handler.newNewTarget(newHolder, targetHolder); return !!newTarget; } diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 70ba0b0ad0bf..13e75074ce17 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -281,7 +281,8 @@ class SyntaxParseHandler Node newSuperElement(Node expr, const TokenPos& pos) { return NodeSuperElement; } - Node newNewTarget(const TokenPos& pos) { return NodeGeneric; } + Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; } + Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl index 035bef2baf82..caab08e524b7 100644 --- a/js/src/jsast.tbl +++ b/js/src/jsast.tbl @@ -38,7 +38,7 @@ ASTDEF(AST_COMP_EXPR, "ComprehensionExpression", "comprehensi ASTDEF(AST_GENERATOR_EXPR, "GeneratorExpression", "generatorExpression") ASTDEF(AST_YIELD_EXPR, "YieldExpression", "yieldExpression") ASTDEF(AST_CLASS_EXPR, "ClassExpression", "classExpression") -ASTDEF(AST_NEWTARGET_EXPR, "NewTargetExpression", "newTargetExpression") +ASTDEF(AST_METAPROPERTY, "MetaProperty", "metaProperty") ASTDEF(AST_EMPTY_STMT, "EmptyStatement", "emptyStatement") ASTDEF(AST_BLOCK_STMT, "BlockStatement", "blockStatement") diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index ec64845a974a..eab5fd9804a9 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -76,7 +76,6 @@ const char js_import_str[] = "import"; const char js_in_str[] = "in"; const char js_instanceof_str[] = "instanceof"; const char js_interface_str[] = "interface"; -const char js_new_str[] = "new"; const char js_package_str[] = "package"; const char js_private_str[] = "private"; const char js_protected_str[] = "protected"; diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 6fce99f5ccf5..0c5b078fe116 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -176,7 +176,6 @@ extern const char js_import_str[]; extern const char js_in_str[]; extern const char js_instanceof_str[]; extern const char js_interface_str[]; -extern const char js_new_str[]; extern const char js_package_str[]; extern const char js_private_str[]; extern const char js_protected_str[]; diff --git a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js index 122b7dce9973..d362e37e9dea 100644 --- a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js +++ b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js @@ -170,9 +170,15 @@ function arrowExpr(args, body) { body: body }); } -function newTarget() { - return Pattern({ type: "NewTargetExpression" }); +function metaProperty(meta, property) { + return Pattern({ type: "MetaProperty", + meta: meta, + property: property }); } +function newTarget() { + return metaProperty(ident("new"), ident("target")); +} + function unExpr(op, arg) { return Pattern({ type: "UnaryExpression", operator: op, argument: arg }); } diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index f9db5d60a408..1d5c2aeae5d1 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -150,6 +150,7 @@ macro(multiline, multiline, "multiline") \ macro(name, name, "name") \ macro(NaN, NaN, "NaN") \ + macro(new, new_, "new") \ macro(next, next, "next") \ macro(NFC, NFC, "NFC") \ macro(NFD, NFD, "NFD") \ diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 67372674d57a..9f88e22b8dfd 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -769,7 +769,7 @@ * Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval * nuses: (argc+3) */ \ - macro(JSOP_NEW, 82, js_new_str, NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \ + macro(JSOP_NEW, 82, "new", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \ /* * Pushes newly created object onto the stack with provided [[Prototype]]. *