Backed out 4 changesets (bug 1168992) for apparently breaking reftests CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 02 Sep 2015 15:51:40 -0700
changeset 260634 c77c5698e85964fdbc3cad110c50b50737f22856
parent 260633 cf61909d89df9774843a3f8d6623039e1900e1f1
child 260635 d6a168f9d80a3e8e35c24e60ffdb5c5176694fe0
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)
bugs1168992
milestone43.0a1
backs outcb3a01796c021e38cdfcaefe64c7a8e80b56668b
45e16ff50caa40ad30f03f0caf9f0c9e9e8798b5
6155cc98258d05da277d70d53fa828f0515f1a64
0ff820964ea067091de3d6171577b6acb83f1cb9
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
Backed out 4 changesets (bug 1168992) for apparently breaking reftests CLOSED TREE Backed out changeset cb3a01796c02 (bug 1168992) Backed out changeset 45e16ff50caa (bug 1168992) Backed out changeset 6155cc98258d (bug 1168992) Backed out changeset 0ff820964ea0 (bug 1168992)
js/src/builtin/ReflectParse.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
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/jit-test/tests/modules/export-declaration.js
js/src/jsast.tbl
js/src/jsatom.cpp
js/src/jsatom.h
js/src/tests/ecma_6/Class/superPropDVG.js
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,19 +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 metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst);
-
-    bool super(TokenPos* pos, MutableHandleValue dst);
+    bool newTargetExpression(TokenPos* pos, MutableHandleValue dst);
 
     /*
      * declarations
      */
 
     bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
                              MutableHandleValue dst);
 
@@ -1816,43 +1814,30 @@ NodeBuilder::classDefinition(bool expr, 
                              TokenPos* pos, MutableHandleValue dst)
 {
     ASTType type = expr ? AST_CLASS_EXPR : AST_CLASS_STMT;
     RootedValue cb(cx, callbacks[type]);
     if (!cb.isNull())
         return callback(cb, name, heritage, block, pos, dst);
 
     return newNode(type, pos,
-                   "id", name,
-                   "superClass", heritage,
+                   "name", name,
+                   "heritage", heritage,
                    "body", block,
                    dst);
 }
 
 bool
