arai-a / smoosh-sync

Automation to make jsparagus and SpiderMonkey bytecode in sync
2 stars 0 forks source link

/js/src/frontend/BytecodeEmitter.cpp and 9 more files have been updated (22e3020f) #82

Closed github-actions[bot] closed 4 years ago

github-actions[bot] commented 4 years ago

Files

Changesets

Diffs

/js/src/frontend/BytecodeEmitter.cpp

--- c742e992415fb5d467ab812caf70c5d30d37d387/js/src/frontend/BytecodeEmitter.cpp
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/BytecodeEmitter.cpp
@@ -38,38 +38,40 @@
 #include "frontend/ForInEmitter.h"                // ForInEmitter
 #include "frontend/ForOfEmitter.h"                // ForOfEmitter
 #include "frontend/ForOfLoopControl.h"            // ForOfLoopControl
 #include "frontend/FunctionEmitter.h"  // FunctionEmitter, FunctionScriptEmitter, FunctionParamsEmitter
 #include "frontend/IfEmitter.h"     // IfEmitter, InternalIfEmitter, CondEmitter
 #include "frontend/LabelEmitter.h"  // LabelEmitter
 #include "frontend/LexicalScopeEmitter.h"  // LexicalScopeEmitter
 #include "frontend/ModuleSharedContext.h"  // ModuleSharedContext
+#include "frontend/NameAnalysisTypes.h"    // PrivateNameKind
 #include "frontend/NameFunctions.h"        // NameFunctions
 #include "frontend/NameOpEmitter.h"        // NameOpEmitter
 #include "frontend/ObjectEmitter.h"  // PropertyEmitter, ObjectEmitter, ClassEmitter
 #include "frontend/OptionalEmitter.h"  // OptionalEmitter
 #include "frontend/ParseNode.h"      // ParseNodeKind, ParseNode and subclasses
 #include "frontend/Parser.h"         // Parser
 #include "frontend/PropOpEmitter.h"  // PropOpEmitter
 #include "frontend/SourceNotes.h"    // SrcNote, SrcNoteType, SrcNoteWriter
 #include "frontend/SwitchEmitter.h"  // SwitchEmitter
 #include "frontend/TDZCheckCache.h"  // TDZCheckCache
 #include "frontend/TryEmitter.h"     // TryEmitter
 #include "frontend/WhileEmitter.h"   // WhileEmitter
 #include "js/CompileOptions.h"       // TransitiveCompileOptions, CompileOptions
 #include "js/friend/StackLimits.h"   // CheckRecursionLimit
+#include "util/StringBuffer.h"       // StringBuffer
 #include "vm/AsyncFunctionResolveKind.h"  // AsyncFunctionResolveKind
 #include "vm/BytecodeUtil.h"  // JOF_*, IsArgOp, IsLocalOp, SET_UINT24, SET_ICINDEX, BytecodeFallsThrough, BytecodeIsJumpTarget
 #include "vm/FunctionPrefixKind.h"  // FunctionPrefixKind
 #include "vm/GeneratorObject.h"     // AbstractGeneratorObject
 #include "vm/JSAtom.h"              // JSAtom, js_*_str
 #include "vm/JSContext.h"           // JSContext
 #include "vm/JSFunction.h"          // JSFunction,
-#include "vm/JSScript.h"  // JSScript, ScriptSourceObject, FieldInitializers, BaseScript
+#include "vm/JSScript.h"  // JSScript, ScriptSourceObject, MemberInitializers, BaseScript
 #include "vm/Opcodes.h"        // JSOp, JSOpLength_*
 #include "vm/SharedStencil.h"  // ScopeNote
 #include "vm/ThrowMsgKind.h"   // ThrowMsgKind
 #include "wasm/AsmJS.h"        // IsAsmJSModule

 #include "vm/JSObject-inl.h"  // JSObject

 using namespace js;
@@ -1692,18 +1694,21 @@ bool BytecodeEmitter::emitGetName(NameNo
   MOZ_ASSERT(name->isKind(ParseNodeKind::Name));

   RootedAtom nameAtom(cx, name->name());
   return emitGetName(nameAtom);
 }

 bool BytecodeEmitter::emitGetPrivateName(NameNode* name) {
   MOZ_ASSERT(name->isKind(ParseNodeKind::PrivateName));
+  return emitGetPrivateName(name->name());
+}

