tor-browser

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

WarpBuilder.cpp (116245B)


      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 "jit/WarpBuilder.h"
      8 
      9 #include "mozilla/DebugOnly.h"
     10 
     11 #include "jit/BaselineFrame.h"
     12 #include "jit/CacheIR.h"
     13 #include "jit/CompileInfo.h"
     14 #include "jit/InlineScriptTree.h"
     15 #include "jit/MIR-wasm.h"
     16 #include "jit/MIR.h"
     17 #include "jit/MIRGenerator.h"
     18 #include "jit/MIRGraph.h"
     19 #include "jit/WarpCacheIRTranspiler.h"
     20 #include "jit/WarpSnapshot.h"
     21 #include "js/friend/ErrorMessages.h"  // JSMSG_BAD_CONST_ASSIGN
     22 #include "vm/ConstantCompareOperand.h"
     23 #include "vm/GeneratorObject.h"
     24 #include "vm/Interpreter.h"
     25 #include "vm/Opcodes.h"
     26 #include "vm/TypeofEqOperand.h"  // TypeofEqOperand
     27 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     28 #  include "vm/UsingHint.h"
     29 #endif
     30 
     31 #include "gc/ObjectKind-inl.h"
     32 #include "vm/BytecodeIterator-inl.h"
     33 #include "vm/BytecodeLocation-inl.h"
     34 #include "vm/JSObject-inl.h"
     35 
     36 using namespace js;
     37 using namespace js::jit;
     38 
     39 // Used for building the outermost script.
     40 WarpBuilder::WarpBuilder(WarpSnapshot& snapshot, MIRGenerator& mirGen,
     41                         WarpCompilation* warpCompilation)
     42    : WarpBuilderShared(snapshot, mirGen, nullptr),
     43      warpCompilation_(warpCompilation),
     44      graph_(mirGen.graph()),
     45      info_(mirGen.outerInfo()),
     46      scriptSnapshot_(snapshot.rootScript()),
     47      script_(snapshot.rootScript()->script()),
     48      loopStack_(mirGen.alloc()) {
     49  opSnapshotIter_ = scriptSnapshot_->opSnapshots().getFirst();
     50 }
     51 
     52 // Used for building inlined scripts.
     53 WarpBuilder::WarpBuilder(WarpBuilder* caller, WarpScriptSnapshot* snapshot,
     54                         CompileInfo& compileInfo, CallInfo* inlineCallInfo,
     55                         MResumePoint* callerResumePoint)
     56    : WarpBuilderShared(caller->snapshot(), caller->mirGen(), nullptr),
     57      warpCompilation_(caller->warpCompilation()),
     58      graph_(caller->mirGen().graph()),
     59      info_(compileInfo),
     60      scriptSnapshot_(snapshot),
     61      script_(snapshot->script()),
     62      loopStack_(caller->mirGen().alloc()),
     63      callerBuilder_(caller),
     64      callerResumePoint_(callerResumePoint),
     65      inlineCallInfo_(inlineCallInfo) {
     66  opSnapshotIter_ = snapshot->opSnapshots().getFirst();
     67 }
     68 
     69 BytecodeSite* WarpBuilder::newBytecodeSite(BytecodeLocation loc) {
     70  jsbytecode* pc = loc.toRawBytecode();
     71  MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
     72  return new (alloc()) BytecodeSite(info().inlineScriptTree(), pc);
     73 }
     74 
     75 const WarpOpSnapshot* WarpBuilder::getOpSnapshotImpl(
     76    BytecodeLocation loc, WarpOpSnapshot::Kind kind) {
     77  uint32_t offset = loc.bytecodeToOffset(script_);
     78 
     79  // Skip snapshots until we get to a snapshot with offset >= offset. This is
     80  // a loop because WarpBuilder can skip unreachable bytecode ops.
     81  while (opSnapshotIter_ && opSnapshotIter_->offset() < offset) {
     82    opSnapshotIter_ = opSnapshotIter_->getNext();
     83  }
     84 
     85  if (!opSnapshotIter_ || opSnapshotIter_->offset() != offset ||
     86      opSnapshotIter_->kind() != kind) {
     87    return nullptr;
     88  }
     89 
     90  return opSnapshotIter_;
     91 }
     92 
     93 void WarpBuilder::initBlock(MBasicBlock* block) {
     94  graph().addBlock(block);
     95 
     96  block->setLoopDepth(loopDepth());
     97 
     98  current = block;
     99 }
    100 
    101 bool WarpBuilder::startNewBlock(MBasicBlock* predecessor, BytecodeLocation loc,
    102                                size_t numToPop) {
    103  MBasicBlock* block =
    104      MBasicBlock::NewPopN(graph(), info(), predecessor, newBytecodeSite(loc),
    105                           MBasicBlock::NORMAL, numToPop);
    106  if (!block) {
    107    return false;
    108  }
    109 
    110  initBlock(block);
    111  return true;
    112 }
    113 
    114 bool WarpBuilder::startNewEntryBlock(size_t stackDepth, BytecodeLocation loc) {
    115  MBasicBlock* block =
    116      MBasicBlock::New(graph(), stackDepth, info(), /* maybePred = */ nullptr,
    117                       newBytecodeSite(loc), MBasicBlock::NORMAL);
    118  if (!block) {
    119    return false;
    120  }
    121 
    122  initBlock(block);
    123  return true;
    124 }
    125 
    126 bool WarpBuilder::startNewLoopHeaderBlock(BytecodeLocation loopHead) {
    127  MBasicBlock* header = MBasicBlock::NewPendingLoopHeader(
    128      graph(), info(), current, newBytecodeSite(loopHead));
    129  if (!header) {
    130    return false;
    131  }
    132 
    133  initBlock(header);
    134  return loopStack_.emplaceBack(header);
    135 }
    136 
    137 bool WarpBuilder::startNewOsrPreHeaderBlock(BytecodeLocation loopHead) {
    138  MOZ_ASSERT(loopHead.is(JSOp::LoopHead));
    139  MOZ_ASSERT(loopHead.toRawBytecode() == info().osrPc());
    140 
    141  // Create two blocks:
    142  // * The OSR entry block. This is always the graph's second block and has no
    143  //   predecessors. This is the entry point for OSR from the Baseline JIT.
    144  // * The OSR preheader block. This has two predecessors: the OSR entry block
    145  //   and the current block.
    146 
    147  MBasicBlock* pred = current;
    148 
    149  // Create the OSR entry block.
    150  if (!startNewEntryBlock(pred->stackDepth(), loopHead)) {
    151    return false;
    152  }
    153 
    154  MBasicBlock* osrBlock = current;
    155  graph().setOsrBlock(osrBlock);
    156  graph().moveBlockAfter(*graph().begin(), osrBlock);
    157 
    158  MOsrEntry* entry = MOsrEntry::New(alloc());
    159  osrBlock->add(entry);
    160 
    161  // Initialize environment chain.
    162  {
    163    uint32_t slot = info().environmentChainSlot();
    164    MInstruction* envv;
    165    if (usesEnvironmentChain()) {
    166      envv = MOsrEnvironmentChain::New(alloc(), entry);
    167    } else {
    168      // Use an undefined value if the script does not need its environment
    169      // chain, to match the main entry point.
    170      envv = MConstant::NewUndefined(alloc());
    171    }
    172    osrBlock->add(envv);
    173    osrBlock->initSlot(slot, envv);
    174  }
    175 
    176  // Initialize return value.
    177  {
    178    MInstruction* returnValue;
    179    if (!script_->noScriptRval()) {
    180      returnValue = MOsrReturnValue::New(alloc(), entry);
    181    } else {
    182      returnValue = MConstant::NewUndefined(alloc());
    183    }
    184    osrBlock->add(returnValue);
    185    osrBlock->initSlot(info().returnValueSlot(), returnValue);
    186  }
    187 
    188  // Initialize arguments object.
    189  MInstruction* argsObj = nullptr;
    190  if (info().needsArgsObj()) {
    191    argsObj = MOsrArgumentsObject::New(alloc(), entry);
    192    osrBlock->add(argsObj);
    193    osrBlock->initSlot(info().argsObjSlot(), argsObj);
    194  }
    195 
    196  if (info().hasFunMaybeLazy()) {
    197    // Initialize |this| parameter.
    198    MParameter* thisv = MParameter::New(alloc(), MParameter::THIS_SLOT);
    199    osrBlock->add(thisv);
    200    osrBlock->initSlot(info().thisSlot(), thisv);
    201 
    202    // Initialize arguments. There are three cases:
    203    //
    204    // 1) There's no ArgumentsObject or it doesn't alias formals. In this case
    205    //    we can just use the frame's argument slot.
    206    // 2) The ArgumentsObject aliases formals and the argument is stored in the
    207    //    CallObject. Use |undefined| because we can't load from the arguments
    208    //    object and code will use the CallObject anyway.
    209    // 3) The ArgumentsObject aliases formals and the argument isn't stored in
    210    //    the CallObject. We have to load it from the ArgumentsObject.
    211    for (uint32_t i = 0; i < info().nargs(); i++) {
    212      uint32_t slot = info().argSlotUnchecked(i);
    213      MInstruction* osrv;
    214      if (!info().argsObjAliasesFormals()) {
    215        osrv = MParameter::New(alloc().fallible(), i);
    216      } else if (script_->formalIsAliased(i)) {
    217        osrv = MConstant::New(alloc().fallible(), UndefinedValue());
    218      } else {
    219        osrv = MGetArgumentsObjectArg::New(alloc().fallible(), argsObj, i);
    220      }
    221      if (!osrv) {
    222        return false;
    223      }
    224      current->add(osrv);
    225      current->initSlot(slot, osrv);
    226    }
    227  }
    228 
    229  // Initialize locals.
    230  uint32_t nlocals = info().nlocals();
    231  for (uint32_t i = 0; i < nlocals; i++) {
    232    uint32_t slot = info().localSlot(i);
    233    ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(i);
    234    MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset);
    235    if (!osrv) {
    236      return false;
    237    }
    238    current->add(osrv);
    239    current->initSlot(slot, osrv);
    240  }
    241 
    242  // Initialize expression stack slots.
    243  uint32_t numStackSlots = current->stackDepth() - info().firstStackSlot();
    244  for (uint32_t i = 0; i < numStackSlots; i++) {
    245    uint32_t slot = info().stackSlot(i);
    246    ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(nlocals + i);
    247    MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset);
    248    if (!osrv) {
    249      return false;
    250    }
    251    current->add(osrv);
    252    current->initSlot(slot, osrv);
    253  }
    254 
    255  MStart* start = MStart::New(alloc());
    256  current->add(start);
    257 
    258  // Note: phi specialization can add type guard instructions to the OSR entry
    259  // block if needed. See TypeAnalyzer::shouldSpecializeOsrPhis.
    260 
    261  // Create the preheader block, with the predecessor block and OSR block as
    262  // predecessors.
    263  if (!startNewBlock(pred, loopHead)) {
    264    return false;
    265  }
    266 
    267  pred->end(MGoto::New(alloc(), current));
    268  osrBlock->end(MGoto::New(alloc(), current));
    269 
    270  if (!current->addPredecessor(alloc(), osrBlock)) {
    271    return false;
    272  }
    273 
    274  return true;
    275 }
    276 
    277 bool WarpBuilder::addPendingEdge(BytecodeLocation target, MBasicBlock* block,
    278                                 uint32_t successor, uint32_t numToPop) {
    279  MOZ_ASSERT(successor < block->lastIns()->numSuccessors());
    280  MOZ_ASSERT(numToPop <= block->stackDepth());
    281 
    282  jsbytecode* targetPC = target.toRawBytecode();
    283  PendingEdgesMap::AddPtr p = pendingEdges_.lookupForAdd(targetPC);
    284  if (p) {
    285    return p->value().emplaceBack(block, successor, numToPop);
    286  }
    287 
    288  PendingEdges edges;
    289  static_assert(PendingEdges::InlineLength >= 1,
    290                "Appending one element should be infallible");
    291  MOZ_ALWAYS_TRUE(edges.emplaceBack(block, successor, numToPop));
    292 
    293  return pendingEdges_.add(p, targetPC, std::move(edges));
    294 }
    295 
    296 bool WarpBuilder::build() {
    297  if (!buildPrologue()) {
    298    return false;
    299  }
    300 
    301  if (!buildBody()) {
    302    return false;
    303  }
    304 
    305  if (!MPhi::markIteratorPhis(*iterators())) {
    306    return false;
    307  }
    308 
    309  MOZ_ASSERT_IF(info().osrPc(), graph().osrBlock());
    310  MOZ_ASSERT(loopStack_.empty());
    311  MOZ_ASSERT(loopDepth() == 0);
    312 
    313  return true;
    314 }
    315 
    316 bool WarpBuilder::buildInline() {
    317  if (!buildInlinePrologue()) {
    318    return false;
    319  }
    320 
    321  if (!buildBody()) {
    322    return false;
    323  }
    324 
    325  MOZ_ASSERT(loopStack_.empty());
    326  return true;
    327 }
    328 
    329 MInstruction* WarpBuilder::buildNamedLambdaEnv(MDefinition* callee,
    330                                               MDefinition* env,
    331                                               NamedLambdaObject* templateObj,
    332                                               gc::Heap initialHeap) {
    333  MOZ_ASSERT(templateObj->numDynamicSlots() == 0);
    334 
    335  MInstruction* namedLambda =
    336      MNewNamedLambdaObject::New(alloc(), templateObj, initialHeap);
    337  current->add(namedLambda);
    338 
    339  // Initialize the object's reserved slots.
    340  if (initialHeap == gc::Heap::Default) {
    341    // No post barrier is needed here: the object will be allocated in the
    342    // nursery if possible, and if the tenured heap is used instead, a minor
    343    // collection will have been performed that moved env/callee to the tenured
    344    // heap.
    345 #ifdef DEBUG
    346    current->add(
    347        MAssertCanElidePostWriteBarrier::New(alloc(), namedLambda, env));
    348    current->add(
    349        MAssertCanElidePostWriteBarrier::New(alloc(), namedLambda, callee));
    350 #endif
    351  } else {
    352    current->add(MPostWriteBarrier::New(alloc(), namedLambda, env));
    353    current->add(MPostWriteBarrier::New(alloc(), namedLambda, callee));
    354  }
    355 
    356  size_t enclosingSlot = NamedLambdaObject::enclosingEnvironmentSlot();
    357  size_t lambdaSlot = NamedLambdaObject::lambdaSlot();
    358  current->add(MStoreFixedSlot::NewUnbarriered(alloc(), namedLambda,
    359                                               enclosingSlot, env));
    360  current->add(MStoreFixedSlot::NewUnbarriered(alloc(), namedLambda, lambdaSlot,
    361                                               callee));
    362 
    363  return namedLambda;
    364 }
    365 
    366 MInstruction* WarpBuilder::buildCallObject(MDefinition* callee,
    367                                           MDefinition* env,
    368                                           CallObject* templateObj,
    369                                           gc::Heap initialHeap) {
    370  MConstant* templateCst = constant(ObjectValue(*templateObj));
    371 
    372  MNewCallObject* callObj =
    373      MNewCallObject::New(alloc(), templateCst, initialHeap);
    374  current->add(callObj);
    375 
    376  // Initialize the object's reserved slots.
    377  if (initialHeap == gc::Heap::Default) {
    378    // No post barrier is needed here, for the same reason as in
    379    // buildNamedLambdaEnv.
    380 #ifdef DEBUG
    381    current->add(MAssertCanElidePostWriteBarrier::New(alloc(), callObj, env));
    382    current->add(
    383        MAssertCanElidePostWriteBarrier::New(alloc(), callObj, callee));
    384 #endif
    385  } else {
    386    current->add(MPostWriteBarrier::New(alloc(), callObj, env));
    387    current->add(MPostWriteBarrier::New(alloc(), callObj, callee));
    388  }
    389 
    390  size_t enclosingSlot = CallObject::enclosingEnvironmentSlot();
    391  size_t calleeSlot = CallObject::calleeSlot();
    392  current->add(
    393      MStoreFixedSlot::NewUnbarriered(alloc(), callObj, enclosingSlot, env));
    394  current->add(
    395      MStoreFixedSlot::NewUnbarriered(alloc(), callObj, calleeSlot, callee));
    396 
    397  return callObj;
    398 }
    399 
    400 bool WarpBuilder::buildEnvironmentChain() {
    401  const WarpEnvironment& env = scriptSnapshot()->environment();
    402 
    403  if (env.is<NoEnvironment>()) {
    404    return true;
    405  }
    406 
    407  MInstruction* envDef = env.match(
    408      [](const NoEnvironment&) -> MInstruction* {
    409        MOZ_CRASH("Already handled");
    410      },
    411      [this](JSObject* obj) -> MInstruction* {
    412        return constant(ObjectValue(*obj));
    413      },
    414      [this](const FunctionEnvironment& env) -> MInstruction* {
    415        MDefinition* callee = getCallee();
    416        MInstruction* envDef = MFunctionEnvironment::New(alloc(), callee);
    417        current->add(envDef);
    418        if (NamedLambdaObject* obj = env.namedLambdaTemplate) {
    419          envDef = buildNamedLambdaEnv(callee, envDef, obj, env.initialHeap);
    420        }
    421        if (CallObject* obj = env.callObjectTemplate) {
    422          envDef = buildCallObject(callee, envDef, obj, env.initialHeap);
    423          if (!envDef) {
    424            return nullptr;
    425          }
    426        }
    427        return envDef;
    428      });
    429  if (!envDef) {
    430    return false;
    431  }
    432 
    433  // Update the environment slot from UndefinedValue only after the initial
    434  // environment is created so that bailout doesn't see a partial environment.
    435  // See: |BaselineStackBuilder::buildBaselineFrame|
    436  current->setEnvironmentChain(envDef);
    437  return true;
    438 }
    439 
    440 bool WarpBuilder::buildPrologue() {
    441  BytecodeLocation startLoc(script_, script_->code());
    442  if (!startNewEntryBlock(info().firstStackSlot(), startLoc)) {
    443    return false;
    444  }
    445 
    446  if (info().hasFunMaybeLazy()) {
    447    // Initialize |this|.
    448    MParameter* param = MParameter::New(alloc(), MParameter::THIS_SLOT);
    449    current->add(param);
    450    current->initSlot(info().thisSlot(), param);
    451 
    452    // Initialize arguments.
    453    for (uint32_t i = 0; i < info().nargs(); i++) {
    454      MParameter* param = MParameter::New(alloc().fallible(), i);
    455      if (!param) {
    456        return false;
    457      }
    458      current->add(param);
    459      current->initSlot(info().argSlotUnchecked(i), param);
    460    }
    461  }
    462 
    463  MConstant* undef = constant(UndefinedValue());
    464 
    465  // Initialize local slots.
    466  for (uint32_t i = 0; i < info().nlocals(); i++) {
    467    current->initSlot(info().localSlot(i), undef);
    468  }
    469 
    470  // Initialize the environment chain, return value, and arguments object slots.
    471  current->initSlot(info().environmentChainSlot(), undef);
    472  current->initSlot(info().returnValueSlot(), undef);
    473  if (info().needsArgsObj()) {
    474    current->initSlot(info().argsObjSlot(), undef);
    475  }
    476 
    477  current->add(MStart::New(alloc()));
    478 
    479  // Guard against over-recursion.
    480  MCheckOverRecursed* check = MCheckOverRecursed::New(alloc());
    481  current->add(check);
    482 
    483  if (!buildEnvironmentChain()) {
    484    return false;
    485  }
    486 
    487 #ifdef JS_CACHEIR_SPEW
    488  if (snapshot().needsFinalWarmUpCount()) {
    489    MIncrementWarmUpCounter* ins =
    490        MIncrementWarmUpCounter::New(alloc(), script_);
    491    current->add(ins);
    492  }
    493 #endif
    494 
    495  return true;
    496 }
    497 
    498 bool WarpBuilder::buildInlinePrologue() {
    499  // Generate entry block.
    500  BytecodeLocation startLoc(script_, script_->code());
    501  if (!startNewEntryBlock(info().firstStackSlot(), startLoc)) {
    502    return false;
    503  }
    504  current->setCallerResumePoint(callerResumePoint());
    505 
    506  // Connect the entry block to the last block in the caller's graph.
    507  MBasicBlock* pred = callerBuilder()->current;
    508  MOZ_ASSERT(pred == callerResumePoint()->block());
    509 
    510  pred->end(MGoto::New(alloc(), current));
    511  if (!current->addPredecessorWithoutPhis(pred)) {
    512    return false;
    513  }
    514 
    515  MConstant* undef = constant(UndefinedValue());
    516 
    517  // Initialize env chain slot to Undefined.  It's set later by
    518  // |buildEnvironmentChain|.
    519  current->initSlot(info().environmentChainSlot(), undef);
    520 
    521  // Initialize |return value| slot.
    522  current->initSlot(info().returnValueSlot(), undef);
    523 
    524  // Initialize |arguments| slot if needed.
    525  if (info().needsArgsObj()) {
    526    current->initSlot(info().argsObjSlot(), undef);
    527  }
    528 
    529  // Initialize |this| slot.
    530  current->initSlot(info().thisSlot(), inlineCallInfo()->thisArg());
    531 
    532  uint32_t callerArgs = inlineCallInfo()->argc();
    533  uint32_t actualArgs = info().nargs();
    534  uint32_t passedArgs = std::min<uint32_t>(callerArgs, actualArgs);
    535 
    536  // Initialize actually set arguments.
    537  for (uint32_t i = 0; i < passedArgs; i++) {
    538    MDefinition* arg = inlineCallInfo()->getArg(i);
    539    current->initSlot(info().argSlotUnchecked(i), arg);
    540  }
    541 
    542  // Pass undefined for missing arguments.
    543  for (uint32_t i = passedArgs; i < actualArgs; i++) {
    544    current->initSlot(info().argSlotUnchecked(i), undef);
    545  }
    546 
    547  // Initialize local slots.
    548  for (uint32_t i = 0; i < info().nlocals(); i++) {
    549    current->initSlot(info().localSlot(i), undef);
    550  }
    551 
    552  MOZ_ASSERT(current->entryResumePoint()->stackDepth() == info().totalSlots());
    553 
    554  if (!buildEnvironmentChain()) {
    555    return false;
    556  }
    557 
    558  return true;
    559 }
    560 
    561 #ifdef DEBUG
    562 // In debug builds, after compiling a bytecode op, this class is used to check
    563 // that all values popped by this opcode either:
    564 //
    565 //   (1) Have the ImplicitlyUsed flag set on them.
    566 //   (2) Have more uses than before compiling this op (the value is
    567 //       used as operand of a new MIR instruction).
    568 //
    569 // This is used to catch problems where WarpBuilder pops a value without
    570 // adding any SSA uses and doesn't call setImplicitlyUsedUnchecked on it.
    571 class MOZ_RAII WarpPoppedValueUseChecker {
    572  Vector<MDefinition*, 4, SystemAllocPolicy> popped_;
    573  Vector<size_t, 4, SystemAllocPolicy> poppedUses_;
    574  MBasicBlock* current_;
    575  BytecodeLocation loc_;
    576 
    577 public:
    578  WarpPoppedValueUseChecker(MBasicBlock* current, BytecodeLocation loc)
    579      : current_(current), loc_(loc) {}
    580 
    581  [[nodiscard]] bool init() {
    582    // Don't require SSA uses for values popped by these ops.
    583    switch (loc_.getOp()) {
    584      case JSOp::Pop:
    585      case JSOp::PopN:
    586      case JSOp::DupAt:
    587      case JSOp::Dup:
    588      case JSOp::Dup2:
    589      case JSOp::Pick:
    590      case JSOp::Unpick:
    591      case JSOp::Swap:
    592      case JSOp::SetArg:
    593      case JSOp::SetLocal:
    594      case JSOp::InitLexical:
    595      case JSOp::SetRval:
    596      case JSOp::Void:
    597        // Basic stack/local/argument management opcodes.
    598        return true;
    599 
    600      case JSOp::Case:
    601      case JSOp::Default:
    602        // These ops have to pop the switch value when branching but don't
    603        // actually use it.
    604        return true;
    605 
    606      default:
    607        break;
    608    }
    609 
    610    unsigned nuses = loc_.useCount();
    611 
    612    for (unsigned i = 0; i < nuses; i++) {
    613      MDefinition* def = current_->peek(-int32_t(i + 1));
    614      if (!popped_.append(def) || !poppedUses_.append(def->defUseCount())) {
    615        return false;
    616      }
    617    }
    618 
    619    return true;
    620  }
    621 
    622  void checkAfterOp() {
    623    for (size_t i = 0; i < popped_.length(); i++) {
    624      // First value popped by JSOp::EndIter is not used at all, it's similar
    625      // to JSOp::Pop above.
    626      if (loc_.is(JSOp::EndIter) && i == 0) {
    627        continue;
    628      }
    629      MOZ_ASSERT(popped_[i]->isImplicitlyUsed() ||
    630                 popped_[i]->defUseCount() > poppedUses_[i]);
    631    }
    632  }
    633 };
    634 #endif
    635 
    636 bool WarpBuilder::buildBody() {
    637  for (BytecodeLocation loc : AllBytecodesIterable(script_)) {
    638    if (mirGen().shouldCancel("WarpBuilder (opcode loop)")) {
    639      return false;
    640    }
    641 
    642    // Skip unreachable ops (for example code after a 'return' or 'throw') until
    643    // we get to the next jump target.
    644    if (hasTerminatedBlock()) {
    645      // Finish any "broken" loops with an unreachable backedge. For example:
    646      //
    647      //   do {
    648      //     ...
    649      //     return;
    650      //     ...
    651      //   } while (x);
    652      //
    653      // This loop never actually loops.
    654      if (loc.isBackedge() && !loopStack_.empty()) {
    655        BytecodeLocation loopHead(script_,
    656                                  loopStack_.back().header()->entryPC());
    657        if (loc.isBackedgeForLoophead(loopHead)) {
    658          decLoopDepth();
    659          loopStack_.popBack();
    660        }
    661      }
    662      if (!loc.isJumpTarget()) {
    663        continue;
    664      }
    665    }
    666 
    667    if (!alloc().ensureBallast()) {
    668      return false;
    669    }
    670 
    671 #ifdef DEBUG
    672    WarpPoppedValueUseChecker useChecker(current, loc);
    673    if (!useChecker.init()) {
    674      return false;
    675    }
    676 #endif
    677    bool wantPreciseLineNumbers = js::jit::PerfEnabled();
    678    if (wantPreciseLineNumbers && !hasTerminatedBlock()) {
    679      current->updateTrackedSite(newBytecodeSite(loc));
    680    }
    681 
    682    JSOp op = loc.getOp();
    683 
    684 #define BUILD_OP(OP, ...)                       \
    685  case JSOp::OP:                                \
    686    if (MOZ_UNLIKELY(!this->build_##OP(loc))) { \
    687      return false;                             \
    688    }                                           \
    689    break;
    690    switch (op) { FOR_EACH_OPCODE(BUILD_OP) }
    691 #undef BUILD_OP
    692 
    693 #ifdef DEBUG
    694    useChecker.checkAfterOp();
    695 #endif
    696  }
    697 
    698  return true;
    699 }
    700 
    701 #define DEF_OP(OP)                                 \
    702  bool WarpBuilder::build_##OP(BytecodeLocation) { \
    703    MOZ_CRASH("Unsupported op");                   \
    704  }
    705 WARP_UNSUPPORTED_OPCODE_LIST(DEF_OP)
    706 #undef DEF_OP
    707 
    708 bool WarpBuilder::build_Nop(BytecodeLocation) { return true; }
    709 
    710 bool WarpBuilder::build_NopDestructuring(BytecodeLocation) { return true; }
    711 
    712 bool WarpBuilder::build_NopIsAssignOp(BytecodeLocation) { return true; }
    713 
    714 bool WarpBuilder::build_TryDestructuring(BytecodeLocation) {
    715  // Set the hasTryBlock flag to turn off optimizations that eliminate dead
    716  // resume points operands because the exception handler code for
    717  // TryNoteKind::Destructuring is effectively a (specialized) catch-block.
    718  graph().setHasTryBlock();
    719  return true;
    720 }
    721 
    722 bool WarpBuilder::build_Lineno(BytecodeLocation) { return true; }
    723 
    724 bool WarpBuilder::build_DebugLeaveLexicalEnv(BytecodeLocation) { return true; }
    725 
    726 bool WarpBuilder::build_Undefined(BytecodeLocation) {
    727  pushConstant(UndefinedValue());
    728  return true;
    729 }
    730 
    731 bool WarpBuilder::build_Void(BytecodeLocation) {
    732  current->pop();
    733  pushConstant(UndefinedValue());
    734  return true;
    735 }
    736 
    737 bool WarpBuilder::build_Null(BytecodeLocation) {
    738  pushConstant(NullValue());
    739  return true;
    740 }
    741 
    742 bool WarpBuilder::build_Hole(BytecodeLocation) {
    743  pushConstant(MagicValue(JS_ELEMENTS_HOLE));
    744  return true;
    745 }
    746 
    747 bool WarpBuilder::build_Uninitialized(BytecodeLocation) {
    748  pushConstant(MagicValue(JS_UNINITIALIZED_LEXICAL));
    749  return true;
    750 }
    751 
    752 bool WarpBuilder::build_IsConstructing(BytecodeLocation) {
    753  pushConstant(MagicValue(JS_IS_CONSTRUCTING));
    754  return true;
    755 }
    756 
    757 bool WarpBuilder::build_False(BytecodeLocation) {
    758  pushConstant(BooleanValue(false));
    759  return true;
    760 }
    761 
    762 bool WarpBuilder::build_True(BytecodeLocation) {
    763  pushConstant(BooleanValue(true));
    764  return true;
    765 }
    766 
    767 bool WarpBuilder::build_Pop(BytecodeLocation) {
    768  current->pop();
    769  return true;
    770 }
    771 
    772 bool WarpBuilder::build_PopN(BytecodeLocation loc) {
    773  for (uint32_t i = 0, n = loc.getPopCount(); i < n; i++) {
    774    current->pop();
    775  }
    776  return true;
    777 }
    778 
    779 bool WarpBuilder::build_Dup(BytecodeLocation) {
    780  current->pushSlot(current->stackDepth() - 1);
    781  return true;
    782 }
    783 
    784 bool WarpBuilder::build_Dup2(BytecodeLocation) {
    785  uint32_t lhsSlot = current->stackDepth() - 2;
    786  uint32_t rhsSlot = current->stackDepth() - 1;
    787  current->pushSlot(lhsSlot);
    788  current->pushSlot(rhsSlot);
    789  return true;
    790 }
    791 
    792 bool WarpBuilder::build_DupAt(BytecodeLocation loc) {
    793  current->pushSlot(current->stackDepth() - 1 - loc.getDupAtIndex());
    794  return true;
    795 }
    796 
    797 bool WarpBuilder::build_Swap(BytecodeLocation) {
    798  current->swapAt(-1);
    799  return true;
    800 }
    801 
    802 bool WarpBuilder::build_Pick(BytecodeLocation loc) {
    803  int32_t depth = -int32_t(loc.getPickDepth());
    804  current->pick(depth);
    805  return true;
    806 }
    807 
    808 bool WarpBuilder::build_Unpick(BytecodeLocation loc) {
    809  int32_t depth = -int32_t(loc.getUnpickDepth());
    810  current->unpick(depth);
    811  return true;
    812 }
    813 
    814 bool WarpBuilder::build_Zero(BytecodeLocation) {
    815  pushConstant(Int32Value(0));
    816  return true;
    817 }
    818 
    819 bool WarpBuilder::build_One(BytecodeLocation) {
    820  pushConstant(Int32Value(1));
    821  return true;
    822 }
    823 
    824 bool WarpBuilder::build_Int8(BytecodeLocation loc) {
    825  pushConstant(Int32Value(loc.getInt8()));
    826  return true;
    827 }
    828 
    829 bool WarpBuilder::build_Uint16(BytecodeLocation loc) {
    830  pushConstant(Int32Value(loc.getUint16()));
    831  return true;
    832 }
    833 
    834 bool WarpBuilder::build_Uint24(BytecodeLocation loc) {
    835  pushConstant(Int32Value(loc.getUint24()));
    836  return true;
    837 }
    838 
    839 bool WarpBuilder::build_Int32(BytecodeLocation loc) {
    840  pushConstant(Int32Value(loc.getInt32()));
    841  return true;
    842 }
    843 
    844 bool WarpBuilder::build_Double(BytecodeLocation loc) {
    845  pushConstant(loc.getInlineValue());
    846  return true;
    847 }
    848 
    849 bool WarpBuilder::build_BigInt(BytecodeLocation loc) {
    850  BigInt* bi = loc.getBigInt(script_);
    851  pushConstant(BigIntValue(bi));
    852  return true;
    853 }
    854 
    855 bool WarpBuilder::build_String(BytecodeLocation loc) {
    856  JSString* str = loc.getString(script_);
    857  pushConstant(StringValue(str));
    858  return true;
    859 }
    860 
    861 bool WarpBuilder::build_Symbol(BytecodeLocation loc) {
    862  uint32_t which = loc.getSymbolIndex();
    863  JS::Symbol* sym = mirGen().runtime->wellKnownSymbols().get(which);
    864  pushConstant(SymbolValue(sym));
    865  return true;
    866 }
    867 
    868 bool WarpBuilder::build_RegExp(BytecodeLocation loc) {
    869  RegExpObject* reObj = loc.getRegExp(script_);
    870 
    871  auto* snapshot = getOpSnapshot<WarpRegExp>(loc);
    872 
    873  MRegExp* regexp = MRegExp::New(alloc(), reObj, snapshot->hasShared());
    874  current->add(regexp);
    875  current->push(regexp);
    876 
    877  return true;
    878 }
    879 
    880 bool WarpBuilder::build_Return(BytecodeLocation) {
    881  MDefinition* def = current->pop();
    882 
    883  MReturn* ret = MReturn::New(alloc(), def);
    884  current->end(ret);
    885 
    886  if (!graph().addReturn(current)) {
    887    return false;
    888  }
    889 
    890  setTerminatedBlock();
    891  return true;
    892 }
    893 
    894 bool WarpBuilder::build_RetRval(BytecodeLocation) {
    895  MDefinition* rval;
    896  if (script_->noScriptRval()) {
    897    rval = constant(UndefinedValue());
    898  } else {
    899    rval = current->getSlot(info().returnValueSlot());
    900  }
    901 
    902  MReturn* ret = MReturn::New(alloc(), rval);
    903  current->end(ret);
    904 
    905  if (!graph().addReturn(current)) {
    906    return false;
    907  }
    908 
    909  setTerminatedBlock();
    910  return true;
    911 }
    912 
    913 bool WarpBuilder::build_SetRval(BytecodeLocation) {
    914  MOZ_ASSERT(!script_->noScriptRval());
    915  MDefinition* rval = current->pop();
    916  current->setSlot(info().returnValueSlot(), rval);
    917  return true;
    918 }
    919 
    920 bool WarpBuilder::build_GetRval(BytecodeLocation) {
    921  MOZ_ASSERT(!script_->noScriptRval());
    922  MDefinition* rval = current->getSlot(info().returnValueSlot());
    923  current->push(rval);
    924  return true;
    925 }
    926 
    927 bool WarpBuilder::build_GetLocal(BytecodeLocation loc) {
    928  current->pushLocal(loc.local());
    929  return true;
    930 }
    931 
    932 bool WarpBuilder::build_SetLocal(BytecodeLocation loc) {
    933  current->setLocal(loc.local());
    934  return true;
    935 }
    936 
    937 bool WarpBuilder::build_InitLexical(BytecodeLocation loc) {
    938  current->setLocal(loc.local());
    939  return true;
    940 }
    941 
    942 bool WarpBuilder::build_GetArg(BytecodeLocation loc) {
    943  uint32_t arg = loc.arg();
    944  if (info().argsObjAliasesFormals()) {
    945    MDefinition* argsObj = current->argumentsObject();
    946    auto* getArg = MGetArgumentsObjectArg::New(alloc(), argsObj, arg);
    947    current->add(getArg);
    948    current->push(getArg);
    949  } else {
    950    current->pushArg(arg);
    951  }
    952  return true;
    953 }
    954 
    955 bool WarpBuilder::build_GetFrameArg(BytecodeLocation loc) {
    956  current->pushArgUnchecked(loc.arg());
    957  return true;
    958 }
    959 
    960 bool WarpBuilder::build_SetArg(BytecodeLocation loc) {
    961  uint32_t arg = loc.arg();
    962  MDefinition* val = current->peek(-1);
    963 
    964  if (!info().argsObjAliasesFormals()) {
    965    // Either |arguments| is never referenced within this function, or
    966    // it doesn't map to the actual arguments values. Either way, we
    967    // don't need to worry about synchronizing the argument values
    968    // when writing to them.
    969    current->setArg(arg);
    970    return true;
    971  }
    972 
    973  // If an arguments object is in use, and it aliases formals, then all SetArgs
    974  // must go through the arguments object.
    975  MDefinition* argsObj = current->argumentsObject();
    976  current->add(MPostWriteBarrier::New(alloc(), argsObj, val));
    977  auto* ins = MSetArgumentsObjectArg::New(alloc(), argsObj, val, arg);
    978  current->add(ins);
    979  return resumeAfter(ins, loc);
    980 }
    981 
    982 bool WarpBuilder::build_ArgumentsLength(BytecodeLocation) {
    983  if (inlineCallInfo()) {
    984    pushConstant(Int32Value(inlineCallInfo()->argc()));
    985  } else {
    986    auto* argsLength = MArgumentsLength::New(alloc());
    987    current->add(argsLength);
    988    current->push(argsLength);
    989  }
    990  return true;
    991 }
    992 
    993 bool WarpBuilder::build_GetActualArg(BytecodeLocation) {
    994  MDefinition* index = current->pop();
    995  MInstruction* arg;
    996  if (inlineCallInfo()) {
    997    arg = MGetInlinedArgument::New(alloc(), index, *inlineCallInfo());
    998    if (!arg) {
    999      return false;
   1000    }
   1001  } else {
   1002    arg = MGetFrameArgument::New(alloc(), index);
   1003  }
   1004  current->add(arg);
   1005  current->push(arg);
   1006  return true;
   1007 }
   1008 
   1009 bool WarpBuilder::build_ToNumeric(BytecodeLocation loc) {
   1010  return buildUnaryOp(loc);
   1011 }
   1012 
   1013 bool WarpBuilder::buildUnaryOp(BytecodeLocation loc) {
   1014  MDefinition* value = current->pop();
   1015  return buildIC(loc, CacheKind::UnaryArith, {value});
   1016 }
   1017 
   1018 bool WarpBuilder::build_Inc(BytecodeLocation loc) { return buildUnaryOp(loc); }
   1019 
   1020 bool WarpBuilder::build_Dec(BytecodeLocation loc) { return buildUnaryOp(loc); }
   1021 
   1022 bool WarpBuilder::build_Pos(BytecodeLocation loc) { return buildUnaryOp(loc); }
   1023 
   1024 bool WarpBuilder::build_Neg(BytecodeLocation loc) { return buildUnaryOp(loc); }
   1025 
   1026 bool WarpBuilder::build_BitNot(BytecodeLocation loc) {
   1027  return buildUnaryOp(loc);
   1028 }
   1029 
   1030 bool WarpBuilder::buildBinaryOp(BytecodeLocation loc) {
   1031  MDefinition* right = current->pop();
   1032  MDefinition* left = current->pop();
   1033  return buildIC(loc, CacheKind::BinaryArith, {left, right});
   1034 }
   1035 
   1036 bool WarpBuilder::build_Add(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1037 
   1038 bool WarpBuilder::build_Sub(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1039 
   1040 bool WarpBuilder::build_Mul(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1041 
   1042 bool WarpBuilder::build_Div(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1043 
   1044 bool WarpBuilder::build_Mod(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1045 
   1046 bool WarpBuilder::build_Pow(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1047 
   1048 bool WarpBuilder::build_BitAnd(BytecodeLocation loc) {
   1049  return buildBinaryOp(loc);
   1050 }
   1051 
   1052 bool WarpBuilder::build_BitOr(BytecodeLocation loc) {
   1053  return buildBinaryOp(loc);
   1054 }
   1055 
   1056 bool WarpBuilder::build_BitXor(BytecodeLocation loc) {
   1057  return buildBinaryOp(loc);
   1058 }
   1059 
   1060 bool WarpBuilder::build_Lsh(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1061 
   1062 bool WarpBuilder::build_Rsh(BytecodeLocation loc) { return buildBinaryOp(loc); }
   1063 
   1064 bool WarpBuilder::build_Ursh(BytecodeLocation loc) {
   1065  return buildBinaryOp(loc);
   1066 }
   1067 
   1068 bool WarpBuilder::buildCompareOp(BytecodeLocation loc) {
   1069  MDefinition* right = current->pop();
   1070  MDefinition* left = current->pop();
   1071  return buildIC(loc, CacheKind::Compare, {left, right});
   1072 }
   1073 
   1074 bool WarpBuilder::build_Eq(BytecodeLocation loc) { return buildCompareOp(loc); }
   1075 
   1076 bool WarpBuilder::build_Ne(BytecodeLocation loc) { return buildCompareOp(loc); }
   1077 
   1078 bool WarpBuilder::build_Lt(BytecodeLocation loc) { return buildCompareOp(loc); }
   1079 
   1080 bool WarpBuilder::build_Le(BytecodeLocation loc) { return buildCompareOp(loc); }
   1081 
   1082 bool WarpBuilder::build_Gt(BytecodeLocation loc) { return buildCompareOp(loc); }
   1083 
   1084 bool WarpBuilder::build_Ge(BytecodeLocation loc) { return buildCompareOp(loc); }
   1085 
   1086 bool WarpBuilder::build_StrictEq(BytecodeLocation loc) {
   1087  return buildCompareOp(loc);
   1088 }
   1089 
   1090 bool WarpBuilder::build_StrictNe(BytecodeLocation loc) {
   1091  return buildCompareOp(loc);
   1092 }
   1093 
   1094 bool WarpBuilder::buildStrictConstantEqOp(BytecodeLocation loc,
   1095                                          JSOp compareOp) {
   1096  auto operand = loc.getConstantCompareOperand();
   1097  MDefinition* value = current->pop();
   1098  switch (operand.type()) {
   1099    case ConstantCompareOperand::EncodedType::Int32: {
   1100      if (value->type() == MIRType::Int32) {
   1101        MConstant* constant = MConstant::NewInt32(alloc(), operand.toInt32());
   1102        current->add(constant);
   1103 
   1104        auto* compare = MCompare::New(alloc(), value, constant, compareOp,
   1105                                      MCompare::Compare_Int32);
   1106        current->add(compare);
   1107        current->push(compare);
   1108        return true;
   1109      }
   1110 
   1111      auto* ins = MStrictConstantCompareInt32::New(
   1112          alloc(), value, operand.toInt32(), compareOp);
   1113      current->add(ins);
   1114      current->push(ins);
   1115      return true;
   1116    }
   1117 
   1118    case ConstantCompareOperand::EncodedType::Boolean: {
   1119      if (value->type() == MIRType::Boolean) {
   1120        MConstant* constant = MConstant::NewInt32(alloc(), operand.toBoolean());
   1121        current->add(constant);
   1122 
   1123        auto* toBoolToInt32 = MBooleanToInt32::New(alloc(), value);
   1124        current->add(toBoolToInt32);
   1125 
   1126        auto* compare = MCompare::New(alloc(), toBoolToInt32, constant,
   1127                                      compareOp, MCompare::Compare_Int32);
   1128        current->add(compare);
   1129        current->push(compare);
   1130        return true;
   1131      }
   1132 
   1133      auto* ins = MStrictConstantCompareBoolean::New(
   1134          alloc(), value, operand.toBoolean(), compareOp);
   1135      current->add(ins);
   1136      current->push(ins);
   1137      return true;
   1138    }
   1139 
   1140    case ConstantCompareOperand::EncodedType::Null: {
   1141      MConstant* constant = MConstant::NewNull(alloc());
   1142      current->add(constant);
   1143 
   1144      auto* ins = MCompare::New(alloc(), value, constant, compareOp,
   1145                                MCompare::Compare_Null);
   1146      current->add(ins);
   1147      current->push(ins);
   1148      return true;
   1149    }
   1150 
   1151    case ConstantCompareOperand::EncodedType::Undefined: {
   1152      MConstant* constant = MConstant::NewUndefined(alloc());
   1153      current->add(constant);
   1154 
   1155      auto* ins = MCompare::New(alloc(), value, constant, compareOp,
   1156                                MCompare::Compare_Undefined);
   1157      current->add(ins);
   1158      current->push(ins);
   1159      return true;
   1160    }
   1161  }
   1162  return true;
   1163 }
   1164 
   1165 bool WarpBuilder::build_StrictConstantEq(BytecodeLocation loc) {
   1166  return buildStrictConstantEqOp(loc, JSOp::StrictEq);
   1167 }
   1168 
   1169 bool WarpBuilder::build_StrictConstantNe(BytecodeLocation loc) {
   1170  return buildStrictConstantEqOp(loc, JSOp::StrictNe);
   1171 }
   1172 
   1173 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
   1174 bool WarpBuilder::build_AddDisposable(BytecodeLocation loc) {
   1175  MOZ_ASSERT(usesEnvironmentChain());
   1176 
   1177  UsingHint hint = loc.getUsingHint();
   1178  MDefinition* needsClosure = current->pop();
   1179  MDefinition* method = current->pop();
   1180  MDefinition* obj = current->pop();
   1181  MDefinition* env = current->environmentChain();
   1182 
   1183  MAddDisposableResource* ins = MAddDisposableResource::New(
   1184      alloc(), env, obj, method, needsClosure, uint8_t(hint));
   1185  current->add(ins);
   1186  return resumeAfter(ins, loc);
   1187 }
   1188 
   1189 bool WarpBuilder::build_TakeDisposeCapability(BytecodeLocation loc) {
   1190  MOZ_ASSERT(usesEnvironmentChain());
   1191  MDefinition* env = current->environmentChain();
   1192 
   1193  MTakeDisposeCapability* ins = MTakeDisposeCapability::New(alloc(), env);
   1194  current->add(ins);
   1195  current->push(ins);
   1196  return resumeAfter(ins, loc);
   1197 }
   1198 
   1199 bool WarpBuilder::build_CreateSuppressedError(BytecodeLocation loc) {
   1200  MDefinition* suppressed = current->pop();
   1201  MDefinition* error = current->pop();
   1202 
   1203  MCreateSuppressedError* ins =
   1204      MCreateSuppressedError::New(alloc(), error, suppressed);
   1205  current->add(ins);
   1206  current->push(ins);
   1207  return true;
   1208 }
   1209 #endif
   1210 
   1211 // Returns true iff the MTest added for |op| has a true-target corresponding
   1212 // with the join point in the bytecode.
   1213 static bool TestTrueTargetIsJoinPoint(JSOp op) {
   1214  switch (op) {
   1215    case JSOp::JumpIfTrue:
   1216    case JSOp::Or:
   1217    case JSOp::Case:
   1218      return true;
   1219 
   1220    case JSOp::JumpIfFalse:
   1221    case JSOp::And:
   1222    case JSOp::Coalesce:
   1223      return false;
   1224 
   1225    default:
   1226      MOZ_CRASH("Unexpected op");
   1227  }
   1228 }
   1229 
   1230 bool WarpBuilder::build_JumpTarget(BytecodeLocation loc) {
   1231  PendingEdgesMap::Ptr p = pendingEdges_.lookup(loc.toRawBytecode());
   1232  if (!p) {
   1233    // No (reachable) jumps so this is just a no-op.
   1234    return true;
   1235  }
   1236 
   1237  PendingEdges edges(std::move(p->value()));
   1238  pendingEdges_.remove(p);
   1239 
   1240  MOZ_ASSERT(!edges.empty());
   1241 
   1242  // Create join block if there's fall-through from the previous bytecode op.
   1243  if (!hasTerminatedBlock()) {
   1244    MBasicBlock* pred = current;
   1245    if (!startNewBlock(pred, loc)) {
   1246      return false;
   1247    }
   1248    pred->end(MGoto::New(alloc(), current));
   1249  }
   1250 
   1251  for (const PendingEdge& edge : edges) {
   1252    MBasicBlock* source = edge.block();
   1253    uint32_t numToPop = edge.numToPop();
   1254 
   1255    if (hasTerminatedBlock()) {
   1256      if (!startNewBlock(source, loc, numToPop)) {
   1257        return false;
   1258      }
   1259    } else {
   1260      MOZ_ASSERT(source->stackDepth() - numToPop == current->stackDepth());
   1261      if (!current->addPredecessorPopN(alloc(), source, numToPop)) {
   1262        return false;
   1263      }
   1264    }
   1265 
   1266    MOZ_ASSERT(source->lastIns()->isTest() || source->lastIns()->isGoto() ||
   1267               source->lastIns()->isTableSwitch());
   1268    source->lastIns()->initSuccessor(edge.successor(), current);
   1269  }
   1270 
   1271  MOZ_ASSERT(!hasTerminatedBlock());
   1272  return true;
   1273 }
   1274 
   1275 bool WarpBuilder::addIteratorLoopPhis(BytecodeLocation loopHead) {
   1276  // When unwinding the stack for a thrown exception, the exception handler must
   1277  // close live iterators. For ForIn and Destructuring loops, the exception
   1278  // handler needs access to values on the stack. To prevent them from being
   1279  // optimized away (and replaced with the JS_OPTIMIZED_OUT MagicValue), we need
   1280  // to mark the phis (and phis they flow into) as having implicit uses.
   1281  // See ProcessTryNotes in vm/Interpreter.cpp and CloseLiveIteratorIon in
   1282  // jit/JitFrames.cpp
   1283 
   1284  MOZ_ASSERT(current->stackDepth() >= info().firstStackSlot());
   1285 
   1286  bool emptyStack = current->stackDepth() == info().firstStackSlot();
   1287  if (emptyStack) {
   1288    return true;
   1289  }
   1290 
   1291  jsbytecode* loopHeadPC = loopHead.toRawBytecode();
   1292 
   1293  for (TryNoteIterAllNoGC tni(script_, loopHeadPC); !tni.done(); ++tni) {
   1294    const TryNote& tn = **tni;
   1295 
   1296    // Stop if we reach an outer loop because outer loops were already
   1297    // processed when we visited their loop headers.
   1298    if (tn.isLoop()) {
   1299      BytecodeLocation tnStart = script_->offsetToLocation(tn.start);
   1300      if (tnStart != loopHead) {
   1301        MOZ_ASSERT(tnStart.is(JSOp::LoopHead));
   1302        MOZ_ASSERT(tnStart < loopHead);
   1303        return true;
   1304      }
   1305    }
   1306 
   1307    switch (tn.kind()) {
   1308      case TryNoteKind::Destructuring:
   1309      case TryNoteKind::ForIn: {
   1310        // For for-in loops we add the iterator object to iterators(). For
   1311        // destructuring loops we add the "done" value that's on top of the
   1312        // stack and used in the exception handler.
   1313        MOZ_ASSERT(tn.stackDepth >= 1);
   1314        uint32_t slot = info().stackSlot(tn.stackDepth - 1);
   1315        MPhi* phi = current->getSlot(slot)->toPhi();
   1316        if (!iterators()->append(phi)) {
   1317          return false;
   1318        }
   1319        break;
   1320      }
   1321      case TryNoteKind::Loop:
   1322      case TryNoteKind::ForOf:
   1323        // Regular loops do not have iterators to close. ForOf loops handle
   1324        // unwinding using catch blocks.
   1325        break;
   1326      default:
   1327        break;
   1328    }
   1329  }
   1330 
   1331  return true;
   1332 }
   1333 
   1334 bool WarpBuilder::build_LoopHead(BytecodeLocation loc) {
   1335  // All loops have the following bytecode structure:
   1336  //
   1337  //    LoopHead
   1338  //    ...
   1339  //    JumpIfTrue/Goto to LoopHead
   1340 
   1341  if (hasTerminatedBlock()) {
   1342    // The whole loop is unreachable.
   1343    return true;
   1344  }
   1345 
   1346  // Handle OSR from Baseline JIT code.
   1347  if (loc.toRawBytecode() == info().osrPc()) {
   1348    if (!startNewOsrPreHeaderBlock(loc)) {
   1349      return false;
   1350    }
   1351  }
   1352 
   1353  incLoopDepth();
   1354 
   1355  MBasicBlock* pred = current;
   1356  if (!startNewLoopHeaderBlock(loc)) {
   1357    return false;
   1358  }
   1359 
   1360  pred->end(MGoto::New(alloc(), current));
   1361 
   1362  if (!addIteratorLoopPhis(loc)) {
   1363    return false;
   1364  }
   1365 
   1366  MInterruptCheck* check = MInterruptCheck::New(alloc());
   1367  current->add(check);
   1368 
   1369 #ifdef JS_CACHEIR_SPEW
   1370  if (snapshot().needsFinalWarmUpCount()) {
   1371    MIncrementWarmUpCounter* ins =
   1372        MIncrementWarmUpCounter::New(alloc(), script_);
   1373    current->add(ins);
   1374  }
   1375 #endif
   1376 
   1377  return true;
   1378 }
   1379 
   1380 bool WarpBuilder::buildTestOp(BytecodeLocation loc) {
   1381  MDefinition* originalValue = current->peek(-1);
   1382 
   1383  if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
   1384    // If we have CacheIR, we can use it to refine the input. Note that
   1385    // the transpiler doesn't generate any control instructions. Instead,
   1386    // we fall through and generate them below.
   1387    MDefinition* value = current->pop();
   1388    if (!TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {value})) {
   1389      return false;
   1390    }
   1391  }
   1392 
   1393  if (loc.isBackedge()) {
   1394    return buildTestBackedge(loc);
   1395  }
   1396 
   1397  JSOp op = loc.getOp();
   1398  BytecodeLocation target1 = loc.next();
   1399  BytecodeLocation target2 = loc.getJumpTarget();
   1400 
   1401  if (TestTrueTargetIsJoinPoint(op)) {
   1402    std::swap(target1, target2);
   1403  }
   1404 
   1405  MDefinition* value = current->pop();
   1406 
   1407  // JSOp::And and JSOp::Or leave the top stack value unchanged.  The
   1408  // top stack value may have been converted to bool by a transpiled
   1409  // ToBool IC, so we push the original value.
   1410  bool mustKeepCondition = (op == JSOp::And || op == JSOp::Or);
   1411  if (mustKeepCondition) {
   1412    current->push(originalValue);
   1413  }
   1414 
   1415  // If this op always branches to the same location we treat this as a
   1416  // JSOp::Goto.
   1417  if (target1 == target2) {
   1418    value->setImplicitlyUsedUnchecked();
   1419    return buildForwardGoto(target1);
   1420  }
   1421 
   1422  MTest* test = MTest::New(alloc(), value, /* ifTrue = */ nullptr,
   1423                           /* ifFalse = */ nullptr);
   1424  current->end(test);
   1425 
   1426  // JSOp::Case must pop a second value on the true-branch (the input to the
   1427  // switch-statement).
   1428  uint32_t numToPop = (loc.getOp() == JSOp::Case) ? 1 : 0;
   1429 
   1430  if (!addPendingEdge(target1, current, MTest::TrueBranchIndex, numToPop)) {
   1431    return false;
   1432  }
   1433  if (!addPendingEdge(target2, current, MTest::FalseBranchIndex)) {
   1434    return false;
   1435  }
   1436 
   1437  if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
   1438    test->setObservedTypes(typesSnapshot->list());
   1439  }
   1440 
   1441  setTerminatedBlock();
   1442  return true;
   1443 }
   1444 
   1445 bool WarpBuilder::buildTestBackedge(BytecodeLocation loc) {
   1446  MOZ_ASSERT(loc.is(JSOp::JumpIfTrue));
   1447  MOZ_ASSERT(loopDepth() > 0);
   1448 
   1449  MDefinition* value = current->pop();
   1450 
   1451  BytecodeLocation loopHead = loc.getJumpTarget();
   1452  MOZ_ASSERT(loopHead.is(JSOp::LoopHead));
   1453 
   1454  BytecodeLocation successor = loc.next();
   1455 
   1456  // We can finish the loop now. Use the loophead pc instead of the current pc
   1457  // because the stack depth at the start of that op matches the current stack
   1458  // depth (after popping our operand).
   1459  MBasicBlock* pred = current;
   1460  if (!startNewBlock(current, loopHead)) {
   1461    return false;
   1462  }
   1463 
   1464  MTest* test = MTest::New(alloc(), value, /* ifTrue = */ current,
   1465                           /* ifFalse = */ nullptr);
   1466  pred->end(test);
   1467 
   1468  if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
   1469    test->setObservedTypes(typesSnapshot->list());
   1470  }
   1471 
   1472  if (!addPendingEdge(successor, pred, MTest::FalseBranchIndex)) {
   1473    return false;
   1474  }
   1475 
   1476  return buildBackedge();
   1477 }
   1478 
   1479 bool WarpBuilder::build_JumpIfFalse(BytecodeLocation loc) {
   1480  return buildTestOp(loc);
   1481 }
   1482 
   1483 bool WarpBuilder::build_JumpIfTrue(BytecodeLocation loc) {
   1484  return buildTestOp(loc);
   1485 }
   1486 
   1487 bool WarpBuilder::build_And(BytecodeLocation loc) { return buildTestOp(loc); }
   1488 
   1489 bool WarpBuilder::build_Or(BytecodeLocation loc) { return buildTestOp(loc); }
   1490 
   1491 bool WarpBuilder::build_Case(BytecodeLocation loc) { return buildTestOp(loc); }
   1492 
   1493 bool WarpBuilder::build_Default(BytecodeLocation loc) {
   1494  current->pop();
   1495  return buildForwardGoto(loc.getJumpTarget());
   1496 }
   1497 
   1498 bool WarpBuilder::build_Coalesce(BytecodeLocation loc) {
   1499  BytecodeLocation target1 = loc.next();
   1500  BytecodeLocation target2 = loc.getJumpTarget();
   1501  MOZ_ASSERT(target2 > target1);
   1502 
   1503  MDefinition* value = current->peek(-1);
   1504 
   1505  MInstruction* isNullOrUndefined = MIsNullOrUndefined::New(alloc(), value);
   1506  current->add(isNullOrUndefined);
   1507 
   1508  current->end(MTest::New(alloc(), isNullOrUndefined, /* ifTrue = */ nullptr,
   1509                          /* ifFalse = */ nullptr));
   1510 
   1511  if (!addPendingEdge(target1, current, MTest::TrueBranchIndex)) {
   1512    return false;
   1513  }
   1514  if (!addPendingEdge(target2, current, MTest::FalseBranchIndex)) {
   1515    return false;
   1516  }
   1517 
   1518  setTerminatedBlock();
   1519  return true;
   1520 }
   1521 
   1522 bool WarpBuilder::buildBackedge() {
   1523  decLoopDepth();
   1524 
   1525  MBasicBlock* header = loopStack_.popCopy().header();
   1526  current->end(MGoto::New(alloc(), header));
   1527 
   1528  if (!header->setBackedge(current)) {
   1529    return false;
   1530  }
   1531 
   1532  setTerminatedBlock();
   1533  return true;
   1534 }
   1535 
   1536 bool WarpBuilder::buildForwardGoto(BytecodeLocation target) {
   1537  current->end(MGoto::New(alloc(), nullptr));
   1538 
   1539  if (!addPendingEdge(target, current, MGoto::TargetIndex)) {
   1540    return false;
   1541  }
   1542 
   1543  setTerminatedBlock();
   1544  return true;
   1545 }
   1546 
   1547 bool WarpBuilder::build_Goto(BytecodeLocation loc) {
   1548  if (loc.isBackedge()) {
   1549    return buildBackedge();
   1550  }
   1551 
   1552  return buildForwardGoto(loc.getJumpTarget());
   1553 }
   1554 
   1555 bool WarpBuilder::build_IsNullOrUndefined(BytecodeLocation loc) {
   1556  MDefinition* value = current->peek(-1);
   1557  auto* isNullOrUndef = MIsNullOrUndefined::New(alloc(), value);
   1558  current->add(isNullOrUndef);
   1559  current->push(isNullOrUndef);
   1560  return true;
   1561 }
   1562 
   1563 bool WarpBuilder::build_DebugCheckSelfHosted(BytecodeLocation loc) {
   1564 #ifdef DEBUG
   1565  MDefinition* val = current->pop();
   1566  MDebugCheckSelfHosted* check = MDebugCheckSelfHosted::New(alloc(), val);
   1567  current->add(check);
   1568  current->push(check);
   1569  if (!resumeAfter(check, loc)) {
   1570    return false;
   1571  }
   1572 #endif
   1573  return true;
   1574 }
   1575 
   1576 bool WarpBuilder::build_DynamicImport(BytecodeLocation loc) {
   1577  MDefinition* options = current->pop();
   1578  MDefinition* specifier = current->pop();
   1579  MDynamicImport* ins = MDynamicImport::New(alloc(), specifier, options);
   1580  current->add(ins);
   1581  current->push(ins);
   1582  return resumeAfter(ins, loc);
   1583 }
   1584 
   1585 bool WarpBuilder::build_Not(BytecodeLocation loc) {
   1586  if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
   1587    // If we have CacheIR, we can use it to refine the input before
   1588    // emitting the MNot.
   1589    MDefinition* value = current->pop();
   1590    if (!TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {value})) {
   1591      return false;
   1592    }
   1593  }
   1594 
   1595  MDefinition* value = current->pop();
   1596  MNot* ins = MNot::New(alloc(), value);
   1597  current->add(ins);
   1598  current->push(ins);
   1599 
   1600  if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
   1601    ins->setObservedTypes(typesSnapshot->list());
   1602  }
   1603 
   1604  return true;
   1605 }
   1606 
   1607 bool WarpBuilder::build_ToString(BytecodeLocation loc) {
   1608  MDefinition* value = current->pop();
   1609 
   1610  if (value->type() == MIRType::String) {
   1611    value->setImplicitlyUsedUnchecked();
   1612    current->push(value);
   1613    return true;
   1614  }
   1615 
   1616  MToString* ins =
   1617      MToString::New(alloc(), value, MToString::SideEffectHandling::Supported);
   1618  current->add(ins);
   1619  current->push(ins);
   1620  if (ins->isEffectful()) {
   1621    return resumeAfter(ins, loc);
   1622  }
   1623  return true;
   1624 }
   1625 
   1626 bool WarpBuilder::usesEnvironmentChain() const {
   1627  return script_->jitScript()->usesEnvironmentChain();
   1628 }
   1629 
   1630 bool WarpBuilder::build_GlobalOrEvalDeclInstantiation(BytecodeLocation loc) {
   1631  MOZ_ASSERT(!script_->isForEval(), "Eval scripts not supported");
   1632  auto* redeclCheck = MGlobalDeclInstantiation::New(alloc());
   1633  current->add(redeclCheck);
   1634  return resumeAfter(redeclCheck, loc);
   1635 }
   1636 
   1637 bool WarpBuilder::build_BindVar(BytecodeLocation) {
   1638  MOZ_ASSERT(usesEnvironmentChain());
   1639 
   1640  MDefinition* env = current->environmentChain();
   1641  MCallBindVar* ins = MCallBindVar::New(alloc(), env);
   1642  current->add(ins);
   1643  current->push(ins);
   1644  return true;
   1645 }
   1646 
   1647 bool WarpBuilder::build_MutateProto(BytecodeLocation loc) {
   1648  MDefinition* value = current->pop();
   1649  MDefinition* obj = current->peek(-1);
   1650  MMutateProto* mutate = MMutateProto::New(alloc(), obj, value);
   1651  current->add(mutate);
   1652  return resumeAfter(mutate, loc);
   1653 }
   1654 
   1655 MDefinition* WarpBuilder::getCallee() {
   1656  if (inlineCallInfo()) {
   1657    return inlineCallInfo()->callee();
   1658  }
   1659 
   1660  MInstruction* callee = MCallee::New(alloc());
   1661  current->add(callee);
   1662  return callee;
   1663 }
   1664 
   1665 bool WarpBuilder::build_Callee(BytecodeLocation) {
   1666  MDefinition* callee = getCallee();
   1667  current->push(callee);
   1668  return true;
   1669 }
   1670 
   1671 bool WarpBuilder::build_ToAsyncIter(BytecodeLocation loc) {
   1672  MDefinition* nextMethod = current->pop();
   1673  MDefinition* iterator = current->pop();
   1674  MToAsyncIter* ins = MToAsyncIter::New(alloc(), iterator, nextMethod);
   1675  current->add(ins);
   1676  current->push(ins);
   1677  return resumeAfter(ins, loc);
   1678 }
   1679 
   1680 bool WarpBuilder::build_ToPropertyKey(BytecodeLocation loc) {
   1681  MDefinition* value = current->pop();
   1682  return buildIC(loc, CacheKind::ToPropertyKey, {value});
   1683 }
   1684 
   1685 bool WarpBuilder::build_Typeof(BytecodeLocation loc) {
   1686  MDefinition* input = current->pop();
   1687 
   1688  if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
   1689    auto* typeOf = MTypeOf::New(alloc(), input);
   1690    typeOf->setObservedTypes(typesSnapshot->list());
   1691    current->add(typeOf);
   1692 
   1693    auto* ins = MTypeOfName::New(alloc(), typeOf);
   1694    current->add(ins);
   1695    current->push(ins);
   1696    return true;
   1697  }
   1698 
   1699  return buildIC(loc, CacheKind::TypeOf, {input});
   1700 }
   1701 
   1702 bool WarpBuilder::build_TypeofExpr(BytecodeLocation loc) {
   1703  return build_Typeof(loc);
   1704 }
   1705 
   1706 bool WarpBuilder::build_TypeofEq(BytecodeLocation loc) {
   1707  auto operand = loc.getTypeofEqOperand();
   1708  JSType type = operand.type();
   1709  JSOp compareOp = operand.compareOp();
   1710  MDefinition* input = current->pop();
   1711 
   1712  if (const auto* typesSnapshot = getOpSnapshot<WarpPolymorphicTypes>(loc)) {
   1713    auto* typeOf = MTypeOf::New(alloc(), input);
   1714    typeOf->setObservedTypes(typesSnapshot->list());
   1715    current->add(typeOf);
   1716 
   1717    auto* typeInt = MConstant::NewInt32(alloc(), type);
   1718    current->add(typeInt);
   1719 
   1720    auto* ins = MCompare::New(alloc(), typeOf, typeInt, compareOp,
   1721                              MCompare::Compare_Int32);
   1722    current->add(ins);
   1723    current->push(ins);
   1724    return true;
   1725  }
   1726 
   1727  return buildIC(loc, CacheKind::TypeOfEq, {input});
   1728 }
   1729 
   1730 bool WarpBuilder::build_Arguments(BytecodeLocation loc) {
   1731  auto* snapshot = getOpSnapshot<WarpArguments>(loc);
   1732  MOZ_ASSERT(info().needsArgsObj());
   1733  MOZ_ASSERT(snapshot);
   1734  MOZ_ASSERT(usesEnvironmentChain());
   1735 
   1736  ArgumentsObject* templateObj = snapshot->templateObj();
   1737  MDefinition* env = current->environmentChain();
   1738 
   1739  MInstruction* argsObj;
   1740  if (inlineCallInfo()) {
   1741    argsObj = MCreateInlinedArgumentsObject::New(
   1742        alloc(), env, getCallee(), inlineCallInfo()->argv(), templateObj);
   1743    if (!argsObj) {
   1744      return false;
   1745    }
   1746  } else {
   1747    argsObj = MCreateArgumentsObject::New(alloc(), env, templateObj);
   1748  }
   1749  current->add(argsObj);
   1750  current->setArgumentsObject(argsObj);
   1751  current->push(argsObj);
   1752 
   1753  return true;
   1754 }
   1755 
   1756 bool WarpBuilder::build_ObjWithProto(BytecodeLocation loc) {
   1757  MDefinition* proto = current->pop();
   1758  MInstruction* ins = MObjectWithProto::New(alloc(), proto);
   1759  current->add(ins);
   1760  current->push(ins);
   1761  return resumeAfter(ins, loc);
   1762 }
   1763 
   1764 MDefinition* WarpBuilder::walkEnvironmentChain(uint32_t numHops) {
   1765  MDefinition* env = current->environmentChain();
   1766 
   1767  for (uint32_t i = 0; i < numHops; i++) {
   1768    if (!alloc().ensureBallast()) {
   1769      return nullptr;
   1770    }
   1771 
   1772    MInstruction* ins = MEnclosingEnvironment::New(alloc(), env);
   1773    current->add(ins);
   1774    env = ins;
   1775  }
   1776 
   1777  return env;
   1778 }
   1779 
   1780 bool WarpBuilder::build_GetAliasedVar(BytecodeLocation loc) {
   1781  EnvironmentCoordinate ec = loc.getEnvironmentCoordinate();
   1782  MDefinition* obj = walkEnvironmentChain(ec.hops());
   1783  if (!obj) {
   1784    return false;
   1785  }
   1786 
   1787  MInstruction* load;
   1788  if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
   1789    load = MLoadFixedSlot::New(alloc(), obj, ec.slot());
   1790  } else {
   1791    MInstruction* slots = MSlots::New(alloc(), obj);
   1792    current->add(slots);
   1793 
   1794    uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
   1795    load = MLoadDynamicSlot::New(alloc(), slots, slot);
   1796  }
   1797 
   1798  current->add(load);
   1799  current->push(load);
   1800  return true;
   1801 }
   1802 
   1803 bool WarpBuilder::build_SetAliasedVar(BytecodeLocation loc) {
   1804  EnvironmentCoordinate ec = loc.getEnvironmentCoordinate();
   1805  MDefinition* val = current->peek(-1);
   1806  MDefinition* obj = walkEnvironmentChain(ec.hops());
   1807  if (!obj) {
   1808    return false;
   1809  }
   1810 
   1811  current->add(MPostWriteBarrier::New(alloc(), obj, val));
   1812 
   1813  MInstruction* store;
   1814  if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) {
   1815    store = MStoreFixedSlot::NewBarriered(alloc(), obj, ec.slot(), val);
   1816  } else {
   1817    MInstruction* slots = MSlots::New(alloc(), obj);
   1818    current->add(slots);
   1819 
   1820    uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec);
   1821    store = MStoreDynamicSlot::NewBarriered(alloc(), slots, slot, val);
   1822  }
   1823 
   1824  current->add(store);
   1825  return resumeAfter(store, loc);
   1826 }
   1827 
   1828 bool WarpBuilder::build_InitAliasedLexical(BytecodeLocation loc) {
   1829  return build_SetAliasedVar(loc);
   1830 }
   1831 
   1832 bool WarpBuilder::build_EnvCallee(BytecodeLocation loc) {
   1833  uint32_t numHops = loc.getEnvCalleeNumHops();
   1834  MDefinition* env = walkEnvironmentChain(numHops);
   1835  if (!env) {
   1836    return false;
   1837  }
   1838 
   1839  auto* callee = MLoadFixedSlot::New(alloc(), env, CallObject::calleeSlot());
   1840  current->add(callee);
   1841  current->push(callee);
   1842  return true;
   1843 }
   1844 
   1845 bool WarpBuilder::build_Iter(BytecodeLocation loc) {
   1846  MDefinition* obj = current->pop();
   1847  return buildIC(loc, CacheKind::GetIterator, {obj});
   1848 }
   1849 
   1850 bool WarpBuilder::build_MoreIter(BytecodeLocation loc) {
   1851  MDefinition* iter = current->peek(-1);
   1852  MInstruction* ins = MIteratorMore::New(alloc(), iter);
   1853  current->add(ins);
   1854  current->push(ins);
   1855  return resumeAfter(ins, loc);
   1856 }
   1857 
   1858 bool WarpBuilder::build_EndIter(BytecodeLocation loc) {
   1859  current->pop();  // Iterator value is not used.
   1860  MDefinition* iter = current->pop();
   1861  MInstruction* ins = MIteratorEnd::New(alloc(), iter);
   1862  current->add(ins);
   1863  return resumeAfter(ins, loc);
   1864 }
   1865 
   1866 bool WarpBuilder::build_CloseIter(BytecodeLocation loc) {
   1867  MDefinition* iter = current->pop();
   1868  iter = unboxObjectInfallible(iter, IsMovable::No);
   1869  return buildIC(loc, CacheKind::CloseIter, {iter});
   1870 }
   1871 
   1872 bool WarpBuilder::build_IsNoIter(BytecodeLocation) {
   1873  MDefinition* def = current->peek(-1);
   1874  MOZ_ASSERT(def->isIteratorMore());
   1875  MInstruction* ins = MIsNoIter::New(alloc(), def);
   1876  current->add(ins);
   1877  current->push(ins);
   1878  return true;
   1879 }
   1880 
   1881 bool WarpBuilder::build_OptimizeGetIterator(BytecodeLocation loc) {
   1882  MDefinition* value = current->pop();
   1883  return buildIC(loc, CacheKind::OptimizeGetIterator, {value});
   1884 }
   1885 
   1886 bool WarpBuilder::transpileCall(BytecodeLocation loc,
   1887                                const WarpCacheIR* cacheIRSnapshot,
   1888                                CallInfo* callInfo) {
   1889  // Synthesize the constant number of arguments for this call op.
   1890  auto* argc = MConstant::NewInt32(alloc(), callInfo->argc());
   1891  current->add(argc);
   1892 
   1893  return TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, {argc}, callInfo);
   1894 }
   1895 
   1896 void WarpBuilder::buildCreateThis(CallInfo& callInfo) {
   1897  MOZ_ASSERT(callInfo.constructing());
   1898 
   1899  // Inline the this-object allocation on the caller-side.
   1900  MDefinition* callee = callInfo.callee();
   1901  MDefinition* newTarget = callInfo.getNewTarget();
   1902  auto* createThis = MCreateThis::New(alloc(), callee, newTarget);
   1903  current->add(createThis);
   1904  callInfo.thisArg()->setImplicitlyUsedUnchecked();
   1905  callInfo.setThis(createThis);
   1906 }
   1907 
   1908 bool WarpBuilder::buildCallOp(BytecodeLocation loc) {
   1909  uint32_t argc = loc.getCallArgc();
   1910  JSOp op = loc.getOp();
   1911  bool constructing = IsConstructOp(op);
   1912  bool ignoresReturnValue = (op == JSOp::CallIgnoresRv || loc.resultIsPopped());
   1913 
   1914  CallInfo callInfo(alloc(), constructing, ignoresReturnValue);
   1915  if (!callInfo.init(current, argc)) {
   1916    return false;
   1917  }
   1918 
   1919  if (const auto* inliningSnapshot = getOpSnapshot<WarpInlinedCall>(loc)) {
   1920    // Transpile the CacheIR to generate the correct guards before
   1921    // inlining.  In this case, CacheOp::CallInlinedFunction updates
   1922    // the CallInfo, but does not generate a call.
   1923    callInfo.markAsInlined();
   1924    if (!transpileCall(loc, inliningSnapshot->cacheIRSnapshot(), &callInfo)) {
   1925      return false;
   1926    }
   1927 
   1928    // Generate the body of the inlined function.
   1929    return buildInlinedCall(loc, inliningSnapshot, callInfo);
   1930  }
   1931 
   1932  if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
   1933    return transpileCall(loc, cacheIRSnapshot, &callInfo);
   1934  }
   1935 
   1936  if (getOpSnapshot<WarpBailout>(loc)) {
   1937    callInfo.setImplicitlyUsedUnchecked();
   1938    return buildBailoutForColdIC(loc, CacheKind::Call);
   1939  }
   1940 
   1941  bool needsThisCheck = false;
   1942  if (callInfo.constructing()) {
   1943    buildCreateThis(callInfo);
   1944    needsThisCheck = true;
   1945  }
   1946 
   1947  MCall* call = makeCall(callInfo, needsThisCheck);
   1948  if (!call) {
   1949    return false;
   1950  }
   1951 
   1952  current->add(call);
   1953  current->push(call);
   1954  return resumeAfter(call, loc);
   1955 }
   1956 
   1957 bool WarpBuilder::build_Call(BytecodeLocation loc) { return buildCallOp(loc); }
   1958 
   1959 bool WarpBuilder::build_CallContent(BytecodeLocation loc) {
   1960  return buildCallOp(loc);
   1961 }
   1962 
   1963 bool WarpBuilder::build_CallIgnoresRv(BytecodeLocation loc) {
   1964  return buildCallOp(loc);
   1965 }
   1966 
   1967 bool WarpBuilder::build_CallIter(BytecodeLocation loc) {
   1968  return buildCallOp(loc);
   1969 }
   1970 
   1971 bool WarpBuilder::build_CallContentIter(BytecodeLocation loc) {
   1972  return buildCallOp(loc);
   1973 }
   1974 
   1975 bool WarpBuilder::build_New(BytecodeLocation loc) { return buildCallOp(loc); }
   1976 
   1977 bool WarpBuilder::build_NewContent(BytecodeLocation loc) {
   1978  return buildCallOp(loc);
   1979 }
   1980 
   1981 bool WarpBuilder::build_SuperCall(BytecodeLocation loc) {
   1982  return buildCallOp(loc);
   1983 }
   1984 
   1985 bool WarpBuilder::build_FunctionThis(BytecodeLocation loc) {
   1986  MOZ_ASSERT(info().hasFunMaybeLazy());
   1987 
   1988  if (script_->strict()) {
   1989    // No need to wrap primitive |this| in strict mode.
   1990    current->pushSlot(info().thisSlot());
   1991    return true;
   1992  }
   1993 
   1994  MOZ_ASSERT(!script_->hasNonSyntacticScope(),
   1995             "WarpOracle should have aborted compilation");
   1996 
   1997  MDefinition* def = current->getSlot(info().thisSlot());
   1998  JSObject* globalThis = snapshot().globalLexicalEnvThis();
   1999 
   2000  auto* thisObj = MBoxNonStrictThis::New(alloc(), def, globalThis);
   2001  current->add(thisObj);
   2002  current->push(thisObj);
   2003 
   2004  return true;
   2005 }
   2006 
   2007 bool WarpBuilder::build_GlobalThis(BytecodeLocation loc) {
   2008  MOZ_ASSERT(!script_->hasNonSyntacticScope());
   2009  JSObject* obj = snapshot().globalLexicalEnvThis();
   2010  pushConstant(ObjectValue(*obj));
   2011  return true;
   2012 }
   2013 
   2014 MConstant* WarpBuilder::globalLexicalEnvConstant() {
   2015  JSObject* globalLexical = snapshot().globalLexicalEnv();
   2016  return constant(ObjectValue(*globalLexical));
   2017 }
   2018 
   2019 bool WarpBuilder::build_GetName(BytecodeLocation loc) {
   2020  MOZ_ASSERT(usesEnvironmentChain());
   2021 
   2022  MDefinition* env = current->environmentChain();
   2023  env = unboxObjectInfallible(env, IsMovable::Yes);
   2024  return buildIC(loc, CacheKind::GetName, {env});
   2025 }
   2026 
   2027 bool WarpBuilder::build_GetGName(BytecodeLocation loc) {
   2028  MOZ_ASSERT(!script_->hasNonSyntacticScope());
   2029 
   2030  MDefinition* env = globalLexicalEnvConstant();
   2031  return buildIC(loc, CacheKind::GetName, {env});
   2032 }
   2033 
   2034 bool WarpBuilder::build_BindName(BytecodeLocation loc) {
   2035  MOZ_ASSERT(usesEnvironmentChain());
   2036 
   2037  MDefinition* env = current->environmentChain();
   2038  env = unboxObjectInfallible(env, IsMovable::Yes);
   2039  return buildIC(loc, CacheKind::BindName, {env});
   2040 }
   2041 
   2042 bool WarpBuilder::build_BindUnqualifiedName(BytecodeLocation loc) {
   2043  MOZ_ASSERT(usesEnvironmentChain());
   2044 
   2045  MDefinition* env = current->environmentChain();
   2046  env = unboxObjectInfallible(env, IsMovable::Yes);
   2047  return buildIC(loc, CacheKind::BindName, {env});
   2048 }
   2049 
   2050 bool WarpBuilder::build_BindUnqualifiedGName(BytecodeLocation loc) {
   2051  MOZ_ASSERT(!script_->hasNonSyntacticScope());
   2052 
   2053  if (const auto* snapshot = getOpSnapshot<WarpBindUnqualifiedGName>(loc)) {
   2054    JSObject* globalEnv = snapshot->globalEnv();
   2055    pushConstant(ObjectValue(*globalEnv));
   2056    return true;
   2057  }
   2058 
   2059  MDefinition* env = globalLexicalEnvConstant();
   2060  return buildIC(loc, CacheKind::BindName, {env});
   2061 }
   2062 
   2063 bool WarpBuilder::build_GetProp(BytecodeLocation loc) {
   2064  MDefinition* val = current->pop();
   2065  return buildIC(loc, CacheKind::GetProp, {val});
   2066 }
   2067 
   2068 bool WarpBuilder::build_GetBoundName(BytecodeLocation loc) {
   2069  MDefinition* val = current->pop();
   2070  return buildIC(loc, CacheKind::GetProp, {val});
   2071 }
   2072 
   2073 bool WarpBuilder::build_GetElem(BytecodeLocation loc) {
   2074  MDefinition* id = current->pop();
   2075  MDefinition* val = current->pop();
   2076  return buildIC(loc, CacheKind::GetElem, {val, id});
   2077 }
   2078 
   2079 bool WarpBuilder::build_SetProp(BytecodeLocation loc) {
   2080  MDefinition* val = current->pop();
   2081  MDefinition* obj = current->pop();
   2082  current->push(val);
   2083  return buildIC(loc, CacheKind::SetProp, {obj, val});
   2084 }
   2085 
   2086 bool WarpBuilder::build_StrictSetProp(BytecodeLocation loc) {
   2087  return build_SetProp(loc);
   2088 }
   2089 
   2090 bool WarpBuilder::build_SetName(BytecodeLocation loc) {
   2091  return build_SetProp(loc);
   2092 }
   2093 
   2094 bool WarpBuilder::build_StrictSetName(BytecodeLocation loc) {
   2095  return build_SetProp(loc);
   2096 }
   2097 
   2098 bool WarpBuilder::build_SetGName(BytecodeLocation loc) {
   2099  return build_SetProp(loc);
   2100 }
   2101 
   2102 bool WarpBuilder::build_StrictSetGName(BytecodeLocation loc) {
   2103  return build_SetProp(loc);
   2104 }
   2105 
   2106 bool WarpBuilder::build_InitGLexical(BytecodeLocation loc) {
   2107  MOZ_ASSERT(!script_->hasNonSyntacticScope());
   2108 
   2109  MDefinition* globalLexical = globalLexicalEnvConstant();
   2110  MDefinition* val = current->peek(-1);
   2111 
   2112  return buildIC(loc, CacheKind::SetProp, {globalLexical, val});
   2113 }
   2114 
   2115 bool WarpBuilder::build_SetElem(BytecodeLocation loc) {
   2116  MDefinition* val = current->pop();
   2117  MDefinition* id = current->pop();
   2118  MDefinition* obj = current->pop();
   2119  current->push(val);
   2120  return buildIC(loc, CacheKind::SetElem, {obj, id, val});
   2121 }
   2122 
   2123 bool WarpBuilder::build_StrictSetElem(BytecodeLocation loc) {
   2124  return build_SetElem(loc);
   2125 }
   2126 
   2127 bool WarpBuilder::build_DelProp(BytecodeLocation loc) {
   2128  PropertyName* name = loc.getPropertyName(script_);
   2129  MDefinition* obj = current->pop();
   2130  bool strict = loc.getOp() == JSOp::StrictDelProp;
   2131 
   2132  MInstruction* ins = MDeleteProperty::New(alloc(), obj, name, strict);
   2133  current->add(ins);
   2134  current->push(ins);
   2135  return resumeAfter(ins, loc);
   2136 }
   2137 
   2138 bool WarpBuilder::build_StrictDelProp(BytecodeLocation loc) {
   2139  return build_DelProp(loc);
   2140 }
   2141 
   2142 bool WarpBuilder::build_DelElem(BytecodeLocation loc) {
   2143  MDefinition* id = current->pop();
   2144  MDefinition* obj = current->pop();
   2145  bool strict = loc.getOp() == JSOp::StrictDelElem;
   2146 
   2147  MInstruction* ins = MDeleteElement::New(alloc(), obj, id, strict);
   2148  current->add(ins);
   2149  current->push(ins);
   2150  return resumeAfter(ins, loc);
   2151 }
   2152 
   2153 bool WarpBuilder::build_StrictDelElem(BytecodeLocation loc) {
   2154  return build_DelElem(loc);
   2155 }
   2156 
   2157 bool WarpBuilder::build_SetFunName(BytecodeLocation loc) {
   2158  FunctionPrefixKind prefixKind = loc.getFunctionPrefixKind();
   2159  MDefinition* name = current->pop();
   2160  MDefinition* fun = current->pop();
   2161 
   2162  MSetFunName* ins = MSetFunName::New(alloc(), fun, name, uint8_t(prefixKind));
   2163  current->add(ins);
   2164  current->push(fun);
   2165  return resumeAfter(ins, loc);
   2166 }
   2167 
   2168 bool WarpBuilder::build_PushLexicalEnv(BytecodeLocation loc) {
   2169  MOZ_ASSERT(usesEnvironmentChain());
   2170 
   2171  const auto* snapshot = getOpSnapshot<WarpLexicalEnvironment>(loc);
   2172  MOZ_ASSERT(snapshot);
   2173 
   2174  MDefinition* env = current->environmentChain();
   2175  MConstant* templateCst = constant(ObjectValue(*snapshot->templateObj()));
   2176 
   2177  auto* ins = MNewLexicalEnvironmentObject::New(alloc(), templateCst);
   2178  current->add(ins);
   2179 
   2180 #ifdef DEBUG
   2181  // Assert in debug mode we can elide the post write barrier.
   2182  current->add(MAssertCanElidePostWriteBarrier::New(alloc(), ins, env));
   2183 #endif
   2184 
   2185  // Initialize the object's reserved slots. No post barrier is needed here,
   2186  // for the same reason as in buildNamedLambdaEnv.
   2187  current->add(MStoreFixedSlot::NewUnbarriered(
   2188      alloc(), ins, EnvironmentObject::enclosingEnvironmentSlot(), env));
   2189 
   2190  current->setEnvironmentChain(ins);
   2191  return true;
   2192 }
   2193 
   2194 bool WarpBuilder::build_PushClassBodyEnv(BytecodeLocation loc) {
   2195  MOZ_ASSERT(usesEnvironmentChain());
   2196 
   2197  const auto* snapshot = getOpSnapshot<WarpClassBodyEnvironment>(loc);
   2198  MOZ_ASSERT(snapshot);
   2199 
   2200  MDefinition* env = current->environmentChain();
   2201  MConstant* templateCst = constant(ObjectValue(*snapshot->templateObj()));
   2202 
   2203  auto* ins = MNewClassBodyEnvironmentObject::New(alloc(), templateCst);
   2204  current->add(ins);
   2205 
   2206 #ifdef DEBUG
   2207  // Assert in debug mode we can elide the post write barrier.
   2208  current->add(MAssertCanElidePostWriteBarrier::New(alloc(), ins, env));
   2209 #endif
   2210 
   2211  // Initialize the object's reserved slots. No post barrier is needed here,
   2212  // for the same reason as in buildNamedLambdaEnv.
   2213  current->add(MStoreFixedSlot::NewUnbarriered(
   2214      alloc(), ins, EnvironmentObject::enclosingEnvironmentSlot(), env));
   2215 
   2216  current->setEnvironmentChain(ins);
   2217  return true;
   2218 }
   2219 
   2220 bool WarpBuilder::build_PopLexicalEnv(BytecodeLocation) {
   2221  MDefinition* enclosingEnv = walkEnvironmentChain(1);
   2222  if (!enclosingEnv) {
   2223    return false;
   2224  }
   2225  current->setEnvironmentChain(enclosingEnv);
   2226  return true;
   2227 }
   2228 
   2229 bool WarpBuilder::build_FreshenLexicalEnv(BytecodeLocation loc) {
   2230  MOZ_ASSERT(usesEnvironmentChain());
   2231 
   2232  const auto* snapshot = getOpSnapshot<WarpLexicalEnvironment>(loc);
   2233  MOZ_ASSERT(snapshot);
   2234 
   2235  MDefinition* enclosingEnv = walkEnvironmentChain(1);
   2236  if (!enclosingEnv) {
   2237    return false;
   2238  }
   2239 
   2240  MDefinition* env = current->environmentChain();
   2241  MConstant* templateCst = constant(ObjectValue(*snapshot->templateObj()));
   2242 
   2243  auto* templateObj = snapshot->templateObj();
   2244  auto* scope = &templateObj->scope();
   2245  MOZ_ASSERT(scope->hasEnvironment());
   2246 
   2247  auto* ins = MNewLexicalEnvironmentObject::New(alloc(), templateCst);
   2248  current->add(ins);
   2249 
   2250 #ifdef DEBUG
   2251  // Assert in debug mode we can elide the post write barrier.
   2252  current->add(
   2253      MAssertCanElidePostWriteBarrier::New(alloc(), ins, enclosingEnv));
   2254 #endif
   2255 
   2256  // Initialize the object's reserved slots. No post barrier is needed here,
   2257  // for the same reason as in buildNamedLambdaEnv.
   2258  current->add(MStoreFixedSlot::NewUnbarriered(
   2259      alloc(), ins, EnvironmentObject::enclosingEnvironmentSlot(),
   2260      enclosingEnv));
   2261 
   2262  // Copy environment slots.
   2263  MSlots* envSlots = nullptr;
   2264  MSlots* slots = nullptr;
   2265  for (BindingIter iter(scope); iter; iter++) {
   2266    auto loc = iter.location();
   2267    if (loc.kind() != BindingLocation::Kind::Environment) {
   2268      MOZ_ASSERT(loc.kind() == BindingLocation::Kind::Frame);
   2269      continue;
   2270    }
   2271 
   2272    if (!alloc().ensureBallast()) {
   2273      return false;
   2274    }
   2275 
   2276    uint32_t slot = loc.slot();
   2277    uint32_t numFixedSlots = templateObj->numFixedSlots();
   2278    if (slot >= numFixedSlots) {
   2279      if (!envSlots) {
   2280        envSlots = MSlots::New(alloc(), env);
   2281        current->add(envSlots);
   2282      }
   2283      if (!slots) {
   2284        slots = MSlots::New(alloc(), ins);
   2285        current->add(slots);
   2286      }
   2287 
   2288      uint32_t dynamicSlot = slot - numFixedSlots;
   2289 
   2290      auto* load = MLoadDynamicSlot::New(alloc(), envSlots, dynamicSlot);
   2291      current->add(load);
   2292 
   2293 #ifdef DEBUG
   2294      // Assert in debug mode we can elide the post write barrier.
   2295      current->add(MAssertCanElidePostWriteBarrier::New(alloc(), ins, load));
   2296 #endif
   2297 
   2298      current->add(
   2299          MStoreDynamicSlot::NewUnbarriered(alloc(), slots, dynamicSlot, load));
   2300    } else {
   2301      auto* load = MLoadFixedSlot::New(alloc(), env, slot);
   2302      current->add(load);
   2303 
   2304 #ifdef DEBUG
   2305      // Assert in debug mode we can elide the post write barrier.
   2306      current->add(MAssertCanElidePostWriteBarrier::New(alloc(), ins, load));
   2307 #endif
   2308 
   2309      current->add(MStoreFixedSlot::NewUnbarriered(alloc(), ins, slot, load));
   2310    }
   2311  }
   2312 
   2313  current->setEnvironmentChain(ins);
   2314  return true;
   2315 }
   2316 
   2317 bool WarpBuilder::build_RecreateLexicalEnv(BytecodeLocation loc) {
   2318  MOZ_ASSERT(usesEnvironmentChain());
   2319 
   2320  const auto* snapshot = getOpSnapshot<WarpLexicalEnvironment>(loc);
   2321  MOZ_ASSERT(snapshot);
   2322 
   2323  MDefinition* enclosingEnv = walkEnvironmentChain(1);
   2324  if (!enclosingEnv) {
   2325    return false;
   2326  }
   2327 
   2328  MConstant* templateCst = constant(ObjectValue(*snapshot->templateObj()));
   2329 
   2330  auto* ins = MNewLexicalEnvironmentObject::New(alloc(), templateCst);
   2331  current->add(ins);
   2332 
   2333 #ifdef DEBUG
   2334  // Assert in debug mode we can elide the post write barrier.
   2335  current->add(
   2336      MAssertCanElidePostWriteBarrier::New(alloc(), ins, enclosingEnv));
   2337 #endif
   2338 
   2339  // Initialize the object's reserved slots. No post barrier is needed here,
   2340  // for the same reason as in buildNamedLambdaEnv.
   2341  current->add(MStoreFixedSlot::NewUnbarriered(
   2342      alloc(), ins, EnvironmentObject::enclosingEnvironmentSlot(),
   2343      enclosingEnv));
   2344 
   2345  current->setEnvironmentChain(ins);
   2346  return true;
   2347 }
   2348 
   2349 bool WarpBuilder::build_PushVarEnv(BytecodeLocation loc) {
   2350  MOZ_ASSERT(usesEnvironmentChain());
   2351 
   2352  const auto* snapshot = getOpSnapshot<WarpVarEnvironment>(loc);
   2353  MOZ_ASSERT(snapshot);
   2354 
   2355  MDefinition* env = current->environmentChain();
   2356  MConstant* templateCst = constant(ObjectValue(*snapshot->templateObj()));
   2357 
   2358  auto* ins = MNewVarEnvironmentObject::New(alloc(), templateCst);
   2359  current->add(ins);
   2360 
   2361 #ifdef DEBUG
   2362  // Assert in debug mode we can elide the post write barrier.
   2363  current->add(MAssertCanElidePostWriteBarrier::New(alloc(), ins, env));
   2364 #endif
   2365 
   2366  // Initialize the object's reserved slots. No post barrier is needed here,
   2367  // for the same reason as in buildNamedLambdaEnv.
   2368  current->add(MStoreFixedSlot::NewUnbarriered(
   2369      alloc(), ins, EnvironmentObject::enclosingEnvironmentSlot(), env));
   2370 
   2371  current->setEnvironmentChain(ins);
   2372  return true;
   2373 }
   2374 
   2375 bool WarpBuilder::build_ImplicitThis(BytecodeLocation loc) {
   2376  MDefinition* env = current->pop();
   2377 
   2378  auto* ins = MImplicitThis::New(alloc(), env);
   2379  current->add(ins);
   2380  current->push(ins);
   2381  return resumeAfter(ins, loc);
   2382 }
   2383 
   2384 bool WarpBuilder::build_CheckClassHeritage(BytecodeLocation loc) {
   2385  MDefinition* def = current->pop();
   2386  auto* ins = MCheckClassHeritage::New(alloc(), def);
   2387  current->add(ins);
   2388  current->push(ins);
   2389  return resumeAfter(ins, loc);
   2390 }
   2391 
   2392 bool WarpBuilder::build_CheckThis(BytecodeLocation loc) {
   2393  MDefinition* def = current->pop();
   2394  auto* ins = MCheckThis::New(alloc(), def);
   2395  current->add(ins);
   2396  current->push(ins);
   2397  return resumeAfter(ins, loc);
   2398 }
   2399 
   2400 bool WarpBuilder::build_CheckThisReinit(BytecodeLocation loc) {
   2401  MDefinition* def = current->pop();
   2402  auto* ins = MCheckThisReinit::New(alloc(), def);
   2403  current->add(ins);
   2404  current->push(ins);
   2405  return resumeAfter(ins, loc);
   2406 }
   2407 
   2408 bool WarpBuilder::build_Generator(BytecodeLocation loc) {
   2409  MOZ_ASSERT(usesEnvironmentChain());
   2410 
   2411  MDefinition* callee = getCallee();
   2412  MDefinition* environmentChain = current->environmentChain();
   2413  MDefinition* argsObj = info().needsArgsObj() ? current->argumentsObject()
   2414                                               : constant(Int32Value(0));
   2415 
   2416  MGenerator* generator =
   2417      MGenerator::New(alloc(), callee, environmentChain, argsObj);
   2418 
   2419  current->add(generator);
   2420  current->push(generator);
   2421  return resumeAfter(generator, loc);
   2422 }
   2423 
   2424 bool WarpBuilder::build_AfterYield(BytecodeLocation loc) {
   2425  // Unreachable blocks don't need to generate a bail.
   2426  if (hasTerminatedBlock()) {
   2427    return true;
   2428  }
   2429 
   2430  // This comes after a yield, which we generate as a return,
   2431  // so we know this should be unreachable code.
   2432  //
   2433  // We emit an unreachable bail for this, which will assert if we
   2434  // ever execute this.
   2435  //
   2436  // An Unreachable bail, instead of MUnreachable, because MUnreachable
   2437  // is a control instruction, and injecting it in the middle of a block
   2438  // causes various graph state assertions to fail.
   2439  MBail* bail = MBail::New(alloc(), BailoutKind::Unreachable);
   2440  current->add(bail);
   2441 
   2442  return true;
   2443 }
   2444 
   2445 bool WarpBuilder::build_FinalYieldRval(BytecodeLocation loc) {
   2446  MDefinition* gen = current->pop();
   2447 
   2448  auto setSlotNull = [this, gen](size_t slot) {
   2449    auto* ins = MStoreFixedSlot::NewBarriered(alloc(), gen, slot,
   2450                                              constant(NullValue()));
   2451    current->add(ins);
   2452  };
   2453 
   2454  // Close the generator
   2455  setSlotNull(AbstractGeneratorObject::calleeSlot());
   2456  setSlotNull(AbstractGeneratorObject::envChainSlot());
   2457  setSlotNull(AbstractGeneratorObject::argsObjectSlot());
   2458  setSlotNull(AbstractGeneratorObject::stackStorageSlot());
   2459  setSlotNull(AbstractGeneratorObject::resumeIndexSlot());
   2460 
   2461  // Return
   2462  return build_RetRval(loc);
   2463 }
   2464 
   2465 bool WarpBuilder::build_AsyncResolve(BytecodeLocation loc) {
   2466  MDefinition* generator = current->pop();
   2467  MDefinition* value = current->pop();
   2468 
   2469  auto* resolve = MAsyncResolve::New(alloc(), generator, value);
   2470  current->add(resolve);
   2471  current->push(resolve);
   2472  return resumeAfter(resolve, loc);
   2473 }
   2474 
   2475 bool WarpBuilder::build_AsyncReject(BytecodeLocation loc) {
   2476  MDefinition* generator = current->pop();
   2477  MDefinition* stack = current->pop();
   2478  MDefinition* reason = current->pop();
   2479 
   2480  auto* reject = MAsyncReject::New(alloc(), generator, reason, stack);
   2481  current->add(reject);
   2482  current->push(reject);
   2483  return resumeAfter(reject, loc);
   2484 }
   2485 
   2486 bool WarpBuilder::build_ResumeKind(BytecodeLocation loc) {
   2487  GeneratorResumeKind resumeKind = loc.resumeKind();
   2488 
   2489  current->push(constant(Int32Value(static_cast<int32_t>(resumeKind))));
   2490  return true;
   2491 }
   2492 
   2493 bool WarpBuilder::build_CheckResumeKind(BytecodeLocation loc) {
   2494  // Outside of `yield*`, this is normally unreachable code in Warp,
   2495  // so we just manipulate the stack appropriately to ensure correct
   2496  // MIR generation.
   2497  //
   2498  // However, `yield*` emits a forced generator return which can be
   2499  // warp compiled, so in order to correctly handle these semantics
   2500  // we also generate a bailout, so that the forced generator return
   2501  // runs in baseline.
   2502  MDefinition* resumeKind = current->pop();
   2503  MDefinition* gen = current->pop();
   2504  MDefinition* rval = current->peek(-1);
   2505 
   2506  // Mark operands as implicitly used.
   2507  resumeKind->setImplicitlyUsedUnchecked();
   2508  gen->setImplicitlyUsedUnchecked();
   2509  rval->setImplicitlyUsedUnchecked();
   2510 
   2511  // Bail out if we encounter CheckResumeKind.
   2512  MBail* bail = MBail::New(alloc(), BailoutKind::Inevitable);
   2513  current->add(bail);
   2514  current->setAlwaysBails();
   2515 
   2516  return true;
   2517 }
   2518 
   2519 bool WarpBuilder::build_CanSkipAwait(BytecodeLocation loc) {
   2520  MDefinition* val = current->pop();
   2521 
   2522  MCanSkipAwait* canSkip = MCanSkipAwait::New(alloc(), val);
   2523  current->add(canSkip);
   2524 
   2525  current->push(val);
   2526  current->push(canSkip);
   2527 
   2528  return resumeAfter(canSkip, loc);
   2529 }
   2530 
   2531 bool WarpBuilder::build_MaybeExtractAwaitValue(BytecodeLocation loc) {
   2532  MDefinition* canSkip = current->pop();
   2533  MDefinition* value = current->pop();
   2534 
   2535  MMaybeExtractAwaitValue* extracted =
   2536      MMaybeExtractAwaitValue::New(alloc(), value, canSkip);
   2537  current->add(extracted);
   2538 
   2539  current->push(extracted);
   2540  current->push(canSkip);
   2541 
   2542  return resumeAfter(extracted, loc);
   2543 }
   2544 
   2545 bool WarpBuilder::build_InitialYield(BytecodeLocation loc) {
   2546  MDefinition* gen = current->pop();
   2547  return buildSuspend(loc, gen, gen);
   2548 }
   2549 
   2550 bool WarpBuilder::build_Await(BytecodeLocation loc) {
   2551  MDefinition* gen = current->pop();
   2552  MDefinition* promiseOrGenerator = current->pop();
   2553 
   2554  return buildSuspend(loc, gen, promiseOrGenerator);
   2555 }
   2556 bool WarpBuilder::build_Yield(BytecodeLocation loc) { return build_Await(loc); }
   2557 
   2558 bool WarpBuilder::buildSuspend(BytecodeLocation loc, MDefinition* gen,
   2559                               MDefinition* retVal) {
   2560  // If required, unbox the generator object explicitly and infallibly.
   2561  //
   2562  // This is done to avoid fuzz-bugs where ApplyTypeInformation does the
   2563  // unboxing, and generates fallible unboxes which can lead to torn object
   2564  // state due to `bailAfter`.
   2565  MDefinition* genObj = gen;
   2566  if (genObj->type() != MIRType::Object) {
   2567    auto* unbox =
   2568        MUnbox::New(alloc(), gen, MIRType::Object, MUnbox::Mode::Infallible);
   2569    current->add(unbox);
   2570 
   2571    genObj = unbox;
   2572  }
   2573 
   2574  int32_t slotsToCopy = current->stackDepth() - info().firstLocalSlot();
   2575  MOZ_ASSERT(slotsToCopy >= 0);
   2576  if (slotsToCopy > 0) {
   2577    auto* arrayObj = MLoadFixedSlotAndUnbox::New(
   2578        alloc(), genObj, AbstractGeneratorObject::stackStorageSlot(),
   2579        MUnbox::Mode::Infallible, MIRType::Object);
   2580    current->add(arrayObj);
   2581 
   2582    auto* stackStorage = MElements::New(alloc(), arrayObj);
   2583    current->add(stackStorage);
   2584 
   2585    for (int32_t i = 0; i < slotsToCopy; i++) {
   2586      if (!alloc().ensureBallast()) {
   2587        return false;
   2588      }
   2589      // Use peekUnchecked because we're also writing out the argument slots
   2590      int32_t peek = -slotsToCopy + i;
   2591      MDefinition* stackElem = current->peekUnchecked(peek);
   2592      auto* store = MStoreElement::NewUnbarriered(
   2593          alloc(), stackStorage, constant(Int32Value(i)), stackElem,
   2594          /* needsHoleCheck = */ false);
   2595 
   2596      current->add(store);
   2597      current->add(MPostWriteBarrier::New(alloc(), arrayObj, stackElem));
   2598    }
   2599 
   2600    auto* len = constant(Int32Value(slotsToCopy - 1));
   2601 
   2602    auto* setInitLength =
   2603        MSetInitializedLength::New(alloc(), stackStorage, len);
   2604    current->add(setInitLength);
   2605 
   2606    auto* setLength = MSetArrayLength::New(alloc(), stackStorage, len);
   2607    current->add(setLength);
   2608  }
   2609 
   2610  // Update Generator Object state
   2611  uint32_t resumeIndex = loc.getResumeIndex();
   2612 
   2613  // This store is unbarriered, as it's only ever storing an integer, and as
   2614  // such doesn't partake of object tracing.
   2615  current->add(MStoreFixedSlot::NewUnbarriered(
   2616      alloc(), genObj, AbstractGeneratorObject::resumeIndexSlot(),
   2617      constant(Int32Value(resumeIndex))));
   2618 
   2619  // This store is barriered because it stores an object value.
   2620  current->add(MStoreFixedSlot::NewBarriered(
   2621      alloc(), genObj, AbstractGeneratorObject::envChainSlot(),
   2622      current->environmentChain()));
   2623 
   2624  current->add(
   2625      MPostWriteBarrier::New(alloc(), genObj, current->environmentChain()));
   2626 
   2627  // GeneratorReturn will return from the method, however to support MIR
   2628  // generation isn't treated like the end of a block
   2629  MGeneratorReturn* ret = MGeneratorReturn::New(alloc(), retVal);
   2630  current->add(ret);
   2631 
   2632  // To ensure the rest of the MIR generation looks correct, fill the stack with
   2633  // the appropriately typed MUnreachable's for the stack pushes from this
   2634  // opcode.
   2635  auto* unreachableResumeKind =
   2636      MUnreachableResult::New(alloc(), MIRType::Int32);
   2637  current->add(unreachableResumeKind);
   2638  current->push(unreachableResumeKind);
   2639 
   2640  auto* unreachableGenerator =
   2641      MUnreachableResult::New(alloc(), MIRType::Object);
   2642  current->add(unreachableGenerator);
   2643  current->push(unreachableGenerator);
   2644 
   2645  auto* unreachableRval = MUnreachableResult::New(alloc(), MIRType::Value);
   2646  current->add(unreachableRval);
   2647  current->push(unreachableRval);
   2648 
   2649  return true;
   2650 }
   2651 
   2652 bool WarpBuilder::build_AsyncAwait(BytecodeLocation loc) {
   2653  MDefinition* gen = current->pop();
   2654  MDefinition* value = current->pop();
   2655 
   2656  MAsyncAwait* asyncAwait = MAsyncAwait::New(alloc(), value, gen);
   2657  current->add(asyncAwait);
   2658  current->push(asyncAwait);
   2659  return resumeAfter(asyncAwait, loc);
   2660 }
   2661 
   2662 bool WarpBuilder::build_CheckReturn(BytecodeLocation loc) {
   2663  MOZ_ASSERT(!script_->noScriptRval());
   2664 
   2665  MDefinition* returnValue = current->getSlot(info().returnValueSlot());
   2666  MDefinition* thisValue = current->pop();
   2667 
   2668  auto* ins = MCheckReturn::New(alloc(), returnValue, thisValue);
   2669  current->add(ins);
   2670  current->push(ins);
   2671  return resumeAfter(ins, loc);
   2672 }
   2673 
   2674 void WarpBuilder::buildCheckLexicalOp(BytecodeLocation loc) {
   2675  JSOp op = loc.getOp();
   2676  MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical);
   2677 
   2678  MDefinition* input = current->pop();
   2679  MInstruction* lexicalCheck = MLexicalCheck::New(alloc(), input);
   2680  current->add(lexicalCheck);
   2681  current->push(lexicalCheck);
   2682 
   2683  if (snapshot().bailoutInfo().failedLexicalCheck()) {
   2684    // If we have previously had a failed lexical check in Ion, we want to avoid
   2685    // hoisting any lexical checks, which can cause spurious failures. In this
   2686    // case, we also have to be careful not to hoist any loads of this lexical
   2687    // past the check. For unaliased lexical variables, we can set the local
   2688    // slot to create a dependency (see below). For aliased lexicals, that
   2689    // doesn't work, so we disable LICM instead.
   2690    lexicalCheck->setNotMovable();
   2691    if (op == JSOp::CheckAliasedLexical) {
   2692      mirGen().disableLICM();
   2693    }
   2694  }
   2695 
   2696  if (op == JSOp::CheckLexical) {
   2697    // Set the local slot so that a subsequent GetLocal without a CheckLexical
   2698    // (the frontend can elide lexical checks) doesn't let a definition with
   2699    // MIRType::MagicUninitializedLexical escape to arbitrary MIR instructions.
   2700    // Note that in this case the GetLocal would be unreachable because we throw
   2701    // an exception here, but we still generate MIR instructions for it.
   2702    uint32_t slot = info().localSlot(loc.local());
   2703    current->setSlot(slot, lexicalCheck);
   2704  }
   2705 }
   2706 
   2707 bool WarpBuilder::build_CheckLexical(BytecodeLocation loc) {
   2708  buildCheckLexicalOp(loc);
   2709  return true;
   2710 }
   2711 
   2712 bool WarpBuilder::build_CheckAliasedLexical(BytecodeLocation loc) {
   2713  buildCheckLexicalOp(loc);
   2714  return true;
   2715 }
   2716 
   2717 bool WarpBuilder::build_InitHomeObject(BytecodeLocation loc) {
   2718  MDefinition* homeObject = current->pop();
   2719  MDefinition* function = current->pop();
   2720 
   2721  current->add(MPostWriteBarrier::New(alloc(), function, homeObject));
   2722 
   2723  auto* ins = MInitHomeObject::New(alloc(), function, homeObject);
   2724  current->add(ins);
   2725  current->push(ins);
   2726  return true;
   2727 }
   2728 
   2729 bool WarpBuilder::build_SuperBase(BytecodeLocation) {
   2730  MDefinition* callee = current->pop();
   2731 
   2732  auto* homeObject = MHomeObject::New(alloc(), callee);
   2733  current->add(homeObject);
   2734 
   2735  auto* superBase = MHomeObjectSuperBase::New(alloc(), homeObject);
   2736  current->add(superBase);
   2737  current->push(superBase);
   2738  return true;
   2739 }
   2740 
   2741 bool WarpBuilder::build_SuperFun(BytecodeLocation) {
   2742  MDefinition* callee = current->pop();
   2743  auto* ins = MSuperFunction::New(alloc(), callee);
   2744  current->add(ins);
   2745  current->push(ins);
   2746  return true;
   2747 }
   2748 
   2749 bool WarpBuilder::build_BuiltinObject(BytecodeLocation loc) {
   2750  if (auto* snapshot = getOpSnapshot<WarpBuiltinObject>(loc)) {
   2751    JSObject* builtin = snapshot->builtin();
   2752    pushConstant(ObjectValue(*builtin));
   2753    return true;
   2754  }
   2755 
   2756  auto kind = loc.getBuiltinObjectKind();
   2757  auto* ins = MBuiltinObject::New(alloc(), kind);
   2758  current->add(ins);
   2759  current->push(ins);
   2760  return resumeAfter(ins, loc);
   2761 }
   2762 
   2763 bool WarpBuilder::build_GetIntrinsic(BytecodeLocation loc) {
   2764  if (auto* snapshot = getOpSnapshot<WarpGetIntrinsic>(loc)) {
   2765    Value intrinsic = snapshot->intrinsic();
   2766    pushConstant(intrinsic);
   2767    return true;
   2768  }
   2769 
   2770  PropertyName* name = loc.getPropertyName(script_);
   2771  MCallGetIntrinsicValue* ins = MCallGetIntrinsicValue::New(alloc(), name);
   2772  current->add(ins);
   2773  current->push(ins);
   2774  return resumeAfter(ins, loc);
   2775 }
   2776 
   2777 bool WarpBuilder::build_ImportMeta(BytecodeLocation loc) {
   2778  ModuleObject* moduleObj = scriptSnapshot()->moduleObject();
   2779  MOZ_ASSERT(moduleObj);
   2780 
   2781  MModuleMetadata* ins = MModuleMetadata::New(alloc(), moduleObj);
   2782  current->add(ins);
   2783  current->push(ins);
   2784  return resumeAfter(ins, loc);
   2785 }
   2786 
   2787 bool WarpBuilder::build_CallSiteObj(BytecodeLocation loc) {
   2788  return build_Object(loc);
   2789 }
   2790 
   2791 bool WarpBuilder::build_NewArray(BytecodeLocation loc) {
   2792  return buildIC(loc, CacheKind::NewArray, {});
   2793 }
   2794 
   2795 bool WarpBuilder::build_NewObject(BytecodeLocation loc) {
   2796  return buildIC(loc, CacheKind::NewObject, {});
   2797 }
   2798 
   2799 bool WarpBuilder::build_NewInit(BytecodeLocation loc) {
   2800  return build_NewObject(loc);
   2801 }
   2802 
   2803 bool WarpBuilder::build_Object(BytecodeLocation loc) {
   2804  JSObject* obj = loc.getObject(script_);
   2805  MConstant* objConst = constant(ObjectValue(*obj));
   2806 
   2807  current->push(objConst);
   2808  return true;
   2809 }
   2810 
   2811 bool WarpBuilder::buildInitPropGetterSetterOp(BytecodeLocation loc) {
   2812  PropertyName* name = loc.getPropertyName(script_);
   2813  MDefinition* value = current->pop();
   2814  MDefinition* obj = current->peek(-1);
   2815 
   2816  auto* ins = MInitPropGetterSetter::New(alloc(), obj, value, name);
   2817  current->add(ins);
   2818  return resumeAfter(ins, loc);
   2819 }
   2820 
   2821 bool WarpBuilder::build_InitPropGetter(BytecodeLocation loc) {
   2822  return buildInitPropGetterSetterOp(loc);
   2823 }
   2824 
   2825 bool WarpBuilder::build_InitPropSetter(BytecodeLocation loc) {
   2826  return buildInitPropGetterSetterOp(loc);
   2827 }
   2828 
   2829 bool WarpBuilder::build_InitHiddenPropGetter(BytecodeLocation loc) {
   2830  return buildInitPropGetterSetterOp(loc);
   2831 }
   2832 
   2833 bool WarpBuilder::build_InitHiddenPropSetter(BytecodeLocation loc) {
   2834  return buildInitPropGetterSetterOp(loc);
   2835 }
   2836 
   2837 bool WarpBuilder::buildInitElemGetterSetterOp(BytecodeLocation loc) {
   2838  MDefinition* value = current->pop();
   2839  MDefinition* id = current->pop();
   2840  MDefinition* obj = current->peek(-1);
   2841 
   2842  auto* ins = MInitElemGetterSetter::New(alloc(), obj, id, value);
   2843  current->add(ins);
   2844  return resumeAfter(ins, loc);
   2845 }
   2846 
   2847 bool WarpBuilder::build_InitElemGetter(BytecodeLocation loc) {
   2848  return buildInitElemGetterSetterOp(loc);
   2849 }
   2850 
   2851 bool WarpBuilder::build_InitElemSetter(BytecodeLocation loc) {
   2852  return buildInitElemGetterSetterOp(loc);
   2853 }
   2854 
   2855 bool WarpBuilder::build_InitHiddenElemGetter(BytecodeLocation loc) {
   2856  return buildInitElemGetterSetterOp(loc);
   2857 }
   2858 
   2859 bool WarpBuilder::build_InitHiddenElemSetter(BytecodeLocation loc) {
   2860  return buildInitElemGetterSetterOp(loc);
   2861 }
   2862 
   2863 bool WarpBuilder::build_In(BytecodeLocation loc) {
   2864  MDefinition* obj = current->pop();
   2865  MDefinition* id = current->pop();
   2866  return buildIC(loc, CacheKind::In, {id, obj});
   2867 }
   2868 
   2869 bool WarpBuilder::build_HasOwn(BytecodeLocation loc) {
   2870  MDefinition* obj = current->pop();
   2871  MDefinition* id = current->pop();
   2872  return buildIC(loc, CacheKind::HasOwn, {id, obj});
   2873 }
   2874 
   2875 bool WarpBuilder::build_CheckPrivateField(BytecodeLocation loc) {
   2876  MDefinition* id = current->peek(-1);
   2877  MDefinition* obj = current->peek(-2);
   2878  return buildIC(loc, CacheKind::CheckPrivateField, {obj, id});
   2879 }
   2880 
   2881 bool WarpBuilder::build_NewPrivateName(BytecodeLocation loc) {
   2882  JSAtom* name = loc.getAtom(script_);
   2883 
   2884  auto* ins = MNewPrivateName::New(alloc(), &name->asOffThreadAtom());
   2885  current->add(ins);
   2886  current->push(ins);
   2887  return resumeAfter(ins, loc);
   2888 }
   2889 
   2890 bool WarpBuilder::build_Instanceof(BytecodeLocation loc) {
   2891  MDefinition* rhs = current->pop();
   2892  MDefinition* obj = current->pop();
   2893  return buildIC(loc, CacheKind::InstanceOf, {obj, rhs});
   2894 }
   2895 
   2896 bool WarpBuilder::build_NewTarget(BytecodeLocation loc) {
   2897  MOZ_ASSERT(script_->isFunction());
   2898  MOZ_ASSERT(info().hasFunMaybeLazy());
   2899  MOZ_ASSERT(!scriptSnapshot()->isArrowFunction());
   2900 
   2901  if (inlineCallInfo()) {
   2902    if (inlineCallInfo()->constructing()) {
   2903      current->push(inlineCallInfo()->getNewTarget());
   2904    } else {
   2905      pushConstant(UndefinedValue());
   2906    }
   2907    return true;
   2908  }
   2909 
   2910  MNewTarget* ins = MNewTarget::New(alloc());
   2911  current->add(ins);
   2912  current->push(ins);
   2913  return true;
   2914 }
   2915 
   2916 bool WarpBuilder::build_CheckIsObj(BytecodeLocation loc) {
   2917  CheckIsObjectKind kind = loc.getCheckIsObjectKind();
   2918 
   2919  MDefinition* toCheck = current->peek(-1);
   2920  if (toCheck->type() == MIRType::Object) {
   2921    toCheck->setImplicitlyUsedUnchecked();
   2922    return true;
   2923  }
   2924 
   2925  MDefinition* val = current->pop();
   2926  MCheckIsObj* ins = MCheckIsObj::New(alloc(), val, uint8_t(kind));
   2927  current->add(ins);
   2928  current->push(ins);
   2929  return resumeAfter(ins, loc);
   2930 }
   2931 
   2932 bool WarpBuilder::build_CheckObjCoercible(BytecodeLocation loc) {
   2933  MDefinition* val = current->pop();
   2934  MCheckObjCoercible* ins = MCheckObjCoercible::New(alloc(), val);
   2935  current->add(ins);
   2936  current->push(ins);
   2937  return resumeAfter(ins, loc);
   2938 }
   2939 
   2940 MInstruction* WarpBuilder::buildLoadSlot(MDefinition* obj,
   2941                                         uint32_t numFixedSlots,
   2942                                         uint32_t slot) {
   2943  if (slot < numFixedSlots) {
   2944    MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot);
   2945    current->add(load);
   2946    return load;
   2947  }
   2948 
   2949  MSlots* slots = MSlots::New(alloc(), obj);
   2950  current->add(slots);
   2951 
   2952  MLoadDynamicSlot* load =
   2953      MLoadDynamicSlot::New(alloc(), slots, slot - numFixedSlots);
   2954  current->add(load);
   2955  return load;
   2956 }
   2957 
   2958 bool WarpBuilder::build_GetImport(BytecodeLocation loc) {
   2959  auto* snapshot = getOpSnapshot<WarpGetImport>(loc);
   2960 
   2961  ModuleEnvironmentObject* targetEnv = snapshot->targetEnv();
   2962 
   2963  // Load the target environment slot.
   2964  MConstant* obj = constant(ObjectValue(*targetEnv));
   2965  auto* load = buildLoadSlot(obj, snapshot->numFixedSlots(), snapshot->slot());
   2966 
   2967  if (snapshot->needsLexicalCheck()) {
   2968    // TODO: IonBuilder has code to mark non-movable. See buildCheckLexicalOp.
   2969    MInstruction* lexicalCheck = MLexicalCheck::New(alloc(), load);
   2970    current->add(lexicalCheck);
   2971    current->push(lexicalCheck);
   2972  } else {
   2973    current->push(load);
   2974  }
   2975 
   2976  return true;
   2977 }
   2978 
   2979 bool WarpBuilder::build_GetPropSuper(BytecodeLocation loc) {
   2980  MDefinition* obj = current->pop();
   2981  MDefinition* receiver = current->pop();
   2982  return buildIC(loc, CacheKind::GetPropSuper, {obj, receiver});
   2983 }
   2984 
   2985 bool WarpBuilder::build_GetElemSuper(BytecodeLocation loc) {
   2986  MDefinition* obj = current->pop();
   2987  MDefinition* id = current->pop();
   2988  MDefinition* receiver = current->pop();
   2989  return buildIC(loc, CacheKind::GetElemSuper, {obj, id, receiver});
   2990 }
   2991 
   2992 bool WarpBuilder::build_InitProp(BytecodeLocation loc) {
   2993  MDefinition* val = current->pop();
   2994  MDefinition* obj = current->peek(-1);
   2995  return buildIC(loc, CacheKind::SetProp, {obj, val});
   2996 }
   2997 
   2998 bool WarpBuilder::build_InitLockedProp(BytecodeLocation loc) {
   2999  return build_InitProp(loc);
   3000 }
   3001 
   3002 bool WarpBuilder::build_InitHiddenProp(BytecodeLocation loc) {
   3003  return build_InitProp(loc);
   3004 }
   3005 
   3006 bool WarpBuilder::build_InitElem(BytecodeLocation loc) {
   3007  MDefinition* val = current->pop();
   3008  MDefinition* id = current->pop();
   3009  MDefinition* obj = current->peek(-1);
   3010  return buildIC(loc, CacheKind::SetElem, {obj, id, val});
   3011 }
   3012 
   3013 bool WarpBuilder::build_InitLockedElem(BytecodeLocation loc) {
   3014  return build_InitElem(loc);
   3015 }
   3016 
   3017 bool WarpBuilder::build_InitHiddenElem(BytecodeLocation loc) {
   3018  return build_InitElem(loc);
   3019 }
   3020 
   3021 bool WarpBuilder::build_InitElemArray(BytecodeLocation loc) {
   3022  MDefinition* val = current->pop();
   3023  MDefinition* obj = current->peek(-1);
   3024 
   3025  // Note: getInitElemArrayIndex asserts the index fits in int32_t.
   3026  uint32_t index = loc.getInitElemArrayIndex();
   3027  MConstant* indexConst = constant(Int32Value(index));
   3028 
   3029  // Note: InitArrayElemOperation asserts the index does not exceed the array's
   3030  // dense element capacity.
   3031 
   3032  auto* elements = MElements::New(alloc(), obj);
   3033  current->add(elements);
   3034 
   3035  if (val->type() == MIRType::MagicHole) {
   3036    val->setImplicitlyUsedUnchecked();
   3037    auto* store = MStoreHoleValueElement::New(alloc(), elements, indexConst);
   3038    current->add(store);
   3039  } else {
   3040    current->add(MPostWriteBarrier::New(alloc(), obj, val));
   3041    auto* store =
   3042        MStoreElement::NewUnbarriered(alloc(), elements, indexConst, val,
   3043                                      /* needsHoleCheck = */ false);
   3044    current->add(store);
   3045  }
   3046 
   3047  auto* setLength = MSetInitializedLength::New(alloc(), elements, indexConst);
   3048  current->add(setLength);
   3049 
   3050  return resumeAfter(setLength, loc);
   3051 }
   3052 
   3053 bool WarpBuilder::build_InitElemInc(BytecodeLocation loc) {
   3054  MDefinition* val = current->pop();
   3055  MDefinition* index = current->pop();
   3056  MDefinition* obj = current->peek(-1);
   3057 
   3058  // Push index + 1.
   3059  MConstant* constOne = constant(Int32Value(1));
   3060  MAdd* nextIndex = MAdd::New(alloc(), index, constOne, TruncateKind::Truncate);
   3061  current->add(nextIndex);
   3062  current->push(nextIndex);
   3063 
   3064  return buildIC(loc, CacheKind::SetElem, {obj, index, val});
   3065 }
   3066 
   3067 bool WarpBuilder::build_Lambda(BytecodeLocation loc) {
   3068  MOZ_ASSERT(usesEnvironmentChain());
   3069  return buildIC(loc, CacheKind::Lambda, {});
   3070 }
   3071 
   3072 bool WarpBuilder::build_FunWithProto(BytecodeLocation loc) {
   3073  MOZ_ASSERT(usesEnvironmentChain());
   3074 
   3075  MDefinition* proto = current->pop();
   3076  MDefinition* env = current->environmentChain();
   3077 
   3078  JSFunction* fun = loc.getFunction(script_);
   3079  MConstant* funConst = constant(ObjectValue(*fun));
   3080 
   3081  auto* ins = MFunctionWithProto::New(alloc(), env, proto, funConst);
   3082  current->add(ins);
   3083  current->push(ins);
   3084  return resumeAfter(ins, loc);
   3085 }
   3086 
   3087 bool WarpBuilder::build_SpreadCall(BytecodeLocation loc) {
   3088  bool constructing = false;
   3089  CallInfo callInfo(alloc(), constructing, loc.resultIsPopped());
   3090  callInfo.initForSpreadCall(current);
   3091 
   3092  // The argument must be an array object. Add an infallible MUnbox if needed,
   3093  // but ensure it's not loop hoisted before the branch in the bytecode guarding
   3094  // that it's not undefined.
   3095  MOZ_ASSERT(callInfo.argc() == 1);
   3096  callInfo.setArg(0, unboxObjectInfallible(callInfo.getArg(0), IsMovable::No));
   3097 
   3098  if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
   3099    return transpileCall(loc, cacheIRSnapshot, &callInfo);
   3100  }
   3101 
   3102  bool needsThisCheck = false;
   3103  MInstruction* call = makeSpreadCall(callInfo, needsThisCheck);
   3104  if (!call) {
   3105    return false;
   3106  }
   3107  call->setBailoutKind(BailoutKind::TooManyArguments);
   3108  current->add(call);
   3109  current->push(call);
   3110  return resumeAfter(call, loc);
   3111 }
   3112 
   3113 bool WarpBuilder::build_SpreadNew(BytecodeLocation loc) {
   3114  bool constructing = true;
   3115  CallInfo callInfo(alloc(), constructing, loc.resultIsPopped());
   3116  callInfo.initForSpreadCall(current);
   3117 
   3118  // See build_SpreadCall.
   3119  MOZ_ASSERT(callInfo.argc() == 1);
   3120  callInfo.setArg(0, unboxObjectInfallible(callInfo.getArg(0), IsMovable::No));
   3121 
   3122  if (auto* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc)) {
   3123    return transpileCall(loc, cacheIRSnapshot, &callInfo);
   3124  }
   3125 
   3126  buildCreateThis(callInfo);
   3127 
   3128  bool needsThisCheck = true;
   3129  MInstruction* call = makeSpreadCall(callInfo, needsThisCheck);
   3130  if (!call) {
   3131    return false;
   3132  }
   3133  call->setBailoutKind(BailoutKind::TooManyArguments);
   3134  current->add(call);
   3135  current->push(call);
   3136  return resumeAfter(call, loc);
   3137 }
   3138 
   3139 bool WarpBuilder::build_SpreadSuperCall(BytecodeLocation loc) {
   3140  return build_SpreadNew(loc);
   3141 }
   3142 
   3143 bool WarpBuilder::build_OptimizeSpreadCall(BytecodeLocation loc) {
   3144  MDefinition* value = current->pop();
   3145  return buildIC(loc, CacheKind::OptimizeSpreadCall, {value});
   3146 }
   3147 
   3148 bool WarpBuilder::build_Debugger(BytecodeLocation loc) {
   3149  // The |debugger;| statement will bail out to Baseline if the realm is a
   3150  // debuggee realm with an onDebuggerStatement hook.
   3151  MDebugger* debugger = MDebugger::New(alloc());
   3152  current->add(debugger);
   3153  return resumeAfter(debugger, loc);
   3154 }
   3155 
   3156 bool WarpBuilder::build_TableSwitch(BytecodeLocation loc) {
   3157  int32_t low = loc.getTableSwitchLow();
   3158  int32_t high = loc.getTableSwitchHigh();
   3159  size_t numCases = high - low + 1;
   3160 
   3161  MDefinition* input = current->pop();
   3162  MTableSwitch* tableswitch = MTableSwitch::New(alloc(), input, low, high);
   3163  current->end(tableswitch);
   3164 
   3165  // Table mapping from target bytecode offset to MTableSwitch successor index.
   3166  // This prevents adding multiple predecessor/successor edges to the same
   3167  // target block, which isn't valid in MIR.
   3168  using TargetToSuccessorMap =
   3169      InlineMap<uint32_t, uint32_t, 8, DefaultHasher<uint32_t>,
   3170                SystemAllocPolicy>;
   3171  TargetToSuccessorMap targetToSuccessor;
   3172 
   3173  // Create |default| edge.
   3174  {
   3175    BytecodeLocation defaultLoc = loc.getTableSwitchDefaultTarget();
   3176    uint32_t defaultOffset = defaultLoc.bytecodeToOffset(script_);
   3177 
   3178    size_t index;
   3179    if (!tableswitch->addDefault(nullptr, &index)) {
   3180      return false;
   3181    }
   3182    if (!addPendingEdge(defaultLoc, current, index)) {
   3183      return false;
   3184    }
   3185    if (!targetToSuccessor.put(defaultOffset, index)) {
   3186      return false;
   3187    }
   3188  }
   3189 
   3190  // Add all cases.
   3191  for (size_t i = 0; i < numCases; i++) {
   3192    BytecodeLocation caseLoc = loc.getTableSwitchCaseTarget(script_, i);
   3193    uint32_t caseOffset = caseLoc.bytecodeToOffset(script_);
   3194 
   3195    size_t index;
   3196    if (auto p = targetToSuccessor.lookupForAdd(caseOffset)) {
   3197      index = p->value();
   3198    } else {
   3199      if (!tableswitch->addSuccessor(nullptr, &index)) {
   3200        return false;
   3201      }
   3202      if (!addPendingEdge(caseLoc, current, index)) {
   3203        return false;
   3204      }
   3205      if (!targetToSuccessor.add(p, caseOffset, index)) {
   3206        return false;
   3207      }
   3208    }
   3209    if (!tableswitch->addCase(index)) {
   3210      return false;
   3211    }
   3212  }
   3213 
   3214  setTerminatedBlock();
   3215  return true;
   3216 }
   3217 
   3218 bool WarpBuilder::build_Rest(BytecodeLocation loc) {
   3219  auto* snapshot = getOpSnapshot<WarpRest>(loc);
   3220  Shape* shape = snapshot ? snapshot->shape() : nullptr;
   3221 
   3222  // NOTE: Keep this code in sync with |ArgumentsReplacer|.
   3223 
   3224  if (inlineCallInfo()) {
   3225    // If we are inlining, we know the actual arguments.
   3226    unsigned numActuals = inlineCallInfo()->argc();
   3227    unsigned numFormals = info().nargs() - 1;
   3228    unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
   3229 
   3230    // TODO: support pre-tenuring.
   3231    gc::Heap heap = gc::Heap::Default;
   3232 
   3233    // Allocate an array of the correct size.
   3234    MInstruction* newArray;
   3235    if (shape && gc::CanUseFixedElementsForArray(numRest)) {
   3236      auto* shapeConstant = MConstant::NewShape(alloc(), shape);
   3237      current->add(shapeConstant);
   3238      newArray = MNewArrayObject::New(alloc(), shapeConstant, numRest, heap);
   3239    } else {
   3240      MConstant* templateConst = constant(NullValue());
   3241      newArray = MNewArray::NewVM(alloc(), numRest, templateConst, heap);
   3242    }
   3243    current->add(newArray);
   3244    current->push(newArray);
   3245 
   3246    if (numRest == 0) {
   3247      // No more updating to do.
   3248      return true;
   3249    }
   3250 
   3251    MElements* elements = MElements::New(alloc(), newArray);
   3252    current->add(elements);
   3253 
   3254    // Unroll the argument copy loop. We don't need to do any bounds or hole
   3255    // checking here.
   3256    MConstant* index = nullptr;
   3257    for (uint32_t i = numFormals; i < numActuals; i++) {
   3258      if (!alloc().ensureBallast()) {
   3259        return false;
   3260      }
   3261 
   3262      index = MConstant::NewInt32(alloc(), i - numFormals);
   3263      current->add(index);
   3264 
   3265      MDefinition* arg = inlineCallInfo()->argv()[i];
   3266      MStoreElement* store =
   3267          MStoreElement::NewUnbarriered(alloc(), elements, index, arg,
   3268                                        /* needsHoleCheck = */ false);
   3269      current->add(store);
   3270      current->add(MPostWriteBarrier::New(alloc(), newArray, arg));
   3271    }
   3272 
   3273    // Update the initialized length for all the (necessarily non-hole)
   3274    // elements added.
   3275    MSetInitializedLength* initLength =
   3276        MSetInitializedLength::New(alloc(), elements, index);
   3277    current->add(initLength);
   3278 
   3279    return true;
   3280  }
   3281 
   3282  MArgumentsLength* numActuals = MArgumentsLength::New(alloc());
   3283  current->add(numActuals);
   3284 
   3285  // Pass in the number of actual arguments, the number of formals (not
   3286  // including the rest parameter slot itself), and the shape.
   3287  unsigned numFormals = info().nargs() - 1;
   3288  MRest* rest = MRest::New(alloc(), numActuals, numFormals, shape);
   3289  current->add(rest);
   3290  current->push(rest);
   3291  return true;
   3292 }
   3293 
   3294 bool WarpBuilder::build_Try(BytecodeLocation loc) {
   3295  graph().setHasTryBlock();
   3296 
   3297  MBasicBlock* pred = current;
   3298  if (!startNewBlock(pred, loc.next())) {
   3299    return false;
   3300  }
   3301 
   3302  pred->end(MGoto::New(alloc(), current));
   3303  return true;
   3304 }
   3305 
   3306 bool WarpBuilder::build_Finally(BytecodeLocation loc) {
   3307  MOZ_ASSERT(graph().hasTryBlock());
   3308  return true;
   3309 }
   3310 
   3311 bool WarpBuilder::build_Exception(BytecodeLocation) {
   3312  MOZ_CRASH("Unreachable because we skip catch-blocks");
   3313 }
   3314 
   3315 bool WarpBuilder::build_ExceptionAndStack(BytecodeLocation) {
   3316  MOZ_CRASH("Unreachable because we skip catch-blocks");
   3317 }
   3318 
   3319 bool WarpBuilder::build_Throw(BytecodeLocation loc) {
   3320  MDefinition* def = current->pop();
   3321 
   3322  MThrow* ins = MThrow::New(alloc(), def);
   3323  current->add(ins);
   3324  if (!resumeAfter(ins, loc)) {
   3325    return false;
   3326  }
   3327 
   3328  // Terminate the block.
   3329  current->end(MUnreachable::New(alloc()));
   3330  setTerminatedBlock();
   3331  return true;
   3332 }
   3333 
   3334 bool WarpBuilder::build_ThrowWithStack(BytecodeLocation loc) {
   3335  MDefinition* stack = current->pop();
   3336  MDefinition* value = current->pop();
   3337 
   3338  auto* ins = MThrowWithStack::New(alloc(), value, stack);
   3339  current->add(ins);
   3340  if (!resumeAfter(ins, loc)) {
   3341    return false;
   3342  }
   3343 
   3344  // Terminate the block.
   3345  current->end(MUnreachable::New(alloc()));
   3346  setTerminatedBlock();
   3347  return true;
   3348 }
   3349 
   3350 bool WarpBuilder::build_ThrowSetConst(BytecodeLocation loc) {
   3351  auto* ins = MThrowRuntimeLexicalError::New(alloc(), JSMSG_BAD_CONST_ASSIGN);
   3352  current->add(ins);
   3353  if (!resumeAfter(ins, loc)) {
   3354    return false;
   3355  }
   3356 
   3357  // Terminate the block.
   3358  current->end(MUnreachable::New(alloc()));
   3359  setTerminatedBlock();
   3360  return true;
   3361 }
   3362 
   3363 bool WarpBuilder::build_ThrowMsg(BytecodeLocation loc) {
   3364  auto* ins = MThrowMsg::New(alloc(), loc.throwMsgKind());
   3365  current->add(ins);
   3366  if (!resumeAfter(ins, loc)) {
   3367    return false;
   3368  }
   3369 
   3370  // Terminate the block.
   3371  current->end(MUnreachable::New(alloc()));
   3372  setTerminatedBlock();
   3373  return true;
   3374 }
   3375 
   3376 bool WarpBuilder::buildIC(BytecodeLocation loc, CacheKind kind,
   3377                          std::initializer_list<MDefinition*> inputs) {
   3378  MOZ_ASSERT(loc.opHasIC());
   3379 
   3380  mozilla::DebugOnly<size_t> numInputs = inputs.size();
   3381  MOZ_ASSERT(numInputs == NumInputsForCacheKind(kind));
   3382 
   3383  const WarpCacheIRBase* cacheIRSnapshot = getOpSnapshot<WarpCacheIR>(loc);
   3384  if (!cacheIRSnapshot) {
   3385    cacheIRSnapshot = getOpSnapshot<WarpCacheIRWithShapeList>(loc);
   3386    if (!cacheIRSnapshot) {
   3387      cacheIRSnapshot = getOpSnapshot<WarpCacheIRWithShapeListAndOffsets>(loc);
   3388    }
   3389  }
   3390  if (cacheIRSnapshot) {
   3391    return TranspileCacheIRToMIR(this, loc, cacheIRSnapshot, inputs);
   3392  }
   3393 
   3394  if (getOpSnapshot<WarpBailout>(loc)) {
   3395    for (MDefinition* input : inputs) {
   3396      input->setImplicitlyUsedUnchecked();
   3397    }
   3398    return buildBailoutForColdIC(loc, kind);
   3399  }
   3400 
   3401  if (const auto* inliningSnapshot = getOpSnapshot<WarpInlinedCall>(loc)) {
   3402    // The CallInfo will be initialized by the transpiler.
   3403    bool ignoresRval = BytecodeIsPopped(loc.toRawBytecode());
   3404    CallInfo callInfo(alloc(), /*constructing =*/false, ignoresRval);
   3405    callInfo.markAsInlined();
   3406 
   3407    if (!TranspileCacheIRToMIR(this, loc, inliningSnapshot->cacheIRSnapshot(),
   3408                               inputs, &callInfo)) {
   3409      return false;
   3410    }
   3411    return buildInlinedCall(loc, inliningSnapshot, callInfo);
   3412  }
   3413 
   3414  // Work around std::initializer_list not defining operator[].
   3415  auto getInput = [&](size_t index) -> MDefinition* {
   3416    MOZ_ASSERT(index < numInputs);
   3417    return inputs.begin()[index];
   3418  };
   3419 
   3420  switch (kind) {
   3421    case CacheKind::UnaryArith: {
   3422      MOZ_ASSERT(numInputs == 1);
   3423      auto* ins = MUnaryCache::New(alloc(), getInput(0));
   3424      current->add(ins);
   3425      current->push(ins);
   3426      return resumeAfter(ins, loc);
   3427    }
   3428    case CacheKind::ToPropertyKey: {
   3429      MOZ_ASSERT(numInputs == 1);
   3430      auto* ins = MToPropertyKeyCache::New(alloc(), getInput(0));
   3431      current->add(ins);
   3432      current->push(ins);
   3433      return resumeAfter(ins, loc);
   3434    }
   3435    case CacheKind::BinaryArith: {
   3436      MOZ_ASSERT(numInputs == 2);
   3437      auto* ins =
   3438          MBinaryCache::New(alloc(), getInput(0), getInput(1), MIRType::Value);
   3439      current->add(ins);
   3440      current->push(ins);
   3441      return resumeAfter(ins, loc);
   3442    }
   3443    case CacheKind::Compare: {
   3444      MOZ_ASSERT(numInputs == 2);
   3445      auto* ins = MBinaryCache::New(alloc(), getInput(0), getInput(1),
   3446                                    MIRType::Boolean);
   3447      current->add(ins);
   3448      current->push(ins);
   3449      return resumeAfter(ins, loc);
   3450    }
   3451    case CacheKind::In: {
   3452      MOZ_ASSERT(numInputs == 2);
   3453      auto* ins = MInCache::New(alloc(), getInput(0), getInput(1));
   3454      current->add(ins);
   3455      current->push(ins);
   3456      return resumeAfter(ins, loc);
   3457    }
   3458    case CacheKind::HasOwn: {
   3459      MOZ_ASSERT(numInputs == 2);
   3460      // Note: the MHasOwnCache constructor takes obj/id instead of id/obj.
   3461      auto* ins = MHasOwnCache::New(alloc(), getInput(1), getInput(0));
   3462      current->add(ins);
   3463      current->push(ins);
   3464      return resumeAfter(ins, loc);
   3465    }
   3466    case CacheKind::CheckPrivateField: {
   3467      MOZ_ASSERT(numInputs == 2);
   3468      auto* ins =
   3469          MCheckPrivateFieldCache::New(alloc(), getInput(0), getInput(1));
   3470      current->add(ins);
   3471      current->push(ins);
   3472      return resumeAfter(ins, loc);
   3473    }
   3474    case CacheKind::InstanceOf: {
   3475      MOZ_ASSERT(numInputs == 2);
   3476      auto* ins = MInstanceOfCache::New(alloc(), getInput(0), getInput(1));
   3477      current->add(ins);
   3478      current->push(ins);
   3479      return resumeAfter(ins, loc);
   3480    }
   3481    case CacheKind::BindName: {
   3482      MOZ_ASSERT(numInputs == 1);
   3483      auto* ins = MBindNameCache::New(alloc(), getInput(0));
   3484      current->add(ins);
   3485      current->push(ins);
   3486      return resumeAfter(ins, loc);
   3487    }
   3488    case CacheKind::GetIterator: {
   3489      MOZ_ASSERT(numInputs == 1);
   3490      auto* ins = MGetIteratorCache::New(alloc(), getInput(0));
   3491      current->add(ins);
   3492      current->push(ins);
   3493      return resumeAfter(ins, loc);
   3494    }
   3495    case CacheKind::GetName: {
   3496      MOZ_ASSERT(numInputs == 1);
   3497      auto* ins = MGetNameCache::New(alloc(), getInput(0));
   3498      current->add(ins);
   3499      current->push(ins);
   3500      return resumeAfter(ins, loc);
   3501    }
   3502    case CacheKind::GetProp: {
   3503      MOZ_ASSERT(numInputs == 1);
   3504      PropertyName* name = loc.getPropertyName(script_);
   3505      MConstant* id = constant(StringValue(name));
   3506      MDefinition* val = getInput(0);
   3507      auto* ins = MGetPropertyCache::New(alloc(), val, id);
   3508      current->add(ins);
   3509      current->push(ins);
   3510      return resumeAfter(ins, loc);
   3511    }
   3512    case CacheKind::GetElem: {
   3513      MOZ_ASSERT(numInputs == 2);
   3514      MDefinition* val = getInput(0);
   3515      auto* ins = MGetPropertyCache::New(alloc(), val, getInput(1));
   3516      current->add(ins);
   3517      current->push(ins);
   3518      return resumeAfter(ins, loc);
   3519    }
   3520    case CacheKind::SetProp: {
   3521      MOZ_ASSERT(numInputs == 2);
   3522      PropertyName* name = loc.getPropertyName(script_);
   3523      MConstant* id = constant(StringValue(name));
   3524      bool strict = loc.isStrictSetOp();
   3525      auto* ins =
   3526          MSetPropertyCache::New(alloc(), getInput(0), id, getInput(1), strict);
   3527      current->add(ins);
   3528      return resumeAfter(ins, loc);
   3529    }
   3530    case CacheKind::SetElem: {
   3531      MOZ_ASSERT(numInputs == 3);
   3532      bool strict = loc.isStrictSetOp();
   3533      auto* ins = MSetPropertyCache::New(alloc(), getInput(0), getInput(1),
   3534                                         getInput(2), strict);
   3535      current->add(ins);
   3536      return resumeAfter(ins, loc);
   3537    }
   3538    case CacheKind::GetPropSuper: {
   3539      MOZ_ASSERT(numInputs == 2);
   3540      PropertyName* name = loc.getPropertyName(script_);
   3541      MConstant* id = constant(StringValue(name));
   3542      auto* ins =
   3543          MGetPropSuperCache::New(alloc(), getInput(0), getInput(1), id);
   3544      current->add(ins);
   3545      current->push(ins);
   3546      return resumeAfter(ins, loc);
   3547    }
   3548    case CacheKind::GetElemSuper: {
   3549      MOZ_ASSERT(numInputs == 3);
   3550      // Note: CacheIR expects obj/id/receiver but MGetPropSuperCache takes
   3551      // obj/receiver/id so swap the last two inputs.
   3552      auto* ins = MGetPropSuperCache::New(alloc(), getInput(0), getInput(2),
   3553                                          getInput(1));
   3554      current->add(ins);
   3555      current->push(ins);
   3556      return resumeAfter(ins, loc);
   3557    }
   3558    case CacheKind::OptimizeSpreadCall: {
   3559      MOZ_ASSERT(numInputs == 1);
   3560      auto* ins = MOptimizeSpreadCallCache::New(alloc(), getInput(0));
   3561      current->add(ins);
   3562      current->push(ins);
   3563      return resumeAfter(ins, loc);
   3564    }
   3565    case CacheKind::TypeOf: {
   3566      // Note: Warp does not have a TypeOf IC, it just inlines the operation.
   3567      MOZ_ASSERT(numInputs == 1);
   3568      auto* typeOf = MTypeOf::New(alloc(), getInput(0));
   3569      current->add(typeOf);
   3570 
   3571      auto* ins = MTypeOfName::New(alloc(), typeOf);
   3572      current->add(ins);
   3573      current->push(ins);
   3574      return true;
   3575    }
   3576    case CacheKind::TypeOfEq: {
   3577      MOZ_ASSERT(numInputs == 1);
   3578      auto operand = loc.getTypeofEqOperand();
   3579      JSType type = operand.type();
   3580      JSOp compareOp = operand.compareOp();
   3581      auto* typeOf = MTypeOf::New(alloc(), getInput(0));
   3582      current->add(typeOf);
   3583 
   3584      auto* typeInt = MConstant::NewInt32(alloc(), type);
   3585      current->add(typeInt);
   3586 
   3587      auto* ins = MCompare::New(alloc(), typeOf, typeInt, compareOp,
   3588                                MCompare::Compare_Int32);
   3589      current->add(ins);
   3590      current->push(ins);
   3591      return true;
   3592    }
   3593    case CacheKind::NewObject: {
   3594      auto* templateConst = constant(NullValue());
   3595      MNewObject* ins = MNewObject::NewVM(
   3596          alloc(), templateConst, gc::Heap::Default, MNewObject::ObjectLiteral);
   3597      current->add(ins);
   3598      current->push(ins);
   3599      return resumeAfter(ins, loc);
   3600    }
   3601    case CacheKind::NewArray: {
   3602      uint32_t length = loc.getNewArrayLength();
   3603      MConstant* templateConst = constant(NullValue());
   3604      MNewArray* ins =
   3605          MNewArray::NewVM(alloc(), length, templateConst, gc::Heap::Default);
   3606      current->add(ins);
   3607      current->push(ins);
   3608      return true;
   3609    }
   3610    case CacheKind::CloseIter: {
   3611      MOZ_ASSERT(numInputs == 1);
   3612      static_assert(sizeof(CompletionKind) == sizeof(uint8_t));
   3613      CompletionKind kind = loc.getCompletionKind();
   3614      auto* ins = MCloseIterCache::New(alloc(), getInput(0), uint8_t(kind));
   3615      current->add(ins);
   3616      return resumeAfter(ins, loc);
   3617    }
   3618    case CacheKind::OptimizeGetIterator: {
   3619      MOZ_ASSERT(numInputs == 1);
   3620      auto* ins = MOptimizeGetIteratorCache::New(alloc(), getInput(0));
   3621      current->add(ins);
   3622      current->push(ins);
   3623      return resumeAfter(ins, loc);
   3624    }
   3625    case CacheKind::Lambda: {
   3626      MDefinition* env = current->environmentChain();
   3627      JSFunction* fun = loc.getFunction(script_);
   3628      MConstant* funConst = constant(ObjectValue(*fun));
   3629      auto* ins = MLambda::New(alloc(), env, funConst, gc::Heap::Default);
   3630      current->add(ins);
   3631      current->push(ins);
   3632      return resumeAfter(ins, loc);
   3633    }
   3634    case CacheKind::LazyConstant:
   3635    case CacheKind::ToBool:
   3636    case CacheKind::Call:
   3637    case CacheKind::GetImport:
   3638      // We're currently not using an IC or transpiling CacheIR for these kinds.
   3639      MOZ_CRASH("Unexpected kind");
   3640  }
   3641 
   3642  return true;
   3643 }
   3644 
   3645 bool WarpBuilder::buildBailoutForColdIC(BytecodeLocation loc, CacheKind kind) {
   3646  MOZ_ASSERT(loc.opHasIC());
   3647 
   3648  MBail* bail = MBail::New(alloc(), BailoutKind::FirstExecution);
   3649  current->add(bail);
   3650  current->setAlwaysBails();
   3651 
   3652  MIRType resultType;
   3653  switch (kind) {
   3654    case CacheKind::UnaryArith:
   3655    case CacheKind::BinaryArith:
   3656    case CacheKind::GetName:
   3657    case CacheKind::GetProp:
   3658    case CacheKind::GetElem:
   3659    case CacheKind::GetPropSuper:
   3660    case CacheKind::GetElemSuper:
   3661    case CacheKind::GetImport:
   3662    case CacheKind::LazyConstant:
   3663    case CacheKind::Call:
   3664    case CacheKind::ToPropertyKey:
   3665    case CacheKind::OptimizeSpreadCall:
   3666      resultType = MIRType::Value;
   3667      break;
   3668    case CacheKind::BindName:
   3669    case CacheKind::GetIterator:
   3670    case CacheKind::NewArray:
   3671    case CacheKind::NewObject:
   3672    case CacheKind::Lambda:
   3673      resultType = MIRType::Object;
   3674      break;
   3675    case CacheKind::TypeOf:
   3676      resultType = MIRType::String;
   3677      break;
   3678    case CacheKind::ToBool:
   3679    case CacheKind::Compare:
   3680    case CacheKind::In:
   3681    case CacheKind::HasOwn:
   3682    case CacheKind::CheckPrivateField:
   3683    case CacheKind::InstanceOf:
   3684    case CacheKind::OptimizeGetIterator:
   3685    case CacheKind::TypeOfEq:
   3686      resultType = MIRType::Boolean;
   3687      break;
   3688    case CacheKind::SetProp:
   3689    case CacheKind::SetElem:
   3690    case CacheKind::CloseIter:
   3691      return true;  // No result.
   3692  }
   3693 
   3694  auto* ins = MUnreachableResult::New(alloc(), resultType);
   3695  current->add(ins);
   3696  current->push(ins);
   3697 
   3698  return true;
   3699 }
   3700 
   3701 class MOZ_RAII AutoAccumulateReturns {
   3702  MIRGraph& graph_;
   3703  MIRGraphReturns* prev_;
   3704 
   3705 public:
   3706  AutoAccumulateReturns(MIRGraph& graph, MIRGraphReturns& returns)
   3707      : graph_(graph) {
   3708    prev_ = graph_.returnAccumulator();
   3709    graph_.setReturnAccumulator(&returns);
   3710  }
   3711  ~AutoAccumulateReturns() { graph_.setReturnAccumulator(prev_); }
   3712 };
   3713 
   3714 bool WarpBuilder::buildInlinedCall(BytecodeLocation loc,
   3715                                   const WarpInlinedCall* inlineSnapshot,
   3716                                   CallInfo& callInfo) {
   3717  jsbytecode* pc = loc.toRawBytecode();
   3718 
   3719  if (callInfo.isSetter()) {
   3720    // build_SetProp pushes the rhs argument onto the stack. Remove it
   3721    // in preparation for pushCallStack.
   3722    current->pop();
   3723  }
   3724 
   3725  callInfo.setImplicitlyUsedUnchecked();
   3726 
   3727  // Capture formals in the outer resume point.
   3728  if (!callInfo.pushCallStack(current)) {
   3729    return false;
   3730  }
   3731  MResumePoint* outerResumePoint =
   3732      MResumePoint::New(alloc(), current, pc, callInfo.inliningResumeMode());
   3733  if (!outerResumePoint) {
   3734    return false;
   3735  }
   3736  current->setOuterResumePoint(outerResumePoint);
   3737 
   3738  // Pop formals again, except leave |callee| on stack for duration of call.
   3739  callInfo.popCallStack(current);
   3740  current->push(callInfo.callee());
   3741 
   3742  // Build the graph.
   3743  CompileInfo* calleeCompileInfo = inlineSnapshot->info();
   3744  MIRGraphReturns returns(alloc());
   3745  AutoAccumulateReturns aar(graph(), returns);
   3746  WarpBuilder inlineBuilder(this, inlineSnapshot->scriptSnapshot(),
   3747                            *calleeCompileInfo, &callInfo, outerResumePoint);
   3748  if (!inlineBuilder.buildInline()) {
   3749    // Note: Inlining only aborts on OOM.  If inlining would fail for
   3750    // any other reason, we detect it in advance and don't inline.
   3751    return false;
   3752  }
   3753 
   3754  // We mark scripts as uninlineable in BytecodeAnalysis if we cannot
   3755  // reach a return statement (without going through a catch/finally).
   3756  MOZ_ASSERT(!returns.empty());
   3757 
   3758  // Create return block
   3759  BytecodeLocation postCall = loc.next();
   3760  MBasicBlock* prev = current;
   3761  if (!startNewEntryBlock(prev->stackDepth(), postCall)) {
   3762    return false;
   3763  }
   3764  // Restore previous value of callerResumePoint.
   3765  current->setCallerResumePoint(callerResumePoint());
   3766  current->inheritSlots(prev);
   3767 
   3768  // Pop |callee|.
   3769  current->pop();
   3770 
   3771  // Accumulate return values.
   3772  MDefinition* returnValue =
   3773      patchInlinedReturns(calleeCompileInfo, callInfo, returns, current);
   3774  if (!returnValue) {
   3775    return false;
   3776  }
   3777  current->push(returnValue);
   3778 
   3779  // Initialize entry slots
   3780  if (!current->initEntrySlots(alloc())) {
   3781    return false;
   3782  }
   3783 
   3784  return true;
   3785 }
   3786 
   3787 MDefinition* WarpBuilder::patchInlinedReturns(CompileInfo* calleeCompileInfo,
   3788                                              CallInfo& callInfo,
   3789                                              MIRGraphReturns& exits,
   3790                                              MBasicBlock* returnBlock) {
   3791  if (exits.length() == 1) {
   3792    return patchInlinedReturn(calleeCompileInfo, callInfo, exits[0],
   3793                              returnBlock);
   3794  }
   3795 
   3796  // Accumulate multiple returns with a phi.
   3797  MPhi* phi = MPhi::New(alloc());
   3798  if (!phi->reserveLength(exits.length())) {
   3799    return nullptr;
   3800  }
   3801 
   3802  for (auto* exit : exits) {
   3803    MDefinition* rdef =
   3804        patchInlinedReturn(calleeCompileInfo, callInfo, exit, returnBlock);
   3805    if (!rdef) {
   3806      return nullptr;
   3807    }
   3808    phi->addInput(rdef);
   3809  }
   3810  returnBlock->addPhi(phi);
   3811  return phi;
   3812 }
   3813 
   3814 MDefinition* WarpBuilder::patchInlinedReturn(CompileInfo* calleeCompileInfo,
   3815                                             CallInfo& callInfo,
   3816                                             MBasicBlock* exit,
   3817                                             MBasicBlock* returnBlock) {
   3818  // Replace the MReturn in the exit block with an MGoto branching to
   3819  // the return block.
   3820  MDefinition* rdef = exit->lastIns()->toReturn()->input();
   3821  exit->discardLastIns();
   3822 
   3823  // Constructors must be patched by the caller to always return an object.
   3824  // Derived class constructors contain extra bytecode to ensure an object
   3825  // is always returned, so no additional patching is needed.
   3826  if (callInfo.constructing() &&
   3827      !calleeCompileInfo->isDerivedClassConstructor()) {
   3828    auto* filter = MReturnFromCtor::New(alloc(), rdef, callInfo.thisArg());
   3829    exit->add(filter);
   3830    rdef = filter;
   3831  } else if (callInfo.isSetter()) {
   3832    // Setters return the rhs argument, not whatever value is returned.
   3833    rdef = callInfo.getArg(0);
   3834  }
   3835 
   3836  exit->end(MGoto::New(alloc(), returnBlock));
   3837  if (!returnBlock->addPredecessorWithoutPhis(exit)) {
   3838    return nullptr;
   3839  }
   3840 
   3841  return rdef;
   3842 }