-NodeBuilder::metaProperty(HandleValue meta, HandleValue property, TokenPos* pos, MutableHandleValue dst)
+NodeBuilder::newTargetExpression(TokenPos* pos, MutableHandleValue dst)
 {
-    RootedValue cb(cx, callbacks[AST_METAPROPERTY]);
-    if (!cb.isNull())
-        return callback(cb, meta, property, pos, dst);
-
-    return newNode(AST_METAPROPERTY, pos,
-                   "meta", meta,
-                   "property", property,
-                   dst);
-}
-
-bool
-NodeBuilder::super(TokenPos* pos, MutableHandleValue dst)
-{
-    RootedValue cb(cx, callbacks[AST_SUPER]);
+    RootedValue cb(cx, callbacks[AST_NEWTARGET_EXPR]);
     if (!cb.isNull())
         return callback(cb, pos, dst);
 
-    return newNode(AST_SUPER, pos, dst);
+    return newNode(AST_NEWTARGET_EXPR, pos, dst);
 }
 
 namespace {
 
 /*
  * Serialization of parse nodes to JavaScript objects.
  *
  * All serialization methods take a non-nullable ParseNode pointer.
@@ -3076,17 +3061,19 @@ ASTSerializer::expression(ParseNode* pn,
       case PNK_INSTANCEOF:
         return leftAssociate(pn, dst);
 
       case PNK_POW:
 	return rightAssociate(pn, dst);
 
       case PNK_DELETENAME:
       case PNK_DELETEPROP:
+      case PNK_DELETESUPERPROP:
       case PNK_DELETEELEM:
+      case PNK_DELETESUPERELEM:
       case PNK_DELETEEXPR:
       case PNK_TYPEOFNAME:
       case PNK_TYPEOFEXPR:
       case PNK_VOID:
       case PNK_NOT:
       case PNK_BITNOT:
       case PNK_POS:
       case PNK_NEG: {
@@ -3137,51 +3124,55 @@ ASTSerializer::expression(ParseNode* pn,
 
             : builder.callExpression(callee, args, &pn->pn_pos, dst);
       }
 
       case PNK_DOT:
       {
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
 
-        RootedValue expr(cx);
-        RootedValue propname(cx);
+        RootedValue expr(cx), id(cx);
         RootedAtom pnAtom(cx, pn->pn_atom);
-
-        if (pn->as<PropertyAccess>().isSuper()) {
-            if (!builder.super(&pn->pn_expr->pn_pos, &expr))
-                return false;
-        } else {
-            if (!expression(pn->pn_expr, &expr))
-                return false;
-        }
-
-        return identifier(pnAtom, nullptr, &propname) &&
-               builder.memberExpression(false, expr, propname, &pn->pn_pos, dst);
+        return expression(pn->pn_expr, &expr) &&
+               identifier(pnAtom, nullptr, &id) &&
+               builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
+      }
+
+      case PNK_SUPERPROP:
+      {
+        RootedValue superBase(cx), id(cx);
+        RootedAtom superAtom(cx, cx->names().super);
+        RootedAtom pnAtom(cx, pn->pn_atom);
+        return identifier(superAtom, nullptr, &superBase) &&
+               identifier(pnAtom, nullptr, &id) &&
+               builder.memberExpression(false, superBase, id, &pn->pn_pos, dst);
       }
 
       case PNK_ELEM:
       {
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
 
         RootedValue left(cx), right(cx);
-
-        if (pn->as<PropertyByValue>().isSuper()) {
-            if (!builder.super(&pn->pn_left->pn_pos, &left))
-                return false;
-        } else {
-            if (!expression(pn->pn_left, &left))
-                return false;
-        }
-
-        return expression(pn->pn_right, &right) &&
+        return expression(pn->pn_left, &left) &&
+               expression(pn->pn_right, &right) &&
                builder.memberExpression(true, left, right, &pn->pn_pos, dst);
       }
 
+      case PNK_SUPERELEM:
+      {
+        MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
+
+        RootedValue superBase(cx), expr(cx);
+        RootedAtom superAtom(cx, cx->names().super);
+        return identifier(superAtom, nullptr, &superBase) &&
+               expression(pn->pn_kid, &expr) &&
+               builder.memberExpression(true, superBase, expr, &pn->pn_pos, dst);
+      }
+
       case PNK_CALLSITEOBJ:
       {
         NodeVector raw(cx);
         if (!raw.reserve(pn->pn_head->pn_count))
             return false;
         for (ParseNode* next = pn->pn_head->pn_head; next; next = next->pn_next) {
             MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
 
@@ -3316,32 +3307,17 @@ 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:
-      {
-        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);
-      }
+        return builder.newTargetExpression(&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,48 +1910,47 @@ 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!
+      case PNK_SUPERPROP:
+        MOZ_ASSERT(pn->isArity(PN_NULLARY));
+        *answer = true;
+        return true;
+
+      // Again, getters.
       case PNK_DOT:
         MOZ_ASSERT(pn->isArity(PN_NAME));
         *answer = true;
         return true;
 
       // Unary cases with side effects only if the child has them.
       case PNK_TYPEOFEXPR:
       case PNK_VOID:
@@ -2007,17 +2006,19 @@ BytecodeEmitter::checkSideEffects(ParseN
       case PNK_YIELD:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         *answer = true;
         return true;
 
       // Deletion generally has side effects, even if isolated cases have none.
       case PNK_DELETENAME:
       case PNK_DELETEPROP:
+      case PNK_DELETESUPERPROP:
       case PNK_DELETEELEM:
+      case PNK_DELETESUPERELEM:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         *answer = true;
         return true;
 
       // Deletion of a non-Reference expression has side effects only through
       // evaluating the expression.
       case PNK_DELETEEXPR: {
         MOZ_ASSERT(pn->isArity(PN_UNARY));
@@ -2115,16 +2116,22 @@ BytecodeEmitter::checkSideEffects(ParseN
         return checkSideEffects(pn->pn_right, answer);
 
       // More getters.
       case PNK_ELEM:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         *answer = true;
         return true;
 
+      // Again, getters.
+      case PNK_SUPERELEM:
+        MOZ_ASSERT(pn->isArity(PN_UNARY));
+        *answer = true;
+        return true;
+
       // These affect visible names in this code, or in other code.
       case PNK_IMPORT:
       case PNK_EXPORT_FROM:
       case PNK_EXPORT_DEFAULT:
         MOZ_ASSERT(pn->isArity(PN_BINARY));
         *answer = true;
         return true;
 
@@ -2308,17 +2315,16 @@ 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");
@@ -2541,36 +2547,33 @@ BytecodeEmitter::emitNameOp(ParseNode* p
 }
 
 bool
 BytecodeEmitter::emitPropLHS(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_DOT));
     ParseNode* pn2 = pn->maybeExpr();
 
-    // Don't want super sneaking in here.
-    MOZ_ASSERT(!pn2->isKind(PNK_POSHOLDER));
-
     /*
      * 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
      * bottom up (reversing again as we go), to avoid excessive recursion.
      */
     if (pn2->isKind(PNK_DOT)) {
         ParseNode* pndot = pn2;
         ParseNode* pnup = nullptr;
         ParseNode* pndown;
         ptrdiff_t top = offset();
         for (;;) {
             /* Reverse pndot->pn_expr to point up, not down. */
             pndot->pn_offset = top;
             MOZ_ASSERT(!pndot->isUsed());
             pndown = pndot->pn_expr;
             pndot->pn_expr = pnup;
-            if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper())
+            if (!pndown->isKind(PNK_DOT))
                 break;
             pnup = pndot;
             pndot = pndown;
         }
 
         /* pndown is a primary expression, not a dotted property reference. */
         if (!emitTree(pndown))
             return false;
@@ -2640,65 +2643,94 @@ BytecodeEmitter::emitSuperPropOp(ParseNo
 }
 
 bool
 BytecodeEmitter::emitPropIncDec(ParseNode* pn)
 {
     MOZ_ASSERT(pn->pn_kid->isKind(PNK_DOT));
 
     bool post;
-    bool isSuper = pn->pn_kid->as<PropertyAccess>().isSuper();
     JSOp binop = GetIncDecInfo(pn->getKind(), &post);
 
-    if (isSuper) {
-        if (!emitSuperPropLHS())                    // THIS OBJ
-            return false;
-        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 (!emitPropLHS(pn->pn_kid))                   // OBJ
+        return false;
+    if (!emit1(JSOP_DUP))                           // OBJ OBJ
+        return false;
+    if (!emitAtomOp(pn->pn_kid, 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
         return false;
 
     if (post) {
-        if (!emit2(JSOP_PICK, 2 + isSuper))        // N? N+1 OBJ
-            return false;
-        if (!emit1(JSOP_SWAP))                     // N? OBJ N+1
-            return false;
-        if (isSuper) {
-            if (!emit2(JSOP_PICK, 3))              // N THIS N+1 OBJ
-                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 (!emit2(JSOP_PICK, 2))                   // N? N+1 OBJ
+            return false;
+        if (!emit1(JSOP_SWAP))                      // N? OBJ N+1
+            return false;
+    }
+
+    JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
     if (!emitAtomOp(pn->pn_kid, setOp))             // N? N+1
         return false;
     if (post && !emit1(JSOP_POP))                   // RESULT
         return false;
 
     return true;
 }
 
 bool
+BytecodeEmitter::emitSuperPropIncDec(ParseNode* pn)
+{
+    MOZ_ASSERT(pn->pn_kid->isKind(PNK_SUPERPROP));
+
+    bool post;
+    JSOp binop = GetIncDecInfo(pn->getKind(), &post);
+
+    if (!emitSuperPropLHS())                                // THIS OBJ
+        return false;
+
+    if (!emit1(JSOP_DUP2))                                  // THIS OBJ THIS OBJ
+        return false;
+    if (!emitAtomOp(pn->pn_kid, JSOP_GETPROP_SUPER))        // THIS OBJ V
+        return false;
+    if (!emit1(JSOP_POS))                                   // THIS OBJ N
+        return false;
+    if (post && !emit1(JSOP_DUP))                           // THIS OBJ N? N
+        return false;
+    if (!emit1(JSOP_ONE))                                   // THIS OBJ N? N 1
+        return false;
+    if (!emit1(binop))                                      // THIS OBJ N? N+1
+        return false;
+
+    if (post) {
+        if (!emit2(JSOP_PICK, 3))                           // OBJ N N+1 THIS
+            return false;
+        if (!emit1(JSOP_SWAP))                              // OBJ N THIS N+1
+            return false;
+        if (!emit2(JSOP_PICK, 3))                           // N THIS N+1 OBJ
+            return false;
+        if (!emit1(JSOP_SWAP))                              // N THIS OBJ N+1
+            return false;
+    }
+
+    JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
+    if (!emitAtomOp(pn->pn_kid, setOp))                     // N? N+1
+        return false;
+    if (post && !emit1(JSOP_POP))                           // RESULT
+        return false;
+
+    return true;
+}
+
+bool
 BytecodeEmitter::emitNameIncDec(ParseNode* pn)
 {
     const JSCodeSpec* cs = &js_CodeSpec[pn->pn_kid->getOp()];
 
     bool global = (cs->format & JOF_GNAME);
     bool post;
     JSOp binop = GetIncDecInfo(pn->getKind(), &post);
 
@@ -2749,24 +2781,24 @@ BytecodeEmitter::emitElemOperands(ParseN
     if (isSetElem && !emit2(JSOP_PICK, 2))
         return false;
     return true;
 }
 
 bool
 BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts)
 {
-    MOZ_ASSERT(pn->isKind(PNK_ELEM) && pn->as<PropertyByValue>().isSuper());
+    MOZ_ASSERT(pn->isKind(PNK_SUPERELEM));
 
     // The ordering here is somewhat screwy. We need to evaluate the propval
     // first, by spec. Do a little dance to not emit more than one JSOP_THIS.
     // Since JSOP_THIS might throw in derived class constructors, we cannot
     // just push it earlier as the receiver. We have to swap it down instead.
 
-    if (!emitTree(pn->pn_right))
+    if (!emitTree(pn->pn_kid))
         return false;
 
     // We need to convert the key to an object id first, so that we do not do
     // it inside both the GETELEM and the SETELEM.
     if (opts == SuperElem_IncDec && !emit1(JSOP_TOID))
         return false;
 
     if (!emit1(JSOP_THIS))
@@ -2826,87 +2858,110 @@ BytecodeEmitter::emitSuperElemOp(ParseNo
     return true;
 }
 
 bool
 BytecodeEmitter::emitElemIncDec(ParseNode* pn)
 {
     MOZ_ASSERT(pn->pn_kid->isKind(PNK_ELEM));
 
-    bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
-
-    if (isSuper) {
-        if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
-            return false;
-    } else {
-        if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
-            return false;
-    }
+    if (!emitElemOperands(pn->pn_kid, JSOP_GETELEM))
+        return false;
 
     bool post;
     JSOp binop = GetIncDecInfo(pn->getKind(), &post);
 
-    JSOp getOp;
-    if (isSuper) {
-        // There's no such thing as JSOP_DUP3, so we have to be creative.
-        // Note that pushing things again is no fewer JSOps.
-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY
-            return false;
-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS
-            return false;
-        if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS OBJ
-            return false;
-        getOp = JSOP_GETELEM_SUPER;
-    } else {
-        // We need to convert the key to an object id first, so that we do not do
-        // it inside both the GETELEM and the SETELEM. In the super case, this is
-        // done by emitSuperElemOperands.
-                                                        // OBJ KEY*
-        if (!emit1(JSOP_TOID))                          // OBJ KEY
-            return false;
-        if (!emit1(JSOP_DUP2))                          // OBJ KEY OBJ KEY
-            return false;
-        getOp = JSOP_GETELEM;
-    }
-    if (!emitElemOpBase(getOp))                         // OBJ KEY V
-        return false;
-    if (!emit1(JSOP_POS))                               // OBJ KEY N
-        return false;
-    if (post && !emit1(JSOP_DUP))                       // OBJ KEY N? N
-        return false;
-    if (!emit1(JSOP_ONE))                               // OBJ KEY N? N 1
-        return false;
-    if (!emit1(binop))                                  // OBJ KEY N? N+1
+    /*
+     * We need to convert the key to an object id first, so that we do not do
+     * it inside both the GETELEM and the SETELEM.
+     */
+                                                    // OBJ KEY*
+    if (!emit1(JSOP_TOID))                          // OBJ KEY
+        return false;
+    if (!emit1(JSOP_DUP2))                          // OBJ KEY OBJ KEY
+        return false;
+    if (!emitElemOpBase(JSOP_GETELEM))              // OBJ KEY V
+        return false;
+    if (!emit1(JSOP_POS))                           // OBJ KEY N
+        return false;
+    if (post && !emit1(JSOP_DUP))                   // OBJ KEY N? N
+        return false;
+    if (!emit1(JSOP_ONE))                           // OBJ KEY N? N 1
+        return false;
+    if (!emit1(binop))                              // OBJ KEY N? N+1
+        return false;
 
     if (post) {
-        if (isSuper) {
-            // We have one more value to rotate around, because of |this|
-            // on the stack
-            if (!emit2(JSOP_PICK, 4))
-                return false;
-        }
-        if (!emit2(JSOP_PICK, 3 + isSuper))             // KEY N N+1 OBJ
-            return false;
-        if (!emit2(JSOP_PICK, 3 + isSuper))             // N N+1 OBJ KEY
-            return false;
-        if (!emit2(JSOP_PICK, 2 + isSuper))             // N OBJ KEY N+1
-            return false;
-    }
-
-    JSOp setOp = isSuper ? (sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER)
-                         : (sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM);
-    if (!emitElemOpBase(setOp))                         // N? N+1
-        return false;
-    if (post && !emit1(JSOP_POP))                       // RESULT
+        if (!emit2(JSOP_PICK, 3))                   // KEY N N+1 OBJ
+            return false;
+        if (!emit2(JSOP_PICK, 3))                   // N N+1 OBJ KEY
+            return false;
+        if (!emit2(JSOP_PICK, 2))                   // N OBJ KEY N+1
+            return false;
+    }
+
+    JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
+    if (!emitElemOpBase(setOp))                     // N? N+1
+        return false;
+    if (post && !emit1(JSOP_POP))                   // RESULT
         return false;
 
     return true;
 }
 
 bool
+BytecodeEmitter::emitSuperElemIncDec(ParseNode* pn)
+{
+    MOZ_ASSERT(pn->pn_kid->isKind(PNK_SUPERELEM));
+
+    if (!emitSuperElemOperands(pn->pn_kid, SuperElem_IncDec))
+        return false;
+
+    bool post;
+    JSOp binop = GetIncDecInfo(pn->getKind(), &post);
+
+    // There's no such thing as JSOP_DUP3, so we have to be creative.
+    // Note that pushing things again is no fewer JSOps.
+    if (!emitDupAt(2))                              // KEY THIS OBJ KEY
+        return false;
+    if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS
+        return false;
+    if (!emitDupAt(2))                              // KEY THIS OBJ KEY THIS OBJ
+        return false;
+    if (!emitElemOpBase(JSOP_GETELEM_SUPER))        // KEY THIS OBJ V
+        return false;
+    if (!emit1(JSOP_POS))                           // KEY THIS OBJ N
+        return false;
+    if (post && !emit1(JSOP_DUP))                   // KEY THIS OBJ N? N
+        return false;
+    if (!emit1(JSOP_ONE))                           // KEY THIS OBJ N? N 1
+        return false;
+    if (!emit1(binop))                              // KEY THIS OBJ N? N+1
+        return false;
+
+    if (post) {
+        if (!emit2(JSOP_PICK, 4))                   // THIS OBJ N N+1 KEY
+            return false;
+        if (!emit2(JSOP_PICK, 4))                   // OBJ N N+1 KEY THIS
+            return false;
+        if (!emit2(JSOP_PICK, 4))                   // N N+1 KEY THIS OBJ
+            return false;
+        if (!emit2(JSOP_PICK, 3))                   // N KEY THIS OBJ N+1
+            return false;
+    }
+
+    JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
+    if (!emitElemOpBase(setOp))                     // N? N+1
+        return false;
+    if (post && !emit1(JSOP_POP))                   // RESULT
+        return false;
+
+    return true;
+}
+bool
 BytecodeEmitter::emitNumberOp(double dval)
 {
     int32_t ival;
     if (NumberIsInt32(dval, &ival)) {
         if (ival == 0)
             return emit1(JSOP_ZERO);
         if (ival == 1)
             return emit1(JSOP_ONE);
@@ -3723,49 +3778,57 @@ BytecodeEmitter::emitDestructuringLHS(Pa
             // See the (PNK_NAME, JSOP_SETNAME) case above.
             //
             // In `a.x = b`, `a` is evaluated first, then `b`, then a
             // JSOP_SETPROP instruction.
             //
             // In `[a.x] = [b]`, per spec, `b` is evaluated before `a`. Then we
             // need a property set -- but the operands are on the stack in the
             // wrong order for JSOP_SETPROP, so we have to add a JSOP_SWAP.
-            JSOp setOp;
-            if (target->as<PropertyAccess>().isSuper()) {
-                if (!emitSuperPropLHS())
-                    return false;
-                if (!emit2(JSOP_PICK, 2))
-                    return false;
-                setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
-            } else {
-                if (!emitTree(target->pn_expr))
-                    return false;
-                if (!emit1(JSOP_SWAP))
-                    return false;
-                setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
-            }
+            if (!emitTree(target->pn_expr))
+                return false;
+            if (!emit1(JSOP_SWAP))
+                return false;
+            JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
+            if (!emitAtomOp(target, setOp))
+                return false;
+            break;
+          }
+
+          case PNK_SUPERPROP:
+          {
+            // See comment above at PNK_DOT. Pick up the pushed value, to fix ordering.
+            if (!emitSuperPropLHS())
+                return false;
+            if (!emit2(JSOP_PICK, 2))
+                return false;
+            JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
             if (!emitAtomOp(target, setOp))
                 return false;
             break;
           }
 
           case PNK_ELEM:
           {
             // See the comment at `case PNK_DOT:` above. This case,
             // `[a[x]] = [b]`, is handled much the same way. The JSOP_SWAP
             // is emitted by emitElemOperands.
-            if (target->as<PropertyByValue>().isSuper()) {
-                JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
-                if (!emitSuperElemOp(target, setOp))
-                    return false;
-            } else {
-                JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
-                if (!emitElemOp(target, setOp))
-                    return false;
-            }
+            JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
+            if (!emitElemOp(target, setOp))
+                return false;
+            break;
+          }
+
+          case PNK_SUPERELEM:
+          {
+            // See comment above in the PNK_ELEM case. Just as there, the
+            // reordering is handled by emitSuperElemOp.
+            JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
+            if (!emitSuperElemOp(target, setOp))
+                return false;
             break;
           }
 
           case PNK_CALL:
             MOZ_ASSERT(target->pn_xflags & PNX_SETCALL);
             if (!emitTree(target))
                 return false;
 
@@ -4380,41 +4443,41 @@ BytecodeEmitter::emitAssignment(ParseNod
                     bindOp = JSOP_BINDINTRINSIC;
                 if (!emitIndex32(bindOp, atomIndex))
                     return false;
                 offset++;
             }
         }
         break;
       case PNK_DOT:
-        if (lhs->as<PropertyAccess>().isSuper()) {
-            if (!emitSuperPropLHS())
-                return false;
-            offset += 2;
-        } else {
-            if (!emitTree(lhs->expr()))
-                return false;
-            offset += 1;
-        }
+        if (!emitTree(lhs->expr()))
+            return false;
+        offset++;
+        if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
+            return false;
+        break;
+      case PNK_SUPERPROP:
+        if (!emitSuperPropLHS())
+            return false;
+        offset += 2;
         if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
             return false;
         break;
       case PNK_ELEM:
         MOZ_ASSERT(lhs->isArity(PN_BINARY));
-        if (lhs->as<PropertyByValue>().isSuper()) {
-            if (!emitSuperElemOperands(lhs))
-                return false;
-            offset += 3;
-        } else {
-            if (!emitTree(lhs->pn_left))
-                return false;
-            if (!emitTree(lhs->pn_right))
-                return false;
-            offset += 2;
-        }
+        if (!emitTree(lhs->pn_left))
+            return false;
+        if (!emitTree(lhs->pn_right))
+            return false;
+        offset += 2;
+        break;
+      case PNK_SUPERELEM:
+        if (!emitSuperElemOperands(lhs))
+            return false;
+        offset += 3;
         break;
       case PNK_ARRAY:
       case PNK_OBJECT:
         break;
       case PNK_CALL:
         MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL);
         if (!emitTree(lhs))
             return false;
@@ -4462,50 +4525,45 @@ BytecodeEmitter::emitAssignment(ParseNod
                   case JSOP_SETALIASEDVAR: op = JSOP_GETALIASEDVAR; break;
                   default: MOZ_CRASH("Bad op");
                 }
                 if (!emitVarOp(lhs, op))
                     return false;
             }
             break;
           case PNK_DOT: {
-            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);
-                getOp = isLength ? JSOP_LENGTH : JSOP_GETPROP;
-            }
-            if (!emitIndex32(getOp, atomIndex))
+            if (!emit1(JSOP_DUP))
+                return false;
+            bool isLength = (lhs->pn_atom == cx->names().length);
+            if (!emitIndex32(isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex))
                 return false;
             break;
           }
-          case PNK_ELEM: {
-            JSOp elemOp;
-            if (lhs->as<PropertyByValue>().isSuper()) {
-                if (!emitDupAt(2))
-                    return false;
-                if (!emitDupAt(2))
-                    return false;
-                if (!emitDupAt(2))
-                    return false;
-                elemOp = JSOP_GETELEM_SUPER;
-            } else {
-                if (!emit1(JSOP_DUP2))
-                    return false;
-                elemOp = JSOP_GETELEM;
-            }
-            if (!emitElemOpBase(elemOp))
+          case PNK_SUPERPROP:
+            if (!emit1(JSOP_DUP2))
+                return false;
+            if (!emitIndex32(JSOP_GETPROP_SUPER, atomIndex))
                 return false;
             break;
-          }
+          case PNK_ELEM:
+            if (!emit1(JSOP_DUP2))
+                return false;
+            if (!emitElemOpBase(JSOP_GETELEM))
+                return false;
+            break;
+          case PNK_SUPERELEM:
+            if (!emitDupAt(2))
+                return false;
+            if (!emitDupAt(2))
+                return false;
+            if (!emitDupAt(2))
+                return false;
+            if (!emitElemOpBase(JSOP_GETELEM_SUPER))
+                return false;
+            break;
           case PNK_CALL:
             /*
              * We just emitted a JSOP_SETCALL (which will always throw) and
              * popped the call's return value. Push a random value to make sure
              * the stack depth is correct.
              */
             MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL);
             if (!emit1(JSOP_NULL))
@@ -4554,32 +4612,42 @@ BytecodeEmitter::emitAssignment(ParseNod
                 return false;
         } else {
             if (!emitIndexOp(lhs->getOp(), atomIndex))
                 return false;
         }
         break;
       case PNK_DOT:
       {
-        JSOp setOp = lhs->as<PropertyAccess>().isSuper() ?
-                       (sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER) :
-                       (sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP);
+        JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP : JSOP_SETPROP;
+        if (!emitIndexOp(setOp, atomIndex))
+            return false;
+        break;
+      }
+      case PNK_SUPERPROP:
+      {
+        JSOp setOp = sc->strict() ? JSOP_STRICTSETPROP_SUPER : JSOP_SETPROP_SUPER;
         if (!emitIndexOp(setOp, atomIndex))
             return false;
         break;
       }
       case PNK_CALL:
         /* Do nothing. The JSOP_SETCALL we emitted will always throw. */
         MOZ_ASSERT(lhs->pn_xflags & PNX_SETCALL);
         break;
       case PNK_ELEM:
       {
-        JSOp setOp = lhs->as<PropertyByValue>().isSuper() ?
-                       sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER :
-                       sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
+        JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM : JSOP_SETELEM;
+        if (!emit1(setOp))
+            return false;
+        break;
+      }
+      case PNK_SUPERELEM:
+      {
+        JSOp setOp = sc->strict() ? JSOP_STRICTSETELEM_SUPER : JSOP_SETELEM_SUPER;
         if (!emit1(setOp))
             return false;
         break;
       }
       case PNK_ARRAY:
       case PNK_OBJECT:
         if (!emitDestructuringOps(lhs))
             return false;
@@ -6445,60 +6513,74 @@ bool
 BytecodeEmitter::emitDeleteProperty(ParseNode* node)
 {
     MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
     MOZ_ASSERT(node->isArity(PN_UNARY));
 
     ParseNode* propExpr = node->pn_kid;
     MOZ_ASSERT(propExpr->isKind(PNK_DOT));
 
-    if (propExpr->as<PropertyAccess>().isSuper()) {
-        // Still have to calculate the base, even though we are are going
-        // to throw unconditionally, as calculating the base could also
-        // throw.
-        if (!emit1(JSOP_SUPERBASE))
-            return false;
-
-        return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
-    }
-
     JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
     return emitPropOp(propExpr, delOp);
 }
 
 bool
+BytecodeEmitter::emitDeleteSuperProperty(ParseNode* node)
+{
+    MOZ_ASSERT(node->isKind(PNK_DELETESUPERPROP));
+    MOZ_ASSERT(node->isArity(PN_UNARY));
+    MOZ_ASSERT(node->pn_kid->isKind(PNK_SUPERPROP));
+
+    // Still have to calculate the base, even though we are are going
+    // to throw unconditionally, as calculating the base could also
+    // throw.
+    if (!emit1(JSOP_SUPERBASE))
+        return false;
+
+    return emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER);
+}
+
+bool
 BytecodeEmitter::emitDeleteElement(ParseNode* node)
 {
     MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
     MOZ_ASSERT(node->isArity(PN_UNARY));
 
     ParseNode* elemExpr = node->pn_kid;
     MOZ_ASSERT(elemExpr->isKind(PNK_ELEM));
 
-    if (elemExpr->as<PropertyByValue>().isSuper()) {
-        // Still have to calculate everything, even though we're gonna throw
-        // since it may have side effects
-        if (!emitTree(elemExpr->pn_right))
-            return false;
-
-        if (!emit1(JSOP_SUPERBASE))
-            return false;
-        if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
-            return false;
-
-        // Another wrinkle: Balance the stack from the emitter's point of view.
-        // Execution will not reach here, as the last bytecode threw.
-        return emit1(JSOP_POP);
-    }
-
     JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
     return emitElemOp(elemExpr, delOp);
 }
 
 bool
