Bug 1168992 - Part 2: Fix reflection of new.target. (r=Waldo)
☠☠ backed out by 5e7324701130 ☠ ☠
authorEric Faust <efaustbmo@gmail.com>
Wed, 02 Sep 2015 15:09:03 -0700
changeset 260641 a14eb650f5be7810203729832da49a95a802306b
parent 260640 a05bfd76c34c42dd351cd96d68bdfefb4115d597
child 260642 4f7c8a5677070cfd021dd205c90d60cebc449ee2
push id29318
push usercbook@mozilla.com
push dateThu, 03 Sep 2015 11:15:07 +0000
treeherdermozilla-central@74fbd245369c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1168992
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1168992 - Part 2: Fix reflection of new.target. (r=Waldo)
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FoldConstants.cpp
js/src/frontend/FullParseHandler.h
js/src/frontend/NameFunctions.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/SyntaxParseHandler.h
js/src/jsast.tbl
js/src/jsatom.cpp
js/src/jsatom.h
js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
js/src/vm/CommonPropertyNames.h
js/src/vm/Opcodes.h
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -751,17 +751,17 @@ class NodeBuilder
     bool comprehensionIf(HandleValue test, TokenPos* pos, MutableHandleValue dst);
 
     bool comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
                                  bool isLegacy, TokenPos* pos, MutableHandleValue dst);
 
     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
      */
 
     bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
                              MutableHandleValue dst);
 
@@ -1821,23 +1821,26 @@ NodeBuilder::classDefinition(bool expr, 
     return newNode(type, pos,
                    "id", name,
                    "superClass", heritage,
                    "body", block,
                    dst);
 }
 
 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 newNode(AST_NEWTARGET_EXPR, pos, dst);
