tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ObjectEmitter.cpp (26207B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "frontend/ObjectEmitter.h"
      8 
      9 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     10 
     11 #include "frontend/BytecodeEmitter.h"  // BytecodeEmitter
     12 #include "frontend/IfEmitter.h"        // IfEmitter
     13 #include "frontend/ParseNode.h"        // AccessorType
     14 #include "frontend/SharedContext.h"    // SharedContext
     15 #include "vm/FunctionPrefixKind.h"     // FunctionPrefixKind
     16 #include "vm/Opcodes.h"                // JSOp
     17 
     18 using namespace js;
     19 using namespace js::frontend;
     20 
     21 PropertyEmitter::PropertyEmitter(BytecodeEmitter* bce) : bce_(bce) {}
     22 
     23 bool PropertyEmitter::prepareForProtoValue(uint32_t keyPos) {
     24  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
     25             propertyState_ == PropertyState::Init);
     26 
     27  //                [stack] CTOR? OBJ CTOR?
     28 
     29  if (!bce_->updateSourceCoordNotes(keyPos)) {
     30    return false;
     31  }
     32 
     33 #ifdef DEBUG
     34  propertyState_ = PropertyState::ProtoValue;
     35 #endif
     36  return true;
     37 }
     38 
     39 bool PropertyEmitter::emitMutateProto() {
     40  MOZ_ASSERT(propertyState_ == PropertyState::ProtoValue);
     41 
     42  //                [stack] OBJ PROTO
     43 
     44  if (!bce_->emit1(JSOp::MutateProto)) {
     45    //              [stack] OBJ
     46    return false;
     47  }
     48 
     49 #ifdef DEBUG
     50  propertyState_ = PropertyState::Init;
     51 #endif
     52  return true;
     53 }
     54 
     55 bool PropertyEmitter::prepareForSpreadOperand(uint32_t spreadPos) {
     56  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
     57             propertyState_ == PropertyState::Init);
     58 
     59  //                [stack] OBJ
     60 
     61  if (!bce_->updateSourceCoordNotes(spreadPos)) {
     62    return false;
     63  }
     64  if (!bce_->emit1(JSOp::Dup)) {
     65    //              [stack] OBJ OBJ
     66    return false;
     67  }
     68 
     69 #ifdef DEBUG
     70  propertyState_ = PropertyState::SpreadOperand;
     71 #endif
     72  return true;
     73 }
     74 
     75 bool PropertyEmitter::emitSpread() {
     76  MOZ_ASSERT(propertyState_ == PropertyState::SpreadOperand);
     77 
     78  //                [stack] OBJ OBJ VAL
     79 
     80  if (!bce_->emitCopyDataProperties(BytecodeEmitter::CopyOption::Unfiltered)) {
     81    //              [stack] OBJ
     82    return false;
     83  }
     84 
     85 #ifdef DEBUG
     86  propertyState_ = PropertyState::Init;
     87 #endif
     88  return true;
     89 }
     90 
     91 MOZ_ALWAYS_INLINE bool PropertyEmitter::prepareForProp(uint32_t keyPos,
     92                                                       bool isStatic,
     93                                                       bool isIndexOrComputed) {
     94  isStatic_ = isStatic;
     95  isIndexOrComputed_ = isIndexOrComputed;
     96 
     97  //                [stack] CTOR? OBJ
     98 
     99  if (!bce_->updateSourceCoordNotes(keyPos)) {
    100    return false;
    101  }
    102 
    103  if (isStatic_) {
    104    if (!bce_->emit1(JSOp::Dup2)) {
    105      //            [stack] CTOR HOMEOBJ CTOR HOMEOBJ
    106      return false;
    107    }
    108    if (!bce_->emit1(JSOp::Pop)) {
    109      //            [stack] CTOR HOMEOBJ CTOR
    110      return false;
    111    }
    112  }
    113 
    114  return true;
    115 }
    116 
    117 bool PropertyEmitter::prepareForPrivateMethod() {
    118  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    119             propertyState_ == PropertyState::Init);
    120  MOZ_ASSERT(isClass_);
    121 
    122  isStatic_ = false;
    123  isIndexOrComputed_ = false;
    124 
    125 #ifdef DEBUG
    126  propertyState_ = PropertyState::PrivateMethodValue;
    127 #endif
    128  return true;
    129 }
    130 
    131 bool PropertyEmitter::prepareForPrivateStaticMethod(uint32_t keyPos) {
    132  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    133             propertyState_ == PropertyState::Init);
    134  MOZ_ASSERT(isClass_);
    135 
    136  //                [stack] CTOR OBJ
    137 
    138  if (!prepareForProp(keyPos,
    139                      /* isStatic_ = */ true,
    140                      /* isIndexOrComputed = */ true)) {
    141    //              [stack] CTOR OBJ CTOR
    142    return false;
    143  }
    144 
    145 #ifdef DEBUG
    146  propertyState_ = PropertyState::PrivateStaticMethod;
    147 #endif
    148  return true;
    149 }
    150 
    151 bool PropertyEmitter::prepareForPropValue(uint32_t keyPos, Kind kind) {
    152  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    153             propertyState_ == PropertyState::Init);
    154 
    155  //                [stack] CTOR? OBJ
    156 
    157  if (!prepareForProp(keyPos,
    158                      /* isStatic_ = */ kind == Kind::Static,
    159                      /* isIndexOrComputed = */ false)) {
    160    //              [stack] CTOR? OBJ CTOR?
    161    return false;
    162  }
    163 
    164 #ifdef DEBUG
    165  propertyState_ = PropertyState::PropValue;
    166 #endif
    167  return true;
    168 }
    169 
    170 bool PropertyEmitter::prepareForIndexPropKey(uint32_t keyPos, Kind kind) {
    171  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    172             propertyState_ == PropertyState::Init);
    173 
    174  //                [stack] CTOR? OBJ
    175 
    176  if (!prepareForProp(keyPos,
    177                      /* isStatic_ = */ kind == Kind::Static,
    178                      /* isIndexOrComputed = */ true)) {
    179    //              [stack] CTOR? OBJ CTOR?
    180    return false;
    181  }
    182 
    183 #ifdef DEBUG
    184  propertyState_ = PropertyState::IndexKey;
    185 #endif
    186  return true;
    187 }
    188 
    189 bool PropertyEmitter::prepareForIndexPropValue() {
    190  MOZ_ASSERT(propertyState_ == PropertyState::IndexKey);
    191 
    192  //                [stack] CTOR? OBJ CTOR? KEY
    193 
    194 #ifdef DEBUG
    195  propertyState_ = PropertyState::IndexValue;
    196 #endif
    197  return true;
    198 }
    199 
    200 bool PropertyEmitter::prepareForComputedPropKey(uint32_t keyPos, Kind kind) {
    201  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    202             propertyState_ == PropertyState::Init);
    203 
    204  //                [stack] CTOR? OBJ
    205 
    206  if (!prepareForProp(keyPos,
    207                      /* isStatic_ = */ kind == Kind::Static,
    208                      /* isIndexOrComputed = */ true)) {
    209    //              [stack] CTOR? OBJ CTOR?
    210    return false;
    211  }
    212 
    213 #ifdef DEBUG
    214  propertyState_ = PropertyState::ComputedKey;
    215 #endif
    216  return true;
    217 }
    218 
    219 bool PropertyEmitter::prepareForComputedPropValue() {
    220  MOZ_ASSERT(propertyState_ == PropertyState::ComputedKey);
    221 
    222  //                [stack] CTOR? OBJ CTOR? KEY
    223 
    224  if (!bce_->emit1(JSOp::ToPropertyKey)) {
    225    //              [stack] CTOR? OBJ CTOR? KEY
    226    return false;
    227  }
    228 
    229 #ifdef DEBUG
    230  propertyState_ = PropertyState::ComputedValue;
    231 #endif
    232  return true;
    233 }
    234 
    235 bool PropertyEmitter::emitInitHomeObject() {
    236  MOZ_ASSERT(propertyState_ == PropertyState::PropValue ||
    237             propertyState_ == PropertyState::PrivateMethodValue ||
    238             propertyState_ == PropertyState::PrivateStaticMethod ||
    239             propertyState_ == PropertyState::IndexValue ||
    240             propertyState_ == PropertyState::ComputedValue);
    241 
    242  //                [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
    243 
    244  // There are the following values on the stack conditionally, between
    245  // HOMEOBJ and FUN:
    246  //   * the 2nd CTOR if isStatic_
    247  //   * KEY if isIndexOrComputed_
    248  //
    249  // JSOp::InitHomeObject uses one of the following:
    250  //   * HOMEOBJ if !isStatic_
    251  //     (`super.foo` points the super prototype property)
    252  //   * the 2nd CTOR if isStatic_
    253  //     (`super.foo` points the super constructor property)
    254  if (!bce_->emitDupAt(1 + isIndexOrComputed_)) {
    255    //              [stack] # non-static method
    256    //              [stack] CTOR? HOMEOBJ CTOR KEY? FUN CTOR
    257    //              [stack] # static method
    258    //              [stack] CTOR? HOMEOBJ KEY? FUN HOMEOBJ
    259    return false;
    260  }
    261  if (!bce_->emit1(JSOp::InitHomeObject)) {
    262    //              [stack] CTOR? HOMEOBJ CTOR? KEY? FUN
    263    return false;
    264  }
    265 
    266 #ifdef DEBUG
    267  if (propertyState_ == PropertyState::PropValue) {
    268    propertyState_ = PropertyState::InitHomeObj;
    269  } else if (propertyState_ == PropertyState::PrivateMethodValue) {
    270    propertyState_ = PropertyState::InitHomeObjForPrivateMethod;
    271  } else if (propertyState_ == PropertyState::PrivateStaticMethod) {
    272    propertyState_ = PropertyState::InitHomeObjForPrivateStaticMethod;
    273  } else if (propertyState_ == PropertyState::IndexValue) {
    274    propertyState_ = PropertyState::InitHomeObjForIndex;
    275  } else {
    276    propertyState_ = PropertyState::InitHomeObjForComputed;
    277  }
    278 #endif
    279  return true;
    280 }
    281 
    282 bool PropertyEmitter::emitInit(AccessorType accessorType,
    283                               TaggedParserAtomIndex key) {
    284  switch (accessorType) {
    285    case AccessorType::None:
    286      return emitInit(isClass_ ? JSOp::InitHiddenProp : JSOp::InitProp, key);
    287    case AccessorType::Getter:
    288      return emitInit(
    289          isClass_ ? JSOp::InitHiddenPropGetter : JSOp::InitPropGetter, key);
    290    case AccessorType::Setter:
    291      return emitInit(
    292          isClass_ ? JSOp::InitHiddenPropSetter : JSOp::InitPropSetter, key);
    293  }
    294  MOZ_CRASH("Invalid op");
    295 }
    296 
    297 bool PropertyEmitter::emitInitIndexOrComputed(AccessorType accessorType) {
    298  switch (accessorType) {
    299    case AccessorType::None:
    300      return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElem
    301                                              : JSOp::InitElem);
    302    case AccessorType::Getter:
    303      return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElemGetter
    304                                              : JSOp::InitElemGetter);
    305    case AccessorType::Setter:
    306      return emitInitIndexOrComputed(isClass_ ? JSOp::InitHiddenElemSetter
    307                                              : JSOp::InitElemSetter);
    308  }
    309  MOZ_CRASH("Invalid op");
    310 }
    311 
    312 bool PropertyEmitter::emitPrivateStaticMethod(AccessorType accessorType) {
    313  MOZ_ASSERT(isClass_);
    314 
    315  switch (accessorType) {
    316    case AccessorType::None:
    317      return emitInitIndexOrComputed(JSOp::InitLockedElem);
    318    case AccessorType::Getter:
    319      return emitInitIndexOrComputed(JSOp::InitHiddenElemGetter);
    320    case AccessorType::Setter:
    321      return emitInitIndexOrComputed(JSOp::InitHiddenElemSetter);
    322  }
    323  MOZ_CRASH("Invalid op");
    324 }
    325 
    326 bool PropertyEmitter::emitInit(JSOp op, TaggedParserAtomIndex key) {
    327  MOZ_ASSERT(propertyState_ == PropertyState::PropValue ||
    328             propertyState_ == PropertyState::InitHomeObj);
    329 
    330  MOZ_ASSERT(op == JSOp::InitProp || op == JSOp::InitHiddenProp ||
    331             op == JSOp::InitPropGetter || op == JSOp::InitHiddenPropGetter ||
    332             op == JSOp::InitPropSetter || op == JSOp::InitHiddenPropSetter);
    333 
    334  //                [stack] CTOR? OBJ CTOR? VAL
    335 
    336  if (!bce_->emitAtomOp(op, key)) {
    337    //              [stack] CTOR? OBJ CTOR?
    338    return false;
    339  }
    340 
    341  if (!emitPopClassConstructor()) {
    342    return false;
    343  }
    344 
    345 #ifdef DEBUG
    346  propertyState_ = PropertyState::Init;
    347 #endif
    348  return true;
    349 }
    350 
    351 bool PropertyEmitter::skipInit() {
    352  MOZ_ASSERT(propertyState_ == PropertyState::PrivateMethodValue ||
    353             propertyState_ == PropertyState::InitHomeObjForPrivateMethod);
    354 #ifdef DEBUG
    355  propertyState_ = PropertyState::Init;
    356 #endif
    357  return true;
    358 }
    359 
    360 bool PropertyEmitter::emitInitIndexOrComputed(JSOp op) {
    361  MOZ_ASSERT(propertyState_ == PropertyState::IndexValue ||
    362             propertyState_ == PropertyState::InitHomeObjForIndex ||
    363             propertyState_ == PropertyState::ComputedValue ||
    364             propertyState_ == PropertyState::InitHomeObjForComputed ||
    365             propertyState_ == PropertyState::PrivateStaticMethod ||
    366             propertyState_ ==
    367                 PropertyState::InitHomeObjForPrivateStaticMethod);
    368 
    369  MOZ_ASSERT(op == JSOp::InitElem || op == JSOp::InitHiddenElem ||
    370             op == JSOp::InitLockedElem || op == JSOp::InitElemGetter ||
    371             op == JSOp::InitHiddenElemGetter || op == JSOp::InitElemSetter ||
    372             op == JSOp::InitHiddenElemSetter);
    373 
    374  //                [stack] CTOR? OBJ CTOR? KEY VAL
    375 
    376  if (!bce_->emit1(op)) {
    377    //              [stack] CTOR? OBJ CTOR?
    378    return false;
    379  }
    380 
    381  if (!emitPopClassConstructor()) {
    382    return false;
    383  }
    384 
    385 #ifdef DEBUG
    386  propertyState_ = PropertyState::Init;
    387 #endif
    388  return true;
    389 }
    390 
    391 bool PropertyEmitter::emitPopClassConstructor() {
    392  if (isStatic_) {
    393    //              [stack] CTOR HOMEOBJ CTOR
    394 
    395    if (!bce_->emit1(JSOp::Pop)) {
    396      //            [stack] CTOR HOMEOBJ
    397      return false;
    398    }
    399  }
    400 
    401  return true;
    402 }
    403 
    404 ObjectEmitter::ObjectEmitter(BytecodeEmitter* bce) : PropertyEmitter(bce) {}
    405 
    406 bool ObjectEmitter::emitObject(size_t propertyCount) {
    407  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    408  MOZ_ASSERT(objectState_ == ObjectState::Start);
    409 
    410  //                [stack]
    411 
    412  // Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing
    413  // a new object and defining (in source order) each property on the object
    414  // (or mutating the object's [[Prototype]], in the case of __proto__).
    415  uint8_t propCount = (propertyCount > 255) ? 255 : uint8_t(propertyCount);
    416  if (!bce_->emit2(JSOp::NewInit, propCount)) {
    417    //              [stack] OBJ
    418    return false;
    419  }
    420 
    421 #ifdef DEBUG
    422  objectState_ = ObjectState::Object;
    423 #endif
    424  return true;
    425 }
    426 
    427 bool ObjectEmitter::emitObjectWithTemplateOnStack() {
    428  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    429  MOZ_ASSERT(objectState_ == ObjectState::Start);
    430 
    431 #ifdef DEBUG
    432  objectState_ = ObjectState::Object;
    433 #endif
    434  return true;
    435 }
    436 
    437 bool ObjectEmitter::emitEnd() {
    438  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    439             propertyState_ == PropertyState::Init);
    440  MOZ_ASSERT(objectState_ == ObjectState::Object);
    441 
    442  //                [stack] OBJ
    443 
    444 #ifdef DEBUG
    445  objectState_ = ObjectState::End;
    446 #endif
    447  return true;
    448 }
    449 
    450 AutoSaveLocalStrictMode::AutoSaveLocalStrictMode(SharedContext* sc) : sc_(sc) {
    451  savedStrictness_ = sc_->setLocalStrictMode(true);
    452 }
    453 
    454 AutoSaveLocalStrictMode::~AutoSaveLocalStrictMode() {
    455  if (sc_) {
    456    restore();
    457  }
    458 }
    459 
    460 void AutoSaveLocalStrictMode::restore() {
    461  MOZ_ALWAYS_TRUE(sc_->setLocalStrictMode(savedStrictness_));
    462  sc_ = nullptr;
    463 }
    464 
    465 ClassEmitter::ClassEmitter(BytecodeEmitter* bce)
    466    : PropertyEmitter(bce), strictMode_(bce->sc) {
    467  isClass_ = true;
    468 }
    469 
    470 bool ClassEmitter::emitScope(LexicalScope::ParserData* scopeBindings) {
    471  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    472  MOZ_ASSERT(classState_ == ClassState::Start);
    473 
    474  tdzCache_.emplace(bce_);
    475 
    476  innerScope_.emplace(bce_);
    477  if (!innerScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings)) {
    478    return false;
    479  }
    480 
    481 #ifdef DEBUG
    482  classState_ = ClassState::Scope;
    483 #endif
    484 
    485  return true;
    486 }
    487 
    488 bool ClassEmitter::emitBodyScope(ClassBodyScope::ParserData* scopeBindings) {
    489  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    490  MOZ_ASSERT(classState_ == ClassState::Start ||
    491             classState_ == ClassState::Scope);
    492 
    493  bodyTdzCache_.emplace(bce_);
    494 
    495  bodyScope_.emplace(bce_);
    496  if (!bodyScope_->enterClassBody(bce_, ScopeKind::ClassBody, scopeBindings)) {
    497    return false;
    498  }
    499 
    500 #ifdef DEBUG
    501  classState_ = ClassState::BodyScope;
    502 #endif
    503 
    504  return true;
    505 }
    506 
    507 bool ClassEmitter::emitClass(TaggedParserAtomIndex name,
    508                             TaggedParserAtomIndex nameForAnonymousClass,
    509                             bool hasNameOnStack, uint8_t membersCount) {
    510  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    511  MOZ_ASSERT(classState_ == ClassState::Start ||
    512             classState_ == ClassState::Scope ||
    513             classState_ == ClassState::BodyScope);
    514  MOZ_ASSERT_IF(nameForAnonymousClass || hasNameOnStack, !name);
    515  MOZ_ASSERT(!(nameForAnonymousClass && hasNameOnStack));
    516 
    517  //                [stack]
    518 
    519  name_ = name;
    520  nameForAnonymousClass_ = nameForAnonymousClass;
    521  hasNameOnStack_ = hasNameOnStack;
    522  isDerived_ = false;
    523 
    524  if (!bce_->emit2(JSOp::NewInit, membersCount)) {
    525    //              [stack] HOMEOBJ
    526    return false;
    527  }
    528 
    529 #ifdef DEBUG
    530  classState_ = ClassState::Class;
    531 #endif
    532  return true;
    533 }
    534 
    535 bool ClassEmitter::emitDerivedClass(TaggedParserAtomIndex name,
    536                                    TaggedParserAtomIndex nameForAnonymousClass,
    537                                    bool hasNameOnStack) {
    538  MOZ_ASSERT(propertyState_ == PropertyState::Start);
    539  MOZ_ASSERT(classState_ == ClassState::Start ||
    540             classState_ == ClassState::Scope ||
    541             classState_ == ClassState::BodyScope);
    542  MOZ_ASSERT_IF(nameForAnonymousClass || hasNameOnStack, !name);
    543  MOZ_ASSERT(!nameForAnonymousClass || !hasNameOnStack);
    544 
    545  //                [stack] HERITAGE
    546 
    547  name_ = name;
    548  nameForAnonymousClass_ = nameForAnonymousClass;
    549  hasNameOnStack_ = hasNameOnStack;
    550  isDerived_ = true;
    551 
    552  InternalIfEmitter ifThenElse(bce_);
    553 
    554  // Heritage must be null or a non-generator constructor
    555  if (!bce_->emit1(JSOp::CheckClassHeritage)) {
    556    //              [stack] HERITAGE
    557    return false;
    558  }
    559 
    560  // [IF] (heritage !== null)
    561  if (!bce_->emit1(JSOp::Dup)) {
    562    //              [stack] HERITAGE HERITAGE
    563    return false;
    564  }
    565  if (!bce_->emit1(JSOp::Null)) {
    566    //              [stack] HERITAGE HERITAGE NULL
    567    return false;
    568  }
    569  if (!bce_->emit1(JSOp::StrictNe)) {
    570    //              [stack] HERITAGE NE
    571    return false;
    572  }
    573 
    574  // [THEN] funProto = heritage, objProto = heritage.prototype
    575  if (!ifThenElse.emitThenElse()) {
    576    return false;
    577  }
    578  if (!bce_->emit1(JSOp::Dup)) {
    579    //              [stack] HERITAGE HERITAGE
    580    return false;
    581  }
    582  if (!bce_->emitAtomOp(JSOp::GetProp,
    583                        TaggedParserAtomIndex::WellKnown::prototype())) {
    584    //              [stack] HERITAGE PROTO
    585    return false;
    586  }
    587 
    588  // [ELSE] funProto = %FunctionPrototype%, objProto = null
    589  if (!ifThenElse.emitElse()) {
    590    return false;
    591  }
    592  if (!bce_->emit1(JSOp::Pop)) {
    593    //              [stack]
    594    return false;
    595  }
    596  if (!bce_->emitBuiltinObject(BuiltinObjectKind::FunctionPrototype)) {
    597    //              [stack] PROTO
    598    return false;
    599  }
    600  if (!bce_->emit1(JSOp::Null)) {
    601    //              [stack] PROTO NULL
    602    return false;
    603  }
    604 
    605  // [ENDIF]
    606  if (!ifThenElse.emitEnd()) {
    607    return false;
    608  }
    609 
    610  if (!bce_->emit1(JSOp::ObjWithProto)) {
    611    //              [stack] HERITAGE HOMEOBJ
    612    return false;
    613  }
    614  if (!bce_->emit1(JSOp::Swap)) {
    615    //              [stack] HOMEOBJ HERITAGE
    616    return false;
    617  }
    618 
    619 #ifdef DEBUG
    620  classState_ = ClassState::Class;
    621 #endif
    622  return true;
    623 }
    624 
    625 bool ClassEmitter::emitInitConstructor(bool needsHomeObject) {
    626  MOZ_ASSERT(classState_ == ClassState::Class ||
    627             classState_ == ClassState::InstanceMemberInitializersEnd);
    628 
    629  //                [stack] HOMEOBJ CTOR
    630 
    631  if (needsHomeObject) {
    632    if (!bce_->emitDupAt(1)) {
    633      //            [stack] HOMEOBJ CTOR HOMEOBJ
    634      return false;
    635    }
    636    if (!bce_->emit1(JSOp::InitHomeObject)) {
    637      //            [stack] HOMEOBJ CTOR
    638      return false;
    639    }
    640  }
    641 
    642  if (!initProtoAndCtor()) {
    643    //              [stack] CTOR HOMEOBJ
    644    return false;
    645  }
    646 
    647 #ifdef DEBUG
    648  classState_ = ClassState::InitConstructor;
    649 #endif
    650  return true;
    651 }
    652 
    653 bool ClassEmitter::initProtoAndCtor() {
    654  //                [stack] NAME? HOMEOBJ CTOR
    655 
    656  if (hasNameOnStack_) {
    657    if (!bce_->emitDupAt(2)) {
    658      //            [stack] NAME HOMEOBJ CTOR NAME
    659      return false;
    660    }
    661    if (!bce_->emit2(JSOp::SetFunName, uint8_t(FunctionPrefixKind::None))) {
    662      //            [stack] NAME HOMEOBJ CTOR
    663      return false;
    664    }
    665  }
    666 
    667  if (!bce_->emit1(JSOp::Swap)) {
    668    //              [stack] NAME? CTOR HOMEOBJ
    669    return false;
    670  }
    671  if (!bce_->emit1(JSOp::Dup2)) {
    672    //              [stack] NAME? CTOR HOMEOBJ CTOR HOMEOBJ
    673    return false;
    674  }
    675  if (!bce_->emitAtomOp(JSOp::InitLockedProp,
    676                        TaggedParserAtomIndex::WellKnown::prototype())) {
    677    //              [stack] NAME? CTOR HOMEOBJ CTOR
    678    return false;
    679  }
    680  if (!bce_->emitAtomOp(JSOp::InitHiddenProp,
    681                        TaggedParserAtomIndex::WellKnown::constructor())) {
    682    //              [stack] NAME? CTOR HOMEOBJ
    683    return false;
    684  }
    685 
    686  return true;
    687 }
    688 
    689 bool ClassEmitter::prepareForMemberInitializers(size_t numInitializers,
    690                                                bool isStatic) {
    691  MOZ_ASSERT_IF(!isStatic, classState_ == ClassState::Class);
    692  MOZ_ASSERT_IF(isStatic, classState_ == ClassState::InitConstructor);
    693  MOZ_ASSERT(memberState_ == MemberState::Start);
    694 
    695  // .initializers is a variable that stores an array of lambdas containing
    696  // code (the initializer) for each field. Upon an object's construction,
    697  // these lambdas will be called, defining the values.
    698  auto initializers =
    699      isStatic ? TaggedParserAtomIndex::WellKnown::dot_staticInitializers_()
    700               : TaggedParserAtomIndex::WellKnown::dot_initializers_();
    701  initializersAssignment_.emplace(bce_, initializers,
    702                                  NameOpEmitter::Kind::Initialize);
    703  if (!initializersAssignment_->prepareForRhs()) {
    704    return false;
    705  }
    706 
    707  if (!bce_->emitUint32Operand(JSOp::NewArray, numInitializers)) {
    708    //              [stack] ARRAY
    709    return false;
    710  }
    711 
    712  initializerIndex_ = 0;
    713 #ifdef DEBUG
    714  if (isStatic) {
    715    classState_ = ClassState::StaticMemberInitializers;
    716  } else {
    717    classState_ = ClassState::InstanceMemberInitializers;
    718  }
    719  numInitializers_ = numInitializers;
    720 #endif
    721  return true;
    722 }
    723 
    724 bool ClassEmitter::prepareForMemberInitializer() {
    725  MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers ||
    726             classState_ == ClassState::StaticMemberInitializers);
    727  MOZ_ASSERT(memberState_ == MemberState::Start);
    728 
    729 #ifdef DEBUG
    730  memberState_ = MemberState::Initializer;
    731 #endif
    732  return true;
    733 }
    734 
    735 bool ClassEmitter::emitMemberInitializerHomeObject(bool isStatic) {
    736  MOZ_ASSERT(memberState_ == MemberState::Initializer);
    737  //                [stack] OBJ HERITAGE? ARRAY METHOD
    738  // or:
    739  //                [stack] CTOR HOMEOBJ ARRAY METHOD
    740 
    741  if (isStatic) {
    742    if (!bce_->emitDupAt(3)) {
    743      //            [stack] CTOR HOMEOBJ ARRAY METHOD CTOR
    744      return false;
    745    }
    746  } else {
    747    if (!bce_->emitDupAt(isDerived_ ? 3 : 2)) {
    748      //            [stack] OBJ HERITAGE? ARRAY METHOD OBJ
    749      return false;
    750    }
    751  }
    752  if (!bce_->emit1(JSOp::InitHomeObject)) {
    753    //              [stack] OBJ HERITAGE? ARRAY METHOD
    754    // or:
    755    //              [stack] CTOR HOMEOBJ ARRAY METHOD
    756    return false;
    757  }
    758 
    759 #ifdef DEBUG
    760  memberState_ = MemberState::InitializerWithHomeObject;
    761 #endif
    762  return true;
    763 }
    764 
    765 bool ClassEmitter::emitStoreMemberInitializer() {
    766  MOZ_ASSERT(memberState_ == MemberState::Initializer ||
    767             memberState_ == MemberState::InitializerWithHomeObject);
    768  MOZ_ASSERT(initializerIndex_ < numInitializers_);
    769  //                [stack] HOMEOBJ HERITAGE? ARRAY METHOD
    770 
    771  if (!bce_->emitUint32Operand(JSOp::InitElemArray, initializerIndex_)) {
    772    //              [stack] HOMEOBJ HERITAGE? ARRAY
    773    return false;
    774  }
    775 
    776  initializerIndex_++;
    777 #ifdef DEBUG
    778  memberState_ = MemberState::Start;
    779 #endif
    780  return true;
    781 }
    782 
    783 bool ClassEmitter::emitMemberInitializersEnd() {
    784  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    785             propertyState_ == PropertyState::Init);
    786  MOZ_ASSERT(classState_ == ClassState::InstanceMemberInitializers ||
    787             classState_ == ClassState::StaticMemberInitializers);
    788  MOZ_ASSERT(memberState_ == MemberState::Start);
    789  MOZ_ASSERT(initializerIndex_ == numInitializers_);
    790 
    791  if (!initializersAssignment_->emitAssignment()) {
    792    //              [stack] HOMEOBJ HERITAGE? ARRAY
    793    return false;
    794  }
    795  initializersAssignment_.reset();
    796 
    797  if (!bce_->emit1(JSOp::Pop)) {
    798    //              [stack] HOMEOBJ HERITAGE?
    799    return false;
    800  }
    801 
    802 #ifdef DEBUG
    803  if (classState_ == ClassState::InstanceMemberInitializers) {
    804    classState_ = ClassState::InstanceMemberInitializersEnd;
    805  } else {
    806    classState_ = ClassState::StaticMemberInitializersEnd;
    807  }
    808 #endif
    809  return true;
    810 }
    811 
    812 #ifdef ENABLE_DECORATORS
    813 bool ClassEmitter::prepareForExtraInitializers(
    814    TaggedParserAtomIndex initializers) {
    815  // TODO: Add support for static and class extra initializers, see bug 1868220
    816  // and bug 1868221.
    817  MOZ_ASSERT(
    818      initializers ==
    819      TaggedParserAtomIndex::WellKnown::dot_instanceExtraInitializers_());
    820 
    821  NameOpEmitter noe(bce_, initializers, NameOpEmitter::Kind::Initialize);
    822  if (!noe.prepareForRhs()) {
    823    return false;
    824  }
    825 
    826  // Because the initializers are created while executing decorators, we don't
    827  // know beforehand how many there will be.
    828  if (!bce_->emitUint32Operand(JSOp::NewArray, 0)) {
    829    //              [stack] ARRAY
    830    return false;
    831  }
    832 
    833  if (!noe.emitAssignment()) {
    834    //              [stack] ARRAY
    835    return false;
    836  }
    837 
    838  return bce_->emit1(JSOp::Pop);
    839  //                [stack]
    840 }
    841 #endif
    842 
    843 bool ClassEmitter::emitBinding() {
    844  MOZ_ASSERT(propertyState_ == PropertyState::Start ||
    845             propertyState_ == PropertyState::Init);
    846  MOZ_ASSERT(classState_ == ClassState::InitConstructor ||
    847             classState_ == ClassState::InstanceMemberInitializersEnd ||
    848             classState_ == ClassState::StaticMemberInitializersEnd);
    849  //                [stack] CTOR HOMEOBJ
    850 
    851  if (!bce_->emit1(JSOp::Pop)) {
    852    //              [stack] CTOR
    853    return false;
    854  }
    855 
    856  if (name_) {
    857    MOZ_ASSERT(innerScope_.isSome());
    858 
    859    if (!bce_->emitLexicalInitialization(name_)) {
    860      //            [stack] CTOR
    861      return false;
    862    }
    863  }
    864 
    865  //                [stack] CTOR
    866 
    867 #ifdef DEBUG
    868  classState_ = ClassState::BoundName;
    869 #endif
    870  return true;
    871 }
    872 
    873 #ifdef ENABLE_DECORATORS
    874 bool ClassEmitter::prepareForDecorators() { return leaveBodyAndInnerScope(); }
    875 #endif
    876 
    877 bool ClassEmitter::leaveBodyAndInnerScope() {
    878  if (bodyScope_.isSome()) {
    879    MOZ_ASSERT(bodyTdzCache_.isSome());
    880 
    881    if (!bodyScope_->leave(bce_)) {
    882      return false;
    883    }
    884    bodyScope_.reset();
    885    bodyTdzCache_.reset();
    886  }
    887 
    888  if (innerScope_.isSome()) {
    889    MOZ_ASSERT(tdzCache_.isSome());
    890 
    891    if (!innerScope_->leave(bce_)) {
    892      return false;
    893    }
    894    innerScope_.reset();
    895    tdzCache_.reset();
    896  } else {
    897    MOZ_ASSERT(tdzCache_.isNothing());
    898  }
    899 
    900  return true;
    901 }
    902 
    903 bool ClassEmitter::emitEnd(Kind kind) {
    904  MOZ_ASSERT(classState_ == ClassState::BoundName);
    905  //                [stack] CTOR
    906 
    907 #ifndef ENABLE_DECORATORS
    908  if (!leaveBodyAndInnerScope()) {
    909    return false;
    910  }
    911 #endif
    912 
    913  if (kind == Kind::Declaration) {
    914    MOZ_ASSERT(name_);
    915 
    916    if (!bce_->emitLexicalInitialization(name_)) {
    917      //            [stack] CTOR
    918      return false;
    919    }
    920    // Only class statements make outer bindings, and they do not leave
    921    // themselves on the stack.
    922    if (!bce_->emit1(JSOp::Pop)) {
    923      //            [stack]
    924      return false;
    925    }
    926  }
    927 
    928  //                [stack] # class declaration
    929  //                [stack]
    930  //                [stack] # class expression
    931  //                [stack] CTOR
    932 
    933  strictMode_.restore();
    934 
    935 #ifdef DEBUG
    936  classState_ = ClassState::End;
    937 #endif
    938  return true;
    939 }