+BytecodeEmitter::emitDeleteSuperElement(ParseNode* node)
+{
+    MOZ_ASSERT(node->isKind(PNK_DELETESUPERELEM));
+    MOZ_ASSERT(node->isArity(PN_UNARY));
+
+    ParseNode* superElemExpr = node->pn_kid;
+    MOZ_ASSERT(superElemExpr->isKind(PNK_SUPERELEM));
+
+    // Still have to calculate everything, even though we're gonna throw
+    // since it may have side effects
+    MOZ_ASSERT(superElemExpr->isArity(PN_UNARY));
+    if (!emitTree(superElemExpr->pn_kid))
+        return false;
+    if (!emit1(JSOP_SUPERBASE))
+        return false;
+    if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER))
+        return false;
+
+    // Another wrinkle: Balance the stack from the emitter's point of view.
+    // Execution will not reach here, as the last bytecode threw.
+    return emit1(JSOP_POP);
+}
+
+bool
 BytecodeEmitter::emitDeleteExpression(ParseNode* node)
 {
     MOZ_ASSERT(node->isKind(PNK_DELETEEXPR));
     MOZ_ASSERT(node->isArity(PN_UNARY));
 
     ParseNode* expression = node->pn_kid;
 
     // If useless, just emit JSOP_TRUE; otherwise convert |delete <expr>| to
@@ -6647,36 +6729,34 @@ BytecodeEmitter::emitCallOrNew(ParseNode
             if (pn2->name() == cx->names().forceInterpreter)
                 return emitSelfHostedForceInterpreter(pn);
             // Fall through.
         }
         if (!emitNameOp(pn2, callop))
             return false;
         break;
       case PNK_DOT:
-        if (pn2->as<PropertyAccess>().isSuper()) {
-            if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
-                return false;
-        } else {
-            if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
+        if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
+            return false;
+        break;
+      case PNK_SUPERPROP:
+        if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
+            return false;
+        break;
+      case PNK_ELEM:
+        if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
+            return false;
+        if (callop) {
+            if (!emit1(JSOP_SWAP))
                 return false;
         }
         break;
-      case PNK_ELEM:
-        if (pn2->as<PropertyByValue>().isSuper()) {
-            if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
-                return false;
-        } else {
-            if (!emitElemOp(pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM))
-                return false;
-            if (callop) {
-                if (!emit1(JSOP_SWAP))
-                    return false;
-            }
-        }
+      case PNK_SUPERELEM:
+        if (!emitSuperElemOp(pn2, JSOP_GETELEM_SUPER, /* isCall = */ callop))
+            return false;
         break;
       case PNK_FUNCTION:
         /*
          * Top level lambdas which are immediately invoked should be
          * treated as only running once. Every time they execute we will
          * create new types and scripts for their contents, to increase
          * the quality of type information within them and enable more
          * backend optimizations. Note that this does not depend on the
@@ -6824,20 +6904,28 @@ BytecodeEmitter::emitIncOrDec(ParseNode*
 {
     /* Emit lvalue-specialized code for ++/-- operators. */
     ParseNode* pn2 = pn->pn_kid;
     switch (pn2->getKind()) {
       case PNK_DOT:
         if (!emitPropIncDec(pn))
             return false;
         break;
+      case PNK_SUPERPROP:
+        if (!emitSuperPropIncDec(pn))
+            return false;
+        break;
       case PNK_ELEM:
         if (!emitElemIncDec(pn))
             return false;
         break;
+      case PNK_SUPERELEM:
+        if (!emitSuperElemIncDec(pn))
+            return false;
+        break;
       case PNK_CALL:
         MOZ_ASSERT(pn2->pn_xflags & PNX_SETCALL);
         if (!emitTree(pn2))
             return false;
         break;
       default:
         MOZ_ASSERT(pn2->isKind(PNK_NAME));
         pn2->setOp(JSOP_SETNAME);
@@ -7791,42 +7879,48 @@ BytecodeEmitter::emitTree(ParseNode* pn)
       case PNK_DELETENAME:
         ok = emitDeleteName(pn);
         break;
 
       case PNK_DELETEPROP:
         ok = emitDeleteProperty(pn);
         break;
 
+      case PNK_DELETESUPERPROP:
+        ok = emitDeleteSuperProperty(pn);
+        break;
+
       case PNK_DELETEELEM:
         ok = emitDeleteElement(pn);
         break;
 
+      case PNK_DELETESUPERELEM:
+        ok = emitDeleteSuperElement(pn);
+        break;
+
       case PNK_DELETEEXPR:
         ok = emitDeleteExpression(pn);
         break;
 
       case PNK_DOT:
-        if (pn->as<PropertyAccess>().isSuper()) {
-            if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
-                return false;
-        } else {
-            if (!emitPropOp(pn, JSOP_GETPROP))
-                return false;
-        }
+        ok = emitPropOp(pn, JSOP_GETPROP);
+        break;
+
+      case PNK_SUPERPROP:
+        if (!emitSuperPropOp(pn, JSOP_GETPROP_SUPER))
+            return false;
         break;
 
       case PNK_ELEM:
-        if (pn->as<PropertyByValue>().isSuper()) {
-            if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
-                return false;
-        } else {
-            if (!emitElemOp(pn, JSOP_GETELEM))
-                return false;
-        }
+        ok = emitElemOp(pn, JSOP_GETELEM);
+        break;
+
+      case PNK_SUPERELEM:
+        if (!emitSuperElemOp(pn, JSOP_GETELEM_SUPER))
+            return false;
         break;
 
       case PNK_NEW:
       case PNK_TAGGED_TEMPLATE:
       case PNK_CALL:
       case PNK_GENEXP:
         ok = emitCallOrNew(pn);
         break;
@@ -7989,19 +8083,16 @@ 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/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -549,17 +549,19 @@ struct BytecodeEmitter
     bool emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs);
 
     bool emitReturn(ParseNode* pn);
     bool emitStatement(ParseNode* pn);
     bool emitStatementList(ParseNode* pn, ptrdiff_t top);
 
     bool emitDeleteName(ParseNode* pn);
     bool emitDeleteProperty(ParseNode* pn);
+    bool emitDeleteSuperProperty(ParseNode* pn);
     bool emitDeleteElement(ParseNode* pn);
+    bool emitDeleteSuperElement(ParseNode* pn);
     bool emitDeleteExpression(ParseNode* pn);
 
     // |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
     bool emitTypeof(ParseNode* node, JSOp op);
 
     bool emitLogical(ParseNode* pn);
     bool emitUnary(ParseNode* pn);
 
@@ -604,17 +606,19 @@ struct BytecodeEmitter
     //
     // Please refer the comment above emitSpread for additional information about
     // stack convention.
     bool emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top);
 
     bool emitClass(ParseNode* pn);
     bool emitSuperPropLHS(bool isCall = false);
     bool emitSuperPropOp(ParseNode* pn, JSOp op, bool isCall = false);
+    bool emitSuperPropIncDec(ParseNode* pn);
     enum SuperElemOptions { SuperElem_Get, SuperElem_Set, SuperElem_Call, SuperElem_IncDec };
     bool emitSuperElemOperands(ParseNode* pn, SuperElemOptions opts = SuperElem_Get);
     bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
+    bool emitSuperElemIncDec(ParseNode* pn);
 };
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_BytecodeEmitter_h */
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -329,17 +329,19 @@ ContainsHoistedDeclaration(ExclusiveCont
       case PNK_CONDITIONAL:
       case PNK_TYPEOFNAME:
       case PNK_TYPEOFEXPR:
       case PNK_VOID:
       case PNK_NOT:
       case PNK_BITNOT:
       case PNK_DELETENAME:
       case PNK_DELETEPROP:
+      case PNK_DELETESUPERPROP:
       case PNK_DELETEELEM:
+      case PNK_DELETESUPERELEM:
       case PNK_DELETEEXPR:
       case PNK_POS:
       case PNK_NEG:
       case PNK_PREINCREMENT:
       case PNK_POSTINCREMENT:
       case PNK_PREDECREMENT:
       case PNK_POSTDECREMENT:
       case PNK_OR:
@@ -407,18 +409,19 @@ ContainsHoistedDeclaration(ExclusiveCont
       case PNK_CATCH:
       case PNK_FORIN:
       case PNK_FOROF:
       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
@@ -624,44 +627,46 @@ FoldDeleteExpr(ExclusiveContext* cx, Par
 
     return true;
 }
 
 static bool
 FoldDeleteElement(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
                   bool inGenexpLambda)
 {
-    MOZ_ASSERT(node->isKind(PNK_DELETEELEM));
+    MOZ_ASSERT(node->isKind(PNK_DELETEELEM) || node->isKind(PNK_DELETESUPERELEM));
     MOZ_ASSERT(node->isArity(PN_UNARY));
-    MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM));
+    MOZ_ASSERT(node->pn_kid->isKind(PNK_ELEM) || node->pn_kid->isKind(PNK_SUPERELEM));
 
     ParseNode*& expr = node->pn_kid;
     if (!Fold(cx, &expr, parser, inGenexpLambda))
         return false;
 
     // If we're deleting an element, but constant-folding converted our
     // element reference into a dotted property access, we must *also*
     // morph the node's kind.
     //
     // In principle this also applies to |super["foo"] -> super.foo|,
     // but we don't constant-fold |super["foo"]| yet.
-    MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
-    if (expr->isKind(PNK_DOT))
-        node->setKind(PNK_DELETEPROP);
+    if (node->isKind(PNK_DELETEELEM)) {
+        MOZ_ASSERT(expr->isKind(PNK_ELEM) || expr->isKind(PNK_DOT));
+        if (expr->isKind(PNK_DOT))
+            node->setKind(PNK_DELETEPROP);
+    }
 
     return true;
 }
 
 static bool
 FoldDeleteProperty(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
                    bool inGenexpLambda)
 {
-    MOZ_ASSERT(node->isKind(PNK_DELETEPROP));
+    MOZ_ASSERT(node->isKind(PNK_DELETEPROP) || node->isKind(PNK_DELETESUPERPROP));
     MOZ_ASSERT(node->isArity(PN_UNARY));
-    MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT));
+    MOZ_ASSERT(node->pn_kid->isKind(PNK_DOT) || node->pn_kid->isKind(PNK_SUPERPROP));
 
     ParseNode*& expr = node->pn_kid;
 #ifdef DEBUG
     ParseNodeKind oldKind = expr->getKind();
 #endif
 
     if (!Fold(cx, &expr, parser, inGenexpLambda))
         return false;