-  RootedAtom nameAtom(cx, name->name());
+bool BytecodeEmitter::emitGetPrivateName(JSAtom* name) {
+  RootedAtom nameAtom(cx, name);

   // The parser ensures the private name is present on the environment chain.
   NameLocation location = lookupName(nameAtom);
   MOZ_ASSERT(location.kind() == NameLocation::Kind::FrameSlot ||
              location.kind() == NameLocation::Kind::EnvironmentCoordinate ||
              location.kind() == NameLocation::Kind::Dynamic);

   return emitGetNameAtLocation(nameAtom, location);
@@ -2332,17 +2337,17 @@ bool BytecodeEmitter::emitSetThis(Binary
     //              [stack] NEWTHIS
     return false;
   }
   if (!noe.emitAssignment()) {
     //              [stack] NEWTHIS
     return false;
   }

-  if (!emitInitializeInstanceFields()) {
+  if (!emitInitializeInstanceMembers()) {
     return false;
   }

   return true;
 }

 bool BytecodeEmitter::defineHoistedTopLevelFunctions(ParseNode* body) {
   MOZ_ASSERT(inPrologue());
@@ -5687,23 +5692,23 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
   }

   if (funbox->isInterpreted()) {
     // Compute the field initializers data and update the funbox.
     //
     // NOTE: For a lazy function, this will be applied to any existing function
     //       in UpdateEmittedInnerFunctions().
     if (classContentsIfConstructor) {
-      mozilla::Maybe<FieldInitializers> fieldInitializers =
-          setupFieldInitializers(classContentsIfConstructor,
-                                 FieldPlacement::Instance);
-      if (!fieldInitializers) {
+      mozilla::Maybe<MemberInitializers> memberInitializers =
+          setupMemberInitializers(classContentsIfConstructor,
+                                  FieldPlacement::Instance);
+      if (!memberInitializers) {
         ReportAllocationOverflow(cx);
       }
-      funbox->setFieldInitializers(*fieldInitializers);
+      funbox->setMemberInitializers(*memberInitializers);
     }

     // A function is a run-once lambda if the following all hold:
     //  - Enclosing script must be run-once lambda or run-once top-level.
     //        `SharedContext::treatAsRunOnce()`
     //  - Function definition must not be in a loop.
     //        `BytecodeEmitter::isInLoop() == false`
     //  - Function must be an IIFE like "(function(){ })()".
@@ -8597,16 +8602,21 @@ bool BytecodeEmitter::emitPropertyList(L
     }

     BinaryNode* prop = &propdef->as<BinaryNode>();

     ParseNode* key = prop->left();
     ParseNode* propVal = prop->right();
     AccessorType accessorType;
     if (prop->is<ClassMethod>()) {
+      if (key->isKind(ParseNodeKind::PrivateName)) {
+        // Private methods are separately added to the .initializers array.
+        continue;
+      }
+
       accessorType = prop->as<ClassMethod>().accessorType();
     } else if (prop->is<PropertyDefinition>()) {
       accessorType = prop->as<PropertyDefinition>().accessorType();
     } else {
       accessorType = AccessorType::None;
     }

     auto emitValue = [this, &key, &propVal, accessorType, &pe]() {
@@ -8741,22 +8751,24 @@ bool BytecodeEmitter::emitPropertyList(L
           !propdef->as<ClassMethod>().isStatic()) {
         continue;
       }

       if (!pe.prepareForPropValue(Some(propdef->pn_pos.begin), kind)) {
         //          [stack] CTOR? OBJ CTOR?
         return false;
       }
+
       if (!emitValue()) {
         //          [stack] CTOR? OBJ CTOR? VAL
         return false;
       }

       RootedAtom keyAtom(cx, key->as<NameNode>().atom());
+
       switch (accessorType) {
         case AccessorType::None:
           if (!pe.emitInitProp(keyAtom)) {
             //      [stack] CTOR? OBJ
             return false;
           }
           break;
         case AccessorType::Getter:
@@ -9032,32 +9044,42 @@ bool BytecodeEmitter::emitObjLiteralValu
       return false;
     }
   } else {
     MOZ_CRASH("Unexpected parse node");
   }
   return true;
 }

-mozilla::Maybe<FieldInitializers> BytecodeEmitter::setupFieldInitializers(
+mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers(
     ListNode* classMembers, FieldPlacement placement) {
   bool isStatic = placement == FieldPlacement::Static;
   auto isClassField = [isStatic](ParseNode* propdef) {
     return propdef->is<ClassField>() &&
            propdef->as<ClassField>().isStatic() == isStatic;
   };
+  auto isPrivateMethod = [isStatic](ParseNode* propdef) {
+    return propdef->is<ClassMethod>() &&
+           propdef->as<ClassMethod>().name().isKind(
+               ParseNodeKind::PrivateName) &&
+           propdef->as<ClassMethod>().isStatic() == isStatic;
+  };

   size_t numFields =
       std::count_if(classMembers->contents().begin(),
                     classMembers->contents().end(), isClassField);
+  size_t numPrivateMethods =
+      std::count_if(classMembers->contents().begin(),
+                    classMembers->contents().end(), isPrivateMethod);
+
   // If there are more initializers than can be represented, return invalid.
-  if (numFields > FieldInitializers::MaxInitializers) {
+  if (numFields + numPrivateMethods > MemberInitializers::MaxInitializers) {
     return Nothing();
   }
-  return Some(FieldInitializers(numFields));
+  return Some(MemberInitializers(numFields + numPrivateMethods));
 }

 // Purpose of .fieldKeys:
 // Computed field names (`["x"] = 2;`) must be ran at class-evaluation time,
 // not object construction time. The transformation to do so is roughly as
 // follows:
 //
 // class C {
@@ -9116,136 +9138,353 @@ bool BytecodeEmitter::emitCreateFieldKey
   if (!emit1(JSOp::Pop)) {
     //              [stack]
     return false;
   }

   return true;
 }

-bool BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce,
-                                                  ListNode* obj,
-                                                  FieldPlacement placement) {
+bool BytecodeEmitter::emitCreateMemberInitializers(ClassEmitter& ce,
+                                                   ListNode* obj,
+                                                   FieldPlacement placement) {
   // FieldPlacement::Instance
   //                [stack] HOMEOBJ HERITAGE?
   //
   // FieldPlacement::Static
   //                [stack] CTOR HOMEOBJ
-  mozilla::Maybe<FieldInitializers> fieldInitializers =
-      setupFieldInitializers(obj, placement);
-  if (!fieldInitializers) {
+  mozilla::Maybe<MemberInitializers> memberInitializers =
+      setupMemberInitializers(obj, placement);
+  if (!memberInitializers) {
     ReportAllocationOverflow(cx);
     return false;
   }
-  size_t numFields = fieldInitializers->numFieldInitializers;

-  if (numFields == 0) {
+  size_t numInitializers = memberInitializers->numMemberInitializers;
+  if (numInitializers == 0) {
     return true;
   }

   bool isStatic = placement == FieldPlacement::Static;
-  if (!ce.prepareForFieldInitializers(numFields, isStatic)) {
+  if (!ce.prepareForMemberInitializers(numInitializers, isStatic)) {
     //              [stack] HOMEOBJ HERITAGE? ARRAY
     // or:
     //              [stack] CTOR HOMEOBJ ARRAY
     return false;
   }

+  // Private methods could be used in the field initializers,
+  // so we stamp them onto the instance first.
+  // Static private methods aren't implemented, so skip this step
+  // if emitting static initializers.
+  if (!isStatic && !emitPrivateMethodInitializers(ce, obj)) {
+    return false;
+  }
+
   for (ParseNode* propdef : obj->contents()) {
     if (!propdef->is<ClassField>()) {
       continue;
     }
     if (propdef->as<ClassField>().isStatic() != isStatic) {
       continue;
     }

     FunctionNode* initializer = propdef->as<ClassField>().initializer();
-    if (!ce.prepareForFieldInitializer()) {
+
+    if (!ce.prepareForMemberInitializer()) {
       return false;
     }
     if (!emitTree(initializer)) {
       //            [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
       // or:
       //            [stack] CTOR HOMEOBJ ARRAY LAMBDA
       return false;
     }
     if (initializer->funbox()->needsHomeObject()) {
       MOZ_ASSERT(initializer->funbox()->allowSuperProperty());
-      if (!ce.emitFieldInitializerHomeObject(isStatic)) {
+      if (!ce.emitMemberInitializerHomeObject(isStatic)) {
         //          [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
         // or:
         //          [stack] CTOR HOMEOBJ ARRAY LAMBDA
         return false;
       }
     }
-    if (!ce.emitStoreFieldInitializer()) {
+    if (!ce.emitStoreMemberInitializer()) {
       //            [stack] HOMEOBJ HERITAGE? ARRAY
       // or:
       //            [stack] CTOR HOMEOBJ ARRAY
       return false;
     }
   }

-  if (!ce.emitFieldInitializersEnd()) {
+  if (!ce.emitMemberInitializersEnd()) {
     //              [stack] HOMEOBJ HERITAGE?
     // or:
     //              [stack] CTOR HOMEOBJ
     return false;
   }

   return true;
 }

-const FieldInitializers& BytecodeEmitter::findFieldInitializersForCall() {
+bool BytecodeEmitter::emitPrivateMethodInitializers(ClassEmitter& ce,
+                                                    ListNode* obj) {
+  for (ParseNode* propdef : obj->contents()) {
+    if (!propdef->is<ClassMethod>()) {
+      continue;
+    }
+    ParseNode* propName = &propdef->as<ClassMethod>().name();
+    if (!propName->isKind(ParseNodeKind::PrivateName)) {
+      continue;
+    }
+
+    if (!ce.prepareForMemberInitializer()) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY
+      return false;
+    }
+
+    // Synthesize a name for the lexical variable that will store the
+    // private method body.
+    StringBuffer storedMethodName(cx);
+    if (!storedMethodName.append(propName->as<NameNode>().atom())) {
+      return false;
+    }
+    AccessorType accessorType = propdef->as<ClassMethod>().accessorType();
+    switch (accessorType) {
+      case AccessorType::None:
+        if (!storedMethodName.append(".method")) {
+          return false;
+        }
+        break;
+      case AccessorType::Getter:
+        if (!storedMethodName.append(".getter")) {
+          return false;
+        }
+        break;
+      case AccessorType::Setter:
+        if (!storedMethodName.append(".setter")) {
+          return false;
+        }
+        break;
+      default:
+        MOZ_CRASH("Invalid private method accessor type");
+    }
+    RootedAtom storedMethodAtom(cx, storedMethodName.finishAtom());
+
+    // Emit the private method body and store it as a lexical var.
+    if (!emitFunction(&propdef->as<ClassMethod>().method())) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY METHOD
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY METHOD
+      return false;
+    }
+    // The private method body needs to access the home object,
+    // and the CE knows where that is on the stack.
+    if (!ce.emitMemberInitializerHomeObject(false)) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY METHOD
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY METHOD
+      return false;
+    }
+    if (!emitLexicalInitialization(storedMethodAtom)) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY METHOD
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY METHOD
+      return false;
+    }
+    if (!emit1(JSOp::Pop)) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY
+      return false;
+    }
+
+    if (!emitPrivateMethodInitializer(ce, propdef, propName, storedMethodAtom,
+                                      accessorType)) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY
+      return false;
+    }
+
+    // Store the emitted initializer function into the .initializers array.
+    if (!ce.emitStoreMemberInitializer()) {
+      //              [stack] HOMEOBJ HERITAGE? ARRAY
+      // or:
+      //              [stack] CTOR HOMEOBJ ARRAY
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool BytecodeEmitter::emitPrivateMethodInitializer(ClassEmitter& ce,
+                                                   ParseNode* prop,
+                                                   ParseNode* propName,
+                                                   HandleAtom storedMethodAtom,
+                                                   AccessorType accessorType) {
+  // Emit the synthesized initializer function.
+  FunctionNode* funNode = prop->as<ClassMethod>().initializerIfPrivate();
+  if (!funNode) {
+    return false;
+  }
+  FunctionBox* funbox = funNode->funbox();
+  FunctionEmitter fe(this, funbox, funNode->syntaxKind(),
+                     FunctionEmitter::IsHoisted::No);
+  if (!fe.prepareForNonLazy()) {
+    //              [stack]
+    return false;
+  }
+
+  BytecodeEmitter bce2(this, parser, funbox, compilationInfo, emitterMode);
+  if (!bce2.init(funNode->pn_pos)) {
+    return false;
+  }
+  ListNode* paramsBody = &funNode->body()->as<ListNode>();
+  FunctionScriptEmitter fse(&bce2, funbox, Nothing(), Nothing());
+  if (!fse.prepareForParameters()) {
+    //              [stack]
+    return false;
+  }
+  if (!bce2.emitFunctionFormalParameters(paramsBody)) {
+    //              [stack]
+    return false;
+  }
+  if (!fse.prepareForBody()) {
+    //              [stack]
+    return false;
+  }
+
+  if (!bce2.emit1(JSOp::FunctionThis)) {
+    //              [stack] THIS
+    return false;
+  }
+  if (!bce2.emitGetPrivateName(&propName->as<NameNode>())) {
+    //              [stack] THIS NAME
+    return false;
+  }
+  if (!bce2.emitGetName(storedMethodAtom)) {
+    //              [stack] THIS NAME METHOD
+    return false;
+  }
+
+  PrivateNameKind kind = propName->as<NameNode>().privateNameKind();
+  switch (kind) {
+    case PrivateNameKind::Method:
+      if (!bce2.emit1(JSOp::InitLockedElem)) {
+        //          [stack] THIS
+        return false;
+      }
+      break;
+    case PrivateNameKind::Setter:
+      if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
+        //          [stack] THIS
+        return false;
+      }
+      if (!bce2.emitGetPrivateName(&propName->as<NameNode>())) {
+        //          [stack] THIS NAME
+        return false;
+      }
+      if (!bce2.emitAtomOp(JSOp::GetIntrinsic,
+                           cx->parserNames().NoPrivateGetter)) {
+        //          [stack] THIS NAME FUN
+        return false;
+      }
+      if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
+        //          [stack] THIS
+        return false;
+      }
+      break;
+    case PrivateNameKind::Getter:
+    case PrivateNameKind::GetterSetter:
+      if (accessorType == AccessorType::Getter) {
+        if (!bce2.emit1(JSOp::InitHiddenElemGetter)) {
+          //        [stack] THIS
+          return false;
+        }
+      } else {
+        if (!bce2.emit1(JSOp::InitHiddenElemSetter)) {
+          //        [stack] THIS
+          return false;
+        }
+      }
+      break;
+    default:
+      MOZ_CRASH("Invalid op");
+  }
+
+  if (!fse.emitEndBody()) {
+    //              [stack]
+    return false;
+  }
+  if (!fse.intoStencil()) {
+    return false;
+  }
+
+  if (!fe.emitNonLazyEnd()) {
+    //              [stack] HOMEOBJ HERITAGE? ARRAY FUN
+    // or:
+    //              [stack] CTOR HOMEOBJ ARRAY FUN
+    return false;
+  }
+
+  return true;
+}
+
+const MemberInitializers& BytecodeEmitter::findMemberInitializersForCall() {
   for (BytecodeEmitter* current = this; current; current = current->parent) {
     if (current->sc->isFunctionBox()) {
       FunctionBox* funbox = current->sc->asFunctionBox();

       if (funbox->isArrow()) {
         continue;
       }

       // If we found a non-arrow / non-constructor we were never allowed to
       // expect fields in the first place.
       MOZ_RELEASE_ASSERT(funbox->isClassConstructor());

-      MOZ_ASSERT(funbox->fieldInitializers().valid);
-      return funbox->fieldInitializers();
+      MOZ_ASSERT(funbox->memberInitializers().valid);
+      return funbox->memberInitializers();
     }
   }

-  MOZ_RELEASE_ASSERT(compilationInfo.scopeContext.fieldInitializers);
-  return *compilationInfo.scopeContext.fieldInitializers;
+  MOZ_RELEASE_ASSERT(compilationInfo.scopeContext.memberInitializers);
+  return *compilationInfo.scopeContext.memberInitializers;
 }

-bool BytecodeEmitter::emitInitializeInstanceFields() {
-  const FieldInitializers& fieldInitializers = findFieldInitializersForCall();
-  size_t numFields = fieldInitializers.numFieldInitializers;
+bool BytecodeEmitter::emitInitializeInstanceMembers() {
+  const MemberInitializers& memberInitializers =
+      findMemberInitializersForCall();
+  size_t numInitializers = memberInitializers.numMemberInitializers;

-  if (numFields == 0) {
+  if (numInitializers == 0) {
     return true;
   }

   if (!emitGetName(cx->parserNames().dotInitializers)) {
     //              [stack] ARRAY
     return false;
   }

-  for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
-    if (fieldIndex < numFields - 1) {
+  for (size_t index = 0; index < numInitializers; index++) {
+    if (index < numInitializers - 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 avoids an extra Pop at the end of the loop.
       if (!emit1(JSOp::Dup)) {
         //          [stack] ARRAY ARRAY
         return false;
       }
     }

-    if (!emitNumberOp(fieldIndex)) {
+    if (!emitNumberOp(index)) {
       //            [stack] ARRAY? ARRAY INDEX
       return false;
     }

     // Don't use CallElem here, because the receiver of the call != the
     // receiver of this getelem. (Specifically, the call receiver is `this`,
     // and the receiver of this getelem is `.initializers`)
     if (!emit1(JSOp::GetElem)) {
@@ -9917,16 +10156,68 @@ static MOZ_ALWAYS_INLINE ParseNode* Find
           methodName.as<NameNode>().atom() == cx->parserNames().constructor) {
         return classElement;
       }
     }
   }
   return nullptr;
 }

+template <class ClassMemberType>
+bool BytecodeEmitter::emitNewPrivateNames(ListNode* classMembers) {
+  for (ParseNode* classElement : classMembers->contents()) {
+    if (!classElement->is<ClassMemberType>()) {
+      continue;
+    }
+
+    ParseNode* elementName = &classElement->as<ClassMemberType>().name();
+    if (!elementName->isKind(ParseNodeKind::PrivateName)) {
+      continue;
+    }
+
+    RootedAtom privateName(cx, elementName->as<NameNode>().name());
+
+    // TODO: Add a new bytecode to create private names.
+    if (!emitAtomOp(JSOp::GetIntrinsic, cx->parserNames().NewPrivateName)) {
+      //          [stack] HERITAGE NEWPRIVATENAME
+      return false;
+    }
+
+    // Push `undefined` as `this` parameter for call.
+    if (!emit1(JSOp::Undefined)) {
+      //          [stack] HERITAGE NEWPRIVATENAME UNDEFINED
+      return false;
+    }
+
+    if (!emitAtomOp(JSOp::String, privateName)) {
+      //          [stack] HERITAGE NEWPRIVATENAME UNDEFINED NAME
+      return false;
+    }
+
+    int argc = 1;
+    if (!emitCall(JSOp::Call, argc)) {
+      //          [stack] HERITAGE PRIVATENAME
+      return false;
+    }
+
+    // Add a binding for #name => privatename
+    if (!emitLexicalInitialization(privateName)) {
+      //          [stack] HERITAGE PRIVATENAME
+      return false;
+    }
+
+    // Pop Private name off the stack.
+    if (!emit1(JSOp::Pop)) {
+      //          [stack] HERITAGE
+      return false;
+    }
+  }
+  return true;
+}
+
 // This follows ES6 14.5.14 (ClassDefinitionEvaluation) and ES6 14.5.15
 // (BindingClassDeclarationEvaluation).
 bool BytecodeEmitter::emitClass(
     ClassNode* classNode,
     ClassNameKind nameKind /* = ClassNameKind::BindingName */,
     HandleAtom nameForAnonymousClass /* = nullptr */) {
   MOZ_ASSERT((nameKind == ClassNameKind::InferredName) ==
              (nameForAnonymousClass != nullptr));
@@ -9980,62 +10271,21 @@ bool BytecodeEmitter::emitClass(
   // the heritage expression and hence the scope must be emitted after the
   // heritage expression.
   if (LexicalScopeNode* bodyScopeBindings = classNode->bodyScopeBindings()) {
     if (!ce.emitBodyScope(bodyScopeBindings->scopeBindings())) {
       //            [stack] HERITAGE
       return false;
     }

-    for (ParseNode* classElement : classNode->memberList()->contents()) {
-      if (!classElement->is<ClassField>()) {
-        continue;
-      }
-
-      ParseNode* fieldName = &classElement->as<ClassField>().name();
-      if (!fieldName->isKind(ParseNodeKind::PrivateName)) {
-        continue;
-      }
-
-      RootedAtom privateName(cx, fieldName->as<NameNode>().name());
-
-      // TODO: Add a new bytecode to create private names.
-      if (!emitAtomOp(JSOp::GetIntrinsic, cx->parserNames().NewPrivateName)) {
-        //          [stack] HERITAGE NEWPRIVATENAME
-        return false;
-      }
-
-      // Push `undefined` as `this` parameter for call.
-      if (!emit1(JSOp::Undefined)) {
-        //          [stack] HERITAGE NEWPRIVATENAME UNDEFINED
-        return false;
-      }
-
-      if (!emitAtomOp(JSOp::String, privateName)) {
-        //          [stack] HERITAGE NEWPRIVATENAME UNDEFINED NAME
-        return false;
-      }
-
-      int argc = 1;
-      if (!emitCall(JSOp::Call, argc)) {
-        //          [stack] HERITAGE PRIVATENAME
-        return false;
-      }
-
-      // Add a binding for #name => privatename
-      if (!emitLexicalInitialization(privateName)) {
-        //          [stack] HERITAGE PRIVATENAME
-        return false;
-      }
-
-      // Pop Private name off the stack.
-      if (!emit1(JSOp::Pop)) {
-        //          [stack] HERITAGE
-        return false;
-      }
+    if (!emitNewPrivateNames<ClassField>(classMembers)) {
+      return false;
+    }
+    if (!emitNewPrivateNames<ClassMethod>(classMembers)) {
+      return false;
     }
   }

   bool hasNameOnStack = nameKind == ClassNameKind::ComputedName;
   if (isDerived) {
     if (!ce.emitDerivedClass(innerName, nameForAnonymousClass,
                              hasNameOnStack)) {
       //            [stack] HERITAGE HOMEOBJ
@@ -10059,36 +10309,39 @@ bool BytecodeEmitter::emitClass(
       LexicalScopeNode* constructorScope = &constructor->as<LexicalScopeNode>();

       // The constructor scope should only contain the |.initializers| binding.
       MOZ_ASSERT(!constructorScope->isEmptyScope());
       MOZ_ASSERT(constructorScope->scopeBindings()->length == 1);
       MOZ_ASSERT(constructorScope->scopeBindings()->trailingNames[0].name() ==
                  cx->parserNames().dotInitializers);

-      auto isInstanceField = [](ParseNode* propdef) {
-        return propdef->is<ClassField>() &&
-               !propdef->as<ClassField>().isStatic();
+      auto needsInitializer = [](ParseNode* propdef) {
+        return (propdef->is<ClassField>() &&
+                !propdef->as<ClassField>().isStatic()) ||
+               (propdef->is<ClassMethod>() &&
+                propdef->as<ClassMethod>().name().isKind(
+                    ParseNodeKind::PrivateName));
       };

       // As an optimization omit the |.initializers| binding when no instance
-      // fields are present.
-      bool hasInstanceFields =
+      // fields or private methods are present.
+      bool needsInitializers =
           std::any_of(classMembers->contents().begin(),
-                      classMembers->contents().end(), isInstanceField);
-      if (hasInstanceFields) {
+                      classMembers->contents().end(), needsInitializer);
+      if (needsInitializers) {
         lse.emplace(this);
         if (!lse->emitScope(ScopeKind::Lexical,
                             constructorScope->scopeBindings())) {
           return false;
         }

         // Any class with field initializers will have a constructor
-        if (!emitCreateFieldInitializers(ce, classMembers,
-                                         FieldPlacement::Instance)) {
+        if (!emitCreateMemberInitializers(ce, classMembers,
+                                          FieldPlacement::Instance)) {
           return false;
         }
       }

       ctor = &constructorScope->scopeBody()->as<ClassMethod>().method();
     } else {
       // The |.initializers| binding is never emitted when in self-hosting mode.
       MOZ_ASSERT(emitterMode == BytecodeEmitter::SelfHosting);
@@ -10123,17 +10376,17 @@ bool BytecodeEmitter::emitClass(
       return false;
     }
   }

   if (!emitCreateFieldKeys(classMembers, FieldPlacement::Instance)) {
     return false;
   }

-  if (!emitCreateFieldInitializers(ce, classMembers, FieldPlacement::Static)) {
+  if (!emitCreateMemberInitializers(ce, classMembers, FieldPlacement::Static)) {
     return false;
   }

   if (!emitCreateFieldKeys(classMembers, FieldPlacement::Static)) {
     return false;
   }

   if (!emitPropertyList(classMembers, ce, ClassBody)) {

/js/src/frontend/BytecodeEmitter.h

--- c742e992415fb5d467ab812caf70c5d30d37d387/js/src/frontend/BytecodeEmitter.h
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/BytecodeEmitter.h
@@ -44,17 +44,17 @@
 #include "vm/BuiltinObjectKind.h"          // BuiltinObjectKind
 #include "vm/BytecodeUtil.h"               // JSOp
 #include "vm/CheckIsObjectKind.h"          // CheckIsObjectKind
 #include "vm/FunctionPrefixKind.h"         // FunctionPrefixKind
 #include "vm/GeneratorResumeKind.h"        // GeneratorResumeKind
 #include "vm/Instrumentation.h"            // InstrumentationKind
 #include "vm/Iteration.h"                  // IteratorKind
 #include "vm/JSFunction.h"                 // JSFunction
-#include "vm/JSScript.h"       // JSScript, BaseScript, FieldInitializers
+#include "vm/JSScript.h"       // JSScript, BaseScript, MemberInitializers
 #include "vm/Runtime.h"        // ReportOutOfMemory
 #include "vm/SharedStencil.h"  // GCThingIndex
 #include "vm/StencilEnums.h"   // TryNoteKind
 #include "vm/StringType.h"     // JSAtom
 #include "vm/ThrowMsgKind.h"   // ThrowMsgKind, ThrowCondition

 namespace js {
 namespace frontend {
@@ -500,26 +500,35 @@ struct MOZ_STACK_CLASS BytecodeEmitter {

   // Is a field value OBJLITERAL-compatible?
   MOZ_MUST_USE bool isRHSObjLiteralCompatible(ParseNode* value);

   MOZ_MUST_USE bool emitObjLiteralValue(ObjLiteralStencil* data,
                                         ParseNode* value);

   enum class FieldPlacement { Instance, Static };
-  mozilla::Maybe<FieldInitializers> setupFieldInitializers(
+  mozilla::Maybe<MemberInitializers> setupMemberInitializers(
       ListNode* classMembers, FieldPlacement placement);
   MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj,
                                         FieldPlacement placement);
-  MOZ_MUST_USE bool emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj,
-                                                FieldPlacement placement);
-  const FieldInitializers& findFieldInitializersForCall();
-  MOZ_MUST_USE bool emitInitializeInstanceFields();
+  MOZ_MUST_USE bool emitCreateMemberInitializers(ClassEmitter& ce,
+                                                 ListNode* obj,
+                                                 FieldPlacement placement);
+  const MemberInitializers& findMemberInitializersForCall();
+  MOZ_MUST_USE bool emitInitializeInstanceMembers();
   MOZ_MUST_USE bool emitInitializeStaticFields(ListNode* classMembers);

+  MOZ_MUST_USE bool emitPrivateMethodInitializers(ClassEmitter& ce,
+                                                  ListNode* obj);
+  MOZ_MUST_USE bool emitPrivateMethodInitializer(ClassEmitter& ce,
+                                                 ParseNode* prop,
+                                                 ParseNode* propName,
+                                                 HandleAtom storedMethodAtom,
+                                                 AccessorType accessorType);
+
   // To catch accidental misuse, emitUint16Operand/emit3 assert that they are
   // not used to unconditionally emit JSOp::GetLocal. Variable access should
   // instead be emitted using EmitVarOp. In special cases, when the caller
   // definitely knows that a given local slot is unaliased, this function may be
   // used as a non-asserting version of emitUint16Operand.
   MOZ_MUST_USE bool emitLocalOp(JSOp op, uint32_t slot);

   MOZ_MUST_USE bool emitArgOp(JSOp op, uint16_t slot);
@@ -534,16 +543,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   MOZ_MUST_USE bool emitGetName(Handle<JSAtom*> name) {
     return emitGetNameAtLocation(name, lookupName(name));
   }
   MOZ_MUST_USE bool emitGetName(ImmutablePropertyNamePtr name) {
     return emitGetNameAtLocation(name, lookupName(name));
   }
   MOZ_MUST_USE bool emitGetName(NameNode* name);
   MOZ_MUST_USE bool emitGetPrivateName(NameNode* name);
+  MOZ_MUST_USE bool emitGetPrivateName(JSAtom* name);

   MOZ_MUST_USE bool emitTDZCheckIfNeeded(HandleAtom name,
                                          const NameLocation& loc,
                                          ValueIsOnStack isOnStack);

   MOZ_MUST_USE bool emitNameIncDec(UnaryNode* incDec);

   MOZ_MUST_USE bool emitDeclarationList(ListNode* declList);
@@ -842,16 +852,19 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   }

   MOZ_MUST_USE bool emitCheckPrivateField(ThrowCondition throwCondition,
                                           ThrowMsgKind msgKind) {
     return emit3(JSOp::CheckPrivateField, uint8_t(throwCondition),
                  uint8_t(msgKind));
   }

+  template <class ClassMemberType>
+  MOZ_MUST_USE bool emitNewPrivateNames(ListNode* classMembers);
+
   MOZ_MUST_USE bool emitInstrumentation(InstrumentationKind kind,
                                         uint32_t npopped = 0) {
     return MOZ_LIKELY(!instrumentationKinds) ||
            emitInstrumentationSlow(kind, std::function<bool(uint32_t)>());
   }

   MOZ_MUST_USE bool emitInstrumentationForOpcode(JSOp op,
                                                  GCThingIndex atomIndex) {

/js/src/frontend/FunctionEmitter.cpp

--- 30e8baeb3addeeef2e4ea3bf3de5e8ab5af11465/js/src/frontend/FunctionEmitter.cpp
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/FunctionEmitter.cpp
@@ -434,17 +434,17 @@ bool FunctionScriptEmitter::prepareForBo
   if (funbox_->needsPromiseResult()) {
     if (!emitAsyncFunctionRejectPrologue()) {
       return false;
     }
   }

   if (funbox_->isClassConstructor()) {
     if (!funbox_->isDerivedClassConstructor()) {
-      if (!bce_->emitInitializeInstanceFields()) {
+      if (!bce_->emitInitializeInstanceMembers()) {
         //          [stack]
         return false;
       }
     }
   }

 #ifdef DEBUG
   state_ = State::Body;

/js/src/frontend/ObjectEmitter.cpp

--- 834447abbbf1080f46eb824d0fbc85a1ac711a09/js/src/frontend/ObjectEmitter.cpp
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/ObjectEmitter.cpp
@@ -592,17 +592,17 @@ bool ClassEmitter::emitDerivedClass(JS::
   classState_ = ClassState::Class;
 #endif
   return true;
 }

 bool ClassEmitter::emitInitConstructor(bool needsHomeObject) {
   MOZ_ASSERT(propertyState_ == PropertyState::Start);
   MOZ_ASSERT(classState_ == ClassState::Class ||
-             classState_ == ClassState::InstanceFieldInitializersEnd);
+             classState_ == ClassState::InstanceMemberInitializersEnd);

   //                [stack] HOMEOBJ CTOR

   if (needsHomeObject) {
     if (!bce_->emitDupAt(1)) {
       //            [stack] HOMEOBJ CTOR HOMEOBJ
       return false;
     }
@@ -705,64 +705,64 @@ bool ClassEmitter::initProtoAndCtor() {
                         bce_->cx->parserNames().constructor)) {
     //              [stack] NAME? CTOR HOMEOBJ
     return false;
   }

   return true;
 }

-bool ClassEmitter::prepareForFieldInitializers(size_t numFields,
-                                               bool isStatic) {
+bool ClassEmitter::prepareForMemberInitializers(size_t numInitializers,
+                                                bool isStatic) {
   MOZ_ASSERT_IF(!isStatic, classState_ == ClassState::Class);
   MOZ_ASSERT_IF(isStatic, classState_ == ClassState::InitConstructor);
-  MOZ_ASSERT(fieldState_ == FieldState::Start);
+  MOZ_ASSERT(memberState_ == MemberState::Start);

   // .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.
   auto initializersName = isStatic ? &JSAtomState::dotStaticInitializers
                                    : &JSAtomState::dotInitializers;
   HandlePropertyName initializers = bce_->cx->parserNames().*initializersName;
   initializersAssignment_.emplace(bce_, initializers,
                                   NameOpEmitter::Kind::Initialize);
   if (!initializersAssignment_->prepareForRhs()) {
     return false;
   }

-  if (!bce_->emitUint32Operand(JSOp::NewArray, numFields)) {
+  if (!bce_->emitUint32Operand(JSOp::NewArray, numInitializers)) {
     //              [stack] ARRAY
     return false;
   }

-  fieldIndex_ = 0;
+  initializerIndex_ = 0;
 #ifdef DEBUG
   if (isStatic) {
-    classState_ = ClassState::StaticFieldInitializers;
+    classState_ = ClassState::StaticMemberInitializers;
   } else {
-    classState_ = ClassState::InstanceFieldInitializers;
+    classState_ = ClassState::InstanceMemberInitializers;
   }
-  numFields_ = numFields;
+  numInitializers_ = numInitializers;
 #endif
   return true;
 }

-bool ClassEmitter::prepareForFieldInitializer() {
-  MOZ_ASSERT(classState_ == ClassState::InstanceFieldInitializers ||
-             classState_ == ClassState::StaticFieldInitializers);
-  MOZ_ASSERT(fieldState_ == FieldState::Start);
+bool ClassEmitter::prepareForMemberInitializer() {
+  MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers ||
+             classState_ == ClassState::StaticMemberInitializers);
+  MOZ_ASSERT(memberState_ == MemberState::Start);

 #ifdef DEBUG
-  fieldState_ = FieldState::Initializer;
+  memberState_ = MemberState::Initializer;
 #endif
   return true;
 }

-bool ClassEmitter::emitFieldInitializerHomeObject(bool isStatic) {
-  MOZ_ASSERT(fieldState_ == FieldState::Initializer);
+bool ClassEmitter::emitMemberInitializerHomeObject(bool isStatic) {
+  MOZ_ASSERT(memberState_ == MemberState::Initializer);
   //                [stack] OBJ HERITAGE? ARRAY METHOD
   // or:
   //                [stack] CTOR HOMEOBJ ARRAY METHOD

   if (isStatic) {
     if (!bce_->emitDupAt(3)) {
       //            [stack] CTOR HOMEOBJ ARRAY METHOD CTOR
       return false;
@@ -776,74 +776,74 @@ bool ClassEmitter::emitFieldInitializerH
   if (!bce_->emit1(JSOp::InitHomeObject)) {
     //              [stack] OBJ HERITAGE? ARRAY METHOD
     // or:
     //              [stack] CTOR HOMEOBJ ARRAY METHOD
     return false;
   }

 #ifdef DEBUG
-  fieldState_ = FieldState::InitializerWithHomeObject;
+  memberState_ = MemberState::InitializerWithHomeObject;
 #endif
   return true;
 }

-bool ClassEmitter::emitStoreFieldInitializer() {
-  MOZ_ASSERT(fieldState_ == FieldState::Initializer ||
-             fieldState_ == FieldState::InitializerWithHomeObject);
-  MOZ_ASSERT(fieldIndex_ < numFields_);
+bool ClassEmitter::emitStoreMemberInitializer() {
+  MOZ_ASSERT(memberState_ == MemberState::Initializer ||
+             memberState_ == MemberState::InitializerWithHomeObject);
+  MOZ_ASSERT(initializerIndex_ < numInitializers_);
   //          [stack] HOMEOBJ HERITAGE? ARRAY METHOD

-  if (!bce_->emitUint32Operand(JSOp::InitElemArray, fieldIndex_)) {
+  if (!bce_->emitUint32Operand(JSOp::InitElemArray, initializerIndex_)) {
     //          [stack] HOMEOBJ HERITAGE? ARRAY
     return false;
   }

-  fieldIndex_++;
+  initializerIndex_++;
 #ifdef DEBUG
-  fieldState_ = FieldState::Start;
+  memberState_ = MemberState::Start;
 #endif
   return true;
 }

-bool ClassEmitter::emitFieldInitializersEnd() {
+bool ClassEmitter::emitMemberInitializersEnd() {
   MOZ_ASSERT(propertyState_ == PropertyState::Start ||
              propertyState_ == PropertyState::Init);
-  MOZ_ASSERT(classState_ == ClassState::InstanceFieldInitializers ||
-             classState_ == ClassState::StaticFieldInitializers);
-  MOZ_ASSERT(fieldState_ == FieldState::Start);
-  MOZ_ASSERT(fieldIndex_ == numFields_);
+  MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers ||
+             classState_ == ClassState::StaticMemberInitializers);
+  MOZ_ASSERT(memberState_ == MemberState::Start);
+  MOZ_ASSERT(initializerIndex_ == numInitializers_);

   if (!initializersAssignment_->emitAssignment()) {
     //              [stack] HOMEOBJ HERITAGE? ARRAY
     return false;
   }
   initializersAssignment_.reset();

   if (!bce_->emit1(JSOp::Pop)) {
     //              [stack] HOMEOBJ HERITAGE?
     return false;
   }

 #ifdef DEBUG
-  if (classState_ == ClassState::InstanceFieldInitializers) {
-    classState_ = ClassState::InstanceFieldInitializersEnd;
+  if (classState_ == ClassState::InstanceMemberInitializers) {
+    classState_ = ClassState::InstanceMemberInitializersEnd;
   } else {
-    classState_ = ClassState::StaticFieldInitializersEnd;
+    classState_ = ClassState::StaticMemberInitializersEnd;
   }
 #endif
   return true;
 }

 bool ClassEmitter::emitBinding() {
   MOZ_ASSERT(propertyState_ == PropertyState::Start ||
              propertyState_ == PropertyState::Init);
   MOZ_ASSERT(classState_ == ClassState::InitConstructor ||
-             classState_ == ClassState::InstanceFieldInitializersEnd ||
-             classState_ == ClassState::StaticFieldInitializersEnd);
+             classState_ == ClassState::InstanceMemberInitializersEnd ||
+             classState_ == ClassState::StaticMemberInitializersEnd);
   //                [stack] CTOR HOMEOBJ

   if (!bce_->emit1(JSOp::Pop)) {
     //              [stack] CTOR
     return false;
   }

   if (name_) {

/js/src/frontend/ObjectEmitter.h

--- 35005419e7c83fc42de7304b55b40d65564912b2/js/src/frontend/ObjectEmitter.h
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/ObjectEmitter.h
@@ -485,38 +485,38 @@ class MOZ_RAII AutoSaveLocalStrictMode {
 //     ce.emitEnd(ClassEmitter::Kind::Expression);
 //
 //   `class X extends Y { field0 = expr0; ... }`
 //     ClassEmitter ce(this);
 //     ce.emitScope(scopeBindings);
 //     emit(Y);
 //     ce.emitDerivedClass(atom_of_X, nullptr, false);
 //
-//     ce.prepareForFieldInitializers(fields.length());
+//     ce.prepareForMemberInitializers(fields.length());
 //     for (auto field : fields) {
 //       emit(field.initializer_method());
-//       ce.emitStoreFieldInitializer();
+//       ce.emitStoreMemberInitializer();
 //     }
-//     ce.emitFieldInitializersEnd();
+//     ce.emitMemberInitializersEnd();
 //
 //     emit(function_for_constructor);
 //     ce.emitInitConstructor(/* needsHomeObject = */ false);
 //     ce.emitEnd(ClassEmitter::Kind::Expression);
 //
 //   `class X { field0 = super.method(); ... }`
 //     // after emitClass/emitDerivedClass
-//     ce.prepareForFieldInitializers(1);
+//     ce.prepareForMemberInitializers(1);
 //     for (auto field : fields) {
 //       emit(field.initializer_method());
 //       if (field.initializer_contains_super_or_eval()) {
-//         ce.emitFieldInitializerHomeObject();
+//         ce.emitMemberInitializerHomeObject();
 //       }
-//       ce.emitStoreFieldInitializer();
+//       ce.emitStoreMemberInitializer();
 //     }
-//     ce.emitFieldInitializersEnd();
+//     ce.emitMemberInitializersEnd();
 //
 //   `m() {}` in class
 //     // after emitInitConstructor/emitInitDefaultConstructor
 //     ce.prepareForPropValue(Some(offset_of_m));
 //     emit(function_for_m);
 //     ce.emitInitProp(atom_of_m);
 //
 //   `m() { super.f(); }` in class
@@ -639,51 +639,51 @@ class MOZ_STACK_CLASS ClassEmitter : pub
   //   +-+----------------->+->| Class |-+
   //     |                  ^  +-------+ |
   //     | emitDerivedClass |            |
   //     +------------------+            |
   //                                     |
   //     +-------------------------------+
   //     |
   //     |
-  //     |  prepareForFieldInitializers(isStatic = false)
+  //     |  prepareForMemberInitializers(isStatic = false)
   //     +---------------+
   //     |               |
-  //     |      +--------v------------------+
-  //     |      | InstanceFieldInitializers |
-  //     |      +---------------------------+
+  //     |      +--------v-------------------+
+  //     |      | InstanceMemberInitializers |
+  //     |      +----------------------------+
   //     |               |
-  //                     | emitFieldInitializersEnd
+  //                     | emitMemberInitializersEnd
   //     |               |
-  //     |      +--------v---------------------+
-  //     |      | InstanceFieldInitializersEnd |
-  //     |      +------------------------------+
+  //     |      +--------v----------------------+
+  //     |      | InstanceMemberInitializersEnd |
+  //     |      +-------------------------------+
   //     |               |
   //     +<--------------+
   //     |
   //     |   emitInitConstructor           +-----------------+
   //     +-+--------------------------->+->| InitConstructor |-+
   //       |                            ^  +-----------------+ |
   //       | emitInitDefaultConstructor |                      |
   //       +----------------------------+                      |
   //                                                           |
   //     +-----------------------------------------------------+
   //     |
-  //     |  prepareForFieldInitializers(isStatic = true)
+  //     |  prepareForMemberInitializers(isStatic = true)
   //     +---------------+
   //     |               |
-  //     |      +--------v----------------+
-  //     |      | StaticFieldInitializers |
-  //     |      +-------------------------+
+  //     |      +--------v-----------------+
+  //     |      | StaticMemberInitializers |
+  //     |      +--------------------------+
   //     |               |
-  //     |               | emitFieldInitializersEnd
+  //     |               | emitMemberInitializersEnd
   //     |               |
-  //     |      +--------v-------------------+
-  //     |      | StaticFieldInitializersEnd |
-  //     |      +----------------------------+
+  //     |      +--------v--------------------+
+  //     |      | StaticMemberInitializersEnd |
+  //     |      +-----------------------------+
   //     |               |
   //     +<--------------+
   //     |
   //     | (do PropertyEmitter operation)
   //     +--------------------------------+
   //                                      |
   //     +-------------+    emitBinding   |
   //     |  BoundName  |<-----------------+
@@ -707,78 +707,78 @@ class MOZ_STACK_CLASS ClassEmitter : pub
     BodyScope,

     // After calling emitClass or emitDerivedClass.
     Class,

     // After calling emitInitConstructor or emitInitDefaultConstructor.
     InitConstructor,

-    // After calling prepareForFieldInitializers(isStatic = false).
-    InstanceFieldInitializers,
+    // After calling prepareForMemberInitializers(isStatic = false).
+    InstanceMemberInitializers,

-    // After calling emitFieldInitializersEnd.
-    InstanceFieldInitializersEnd,
+    // After calling emitMemberInitializersEnd.
+    InstanceMemberInitializersEnd,

-    // After calling prepareForFieldInitializers(isStatic = true).
-    StaticFieldInitializers,
+    // After calling prepareForMemberInitializers(isStatic = true).
+    StaticMemberInitializers,

-    // After calling emitFieldInitializersEnd.
-    StaticFieldInitializersEnd,
+    // After calling emitMemberInitializersEnd.
+    StaticMemberInitializersEnd,

     // After calling emitBinding.
     BoundName,

     // After calling emitEnd.
     End,
   };
   ClassState classState_ = ClassState::Start;

-  // The state of the fields emitter.
+  // The state of the members emitter.
   //
   // clang-format off
   //
   //   +-------+
   //   | Start +<-----------------------------+
   //   +-------+                              |
   //       |                                  |
-  //       | prepareForFieldInitializer       | emitStoreFieldInitializer
+  //       | prepareForMemberInitializer      | emitStoreMemberInitializer
   //       v                                  |
   // +-------------+                          |
   // | Initializer +------------------------->+
   // +-------------+                          |
   //       |                                  |
-  //       | emitFieldInitializerHomeObject   |
+  //       | emitMemberInitializerHomeObject  |
   //       v                                  |
   // +---------------------------+            |
   // | InitializerWithHomeObject +------------+
   // +---------------------------+
   //
   // clang-format on
-  enum class FieldState {
-    // After calling prepareForFieldInitializers
-    // and 0 or more calls to emitStoreFieldInitializer.
+  enum class MemberState {
+    // After calling prepareForMemberInitializers
+    // and 0 or more calls to emitStoreMemberInitializer.
     Start,

-    // After calling prepareForFieldInitializer
+    // After calling prepareForMemberInitializer
     Initializer,

-    // After calling emitFieldInitializerHomeObject
+    // After calling emitMemberInitializerHomeObject
     InitializerWithHomeObject,
   };
-  FieldState fieldState_ = FieldState::Start;
+  MemberState memberState_ = MemberState::Start;

-  size_t numFields_ = 0;
+  size_t numInitializers_ = 0;
 #endif

   JS::Rooted<JSAtom*> name_;
   JS::Rooted<JSAtom*> nameForAnonymousClass_;
   bool hasNameOnStack_ = false;
   mozilla::Maybe<NameOpEmitter> initializersAssignment_;
-  size_t fieldIndex_ = 0;
+  size_t initializerIndex_ = 0;

  public:
   explicit ClassEmitter(BytecodeEmitter* bce);

   bool emitScope(JS::Handle<LexicalScope::Data*> scopeBindings);

   bool emitBodyScope(JS::Handle<LexicalScope::Data*> scopeBindings);

@@ -806,22 +806,22 @@ class MOZ_STACK_CLASS ClassEmitter : pub
   //   |                  |
   //   |                  classEnd
   //   |
   //   classStart
   //
   MOZ_MUST_USE bool emitInitDefaultConstructor(uint32_t classStart,
                                                uint32_t classEnd);

-  MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields,
-                                                bool isStatic);
-  MOZ_MUST_USE bool prepareForFieldInitializer();
-  MOZ_MUST_USE bool emitFieldInitializerHomeObject(bool isStatic);
-  MOZ_MUST_USE bool emitStoreFieldInitializer();
-  MOZ_MUST_USE bool emitFieldInitializersEnd();
+  MOZ_MUST_USE bool prepareForMemberInitializers(size_t numInitializers,
+                                                 bool isStatic);
+  MOZ_MUST_USE bool prepareForMemberInitializer();
+  MOZ_MUST_USE bool emitMemberInitializerHomeObject(bool isStatic);
+  MOZ_MUST_USE bool emitStoreMemberInitializer();
+  MOZ_MUST_USE bool emitMemberInitializersEnd();

   MOZ_MUST_USE bool emitBinding();

   MOZ_MUST_USE bool emitEnd(Kind kind);

  private:
   MOZ_MUST_USE bool initProtoAndCtor();
 };

/js/src/frontend/Stencil.cpp

--- b102e788194404d0162d8758be1945ba7ad5409b/js/src/frontend/Stencil.cpp
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/Stencil.cpp
@@ -532,18 +532,18 @@ static void UpdateEmittedInnerFunctions(
       BaseScript* script = fun->baseScript();

       ScopeIndex index = *stencil.lazyFunctionEnclosingScopeIndex_;
       Scope* scope = compilationInfo.scopes[index].get();
       script->setEnclosingScope(scope);
       script->initTreatAsRunOnce(stencil.immutableFlags.hasFlag(
           ImmutableScriptFlagsEnum::TreatAsRunOnce));

-      if (stencil.fieldInitializers) {
-        script->setFieldInitializers(*stencil.fieldInitializers);
+      if (stencil.memberInitializers) {
+        script->setMemberInitializers(*stencil.memberInitializers);
       }
     }

     // Inferred and Guessed names are computed by BytecodeEmitter and so may
     // need to be applied to existing JSFunctions during delazification.
     if (fun->displayAtom() == nullptr) {
       if (stencil.functionFlags.hasInferredName()) {
         fun->setInferredName(stencil.functionAtom);
@@ -1193,21 +1193,21 @@ void ScriptStencil::dump(js::JSONPrinter
   json.endObject();
 }

 void ScriptStencil::dumpFields(js::JSONPrinter& json) {
   json.beginListProperty("immutableFlags");
   DumpImmutableScriptFlags(json, immutableFlags);
   json.endList();

-  if (fieldInitializers) {
-    json.formatProperty("fieldInitializers", "Some(%u)",
-                        (*fieldInitializers).numFieldInitializers);
+  if (memberInitializers) {
+    json.formatProperty("memberInitializers", "Some(%u)",
+                        (*memberInitializers).numMemberInitializers);
   } else {
-    json.property("fieldInitializers", "Nothing");
+    json.property("memberInitializers", "Nothing");
   }

   json.beginListProperty("gcThings");
   for (auto& thing : gcThings) {
     DumpScriptThing(json, thing);
   }
   json.endList();

/js/src/frontend/Stencil.h

--- b102e788194404d0162d8758be1945ba7ad5409b/js/src/frontend/Stencil.h
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/frontend/Stencil.h
@@ -24,17 +24,17 @@
 #include "js/TypeDecls.h"                 // JSContext,JSAtom,JSFunction
 #include "js/UniquePtr.h"                 // js::UniquePtr
 #include "js/Utility.h"                   // UniqueTwoByteChars
 #include "js/Vector.h"                    // js::Vector
 #include "util/Text.h"                    // DuplicateString
 #include "vm/BigIntType.h"                // ParseBigIntLiteral
 #include "vm/FunctionFlags.h"             // FunctionFlags
 #include "vm/GeneratorAndAsyncKind.h"     // GeneratorKind, FunctionAsyncKind
-#include "vm/JSScript.h"                  // FieldInitializers
+#include "vm/JSScript.h"                  // MemberInitializers
 #include "vm/Scope.h"  // BaseScopeData, FunctionScope, LexicalScope, VarScope, GlobalScope, EvalScope, ModuleScope
 #include "vm/ScopeKind.h"      // ScopeKind
 #include "vm/SharedStencil.h"  // ImmutableScriptFlags, GCThingIndex
 #include "vm/StencilEnums.h"   // ImmutableScriptFlagsEnum

 class JS_PUBLIC_API JSTracer;

 namespace js {
@@ -421,17 +421,17 @@ class ScriptStencil {
   //   * Module
   //   * non-lazy Function (except asm.js module)
   //   * lazy Function (cannot be asm.js module)

   // See `BaseScript::immutableFlags_`.
   ImmutableScriptFlags immutableFlags;

   // See `BaseScript::data_`.
-  mozilla::Maybe<FieldInitializers> fieldInitializers;
+  mozilla::Maybe<MemberInitializers> memberInitializers;
   ScriptThingsVector gcThings;

   // See `BaseScript::sharedData_`.
   js::UniquePtr<js::ImmutableScriptData> immutableScriptData = nullptr;

   // The location of this script in the source.
   SourceExtent extent = {};

/js/src/vm/BytecodeUtil.cpp

--- 780d9ef6deaa998fffa821a464fe260d575d7b24/js/src/vm/BytecodeUtil.cpp
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/vm/BytecodeUtil.cpp
@@ -583,16 +583,17 @@ uint32_t BytecodeParser::simulateOp(JSOp
         goto end;

       case JSOp::InitElem:
       case JSOp::InitElemGetter:
       case JSOp::InitElemSetter:
       case JSOp::InitHiddenElem:
       case JSOp::InitHiddenElemGetter:
       case JSOp::InitHiddenElemSetter:
+      case JSOp::InitLockedElem:
         // Keep the third value.
         MOZ_ASSERT(nuses == 3);
         MOZ_ASSERT(ndefs == 1);
         goto end;

       default:
         break;
     }

/js/src/vm/BytecodeUtil.h

--- f25c329fad71e0c909ee2131bb2cdb13e6f0eba5/js/src/vm/BytecodeUtil.h
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/vm/BytecodeUtil.h
@@ -533,17 +533,18 @@ inline bool IsGetPropOp(JSOp op) {
   return op == JSOp::Length || op == JSOp::GetProp || op == JSOp::CallProp;
 }

 inline bool IsGetPropPC(const jsbytecode* pc) { return IsGetPropOp(JSOp(*pc)); }

 inline bool IsHiddenInitOp(JSOp op) {
   return op == JSOp::InitHiddenProp || op == JSOp::InitHiddenElem ||
          op == JSOp::InitHiddenPropGetter || op == JSOp::InitHiddenElemGetter ||
-         op == JSOp::InitHiddenPropSetter || op == JSOp::InitHiddenElemSetter;
+         op == JSOp::InitHiddenPropSetter || op == JSOp::InitHiddenElemSetter ||
+         op == JSOp::InitLockedElem;
 }

 inline bool IsStrictSetPC(jsbytecode* pc) {
   JSOp op = JSOp(*pc);
   return op == JSOp::StrictSetProp || op == JSOp::StrictSetName ||
          op == JSOp::StrictSetGName || op == JSOp::StrictSetElem;
 }

/js/src/vm/Opcodes.h

--- 834447abbbf1080f46eb824d0fbc85a1ac711a09/js/src/vm/Opcodes.h
+++ 22e3020fa080afeaa79292e085aa4d7346a6f9ec/js/src/vm/Opcodes.h
@@ -920,26 +920,29 @@
      * `obj` must be an object.
      *
      * Implements: [CreateDataPropertyOrThrow][1]. This instruction is used for
      * object literals like `{0: val}` and `{[id]: val}`, and methods like
      * `*[Symbol.iterator]() {}`.
      *
      * `JSOp::InitHiddenElem` is the same but defines a non-enumerable property,
      * for class methods.
+     * `JSOp::InitLockedElem` is the same but defines a non-enumerable, non-writable, non-configurable property,
+     * for private class methods.
      *
      *    [1]: https://tc39.es/ecma262/#sec-createdatapropertyorthrow
      *
      *   Category: Objects
      *   Type: Defining properties
      *   Operands:
      *   Stack: obj, id, val => obj
      */ \
     MACRO(InitElem, init_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
     MACRO(InitHiddenElem, init_hidden_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
+    MACRO(InitLockedElem, init_locked_elem, NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_PROPINIT|JOF_IC) \
     /*
      * Define an accessor property on `obj` with the given `getter`.
      * `nameIndex` gives the property name.
      *
      * `obj` must be an object and `getter` must be a function.
      *
      * `JSOp::InitHiddenPropGetter` is the same but defines a non-enumerable
      * property, for getters in classes.
@@ -3670,17 +3673,16 @@

 // clang-format on

 /*
  * In certain circumstances it may be useful to "pad out" the opcode space to
  * a power of two.  Use this macro to do so.
  */
 #define FOR_EACH_TRAILING_UNUSED_OPCODE(MACRO) \
-  MACRO(238)                                   \
   MACRO(239)                                   \
   MACRO(240)                                   \
   MACRO(241)                                   \
   MACRO(242)                                   \
   MACRO(243)                                   \
   MACRO(244)                                   \
   MACRO(245)                                   \
   MACRO(246)                                   \
arai-a commented 4 years ago

handled in https://bugzilla.mozilla.org/show_bug.cgi?id=1659304