Bug 1499448 - Implement .initializers local variable. r=jorendorff
authorAshley Hauck <khyperia@mozilla.com>
Tue, 26 Feb 2019 21:23:46 +0000
changeset 519139 70eb46335a2ca23516774624f7ce1cbe34de56ea
parent 519138 f67d5891bef8d40fdce3c1ad266ff787cd19a4d2
child 519140 948362bfcaf31849df085dde4967379d4d50a8bc
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1499448
milestone67.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 1499448 - Implement .initializers local variable. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D21042
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2454,29 +2454,17 @@ bool BytecodeEmitter::emitInitializeInst
   FieldInitializers fieldInfo = this->fieldInitializers_;
   MOZ_ASSERT(fieldInfo.valid);
   size_t numFields = fieldInfo.numFieldInitializers;
 
   if (numFields == 0) {
     return true;
   }
 
-  PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
-                    PropOpEmitter::ObjKind::Other);
-  if (!poe.prepareForObj()) {
-    return false;
-  }
-
-  // This is guaranteed to run after super(), so we don't need TDZ checks.
-  if (!emitGetName(cx->names().dotThis)) {
-    //              [stack] THIS
-    return false;
-  }
-
-  if (!poe.emitGet(cx->names().dotInitializers)) {
+  if (!emitGetName(cx->names().dotInitializers)) {
     //              [stack] ARRAY
     return false;
   }
 
   for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
     if (fieldIndex < numFields - 1) {
       // We DUP to keep the array around (it is consumed in the bytecode below)
       // for next iterations of this loop, except for the last iteration, which
@@ -8063,59 +8051,50 @@ bool BytecodeEmitter::emitPropertyList(L
     }
   }
 
   if (numFields > 0) {
     // .initializers is a variable that stores an array of lambdas containing
     // code (the initializer) for each field. Upon an object's construction,
     // these lambdas will be called, defining the values.
 
-    PropOpEmitter poe(this, PropOpEmitter::Kind::SimpleAssignment,
-                      PropOpEmitter::ObjKind::Other);
-    if (!poe.prepareForObj()) {
-      return false;
-    }
-
-    if (!emit1(JSOP_DUP)) {
-      //            [stack] CTOR? OBJ OBJ
-      return false;
-    }
-
-    if (!poe.prepareForRhs()) {
+    NameOpEmitter noe(this, cx->names().dotInitializers,
+                      NameOpEmitter::Kind::Initialize);
+    if (!noe.prepareForRhs()) {
       return false;
     }
 
     if (!emitUint32Operand(JSOP_NEWARRAY, numFields)) {
-      //            [stack] CTOR? OBJ OBJ ARRAY
+      //            [stack] CTOR? OBJ ARRAY
       return false;
     }
 
     size_t curFieldIndex = 0;
     for (ParseNode* propdef : obj->contents()) {
       if (propdef->is<ClassField>()) {
         FunctionNode* initializer = &propdef->as<ClassField>().initializer();
         if (initializer == nullptr) {
           continue;
         }
 
         if (!emitTree(initializer)) {
-          //        [stack] CTOR? OBJ OBJ ARRAY LAMBDA
+          //        [stack] CTOR? OBJ ARRAY LAMBDA
           return false;
         }
 
         if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldIndex)) {
-          //        [stack] CTOR? OBJ OBJ ARRAY
+          //        [stack] CTOR? OBJ ARRAY
           return false;
         }
 
         curFieldIndex++;
       }
     }
 
-    if (!poe.emitAssignment(cx->names().dotInitializers)) {
+    if (!noe.emitAssignment()) {
       //            [stack] CTOR? OBJ ARRAY
       return false;
     }
 
     if (!emit1(JSOP_POP)) {
       //            [stack] CTOR? OBJ
       return false;
     }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1824,16 +1824,24 @@ GeneralParser<ParseHandler, Unit>::funct
                                                 FunctionSyntaxKind kind,
                                                 FunctionBodyType type) {
   MOZ_ASSERT(pc_->isFunctionBox());
 
 #ifdef DEBUG
   uint32_t startYieldOffset = pc_->lastYieldOffset;
 #endif
 
+  if (kind == FunctionSyntaxKind::ClassConstructor) {
+    // Don't do DerivedClassConstructor here, that gets marked after super()
+    // calls.
+    if (!noteUsedName(cx_->names().dotInitializers)) {
+      return null();
+    }
+  }
+
   Node body;
   if (type == StatementListBody) {
     bool inheritedStrict = pc_->sc()->strict();
     body = statementList(yieldHandling);
     if (!body) {
       return null();
     }
 
@@ -6759,22 +6767,20 @@ GeneralParser<ParseHandler, Unit>::class
   ParseContext::ClassStatement classStmt(pc_);
 
   RootedAtom propAtom(cx_);
 
   // A named class creates a new lexical scope with a const binding of the
   // class name for the "inner name".
   Maybe<ParseContext::Statement> innerScopeStmt;
   Maybe<ParseContext::Scope> innerScope;
-  if (className) {
-    innerScopeStmt.emplace(pc_, StatementKind::Block);
-    innerScope.emplace(this);
-    if (!innerScope->init(pc_)) {
-      return null();
-    }
+  innerScopeStmt.emplace(pc_, StatementKind::Block);
+  innerScope.emplace(this);
+  if (!innerScope->init(pc_)) {
+    return null();
   }
 
   // Because the binding definitions keep track of their blockId, we need to
   // create at least the inner binding later. Keep track of the name's position
   // in order to provide it for the nodes created later.
   TokenPos namePos = pos();
 
   Node classHeritage = null();
@@ -7003,40 +7009,45 @@ GeneralParser<ParseHandler, Unit>::class
       // Field initializers can be retrieved if the class and constructor are
       // being compiled at the same time, but we need to stash the field
       // information if the constructor is being compiled lazily.
       FieldInitializers fieldInfo(numFieldsWithInitializers);
       ctorbox->function()->lazyScript()->setFieldInitializers(fieldInfo);
     }
   }
 
+  NameNodeType innerName;
   Node nameNode = null();
-  Node membersOrBlock = classMembers;
   if (className) {
     // The inner name is immutable.
     if (!noteDeclaredName(className, DeclarationKind::Const, namePos)) {
       return null();
     }
 
-    NameNodeType innerName = newName(className, namePos);
+    innerName = newName(className, namePos);
     if (!innerName) {
       return null();
     }
-
-    Node classBlock = finishLexicalScope(*innerScope, classMembers);
-    if (!classBlock) {
-      return null();
-    }
-
-    membersOrBlock = classBlock;
-
-    // Pop the inner scope.
-    innerScope.reset();
-    innerScopeStmt.reset();
-
+  }
+
+  if (!noteDeclaredName(cx_->names().dotInitializers, DeclarationKind::Const,
+                        namePos)) {
+    return null();
+  }
+
+  Node classBlock = finishLexicalScope(*innerScope, classMembers);
+  if (!classBlock) {
+    return null();
+  }
+
+  // Pop the inner scope.
+  innerScope.reset();
+  innerScopeStmt.reset();
+
+  if (className) {
     NameNodeType outerName = null();
     if (classContext == ClassStatement) {
       // The outer name is mutable.
       if (!noteDeclaredName(className, DeclarationKind::Class, namePos)) {
         return null();
       }
 
       outerName = newName(className, namePos);
@@ -7048,17 +7059,17 @@ GeneralParser<ParseHandler, Unit>::class
     nameNode = handler_.newClassNames(outerName, innerName, namePos);
     if (!nameNode) {
       return null();
     }
   }
 
   MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
 
-  return handler_.newClass(nameNode, classHeritage, membersOrBlock,
+  return handler_.newClass(nameNode, classHeritage, classBlock,
                            TokenPos(classStartOffset, classEndOffset));
 }
 
 template <class ParseHandler, typename Unit>
 typename ParseHandler::FunctionNodeType
 GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
     HandleAtom className, uint32_t classNameOffset) {
   FunctionSyntaxKind functionSyntaxKind = FunctionSyntaxKind::ClassConstructor;
@@ -7112,16 +7123,20 @@ GeneralParser<ParseHandler, Unit>::synth
     return null();
   }
 
   auto stmtList = handler_.newStatementList(synthesizedBodyPos);
   if (!stmtList) {
     return null();
   }
 
+  if (!noteUsedName(cx_->names().dotInitializers)) {
+    return null();
+  }
+
   if (!noteUsedName(cx_->names().dotThis)) {
     return null();
   }
 
   bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
   if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
     return null();
   }