@@ -1699,34 +1704,35 @@ 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:
       case PNK_DEBUGGER:
       case PNK_BREAK:
       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;
@@ -1739,19 +1745,21 @@ Fold(ExclusiveContext* cx, ParseNode** p
         MOZ_ASSERT(pn->pn_kid->isKind(PNK_NAME));
         return true;
       }
 
       case PNK_DELETEEXPR:
         return FoldDeleteExpr(cx, pn, parser, inGenexpLambda);
 
       case PNK_DELETEELEM:
+      case PNK_DELETESUPERELEM:
         return FoldDeleteElement(cx, pn, parser, inGenexpLambda);
 
       case PNK_DELETEPROP:
+      case PNK_DELETESUPERPROP:
         return FoldDeleteProperty(cx, pn, parser, inGenexpLambda);
 
       case PNK_CONDITIONAL:
         return FoldConditional(cx, pnp, parser, inGenexpLambda);
 
       case PNK_IF:
         return FoldIf(cx, pnp, parser, inGenexpLambda);
 
@@ -1769,16 +1777,17 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_POSTDECREMENT:
         return FoldIncrementDecrement(cx, pn, parser, inGenexpLambda);
 
       case PNK_THROW:
       case PNK_ARRAYPUSH:
       case PNK_MUTATEPROTO:
       case PNK_COMPUTED_NAME:
       case PNK_SPREAD:
+      case PNK_SUPERELEM:
       case PNK_EXPORT:
       case PNK_EXPORT_DEFAULT:
       case PNK_VOID:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
 
       case PNK_SEMI:
         MOZ_ASSERT(pn->isArity(PN_UNARY));
@@ -1904,22 +1913,16 @@ 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
@@ -68,17 +68,19 @@ class FullParseHandler
 
     /* new_ methods for creating parse nodes. These report OOM on context. */
     JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
 
     typedef ParseNode* Node;
     typedef Definition* DefinitionNode;
 
     bool isPropertyAccess(ParseNode* node) {
-        return node->isKind(PNK_DOT) || node->isKind(PNK_ELEM);
+        if (node->isKind(PNK_DOT) || node->isKind(PNK_ELEM))
+            return true;
+        return node->isKind(PNK_SUPERPROP) || node->isKind(PNK_SUPERELEM);
     }
 
     bool isFunctionCall(ParseNode* node) {
         // Note: super() is a special form, *not* a function call.
         return node->isKind(PNK_CALL);
     }
 
     static bool isUnparenthesizedDestructuringPattern(ParseNode* node) {
@@ -218,19 +220,23 @@ class FullParseHandler
         if (expr->isKind(PNK_NAME)) {
             expr->pn_dflags |= PND_DEOPTIMIZED;
             expr->setOp(JSOP_DELNAME);
             return newUnary(PNK_DELETENAME, JSOP_NOP, begin, expr);
         }
 
         if (expr->isKind(PNK_DOT))
             return newUnary(PNK_DELETEPROP, JSOP_NOP, begin, expr);
+        if (expr->isKind(PNK_SUPERPROP))
+            return newUnary(PNK_DELETESUPERPROP, JSOP_NOP, begin, expr);
 
         if (expr->isKind(PNK_ELEM))
             return newUnary(PNK_DELETEELEM, JSOP_NOP, begin, expr);
+        if (expr->isKind(PNK_SUPERELEM))
+            return newUnary(PNK_DELETESUPERELEM, JSOP_NOP, begin, expr);
 
         return newUnary(PNK_DELETEEXPR, JSOP_NOP, begin, expr);
     }
 
     ParseNode* newTypeof(uint32_t begin, ParseNode* kid) {
         TokenPos pos(begin, kid->pn_pos.end);
         ParseNodeKind kind = kid->isKind(PNK_NAME) ? PNK_TYPEOFNAME : PNK_TYPEOFEXPR;
         return new_<UnaryNode>(kind, JSOP_NOP, pos, kid);
@@ -335,30 +341,24 @@ class FullParseHandler
         return new_<ClassNode>(name, heritage, methodBlock);
     }
     ParseNode* newClassMethodList(uint32_t begin) {
         return new_<ListNode>(PNK_CLASSMETHODLIST, TokenPos(begin, begin + 1));
     }
     ParseNode* newClassNames(ParseNode* outer, ParseNode* inner, const TokenPos& pos) {
         return new_<ClassNames>(outer, inner, 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);
+    ParseNode* newSuperProperty(JSAtom* atom, const TokenPos& pos) {
+        return new_<SuperProperty>(atom, pos);
     }
-    ParseNode* newSuperBase(const TokenPos& pos, ExclusiveContext* cx) {
-        ParseNode* node = newPosHolder(pos);
-#ifdef DEBUG
-        // Set the atom for assertion purposes
-        if (node)
-            node->pn_atom = cx->names().super;
-#endif
-        return node;
+    ParseNode* newSuperElement(ParseNode* expr, const TokenPos& pos) {
+        return new_<SuperElement>(expr, pos);
+    }
+    ParseNode* newNewTarget(const TokenPos& pos) {
+        return new_<NullaryNode>(PNK_NEWTARGET, 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);
@@ -706,21 +706,16 @@ class FullParseHandler
     }
 
     bool isStatementPermittedAfterReturnStatement(ParseNode *node) {
         ParseNodeKind kind = node->getKind();
         return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW ||
                (kind == PNK_SEMI && !node->pn_kid);
     }
 
-    bool isSuperBase(ParseNode* node, ExclusiveContext* cx) {
-        MOZ_ASSERT_IF(node->isKind(PNK_POSHOLDER), node->pn_atom == cx->names().super);
-        return node->isKind(PNK_POSHOLDER);
-    }
-
     inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
 
     void setBeginPosition(ParseNode* pn, ParseNode* oth) {
         setBeginPosition(pn, oth->pn_pos.begin);
     }
     void setBeginPosition(ParseNode* pn, uint32_t begin) {
         pn->pn_pos.begin = begin;
         MOZ_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -370,52 +370,51 @@ class NameResolver
           case PNK_ELISION:
           case PNK_GENERATOR:
           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:
+          case PNK_DELETESUPERPROP:
           case PNK_DELETEELEM:
+          case PNK_DELETESUPERELEM:
           case PNK_DELETEEXPR:
           case PNK_NEG:
           case PNK_POS:
           case PNK_PREINCREMENT:
           case PNK_POSTINCREMENT:
           case PNK_PREDECREMENT:
           case PNK_POSTDECREMENT:
           case PNK_COMPUTED_NAME:
           case PNK_ARRAYPUSH:
           case PNK_SPREAD:
           case PNK_MUTATEPROTO:
+          case PNK_SUPERELEM:
           case PNK_EXPORT:
           case PNK_EXPORT_DEFAULT:
             MOZ_ASSERT(cur->isArity(PN_UNARY));
             if (!resolve(cur->pn_kid, prefix))
                 return false;
             break;
 
           // Nodes with a single nullable child.
@@ -436,40 +435,33 @@ class NameResolver
           case PNK_BITANDASSIGN:
           case PNK_LSHASSIGN:
           case PNK_RSHASSIGN:
           case PNK_URSHASSIGN:
           case PNK_MULASSIGN:
           case PNK_DIVASSIGN:
           case PNK_MODASSIGN:
           case PNK_POWASSIGN:
+          case PNK_ELEM:
           case PNK_COLON:
           case PNK_CASE:
           case PNK_SHORTHAND:
           case PNK_DOWHILE:
           case PNK_WHILE:
           case PNK_SWITCH:
           case PNK_LETBLOCK:
           case PNK_FOR:
           case PNK_CLASSMETHOD:
             MOZ_ASSERT(cur->isArity(PN_BINARY));
             if (!resolve(cur->pn_left, prefix))
                 return false;
             if (!resolve(cur->pn_right, prefix))
                 return false;
             break;
 
-          case PNK_ELEM:
-            MOZ_ASSERT(cur->isArity(PN_BINARY));
-            if (!cur->as<PropertyByValue>().isSuper() && !resolve(cur->pn_left, prefix))
-                return false;
-            if (!resolve(cur->pn_right, prefix))
-                return false;
-            break;
-
           case PNK_WITH:
             MOZ_ASSERT(cur->isArity(PN_BINARY_OBJ));
             if (!resolve(cur->pn_left, prefix))
                 return false;
             if (!resolve(cur->pn_right, prefix))
                 return false;
             break;
 
@@ -755,28 +747,19 @@ class NameResolver
                 MOZ_ASSERT(catchNode->expr()->isKind(PNK_CATCH));
                 MOZ_ASSERT(catchNode->expr()->isArity(PN_TERNARY));
                 if (!resolve(catchNode->expr(), prefix))
                     return false;
             }
             break;
           }
 
+          case PNK_LABEL:
           case PNK_DOT:
             MOZ_ASSERT(cur->isArity(PN_NAME));
-
-            // Super prop nodes do not have a meaningful LHS
-            if (cur->as<PropertyAccess>().isSuper())
-                break;
-            if (!resolve(cur->expr(), prefix))
-                return false;
-            break;
-
-          case PNK_LABEL:
-            MOZ_ASSERT(cur->isArity(PN_NAME));
             if (!resolve(cur->expr(), prefix))
                 return false;
             break;
 
           case PNK_LEXICALSCOPE:
           case PNK_NAME:
             MOZ_ASSERT(cur->isArity(PN_NAME));
             if (!resolve(cur->maybeExpr(), prefix))
@@ -791,17 +774,16 @@ 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, PNK_DOT
             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
@@ -209,45 +209,49 @@ PushNodeChildren(ParseNode* pn, NodeStac
       case PNK_GENERATOR:
       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_POSHOLDER:
+      case PNK_SUPERPROP:
+      case PNK_NEWTARGET:
         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:
       case PNK_VOID:
       case PNK_NOT:
       case PNK_BITNOT:
       case PNK_THROW:
       case PNK_DELETENAME:
       case PNK_DELETEPROP:
+      case PNK_DELETESUPERPROP:
       case PNK_DELETEELEM:
+      case PNK_DELETESUPERELEM:
       case PNK_DELETEEXPR:
       case PNK_POS:
       case PNK_NEG:
       case PNK_PREINCREMENT:
       case PNK_POSTINCREMENT:
       case PNK_PREDECREMENT:
       case PNK_POSTDECREMENT:
       case PNK_COMPUTED_NAME:
       case PNK_ARRAYPUSH:
       case PNK_SPREAD:
       case PNK_MUTATEPROTO:
       case PNK_EXPORT:
       case PNK_EXPORT_DEFAULT:
+      case PNK_SUPERELEM:
         return PushUnaryNodeChild(pn, stack);
 
       // Nodes with a single nullable child.
       case PNK_SEMI: {
         MOZ_ASSERT(pn->isArity(PN_UNARY));
         if (pn->pn_kid)
             stack->push(pn->pn_kid);
         return PushResult::Recyclable;
@@ -276,17 +280,16 @@ 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
@@ -1098,20 +1101,17 @@ NameNode::dump(int indent)
             if (pn_atom->hasLatin1Chars())
                 DumpName(pn_atom->latin1Chars(nogc), pn_atom->length());
             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);
+            DumpParseTree(expr(), indent + 2);
             fputc(')', stderr);
         }
         return;
     }
 
     MOZ_ASSERT(!isUsed());
     const char* name = parseNodeNames[getKind()];
     if (isUsed())
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -133,17 +133,19 @@ class PackedScopeCoordinate
     F(CONST) \
     F(GLOBALCONST) \
     F(WITH) \
     F(RETURN) \
     F(NEW) \
     /* Delete operations.  These must be sequential. */ \
     F(DELETENAME) \
     F(DELETEPROP) \