+        return callback(cb, meta, property, pos, dst);
+
+    return newNode(AST_METAPROPERTY, pos,
+                   "meta", meta,
+                   "property", property,
+                   dst);
 }
 
 namespace {
 
 /*
  * Serialization of parse nodes to JavaScript objects.
  *
  * All serialization methods take a non-nullable ParseNode pointer.
@@ -3307,17 +3310,32 @@ ASTSerializer::expression(ParseNode* pn,
         /* NB: it's no longer the case that pn_count could be 2. */
         LOCAL_ASSERT(pn->pn_count == 1);
         return comprehension(pn->pn_head, dst);
 
       case PNK_CLASS:
         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");
     }
 }
 
 bool
 ASTSerializer::propertyName(ParseNode* pn, MutableHandleValue dst)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1910,33 +1910,40 @@ bool
 BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
 {
     JS_CHECK_RECURSION(cx, return false);
 
  restart:
 
     switch (pn->getKind()) {
       // Trivial cases with no side effects.
-      case PNK_NEWTARGET:
       case PNK_NOP:
       case PNK_STRING:
       case PNK_TEMPLATE_STRING:
       case PNK_REGEXP:
       case PNK_TRUE:
       case PNK_FALSE:
       case PNK_NULL:
       case PNK_THIS:
       case PNK_ELISION:
       case PNK_GENERATOR:
       case PNK_NUMBER:
       case PNK_OBJECT_PROPERTY_NAME:
         MOZ_ASSERT(pn->isArity(PN_NULLARY));
         *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:
         MOZ_ASSERT(pn->isArity(PN_NULLARY));
         *answer = true;
         return true;
 
       // Watch out for getters!
@@ -2315,16 +2322,17 @@ BytecodeEmitter::checkSideEffects(ParseN
       case PNK_CLASSNAMES:      // by PNK_CLASS
       case PNK_CLASSMETHODLIST: // by PNK_CLASS
       case PNK_IMPORT_SPEC_LIST: // by PNK_IMPORT
       case PNK_IMPORT_SPEC:      // by PNK_IMPORT
       case PNK_EXPORT_BATCH_SPEC:// by PNK_EXPORT
       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
         MOZ_CRASH("invalid node kind");
     }
 
     MOZ_CRASH("invalid, unenumerated ParseNodeKind value encountered in "
               "BytecodeEmitter::checkSideEffects");
@@ -8083,16 +8091,19 @@ BytecodeEmitter::emitTree(ParseNode* pn)
         ok = emitClass(pn);
         break;
 
       case PNK_NEWTARGET:
         if (!emit1(JSOP_NEWTARGET))
             return false;
         break;
 
+      case PNK_POSHOLDER:
+        MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");
+
       default:
         MOZ_ASSERT(0);
     }
 
     /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
     if (ok && emitLevel == 1) {
         if (!updateSourceCoordNotes(pn->pn_pos.end))
             return false;
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -412,16 +412,17 @@ ContainsHoistedDeclaration(ExclusiveCont
       case PNK_FORHEAD:
       case PNK_FRESHENBLOCK:
       case PNK_CLASSMETHOD:
       case PNK_CLASSMETHODLIST:
       case PNK_CLASSNAMES:
       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");
 
       case PNK_GLOBALCONST:
         MOZ_CRASH("ContainsHoistedDeclaration is only called on nested nodes where "
                   "globalconst nodes should never have been generated");
 
       case PNK_LIMIT: // invalid sentinel value
@@ -1704,17 +1705,16 @@ FoldName(ExclusiveContext* cx, ParseNode
 bool
 Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bool inGenexpLambda)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     ParseNode* pn = *pnp;
 
     switch (pn->getKind()) {
-      case PNK_NEWTARGET:
       case PNK_NOP:
       case PNK_REGEXP:
       case PNK_STRING:
       case PNK_TRUE:
       case PNK_FALSE:
       case PNK_NULL:
       case PNK_ELISION:
       case PNK_NUMBER:
@@ -1723,16 +1723,17 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_CONTINUE:
       case PNK_TEMPLATE_STRING:
       case PNK_THIS:
       case PNK_GENERATOR:
       case PNK_EXPORT_BATCH_SPEC:
       case PNK_OBJECT_PROPERTY_NAME:
       case PNK_SUPERPROP:
       case PNK_FRESHENBLOCK:
+      case PNK_POSHOLDER:
         MOZ_ASSERT(pn->isArity(PN_NULLARY));
         return true;
 
       case PNK_TYPEOFNAME:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
         MOZ_ASSERT(!pn->pn_kid->maybeExpr());
         return true;
@@ -1913,16 +1914,22 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_FOR:
       case PNK_CLASSMETHOD:
       case PNK_IMPORT_SPEC:
       case PNK_EXPORT_SPEC:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         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) {
             if (!Fold(cx, &outerBinding, parser, inGenexpLambda))
                 return false;
         }
         return Fold(cx, &pn->pn_right, parser, inGenexpLambda);
 
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -347,18 +347,21 @@ class FullParseHandler
         return new_<ClassNames>(outer, inner, pos);
     }
     ParseNode* newSuperProperty(JSAtom* atom, const TokenPos& pos) {
         return new_<SuperProperty>(atom, pos);
     }
     ParseNode* newSuperElement(ParseNode* expr, const TokenPos& pos) {
         return new_<SuperElement>(expr, pos);
     }
-    ParseNode* newNewTarget(const TokenPos& pos) {
-        return new_<NullaryNode>(PNK_NEWTARGET, pos);
+    ParseNode* newNewTarget(ParseNode* newHolder, ParseNode* targetHolder) {
+        return new_<BinaryNode>(PNK_NEWTARGET, JSOP_NOP, newHolder, targetHolder);
+    }
+    ParseNode* newPosHolder(const TokenPos& pos) {
+        return new_<NullaryNode>(PNK_POSHOLDER, pos);
     }
 
     bool addPrototypeMutation(ParseNode* literal, uint32_t begin, ParseNode* expr) {
         // Object literals with mutated [[Prototype]] are non-constant so that
         // singleton objects will have Object.prototype as their [[Prototype]].
         setListFlag(literal, PNX_NONCONST);
 
         ParseNode* mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr);
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -372,26 +372,31 @@ class NameResolver
           case PNK_NUMBER:
           case PNK_BREAK:
           case PNK_CONTINUE:
           case PNK_DEBUGGER:
           case PNK_EXPORT_BATCH_SPEC:
           case PNK_FRESHENBLOCK:
           case PNK_SUPERPROP:
           case PNK_OBJECT_PROPERTY_NAME:
-          case PNK_NEWTARGET:
             MOZ_ASSERT(cur->isArity(PN_NULLARY));
             break;
 
           case PNK_TYPEOFNAME:
             MOZ_ASSERT(cur->isArity(PN_UNARY));
             MOZ_ASSERT(cur->pn_kid->isKind(PNK_NAME));
             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:
           case PNK_NOT:
           case PNK_BITNOT:
           case PNK_THROW:
           case PNK_DELETENAME:
           case PNK_DELETEPROP:
@@ -774,16 +779,17 @@ class NameResolver
             break;
 
           // Kinds that should be handled by parent node resolution.
 
           case PNK_IMPORT_SPEC: // by PNK_IMPORT_SPEC_LIST
           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
             MOZ_CRASH("invalid node kind");
         }
 
         nparents--;
         return true;
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -210,17 +210,17 @@ PushNodeChildren(ParseNode* pn, NodeStac
       case PNK_NUMBER:
       case PNK_BREAK:
       case PNK_CONTINUE:
       case PNK_DEBUGGER:
       case PNK_EXPORT_BATCH_SPEC:
       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");
         return PushResult::Recyclable;
 
       // Nodes with a single non-null child.
       case PNK_TYPEOFNAME:
       case PNK_TYPEOFEXPR:
@@ -280,16 +280,17 @@ PushNodeChildren(ParseNode* pn, NodeStac
       case PNK_COLON:
       case PNK_CASE:
       case PNK_SHORTHAND:
       case PNK_DOWHILE:
       case PNK_WHILE:
       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);
         stack->push(pn->pn_right);
         return PushResult::Recyclable;
       }
 
       // Named class expressions do not have outer binding nodes
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -174,16 +174,17 @@ class PackedScopeCoordinate
     F(MUTATEPROTO) \
     F(CLASS) \
     F(CLASSMETHOD) \
     F(CLASSMETHODLIST) \
     F(CLASSNAMES) \
     F(SUPERPROP) \
     F(SUPERELEM) \
     F(NEWTARGET) \
+    F(POSHOLDER) \
     \
     /* Unary operators. */ \
     F(TYPEOFNAME) \
     F(TYPEOFEXPR) \
     F(VOID) \
     F(NOT) \
     F(BITNOT) \
     \
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -8944,18 +8944,23 @@ Parser<ParseHandler>::methodDefinition(Y
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::tryNewTarget(Node &newTarget)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NEW));
 
+    newTarget = null();
+
+    Node newHolder = handler.newPosHolder(pos());
+    if (!newHolder)
+        return false;
+
     uint32_t begin = pos().begin;
-    newTarget = null();
 
     // |new| expects to look for an operand, so we will honor that.
     TokenKind next;
     if (!tokenStream.getToken(&next, TokenStream::Operand))
         return false;
 
     // Don't unget the token, since lookahead cannot handle someone calling
     // getToken() with a different modifier. Callers should inspect currentToken().
@@ -8970,17 +8975,21 @@ Parser<ParseHandler>::tryNewTarget(Node 
         return false;
     }
 
     if (!pc->sc->allowNewTarget()) {
         reportWithOffset(ParseError, false, begin, JSMSG_BAD_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;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TokenKind tt,
                                   InvokedPrediction invoked)
 {
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -276,17 +276,18 @@ class SyntaxParseHandler
 
     Node newSuperProperty(PropertyName* prop, const TokenPos& pos) {
         return NodeSuperProperty;
     }
 
     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; }
     bool addShorthand(Node literal, Node name, Node expr) { return true; }
     bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
     bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
     Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
     Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
--- a/js/src/jsast.tbl
+++ b/js/src/jsast.tbl
@@ -33,17 +33,17 @@ ASTDEF(AST_ARROW_EXPR,            "Arrow
 ASTDEF(AST_ARRAY_EXPR,            "ArrayExpression",                "arrayExpression")
 ASTDEF(AST_SPREAD_EXPR,           "SpreadExpression",               "spreadExpression")
 ASTDEF(AST_OBJECT_EXPR,           "ObjectExpression",               "objectExpression")
 ASTDEF(AST_THIS_EXPR,             "ThisExpression",                 "thisExpression")
 ASTDEF(AST_COMP_EXPR,             "ComprehensionExpression",        "comprehensionExpression")
 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")
 ASTDEF(AST_EXPR_STMT,             "ExpressionStatement",            "expressionStatement")
 ASTDEF(AST_LAB_STMT,              "LabeledStatement",               "labeledStatement")
 ASTDEF(AST_IF_STMT,               "IfStatement",                    "ifStatement")
 ASTDEF(AST_SWITCH_STMT,           "SwitchStatement",                "switchStatement")
 ASTDEF(AST_WHILE_STMT,            "WhileStatement",                 "whileStatement")
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -71,17 +71,16 @@ const char js_finally_str[]         = "f
 const char js_for_str[]             = "for";
 const char js_getter_str[]          = "getter";
 const char js_if_str[]              = "if";
 const char js_implements_str[]      = "implements";
 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";
 const char js_public_str[]          = "public";
 const char js_send_str[]            = "send";
 const char js_setter_str[]          = "setter";
 const char js_switch_str[]          = "switch";
 const char js_this_str[]            = "this";
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -171,17 +171,16 @@ extern const char js_finally_str[];
 extern const char js_for_str[];
 extern const char js_getter_str[];
 extern const char js_if_str[];
 extern const char js_implements_str[];
 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[];
 extern const char js_public_str[];
 extern const char js_send_str[];
 extern const char js_setter_str[];
 extern const char js_static_str[];
 extern const char js_super_str[];
--- a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
+++ b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
@@ -165,19 +165,25 @@ function genFunExpr(id, args, body) {
                      generator: true });
 }
 function arrowExpr(args, body) {
     return Pattern({ type: "ArrowFunctionExpression",
                      params: args,
                      body: body });
 }
 
+function metaProperty(meta, property) {
+    return Pattern({ type: "MetaProperty",
+                     meta: meta,
+                     property: property });
+}
 function newTarget() {
-    return Pattern({ type: "NewTargetExpression" });
+    return metaProperty(ident("new"), ident("target"));
 }
+
 function unExpr(op, arg) {
     return Pattern({ type: "UnaryExpression", operator: op, argument: arg });
 }
 function binExpr(op, left, right) {
     return Pattern({ type: "BinaryExpression", operator: op, left: left, right: right });
 }
 function aExpr(op, left, right) {
     return Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right });
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -145,16 +145,17 @@
     macro(minimumFractionDigits, minimumFractionDigits, "minimumFractionDigits") \
     macro(minimumIntegerDigits, minimumIntegerDigits, "minimumIntegerDigits") \
     macro(minimumSignificantDigits, minimumSignificantDigits, "minimumSignificantDigits") \
     macro(missingArguments, missingArguments, "missingArguments") \
     macro(module, module, "module") \
     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") \
     macro(NFKC, NFKC, "NFKC") \
     macro(NFKD, NFKD, "NFKD") \
     macro(nonincrementalReason, nonincrementalReason, "nonincrementalReason") \
     macro(noStack, noStack, "noStack") \
     macro(noSuchMethod, noSuchMethod, "__noSuchMethod__") \
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -764,17 +764,17 @@ 1234567890123456789012345678901234567890
      * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
      * value onto the stack.
      *   Category: Statements
      *   Type: Function
      *   Operands: uint16_t argc
      *   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]].
      *
      *   Category: Literals
      *   Type: Object
      *   Operands:
      *   Stack: proto => obj
      */ \