+    F(DELETESUPERPROP) \
     F(DELETEELEM) \
+    F(DELETESUPERELEM) \
     F(DELETEEXPR) \
     F(TRY) \
     F(CATCH) \
     F(CATCHLIST) \
     F(THROW) \
     F(DEBUGGER) \
     F(GENERATOR) \
     F(YIELD) \
@@ -169,18 +171,19 @@ class PackedScopeCoordinate
     F(FRESHENBLOCK) \
     F(ARGSBODY) \
     F(SPREAD) \
     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) \
     \
@@ -424,16 +427,17 @@ IsDeleteKind(ParseNodeKind kind)
  * PNK_POSTINCREMENT,
  * PNK_PREDECREMENT,
  * PNK_POSTDECREMENT
  * PNK_NEW      list        pn_head: list of ctor, arg1, arg2, ... argN
  *                          pn_count: 1 + N (where N is number of args)
  *                          ctor is a MEMBER expr
  * PNK_DELETENAME unary     pn_kid: PNK_NAME expr
  * PNK_DELETEPROP unary     pn_kid: PNK_DOT expr
+ * PNK_DELETESUPERPROP unary pn_kid: PNK_SUPERPROP expr
  * PNK_DELETEELEM unary     pn_kid: PNK_ELEM expr
  * PNK_DELETESUPERELEM unary pn_kid: PNK_SUPERELEM expr
  * PNK_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
  * PNK_DOT      name        pn_expr: MEMBER expr to left of .
@@ -1314,43 +1318,27 @@ class PropertyAccess : public ParseNode
 
     ParseNode& expression() const {
         return *pn_u.name.expr;
     }
 
     PropertyName& name() const {
         return *pn_u.name.atom->asPropertyName();
     }
-
-    bool isSuper() const {
-        // PNK_POSHOLDER cannot result from any expression syntax.
-        return expression().isKind(PNK_POSHOLDER);
-    }
 };
 
 class PropertyByValue : public ParseNode
 {
   public:
     PropertyByValue(ParseNode* lhs, ParseNode* propExpr, uint32_t begin, uint32_t end)
       : ParseNode(PNK_ELEM, JSOP_NOP, PN_BINARY, TokenPos(begin, end))
     {
         pn_u.binary.left = lhs;
         pn_u.binary.right = propExpr;
     }
-
-    static bool test(const ParseNode& node) {
-        bool match = node.isKind(PNK_ELEM);
-        MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
-        return match;
-    }
-
-    bool isSuper() const {
-        // Like PropertyAccess above, PNK_POSHOLDER is "good enough".
-        return pn_left->isKind(PNK_POSHOLDER);
-    }
 };
 
 /*
  * A CallSiteNode represents the implicit call site object argument in a TaggedTemplate.
  */
 struct CallSiteNode : public ListNode {
     explicit CallSiteNode(uint32_t begin): ListNode(PNK_CALLSITEOBJ, TokenPos(begin, begin + 1)) {}
 
@@ -1453,16 +1441,48 @@ struct ClassNode : public TernaryNode {
         return list;
     }
     ObjectBox* scopeObject() const {
         MOZ_ASSERT(pn_kid3->is<LexicalScopeNode>());
         return pn_kid3->pn_objbox;
     }
 };
 
+struct SuperProperty : public NullaryNode {
+    SuperProperty(JSAtom* atom, const TokenPos& pos)
+      : NullaryNode(PNK_SUPERPROP, JSOP_NOP, pos, atom)
+    { }
+
+    static bool test(const ParseNode& node) {
+        bool match = node.isKind(PNK_SUPERPROP);
+        MOZ_ASSERT_IF(match, node.isArity(PN_NULLARY));
+        return match;
+    }
+
+    JSAtom* propName() const {
+        return pn_atom;
+    }
+};
+
+struct SuperElement : public UnaryNode {
+    SuperElement(ParseNode* expr, const TokenPos& pos)
+      : UnaryNode(PNK_SUPERELEM, JSOP_NOP, pos, expr)
+    { }
+
+    static bool test(const ParseNode& node) {
+        bool match = node.isKind(PNK_SUPERELEM);
+        MOZ_ASSERT_IF(match, node.isArity(PN_UNARY));
+        return match;
+    }
+
+    ParseNode* expr() const {
+        return pn_kid;
+    }
+};
+
 #ifdef DEBUG
 void DumpParseTree(ParseNode* pn, int indent = 0);
 #endif
 
 /*
  * js::Definition is a degenerate subtype of the PN_FUNC and PN_NAME variants
  * of js::ParseNode, allocated only for function, var, const, and let
  * declarations that define truly lexical bindings. This means that a child of
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4960,17 +4960,19 @@ Parser<FullParseHandler>::isValidForStat
 {
     if (isForDecl)
         return pn1->pn_count < 2 && !pn1->isKind(PNK_CONST);
 
     switch (pn1->getKind()) {
       case PNK_ARRAY:
       case PNK_CALL:
       case PNK_DOT:
+      case PNK_SUPERPROP:
       case PNK_ELEM:
+      case PNK_SUPERELEM:
       case PNK_NAME:
       case PNK_OBJECT:
         return true;
 
       default:
         return false;
     }
 }
@@ -8243,16 +8245,19 @@ Parser<ParseHandler>::memberExpr(YieldHa
                                  InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(tt));
 
     Node lhs;
 
     JS_CHECK_RECURSION(context, return null());
 
+    bool isSuper = false;
+    uint32_t superBegin = pos().begin;
+
     /* Check for new expression first. */
     if (tt == TOK_NEW) {
         uint32_t newBegin = pos().begin;
         // Make sure this wasn't a |new.target| in disguise.
         Node newTarget;
         if (!tryNewTarget(newTarget))
             return null();
         if (newTarget) {
@@ -8277,69 +8282,76 @@ Parser<ParseHandler>::memberExpr(YieldHa
                 bool isSpread = false;
                 if (!argumentList(yieldHandling, lhs, &isSpread))
                     return null();
                 if (isSpread)
                     handler.setOp(lhs, JSOP_SPREADNEW);
             }
         }
     } else if (tt == TOK_SUPER) {
-        lhs = handler.newSuperBase(pos(), context);
-        if (!lhs)
-            return null();
+        lhs = null();
+        isSuper = true;
     } else {
         lhs = primaryExpr(yieldHandling, tt, invoked);
         if (!lhs)
             return null();
     }
 
-    MOZ_ASSERT_IF(handler.isSuperBase(lhs, context), tokenStream.isCurrentTokenType(TOK_SUPER));
-
     while (true) {
         if (!tokenStream.getToken(&tt))
             return null();
         if (tt == TOK_EOF)
             break;
 
         Node nextMember;
         if (tt == TOK_DOT) {
             if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
                 return null();
             if (tt == TOK_NAME) {
                 PropertyName* field = tokenStream.currentName();
-                if (handler.isSuperBase(lhs, context) && !checkAndMarkSuperScope()) {
-                    report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
-                    return null();
+                if (isSuper) {
+                    isSuper = false;
+                    if (!checkAndMarkSuperScope()) {
+                        report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "property");
+                        return null();
+                    }
+                    nextMember = handler.newSuperProperty(field, TokenPos(superBegin, pos().end));
+                } else {
+                    nextMember = handler.newPropertyAccess(lhs, field, pos().end);
                 }
-                nextMember = handler.newPropertyAccess(lhs, field, pos().end);
                 if (!nextMember)
                     return null();
             } else {
                 report(ParseError, false, null(), JSMSG_NAME_AFTER_DOT);
                 return null();
             }
         } else if (tt == TOK_LB) {
             Node propExpr = expr(InAllowed, yieldHandling);
             if (!propExpr)
                 return null();
 
             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);
 
-            if (handler.isSuperBase(lhs, context) && !checkAndMarkSuperScope()) {
+            if (isSuper) {
+                isSuper = false;
+                if (!checkAndMarkSuperScope()) {
                     report(ParseError, false, null(), JSMSG_BAD_SUPERPROP, "member");
                     return null();
+                }
+                nextMember = handler.newSuperElement(propExpr, TokenPos(superBegin, pos().end));
+            } else {
+                nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
             }
-            nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
             if (!nextMember)
                 return null();
         } else if ((allowCallSyntax && tt == TOK_LP) ||
                    tt == TOK_TEMPLATE_HEAD ||
                    tt == TOK_NO_SUBS_TEMPLATE)
         {
-            if (handler.isSuperBase(lhs, context)) {
+            if (isSuper) {
                 // For now...
                 report(ParseError, false, null(), JSMSG_BAD_SUPER);
                 return null();
             }
 
             nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
             if (!nextMember)
                 return null();
@@ -8393,26 +8405,28 @@ Parser<ParseHandler>::memberExpr(YieldHa
                         op = JSOP_SPREADCALL;
                 }
             } else {
                 if (!taggedTemplate(yieldHandling, nextMember, tt))
                     return null();
             }
             handler.setOp(nextMember, op);
         } else {
+            if (isSuper) {
+                report(ParseError, false, null(), JSMSG_BAD_SUPER);
+                return null();
+            }
             tokenStream.ungetToken();
-            if (handler.isSuperBase(lhs, context))
-                break;
             return lhs;
         }
 
         lhs = nextMember;
     }
 
-    if (handler.isSuperBase(lhs, context)) {
+    if (isSuper) {
         report(ParseError, false, null(), JSMSG_BAD_SUPER);
         return null();
     }
 
     return lhs;
 }
 
 template <typename ParseHandler>
@@ -8930,24 +8944,19 @@ Parser<ParseHandler>::methodDefinition(Y
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::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))
         return false;
 
     // Don't unget the token, since lookahead cannot handle someone calling
     // getToken() with a different modifier. Callers should inspect currentToken().
     if (next != TOK_DOT)
@@ -8961,21 +8970,17 @@ Parser<ParseHandler>::tryNewTarget(Node 
         return false;
     }
 
     if (!pc->sc->allowNewTarget()) {
         reportWithOffset(ParseError, false, begin, JSMSG_BAD_NEWTARGET);
         return false;
     }
 
-    Node targetHolder = handler.newPosHolder(pos());
-    if (!targetHolder)
-        return false;
-
-    newTarget = handler.newNewTarget(newHolder, targetHolder);
+    newTarget = handler.newNewTarget(TokenPos(begin, pos().end));
     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
@@ -42,16 +42,19 @@ class SyntaxParseHandler
         NodeGetProp,
         NodeStringExprStatement,
         NodeReturn,
         NodeHoistableDeclaration,
         NodeBreak,
         NodeThrow,
         NodeEmptyStatement,
 
+        NodeSuperProperty,
+        NodeSuperElement,
+
         // This is needed for proper assignment-target handling.  ES6 formally
         // requires function calls *not* pass IsValidSimpleAssignmentTarget,
         // but at last check there were still sites with |f() = 5| and similar
         // in code not actually executed (or at least not executed enough to be
         // noticed).
         NodeFunctionCall,
 
         // Nodes representing *parenthesized* IsValidSimpleAssignmentTarget
@@ -124,26 +127,23 @@ class SyntaxParseHandler
         // equality checks.  (Think |if (x = y)| versus |if (x == y)|.)  Thus
         // we need this to treat |if (x = y)| as a possible typo and
         // |if ((x = y))| as a deliberate assignment within a condition.
         //
         // (Technically this isn't needed, as these are *only* extraWarnings
         // warnings, and parsing with that option disables syntax parsing.  But
         // it seems best to be consistent, and perhaps the syntax parser will
         // eventually enforce extraWarnings and will require this then.)
-        NodeUnparenthesizedAssignment,
-
-        // This node is necessary to determine if the LHS of a property access is
-        // super related.
-        NodeSuperBase
+        NodeUnparenthesizedAssignment
     };
     typedef Definition::Kind DefinitionNode;
 
     bool isPropertyAccess(Node node) {
-        return node == NodeDottedProperty || node == NodeElement;
+        return node == NodeDottedProperty || node == NodeElement ||
+               node == NodeSuperProperty || node == NodeSuperElement;
     }
 
     bool isFunctionCall(Node node) {
         // Note: super() is a special form, *not* a function call.
         return node == NodeFunctionCall;
     }
 
     static bool isUnparenthesizedDestructuringPattern(Node node) {
@@ -269,19 +269,24 @@ class SyntaxParseHandler
     void addArrayElement(Node literal, Node element) { }
 
     Node newCall() { return NodeFunctionCall; }
     Node newTaggedTemplate() { return NodeGeneric; }
 
     Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
     Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
 
-    Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
-    Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }
-    Node newSuperBase(const TokenPos& pos, ExclusiveContext* cx) { return NodeSuperBase; }
+    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; }
 
     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; }
@@ -426,22 +431,16 @@ class SyntaxParseHandler
         return node == NodeReturn;
     }
 
     bool isStatementPermittedAfterReturnStatement(Node pn) {
         return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow ||
                pn == NodeEmptyStatement;
     }
 
-    bool isSuperBase(Node pn, ExclusiveContext* cx) {
-        // While NodePosHolder is used in other places than just as super-base,
-        // it is unique enough for our purposes.
-        return pn == NodeSuperBase;
-    }
-
     void setOp(Node pn, JSOp op) {}
     void setBlockId(Node pn, unsigned blockid) {}
     void setFlag(Node pn, unsigned flag) {}
     void setListFlag(Node pn, unsigned flag) {}
     MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) {
         // A number of nodes have different behavior upon parenthesization, but
         // only in some circumstances.  Convert these nodes to special
         // parenthesized forms.
--- a/js/src/jit-test/tests/modules/export-declaration.js
+++ b/js/src/jit-test/tests/modules/export-declaration.js
@@ -33,17 +33,17 @@ functionDeclaration = (id, params, body)
     params: params,
     defaults: [],
     body: body,
     rest: null,
     generator: false
 });
 classDeclaration = (name) => Pattern({
     type: "ClassStatement",
-    id: name
+    name: name
 });
 variableDeclaration = (decls) => Pattern({
     type: "VariableDeclaration",
     kind: "var",
     declarations: decls
 });
 constDeclaration = (decls) => Pattern({
     type: "VariableDeclaration",
--- a/js/src/jsast.tbl
+++ b/js/src/jsast.tbl
@@ -33,18 +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_METAPROPERTY,          "MetaProperty",                   "metaProperty")
-ASTDEF(AST_SUPER,                 "Super",                          "super")
+ASTDEF(AST_NEWTARGET_EXPR,        "NewTargetExpression",            "newTargetExpression")
 
 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,16 +71,17 @@ 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,16 +171,17 @@ 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/ecma_6/Class/superPropDVG.js
+++ b/js/src/tests/ecma_6/Class/superPropDVG.js
@@ -2,24 +2,20 @@
 
 var test = `
 
 class testNonExistent {
     constructor() {
         super["prop"]();
     }
 }
-// Should fold to super.prop
-assertThrownErrorContains(() => new testNonExistent(), 'super.prop');
+assertThrownErrorContains(() => new testNonExistent(), 'super["prop"]');
 
 var ol = { testNonExistent() { super.prop(); } };
 assertThrownErrorContains(() => ol.testNonExistent(), "super.prop");
 
-var olElem = { testNonExistent() { var prop = "prop"; super[prop](); } };
-assertThrownErrorContains(() => olElem.testNonExistent(), "super[prop]");
-
 `;
 
 if (classesEnabled())
     eval(test);
 
 if (typeof reportCompare === 'function')
     reportCompare(0,0,"OK");
--- a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
+++ b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
@@ -119,32 +119,32 @@ function catchClause(id, guard, body) {
 function tryStmt(body, guarded, unguarded, fin) {
     return Pattern({ type: "TryStatement", block: body, guardedHandlers: guarded, handler: unguarded, finalizer: fin });
 }
 function letStmt(head, body) {
     return Pattern({ type: "LetStatement", head: head, body: body });
 }
 
 function superProp(id) {
-    return dotExpr(Pattern({ type: "Super" }), id);
+    return dotExpr(ident("super"), id);
 }
 function superElem(id) {
     return memExpr(ident("super"), id);
 }
 
 function classStmt(id, heritage, body) {
     return Pattern({ type: "ClassStatement",
-                     id: id,
-                     superClass: heritage,
+                     name: id,
+                     heritage: heritage,
                      body: body});
 }
 function classExpr(id, heritage, body) {
     return Pattern({ type: "ClassExpression",
-                     id: id,
-                     superClass: heritage,
+                     name: id,
+                     heritage: heritage,
                      body: body});
 }
 function classMethod(id, body, kind, static) {
     return Pattern({ type: "ClassMethod",
                      name: id,
                      body: body,
                      kind: kind,
                      static: static });
@@ -165,25 +165,19 @@ 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" });
 }
-function newTarget() {
-    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,17 +145,16 @@
     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, "new",   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+    macro(JSOP_NEW,       82, js_new_str,   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
      */ \