tor-browser

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

WarpCacheIRTranspiler.cpp (232357B)


      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/WarpCacheIRTranspiler.h"
      8 
      9 #include "mozilla/Casting.h"
     10 #include "mozilla/Maybe.h"
     11 
     12 #include "jsmath.h"
     13 
     14 #include "jit/AtomicOp.h"
     15 #include "jit/CacheIR.h"
     16 #include "jit/CacheIRCompiler.h"
     17 #include "jit/CacheIROpsGenerated.h"
     18 #include "jit/CacheIRReader.h"
     19 #include "jit/LIR.h"
     20 #include "jit/MIR-wasm.h"
     21 #include "jit/MIR.h"
     22 #include "jit/MIRGenerator.h"
     23 #include "jit/MIRGraph.h"
     24 #include "jit/WarpBuilder.h"
     25 #include "jit/WarpBuilderShared.h"
     26 #include "jit/WarpSnapshot.h"
     27 #include "js/ScalarType.h"  // js::Scalar::Type
     28 #include "vm/BytecodeLocation.h"
     29 #include "vm/ObjectFuse.h"
     30 #include "vm/TypeofEqOperand.h"  // TypeofEqOperand
     31 #include "wasm/WasmCode.h"
     32 
     33 #include "gc/ObjectKind-inl.h"
     34 #include "vm/NativeObject-inl.h"
     35 #include "wasm/WasmInstance-inl.h"
     36 
     37 using namespace js;
     38 using namespace js::jit;
     39 
     40 // The CacheIR transpiler generates MIR from Baseline CacheIR.
     41 class MOZ_RAII WarpCacheIRTranspiler : public WarpBuilderShared {
     42  WarpBuilder* builder_;
     43  BytecodeLocation loc_;
     44  const WarpCacheIRBase* cacheIRSnapshot_;
     45  const CacheIRStubInfo* stubInfo_;
     46  const uint8_t* stubData_;
     47 
     48  // Vector mapping OperandId to corresponding MDefinition.
     49  using MDefinitionStackVector = Vector<MDefinition*, 8, SystemAllocPolicy>;
     50  MDefinitionStackVector operands_;
     51 
     52  CallInfo* callInfo_;
     53 
     54  // Array mapping call arguments to OperandId.
     55  using ArgumentKindArray =
     56      mozilla::EnumeratedArray<ArgumentKind, OperandId,
     57                               size_t(ArgumentKind::NumKinds)>;
     58  ArgumentKindArray argumentOperandIds_;
     59 
     60  void setArgumentId(ArgumentKind kind, OperandId id) {
     61    MOZ_ASSERT(kind != ArgumentKind::Callee);
     62    MOZ_ASSERT(!argumentOperandIds_[kind].valid());
     63    argumentOperandIds_[kind] = id;
     64  }
     65 
     66  void updateArgumentsFromOperands();
     67 
     68 #ifdef DEBUG
     69  // Used to assert that there is only one effectful instruction
     70  // per stub. And that this instruction has a resume point.
     71  MInstruction* effectful_ = nullptr;
     72  bool pushedResult_ = false;
     73 #endif
     74 
     75  inline void addUnchecked(MInstruction* ins) {
     76    current->add(ins);
     77 
     78    // If we have not set a more specific bailout kind, mark this instruction
     79    // as transpiled CacheIR. If one of these instructions bails out, we
     80    // expect to hit the baseline fallback stub and invalidate the Warp script
     81    // in tryAttach.
     82    if (ins->bailoutKind() == BailoutKind::Unknown) {
     83      ins->setBailoutKind(BailoutKind::TranspiledCacheIR);
     84    }
     85  }
     86 
     87  inline void add(MInstruction* ins) {
     88    MOZ_ASSERT(!ins->isEffectful());
     89    addUnchecked(ins);
     90  }
     91 
     92  inline void addEffectful(MInstruction* ins) {
     93    MOZ_ASSERT(ins->isEffectful());
     94    MOZ_ASSERT(!effectful_, "Can only have one effectful instruction");
     95    addUnchecked(ins);
     96 #ifdef DEBUG
     97    effectful_ = ins;
     98 #endif
     99  }
    100 
    101  // Bypasses all checks in addEffectful. Use with caution!
    102  inline void addEffectfulUnsafe(MInstruction* ins) {
    103    MOZ_ASSERT(ins->isEffectful());
    104    addUnchecked(ins);
    105  }
    106 
    107  [[nodiscard]] bool resumeAfterUnchecked(MInstruction* ins) {
    108    return WarpBuilderShared::resumeAfter(ins, loc_);
    109  }
    110  [[nodiscard]] bool resumeAfter(MInstruction* ins) {
    111    MOZ_ASSERT(effectful_ == ins);
    112    return resumeAfterUnchecked(ins);
    113  }
    114 
    115  // CacheIR instructions writing to the IC's result register (the *Result
    116  // instructions) must call this to push the result onto the virtual stack.
    117  void pushResult(MDefinition* result) {
    118    MOZ_ASSERT(!pushedResult_, "Can't have more than one result");
    119    current->push(result);
    120 #ifdef DEBUG
    121    pushedResult_ = true;
    122 #endif
    123  }
    124 
    125  MDefinition* getOperand(OperandId id) const { return operands_[id.id()]; }
    126 
    127  void setOperand(OperandId id, MDefinition* def) { operands_[id.id()] = def; }
    128 
    129  [[nodiscard]] bool defineOperand(OperandId id, MDefinition* def) {
    130    MOZ_ASSERT(id.id() == operands_.length());
    131    return operands_.append(def);
    132  }
    133 
    134  uintptr_t readStubWord(uint32_t offset) {
    135    return stubInfo_->getStubRawWord(stubData_, offset);
    136  }
    137 
    138  Shape* shapeStubField(uint32_t offset) {
    139    return reinterpret_cast<Shape*>(readStubWord(offset));
    140  }
    141  GetterSetter* getterSetterStubField(uint32_t offset) {
    142    return reinterpret_cast<GetterSetter*>(readStubWord(offset));
    143  }
    144  const JSClass* classStubField(uint32_t offset) {
    145    return reinterpret_cast<const JSClass*>(readStubWord(offset));
    146  }
    147  JSString* stringStubField(uint32_t offset) {
    148    return reinterpret_cast<JSString*>(readStubWord(offset));
    149  }
    150  JS::Symbol* symbolStubField(uint32_t offset) {
    151    return reinterpret_cast<JS::Symbol*>(readStubWord(offset));
    152  }
    153  BaseScript* baseScriptStubField(uint32_t offset) {
    154    return reinterpret_cast<BaseScript*>(readStubWord(offset));
    155  }
    156  const JSJitInfo* jitInfoStubField(uint32_t offset) {
    157    return reinterpret_cast<const JSJitInfo*>(readStubWord(offset));
    158  }
    159  JSNative jsnativeStubField(uint32_t offset) {
    160    return reinterpret_cast<JSNative>(readStubWord(offset));
    161  }
    162  JS::ExpandoAndGeneration* expandoAndGenerationField(uint32_t offset) {
    163    return reinterpret_cast<JS::ExpandoAndGeneration*>(readStubWord(offset));
    164  }
    165  const wasm::FuncExport* wasmFuncExportField(uint32_t offset) {
    166    return reinterpret_cast<const wasm::FuncExport*>(readStubWord(offset));
    167  }
    168  NativeIteratorListHead* nativeIteratorListHeadStubField(uint32_t offset) {
    169    return reinterpret_cast<NativeIteratorListHead*>(readStubWord(offset));
    170  }
    171  size_t* fuseStubField(uint32_t offset) {
    172    return reinterpret_cast<size_t*>(readStubWord(offset));
    173  }
    174  ObjectFuse* objectFuseStubField(uint32_t offset) {
    175    return reinterpret_cast<ObjectFuse*>(readStubWord(offset));
    176  }
    177  gc::Heap allocSiteInitialHeapField(uint32_t offset) {
    178    uintptr_t word = readStubWord(offset);
    179    MOZ_ASSERT(word == uintptr_t(gc::Heap::Default) ||
    180               word == uintptr_t(gc::Heap::Tenured));
    181    return gc::Heap(word);
    182  }
    183  const void* rawPointerField(uint32_t offset) {
    184    return reinterpret_cast<const void*>(readStubWord(offset));
    185  }
    186  jsid idStubField(uint32_t offset) {
    187    return jsid::fromRawBits(readStubWord(offset));
    188  }
    189  int32_t int32StubField(uint32_t offset) {
    190    return static_cast<int32_t>(readStubWord(offset));
    191  }
    192  uint32_t uint32StubField(uint32_t offset) {
    193    return static_cast<uint32_t>(readStubWord(offset));
    194  }
    195  uint64_t uint64StubField(uint32_t offset) {
    196    return static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset));
    197  }
    198  ValueOrNurseryValueIndex valueStubField(uint32_t offset) {
    199    uint64_t raw =
    200        static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset));
    201    Value val = Value::fromRawBits(raw);
    202    MOZ_ASSERT_IF(val.isGCThing(), val.toGCThing()->isTenured());
    203    return ValueOrNurseryValueIndex::fromValueOrNurseryIndex(val);
    204  }
    205  double doubleStubField(uint32_t offset) {
    206    uint64_t raw =
    207        static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset));
    208    return mozilla::BitwiseCast<double>(raw);
    209  }
    210 
    211  // This must only be called when the caller knows the object is tenured and
    212  // not a nursery index.
    213  JSObject* tenuredObjectStubField(uint32_t offset) {
    214    WarpObjectField field = WarpObjectField::fromData(readStubWord(offset));
    215    return field.toObject();
    216  }
    217 
    218  // Returns either MConstant or MNurseryIndex. See WarpObjectField.
    219  MInstruction* objectStubField(uint32_t offset);
    220 
    221  const JSClass* classForGuardClassKind(GuardClassKind kind);
    222 
    223  [[nodiscard]] bool emitGuardTo(ValOperandId inputId, MIRType type);
    224 
    225  [[nodiscard]] bool emitToString(OperandId inputId, StringOperandId resultId);
    226 
    227  template <typename T>
    228  [[nodiscard]] bool emitDoubleBinaryArithResult(NumberOperandId lhsId,
    229                                                 NumberOperandId rhsId);
    230 
    231  template <typename T>
    232  [[nodiscard]] bool emitInt32BinaryArithResult(Int32OperandId lhsId,
    233                                                Int32OperandId rhsId);
    234 
    235  template <typename T>
    236  [[nodiscard]] bool emitBigIntBinaryArithResult(BigIntOperandId lhsId,
    237                                                 BigIntOperandId rhsId);
    238 
    239  template <typename T>
    240  [[nodiscard]] bool emitBigIntBinaryArithEffectfulResult(
    241      BigIntOperandId lhsId, BigIntOperandId rhsId);
    242 
    243  template <typename T>
    244  [[nodiscard]] bool emitBigIntUnaryArithResult(BigIntOperandId inputId);
    245 
    246  template <typename T>
    247  [[nodiscard]] bool emitBigIntPtrBinaryArith(IntPtrOperandId lhsId,
    248                                              IntPtrOperandId rhsId,
    249                                              IntPtrOperandId resultId);
    250 
    251  [[nodiscard]] bool emitCompareResult(JSOp op, OperandId lhsId,
    252                                       OperandId rhsId,
    253                                       MCompare::CompareType compareType);
    254 
    255  [[nodiscard]] bool emitTruthyResult(OperandId inputId);
    256 
    257  [[nodiscard]] bool emitNewIteratorResult(MNewIterator::Type type,
    258                                           uint32_t templateObjectOffset);
    259 
    260  MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
    261 
    262  [[nodiscard]] MInstruction* convertToBoolean(MDefinition* input);
    263 
    264  bool emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind kind,
    265                                 ObjOperandId objId, uint32_t offsetOffset,
    266                                 ValOperandId rhsId, uint32_t newShapeOffset,
    267                                 bool preserveWrapper);
    268 
    269  MInstruction* emitTypedArrayLength(ArrayBufferViewKind viewKind,
    270                                     MDefinition* obj);
    271 
    272  MInstruction* emitDataViewLength(ArrayBufferViewKind viewKind,
    273                                   MDefinition* obj);
    274 
    275  void addDataViewData(ArrayBufferViewKind viewKind, MDefinition* obj,
    276                       Scalar::Type type, MDefinition** offset,
    277                       MInstruction** elements);
    278 
    279  [[nodiscard]] bool emitAtomicsBinaryOp(
    280      ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
    281      Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind,
    282      AtomicOp op);
    283 
    284  [[nodiscard]] bool emitLoadArgumentSlot(ValOperandId resultId,
    285                                          uint32_t slotIndex);
    286 
    287  // Calls are either Native (native function without a JitEntry),
    288  // a DOM Native (native function with a JitInfo OpType::Method),
    289  // or Scripted (scripted function or native function with a JitEntry).
    290  enum class CallKind { Native, DOM, Scripted };
    291 
    292  [[nodiscard]] bool updateCallInfo(MDefinition* callee, CallFlags flags);
    293 
    294  [[nodiscard]] bool emitCallFunction(
    295      ObjOperandId calleeId, Int32OperandId argcId,
    296      mozilla::Maybe<ObjOperandId> thisObjId, CallFlags flags, CallKind kind,
    297      mozilla::Maybe<uint32_t> siteOffset = mozilla::Nothing());
    298  [[nodiscard]] bool emitFunApplyArgsObj(WrappedFunction* wrappedTarget,
    299                                         CallFlags flags);
    300 
    301  MDefinition* convertWasmArg(MDefinition* arg, wasm::ValType::Kind kind);
    302 
    303  WrappedFunction* maybeWrappedFunction(MDefinition* callee, CallKind kind,
    304                                        uint16_t nargs, FunctionFlags flags);
    305  WrappedFunction* maybeCallTarget(MDefinition* callee, CallKind kind);
    306  WrappedFunction* maybeGetterSetterTarget(MDefinition* callee, CallKind kind,
    307                                           uint16_t nargs, FunctionFlags flags);
    308 
    309  bool maybeCreateThis(MDefinition* callee, CallFlags flags, CallKind kind);
    310 
    311  [[nodiscard]] bool emitCallGetterResult(CallKind kind,
    312                                          ValOperandId receiverId,
    313                                          MDefinition* getter, bool sameRealm,
    314                                          uint32_t nargsAndFlagsOffset);
    315  [[nodiscard]] bool emitCallSetter(CallKind kind, ObjOperandId receiverId,
    316                                    MDefinition* setter, ValOperandId rhsId,
    317                                    bool sameRealm,
    318                                    uint32_t nargsAndFlagsOffset);
    319 
    320 #ifndef JS_CODEGEN_X86
    321  [[nodiscard]] bool emitCallScriptedProxyGetShared(
    322      MDefinition* target, MDefinition* receiver, MDefinition* handler,
    323      MDefinition* id, MDefinition* trapDef, WrappedFunction* trap);
    324 #endif
    325 
    326  CACHE_IR_TRANSPILER_GENERATED
    327 
    328 public:
    329  WarpCacheIRTranspiler(WarpBuilder* builder, BytecodeLocation loc,
    330                        CallInfo* callInfo,
    331                        const WarpCacheIRBase* cacheIRSnapshot)
    332      : WarpBuilderShared(builder->snapshot(), builder->mirGen(),
    333                          builder->currentBlock()),
    334        builder_(builder),
    335        loc_(loc),
    336        cacheIRSnapshot_(cacheIRSnapshot),
    337        stubInfo_(cacheIRSnapshot->stubInfo()),
    338        stubData_(cacheIRSnapshot->stubData()),
    339        callInfo_(callInfo) {}
    340 
    341  [[nodiscard]] bool transpile(std::initializer_list<MDefinition*> inputs);
    342 };
    343 
    344 bool WarpCacheIRTranspiler::transpile(
    345    std::initializer_list<MDefinition*> inputs) {
    346  if (!operands_.append(inputs.begin(), inputs.end())) {
    347    return false;
    348  }
    349 
    350  CacheIRReader reader(stubInfo_);
    351  do {
    352    CacheOp op = reader.readOp();
    353    switch (op) {
    354 #define DEFINE_OP(op, ...)   \
    355  case CacheOp::op:          \
    356    if (!emit##op(reader)) { \
    357      return false;          \
    358    }                        \
    359    break;
    360      CACHE_IR_TRANSPILER_OPS(DEFINE_OP)
    361 #undef DEFINE_OP
    362 
    363      default:
    364        MOZ_CRASH("Unsupported op");
    365    }
    366  } while (reader.more());
    367 
    368  // Effectful instructions should have a resume point. We allow a limited
    369  // number of exceptions:
    370  // - MIonToWasmCall: Resumes after MInt64ToBigInt
    371  // - MLoadUnboxedScalar: Resumes after MInt64ToBigInt
    372  // - MAtomicTypedArrayElementBinop: Resumes after MInt64ToBigInt
    373  // - MAtomicExchangeTypedArrayElement: Resumes after MInt64ToBigInt
    374  // - MCompareExchangeTypedArrayElement: Resumes after MInt64ToBigInt
    375  // - MResizableTypedArrayLength: Resumes after MPostIntPtrConversion
    376  // - MResizableDataViewByteLength: Resumes after MPostIntPtrConversion
    377  // - MGrowableSharedArrayBufferByteLength: Resumes after MPostIntPtrConversion
    378  MOZ_ASSERT_IF(effectful_,
    379                effectful_->resumePoint() || effectful_->isIonToWasmCall() ||
    380                    effectful_->isLoadUnboxedScalar() ||
    381                    effectful_->isAtomicTypedArrayElementBinop() ||
    382                    effectful_->isAtomicExchangeTypedArrayElement() ||
    383                    effectful_->isCompareExchangeTypedArrayElement() ||
    384                    effectful_->isResizableTypedArrayLength() ||
    385                    effectful_->isResizableDataViewByteLength() ||
    386                    effectful_->isGrowableSharedArrayBufferByteLength());
    387  return true;
    388 }
    389 
    390 MInstruction* WarpCacheIRTranspiler::objectStubField(uint32_t offset) {
    391  WarpObjectField field = WarpObjectField::fromData(readStubWord(offset));
    392 
    393  if (field.isNurseryIndex()) {
    394    auto* ins = MNurseryObject::New(alloc(), field.toNurseryIndex());
    395    add(ins);
    396    return ins;
    397  }
    398 
    399  auto* ins = MConstant::NewObject(alloc(), field.toObject());
    400  add(ins);
    401  return ins;
    402 }
    403 
    404 bool WarpCacheIRTranspiler::emitGuardClass(ObjOperandId objId,
    405                                           GuardClassKind kind) {
    406  MDefinition* def = getOperand(objId);
    407 
    408  MInstruction* ins;
    409  if (kind == GuardClassKind::JSFunction) {
    410    ins = MGuardToFunction::New(alloc(), def);
    411  } else {
    412    const JSClass* classp = classForGuardClassKind(kind);
    413    ins = MGuardToClass::New(alloc(), def, classp);
    414  }
    415 
    416  add(ins);
    417 
    418  setOperand(objId, ins);
    419  return true;
    420 }
    421 
    422 const JSClass* WarpCacheIRTranspiler::classForGuardClassKind(
    423    GuardClassKind kind) {
    424  switch (kind) {
    425    case GuardClassKind::Array:
    426    case GuardClassKind::PlainObject:
    427    case GuardClassKind::FixedLengthArrayBuffer:
    428    case GuardClassKind::ImmutableArrayBuffer:
    429    case GuardClassKind::ResizableArrayBuffer:
    430    case GuardClassKind::FixedLengthSharedArrayBuffer:
    431    case GuardClassKind::GrowableSharedArrayBuffer:
    432    case GuardClassKind::FixedLengthDataView:
    433    case GuardClassKind::ImmutableDataView:
    434    case GuardClassKind::ResizableDataView:
    435    case GuardClassKind::MappedArguments:
    436    case GuardClassKind::UnmappedArguments:
    437    case GuardClassKind::Set:
    438    case GuardClassKind::Map:
    439    case GuardClassKind::BoundFunction:
    440    case GuardClassKind::Date:
    441    case GuardClassKind::WeakMap:
    442    case GuardClassKind::WeakSet:
    443      return ClassFor(kind);
    444    case GuardClassKind::WindowProxy:
    445      return mirGen().runtime->maybeWindowProxyClass();
    446    case GuardClassKind::JSFunction:
    447      break;
    448  }
    449  MOZ_CRASH("unexpected kind");
    450 }
    451 
    452 bool WarpCacheIRTranspiler::emitGuardAnyClass(ObjOperandId objId,
    453                                              uint32_t claspOffset) {
    454  MDefinition* def = getOperand(objId);
    455  const JSClass* classp = classStubField(claspOffset);
    456 
    457  auto* ins = MGuardToClass::New(alloc(), def, classp);
    458  add(ins);
    459 
    460  setOperand(objId, ins);
    461  return true;
    462 }
    463 
    464 bool WarpCacheIRTranspiler::emitGuardShape(ObjOperandId objId,
    465                                           uint32_t shapeOffset) {
    466  MDefinition* def = getOperand(objId);
    467 
    468  // No read barrier is required because snapshot data is not weak and is traced
    469  // as part of IonCompileTask.
    470  Shape* shape = shapeStubField(shapeOffset);
    471 
    472  auto* ins = MGuardShape::New(alloc(), def, shape);
    473  add(ins);
    474 
    475  setOperand(objId, ins);
    476  return true;
    477 }
    478 
    479 bool WarpCacheIRTranspiler::emitGuardFuse(RealmFuses::FuseIndex fuseIndex) {
    480  switch (fuseIndex) {
    481    case RealmFuses::FuseIndex::OptimizeGetIteratorFuse:
    482    case RealmFuses::FuseIndex::OptimizeArraySpeciesFuse:
    483    case RealmFuses::FuseIndex::OptimizeTypedArraySpeciesFuse:
    484    case RealmFuses::FuseIndex::OptimizeRegExpPrototypeFuse:
    485      // This is a no-op because WarpOracle has added a compilation dependency.
    486      MOZ_ASSERT(RealmFuses::isInvalidatingFuse(fuseIndex));
    487      return true;
    488    default:
    489      MOZ_ASSERT(!RealmFuses::isInvalidatingFuse(fuseIndex));
    490      auto* ins = MGuardFuse::New(alloc(), fuseIndex);
    491      add(ins);
    492      return true;
    493  }
    494 }
    495 
    496 bool WarpCacheIRTranspiler::emitGuardRuntimeFuse(
    497    RuntimeFuses::FuseIndex fuseIndex) {
    498  // This is a no-op because WarpOracle has added a compilation dependency.
    499  MOZ_ASSERT(RuntimeFuses::isInvalidatingFuse(fuseIndex));
    500  return true;
    501 }
    502 
    503 bool WarpCacheIRTranspiler::emitGuardObjectFuseProperty(
    504    ObjOperandId objId, uint32_t objFuseOwnerOffset, uint32_t objFuseOffset,
    505    uint32_t expectedGenerationOffset, uint32_t propIndexOffset,
    506    uint32_t propMaskOffset, bool canUseFastPath) {
    507  // A compilation dependency was added by WarpOracle.
    508  return true;
    509 }
    510 
    511 bool WarpCacheIRTranspiler::emitGuardMultipleShapes(ObjOperandId objId,
    512                                                    uint32_t shapesOffset) {
    513  MDefinition* def = getOperand(objId);
    514 
    515  // Use MGuardShapeList if we snapshotted the list of shapes on the main
    516  // thread.
    517  MInstruction* ins;
    518  if (cacheIRSnapshot_->is<WarpCacheIRWithShapeList>()) {
    519    auto* shapes = cacheIRSnapshot_->as<WarpCacheIRWithShapeList>()->shapes();
    520    ins = MGuardShapeList::New(alloc(), def, shapes);
    521  } else {
    522    MInstruction* shapeList = objectStubField(shapesOffset);
    523    ins = MGuardMultipleShapes::New(alloc(), def, shapeList);
    524    ins->setBailoutKind(BailoutKind::StubFoldingGuardMultipleShapes);
    525  }
    526  add(ins);
    527 
    528  setOperand(objId, ins);
    529  return true;
    530 }
    531 
    532 bool WarpCacheIRTranspiler::emitGuardMultipleShapesToOffset(
    533    ObjOperandId objId, uint32_t shapesOffset, Int32OperandId offsetId) {
    534  MDefinition* obj = getOperand(objId);
    535 
    536  // Use MGuardShapeListToOffset if we snapshotted the list of shapes on the
    537  // main thread.
    538  MInstruction* ins;
    539  if (cacheIRSnapshot_->is<WarpCacheIRWithShapeListAndOffsets>()) {
    540    auto* shapes = (ShapeListWithOffsetsSnapshot*)cacheIRSnapshot_
    541                       ->as<WarpCacheIRWithShapeListAndOffsets>()
    542                       ->shapes();
    543    ins = MGuardShapeListToOffset::New(alloc(), obj, shapes);
    544  } else {
    545    MInstruction* shapeList = objectStubField(shapesOffset);
    546    ins = MGuardMultipleShapesToOffset::New(alloc(), obj, shapeList);
    547    ins->setBailoutKind(BailoutKind::StubFoldingGuardMultipleShapes);
    548  }
    549  add(ins);
    550 
    551  return defineOperand(offsetId, ins);
    552 }
    553 
    554 bool WarpCacheIRTranspiler::emitGuardNullProto(ObjOperandId objId) {
    555  MDefinition* def = getOperand(objId);
    556 
    557  auto* ins = MGuardNullProto::New(alloc(), def);
    558  add(ins);
    559 
    560  setOperand(objId, ins);
    561  return true;
    562 }
    563 
    564 bool WarpCacheIRTranspiler::emitGuardIsNativeObject(ObjOperandId objId) {
    565  MDefinition* obj = getOperand(objId);
    566 
    567  auto* ins = MGuardIsNativeObject::New(alloc(), obj);
    568  add(ins);
    569 
    570  setOperand(objId, ins);
    571  return true;
    572 }
    573 
    574 bool WarpCacheIRTranspiler::emitGuardIsProxy(ObjOperandId objId) {
    575  MDefinition* obj = getOperand(objId);
    576 
    577  auto* ins = MGuardIsProxy::New(alloc(), obj);
    578  add(ins);
    579 
    580  setOperand(objId, ins);
    581  return true;
    582 }
    583 
    584 bool WarpCacheIRTranspiler::emitGuardIsNotProxy(ObjOperandId objId) {
    585  MDefinition* obj = getOperand(objId);
    586 
    587  auto* ins = MGuardIsNotProxy::New(alloc(), obj);
    588  add(ins);
    589 
    590  setOperand(objId, ins);
    591  return true;
    592 }
    593 
    594 bool WarpCacheIRTranspiler::emitGuardIsNotDOMProxy(ObjOperandId objId) {
    595  MDefinition* obj = getOperand(objId);
    596 
    597  auto* ins = MGuardIsNotDOMProxy::New(alloc(), obj);
    598  add(ins);
    599 
    600  setOperand(objId, ins);
    601  return true;
    602 }
    603 
    604 bool WarpCacheIRTranspiler::emitLoadGetterSetterFunction(
    605    ValOperandId getterSetterId, bool isGetter, bool needsClassGuard,
    606    ObjOperandId resultId) {
    607  MDefinition* getterSetter = getOperand(getterSetterId);
    608 
    609  auto* ins = MLoadGetterSetterFunction::New(alloc(), getterSetter, isGetter,
    610                                             needsClassGuard);
    611  add(ins);
    612 
    613  return defineOperand(resultId, ins);
    614 }
    615 
    616 bool WarpCacheIRTranspiler::emitGuardHasGetterSetter(
    617    ObjOperandId objId, uint32_t idOffset, uint32_t getterSetterOffset) {
    618  MDefinition* obj = getOperand(objId);
    619  jsid id = idStubField(idOffset);
    620  ValueOrNurseryValueIndex val = valueStubField(getterSetterOffset);
    621  MOZ_ASSERT_IF(val.isValue(), val.toValue().toGCThing()->is<GetterSetter>());
    622 
    623  auto* ins = MGuardHasGetterSetter::New(alloc(), obj, id, val);
    624  add(ins);
    625 
    626  setOperand(objId, ins);
    627  return true;
    628 }
    629 
    630 bool WarpCacheIRTranspiler::emitProxyGetResult(ObjOperandId objId,
    631                                               uint32_t idOffset) {
    632  MDefinition* obj = getOperand(objId);
    633  jsid id = idStubField(idOffset);
    634 
    635  auto* ins = MProxyGet::New(alloc(), obj, id);
    636  addEffectful(ins);
    637 
    638  pushResult(ins);
    639  return resumeAfter(ins);
    640 }
    641 
    642 bool WarpCacheIRTranspiler::emitProxyGetByValueResult(ObjOperandId objId,
    643                                                      ValOperandId idId) {
    644  MDefinition* obj = getOperand(objId);
    645  MDefinition* id = getOperand(idId);
    646 
    647  auto* ins = MProxyGetByValue::New(alloc(), obj, id);
    648  addEffectful(ins);
    649 
    650  pushResult(ins);
    651  return resumeAfter(ins);
    652 }
    653 
    654 bool WarpCacheIRTranspiler::emitProxyHasPropResult(ObjOperandId objId,
    655                                                   ValOperandId idId,
    656                                                   bool hasOwn) {
    657  MDefinition* obj = getOperand(objId);
    658  MDefinition* id = getOperand(idId);
    659 
    660  auto* ins = MProxyHasProp::New(alloc(), obj, id, hasOwn);
    661  addEffectful(ins);
    662 
    663  pushResult(ins);
    664  return resumeAfter(ins);
    665 }
    666 
    667 bool WarpCacheIRTranspiler::emitProxySet(ObjOperandId objId, uint32_t idOffset,
    668                                         ValOperandId rhsId, bool strict) {
    669  MDefinition* obj = getOperand(objId);
    670  jsid id = idStubField(idOffset);
    671  MDefinition* rhs = getOperand(rhsId);
    672 
    673  auto* ins = MProxySet::New(alloc(), obj, rhs, id, strict);
    674  addEffectful(ins);
    675 
    676  return resumeAfter(ins);
    677 }
    678 
    679 bool WarpCacheIRTranspiler::emitProxySetByValue(ObjOperandId objId,
    680                                                ValOperandId idId,
    681                                                ValOperandId rhsId,
    682                                                bool strict) {
    683  MDefinition* obj = getOperand(objId);
    684  MDefinition* id = getOperand(idId);
    685  MDefinition* rhs = getOperand(rhsId);
    686 
    687  auto* ins = MProxySetByValue::New(alloc(), obj, id, rhs, strict);
    688  addEffectful(ins);
    689 
    690  return resumeAfter(ins);
    691 }
    692 
    693 bool WarpCacheIRTranspiler::emitCallSetArrayLength(ObjOperandId objId,
    694                                                   bool strict,
    695                                                   ValOperandId rhsId) {
    696  MDefinition* obj = getOperand(objId);
    697  MDefinition* rhs = getOperand(rhsId);
    698 
    699  auto* ins = MCallSetArrayLength::New(alloc(), obj, rhs, strict);
    700  addEffectful(ins);
    701 
    702  return resumeAfter(ins);
    703 }
    704 
    705 bool WarpCacheIRTranspiler::emitCallDOMGetterResult(ObjOperandId objId,
    706                                                    uint32_t jitInfoOffset) {
    707  MDefinition* obj = getOperand(objId);
    708  const JSJitInfo* jitInfo = jitInfoStubField(jitInfoOffset);
    709 
    710  MInstruction* ins;
    711  if (jitInfo->isAlwaysInSlot) {
    712    ins = MGetDOMMember::New(alloc(), jitInfo, obj, nullptr, nullptr);
    713  } else {
    714    // TODO(post-Warp): realms, guard operands (movable?).
    715    ins = MGetDOMProperty::New(alloc(), jitInfo, DOMObjectKind::Native,
    716                               (JS::Realm*)mirGen().realm->realmPtr(), obj,
    717                               nullptr, nullptr);
    718  }
    719 
    720  if (!ins) {
    721    return false;
    722  }
    723 
    724  if (ins->isEffectful()) {
    725    addEffectful(ins);
    726    pushResult(ins);
    727    return resumeAfter(ins);
    728  }
    729 
    730  add(ins);
    731  pushResult(ins);
    732  return true;
    733 }
    734 
    735 bool WarpCacheIRTranspiler::emitCallDOMSetter(ObjOperandId objId,
    736                                              uint32_t jitInfoOffset,
    737                                              ValOperandId rhsId) {
    738  MDefinition* obj = getOperand(objId);
    739  const JSJitInfo* jitInfo = jitInfoStubField(jitInfoOffset);
    740  MDefinition* value = getOperand(rhsId);
    741 
    742  MOZ_ASSERT(jitInfo->type() == JSJitInfo::Setter);
    743  auto* set =
    744      MSetDOMProperty::New(alloc(), jitInfo->setter, DOMObjectKind::Native,
    745                           (JS::Realm*)mirGen().realm->realmPtr(), obj, value);
    746  addEffectful(set);
    747  return resumeAfter(set);
    748 }
    749 
    750 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValue(ObjOperandId objId,
    751                                                    ValOperandId resultId) {
    752  MDefinition* proxy = getOperand(objId);
    753 
    754  auto* ins = MLoadDOMExpandoValue::New(alloc(), proxy);
    755  add(ins);
    756 
    757  return defineOperand(resultId, ins);
    758 }
    759 
    760 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueGuardGeneration(
    761    ObjOperandId objId, uint32_t expandoAndGenerationOffset,
    762    uint32_t generationOffset, ValOperandId resultId) {
    763  MDefinition* proxy = getOperand(objId);
    764  JS::ExpandoAndGeneration* expandoAndGeneration =
    765      expandoAndGenerationField(expandoAndGenerationOffset);
    766  uint64_t generation = uint64StubField(generationOffset);
    767 
    768  auto* ins = MLoadDOMExpandoValueGuardGeneration::New(
    769      alloc(), proxy, expandoAndGeneration, generation);
    770  add(ins);
    771 
    772  return defineOperand(resultId, ins);
    773 }
    774 
    775 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueIgnoreGeneration(
    776    ObjOperandId objId, ValOperandId resultId) {
    777  MDefinition* proxy = getOperand(objId);
    778 
    779  auto* ins = MLoadDOMExpandoValueIgnoreGeneration::New(alloc(), proxy);
    780  add(ins);
    781 
    782  return defineOperand(resultId, ins);
    783 }
    784 
    785 bool WarpCacheIRTranspiler::emitGuardDOMExpandoMissingOrGuardShape(
    786    ValOperandId expandoId, uint32_t shapeOffset) {
    787  MDefinition* expando = getOperand(expandoId);
    788  Shape* shape = shapeStubField(shapeOffset);
    789 
    790  auto* ins = MGuardDOMExpandoMissingOrGuardShape::New(alloc(), expando, shape);
    791  add(ins);
    792 
    793  setOperand(expandoId, ins);
    794  return true;
    795 }
    796 
    797 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotResult(ObjOperandId objId,
    798                                                          uint32_t nameOffset) {
    799  MDefinition* obj = getOperand(objId);
    800  PropertyName* name = stringStubField(nameOffset)->asAtom().asPropertyName();
    801 
    802  auto* ins = MMegamorphicLoadSlot::New(alloc(), obj, NameToId(name));
    803 
    804  add(ins);
    805  pushResult(ins);
    806  return true;
    807 }
    808 
    809 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotPermissiveResult(
    810    ObjOperandId objId, uint32_t nameOffset) {
    811  MDefinition* obj = getOperand(objId);
    812  PropertyName* name = stringStubField(nameOffset)->asAtom().asPropertyName();
    813 
    814  auto* ins = MMegamorphicLoadSlotPermissive::New(alloc(), obj, NameToId(name));
    815 
    816  addEffectful(ins);
    817  pushResult(ins);
    818  return resumeAfter(ins);
    819 }
    820 
    821 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValueResult(
    822    ObjOperandId objId, ValOperandId idId) {
    823  MDefinition* obj = getOperand(objId);
    824  MDefinition* id = getOperand(idId);
    825 
    826  auto* ins = MMegamorphicLoadSlotByValue::New(alloc(), obj, id);
    827 
    828  add(ins);
    829  pushResult(ins);
    830  return true;
    831 }
    832 
    833 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValuePermissiveResult(
    834    ObjOperandId objId, ValOperandId idId) {
    835  MDefinition* obj = getOperand(objId);
    836  MDefinition* id = getOperand(idId);
    837 
    838  auto* ins = MMegamorphicLoadSlotByValuePermissive::New(alloc(), obj, id);
    839 
    840  addEffectful(ins);
    841  pushResult(ins);
    842  return resumeAfter(ins);
    843 }
    844 
    845 bool WarpCacheIRTranspiler::emitMegamorphicStoreSlot(ObjOperandId objId,
    846                                                     uint32_t idOffset,
    847                                                     ValOperandId rhsId,
    848                                                     bool strict) {
    849  MDefinition* obj = getOperand(objId);
    850  jsid id = idStubField(idOffset);
    851  MDefinition* rhs = getOperand(rhsId);
    852 
    853  auto* ins = MMegamorphicStoreSlot::New(alloc(), obj, rhs, id, strict);
    854  addEffectful(ins);
    855 
    856  return resumeAfter(ins);
    857 }
    858 
    859 bool WarpCacheIRTranspiler::emitMegamorphicHasPropResult(ObjOperandId objId,
    860                                                         ValOperandId idId,
    861                                                         bool hasOwn) {
    862  MDefinition* obj = getOperand(objId);
    863  MDefinition* id = getOperand(idId);
    864 
    865  auto* ins = MMegamorphicHasProp::New(alloc(), obj, id, hasOwn);
    866  add(ins);
    867 
    868  pushResult(ins);
    869  return true;
    870 }
    871 
    872 bool WarpCacheIRTranspiler::emitSmallObjectVariableKeyHasOwnResult(
    873    StringOperandId idId, uint32_t propNamesOffset, uint32_t shapeOffset) {
    874  MDefinition* id = getOperand(idId);
    875  SharedShape* shape = &shapeStubField(shapeOffset)->asShared();
    876 
    877  auto* ins = MSmallObjectVariableKeyHasProp::New(alloc(), id, shape);
    878  add(ins);
    879 
    880  pushResult(ins);
    881  return true;
    882 }
    883 
    884 bool WarpCacheIRTranspiler::emitMegamorphicSetElement(ObjOperandId objId,
    885                                                      ValOperandId idId,
    886                                                      ValOperandId rhsId,
    887                                                      bool strict) {
    888  MDefinition* obj = getOperand(objId);
    889  MDefinition* id = getOperand(idId);
    890  MDefinition* rhs = getOperand(rhsId);
    891 
    892  auto* ins = MMegamorphicSetElement::New(alloc(), obj, id, rhs, strict);
    893  addEffectful(ins);
    894 
    895  return resumeAfter(ins);
    896 }
    897 
    898 bool WarpCacheIRTranspiler::emitObjectToIteratorResult(
    899    ObjOperandId objId, uint32_t enumeratorsAddrOffset) {
    900  MDefinition* obj = getOperand(objId);
    901  NativeIteratorListHead* enumeratorsAddr =
    902      nativeIteratorListHeadStubField(enumeratorsAddrOffset);
    903 
    904  auto* ins = MObjectToIterator::New(alloc(), obj, enumeratorsAddr);
    905  addEffectful(ins);
    906  pushResult(ins);
    907  if (!resumeAfter(ins)) {
    908    return false;
    909  }
    910 
    911  return true;
    912 }
    913 
    914 bool WarpCacheIRTranspiler::emitValueToIteratorResult(ValOperandId valId) {
    915  MDefinition* val = getOperand(valId);
    916 
    917  auto* ins = MValueToIterator::New(alloc(), val);
    918  addEffectful(ins);
    919 
    920  pushResult(ins);
    921  return resumeAfter(ins);
    922 }
    923 
    924 bool WarpCacheIRTranspiler::emitGuardToArrayBuffer(ObjOperandId objId) {
    925  MDefinition* obj = getOperand(objId);
    926 
    927  auto* ins = MGuardToArrayBuffer::New(alloc(), obj);
    928  add(ins);
    929 
    930  setOperand(objId, ins);
    931  return true;
    932 }
    933 
    934 bool WarpCacheIRTranspiler::emitGuardToSharedArrayBuffer(ObjOperandId objId) {
    935  MDefinition* obj = getOperand(objId);
    936 
    937  auto* ins = MGuardToSharedArrayBuffer::New(alloc(), obj);
    938  add(ins);
    939 
    940  setOperand(objId, ins);
    941  return true;
    942 }
    943 
    944 bool WarpCacheIRTranspiler::emitGuardIsNotArrayBufferMaybeShared(
    945    ObjOperandId objId) {
    946  MDefinition* obj = getOperand(objId);
    947 
    948  auto* ins = MGuardIsNotArrayBufferMaybeShared::New(alloc(), obj);
    949  add(ins);
    950 
    951  setOperand(objId, ins);
    952  return true;
    953 }
    954 
    955 bool WarpCacheIRTranspiler::emitGuardIsTypedArray(ObjOperandId objId) {
    956  MDefinition* obj = getOperand(objId);
    957 
    958  auto* ins = MGuardIsTypedArray::New(alloc(), obj);
    959  add(ins);
    960 
    961  setOperand(objId, ins);
    962  return true;
    963 }
    964 
    965 bool WarpCacheIRTranspiler::emitGuardIsNonResizableTypedArray(
    966    ObjOperandId objId) {
    967  MDefinition* obj = getOperand(objId);
    968 
    969  auto* ins = MGuardIsNonResizableTypedArray::New(alloc(), obj);
    970  add(ins);
    971 
    972  setOperand(objId, ins);
    973  return true;
    974 }
    975 
    976 bool WarpCacheIRTranspiler::emitGuardIsResizableTypedArray(ObjOperandId objId) {
    977  MDefinition* obj = getOperand(objId);
    978 
    979  auto* ins = MGuardIsResizableTypedArray::New(alloc(), obj);
    980  add(ins);
    981 
    982  setOperand(objId, ins);
    983  return true;
    984 }
    985 
    986 bool WarpCacheIRTranspiler::emitGuardHasProxyHandler(ObjOperandId objId,
    987                                                     uint32_t handlerOffset) {
    988  MDefinition* obj = getOperand(objId);
    989  const void* handler = rawPointerField(handlerOffset);
    990 
    991  auto* ins = MGuardHasProxyHandler::New(alloc(), obj, handler);
    992  add(ins);
    993 
    994  setOperand(objId, ins);
    995  return true;
    996 }
    997 
    998 bool WarpCacheIRTranspiler::emitGuardProto(ObjOperandId objId,
    999                                           uint32_t protoOffset) {
   1000  MDefinition* def = getOperand(objId);
   1001  MDefinition* proto = objectStubField(protoOffset);
   1002 
   1003  auto* ins = MGuardProto::New(alloc(), def, proto);
   1004  add(ins);
   1005 
   1006  setOperand(objId, ins);
   1007  return true;
   1008 }
   1009 
   1010 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsSpecificObject(
   1011    ObjOperandId objId, ObjOperandId expectedId, uint32_t slotOffset) {
   1012  size_t slotIndex = int32StubField(slotOffset);
   1013  MDefinition* obj = getOperand(objId);
   1014  MDefinition* expected = getOperand(expectedId);
   1015 
   1016  auto* slots = MSlots::New(alloc(), obj);
   1017  add(slots);
   1018 
   1019  auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex);
   1020  add(load);
   1021 
   1022  auto* unbox = MUnbox::New(alloc(), load, MIRType::Object, MUnbox::Fallible);
   1023  add(unbox);
   1024 
   1025  auto* guard = MGuardObjectIdentity::New(alloc(), unbox, expected,
   1026                                          /* bailOnEquality = */ false);
   1027  add(guard);
   1028  return true;
   1029 }
   1030 
   1031 bool WarpCacheIRTranspiler::emitLoadDynamicSlot(ValOperandId resultId,
   1032                                                ObjOperandId objId,
   1033                                                uint32_t slotOffset) {
   1034  size_t slotIndex = int32StubField(slotOffset);
   1035  MDefinition* obj = getOperand(objId);
   1036 
   1037  auto* slots = MSlots::New(alloc(), obj);
   1038  add(slots);
   1039 
   1040  auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex);
   1041  add(load);
   1042 
   1043  return defineOperand(resultId, load);
   1044 }
   1045 
   1046 bool WarpCacheIRTranspiler::emitLoadDynamicSlotFromOffsetResult(
   1047    ObjOperandId objId, Int32OperandId offsetId) {
   1048  MDefinition* obj = getOperand(objId);
   1049  MDefinition* offset = getOperand(offsetId);
   1050 
   1051  auto* slots = MSlots::New(alloc(), obj);
   1052  add(slots);
   1053 
   1054  auto* load = MLoadDynamicSlotFromOffset::New(alloc(), slots, offset);
   1055  add(load);
   1056 
   1057  pushResult(load);
   1058  return true;
   1059 }
   1060 
   1061 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsNotObject(
   1062    ObjOperandId objId, uint32_t slotOffset) {
   1063  size_t slotIndex = int32StubField(slotOffset);
   1064  MDefinition* obj = getOperand(objId);
   1065 
   1066  auto* slots = MSlots::New(alloc(), obj);
   1067  add(slots);
   1068 
   1069  auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex);
   1070  add(load);
   1071 
   1072  auto* guard = MGuardIsNotObject::New(alloc(), load);
   1073  add(guard);
   1074  return true;
   1075 }
   1076 
   1077 bool WarpCacheIRTranspiler::emitGuardFixedSlotValue(ObjOperandId objId,
   1078                                                    uint32_t offsetOffset,
   1079                                                    uint32_t valOffset) {
   1080  MDefinition* obj = getOperand(objId);
   1081 
   1082  size_t offset = int32StubField(offsetOffset);
   1083  ValueOrNurseryValueIndex val = valueStubField(valOffset);
   1084 
   1085  uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   1086 
   1087  auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex);
   1088  add(load);
   1089 
   1090  auto* guard = MGuardValue::New(alloc(), load, val);
   1091  add(guard);
   1092  return true;
   1093 }
   1094 
   1095 bool WarpCacheIRTranspiler::emitGuardDynamicSlotValue(ObjOperandId objId,
   1096                                                      uint32_t offsetOffset,
   1097                                                      uint32_t valOffset) {
   1098  MDefinition* obj = getOperand(objId);
   1099 
   1100  size_t offset = int32StubField(offsetOffset);
   1101  ValueOrNurseryValueIndex val = valueStubField(valOffset);
   1102 
   1103  size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset);
   1104 
   1105  auto* slots = MSlots::New(alloc(), obj);
   1106  add(slots);
   1107 
   1108  auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex);
   1109  add(load);
   1110 
   1111  auto* guard = MGuardValue::New(alloc(), load, val);
   1112  add(guard);
   1113  return true;
   1114 }
   1115 
   1116 bool WarpCacheIRTranspiler::emitLoadScriptedProxyHandler(ObjOperandId resultId,
   1117                                                         ObjOperandId objId) {
   1118  MDefinition* obj = getOperand(objId);
   1119 
   1120  auto* load = MLoadScriptedProxyHandler::New(alloc(), obj);
   1121  add(load);
   1122 
   1123  return defineOperand(resultId, load);
   1124 }
   1125 
   1126 bool WarpCacheIRTranspiler::emitIdToStringOrSymbol(ValOperandId resultId,
   1127                                                   ValOperandId idId) {
   1128  MDefinition* id = getOperand(idId);
   1129 
   1130  auto* ins = MIdToStringOrSymbol::New(alloc(), id);
   1131  add(ins);
   1132 
   1133  return defineOperand(resultId, ins);
   1134 }
   1135 
   1136 bool WarpCacheIRTranspiler::emitGuardSpecificAtom(StringOperandId strId,
   1137                                                  uint32_t expectedOffset) {
   1138  MDefinition* str = getOperand(strId);
   1139  JSString* expected = stringStubField(expectedOffset);
   1140 
   1141  auto* ins =
   1142      MGuardSpecificAtom::New(alloc(), str, &expected->asOffThreadAtom());
   1143  add(ins);
   1144 
   1145  setOperand(strId, ins);
   1146  return true;
   1147 }
   1148 
   1149 bool WarpCacheIRTranspiler::emitGuardSpecificSymbol(SymbolOperandId symId,
   1150                                                    uint32_t expectedOffset) {
   1151  MDefinition* symbol = getOperand(symId);
   1152  JS::Symbol* expected = symbolStubField(expectedOffset);
   1153 
   1154  auto* ins = MGuardSpecificSymbol::New(alloc(), symbol, expected);
   1155  add(ins);
   1156 
   1157  setOperand(symId, ins);
   1158  return true;
   1159 }
   1160 
   1161 bool WarpCacheIRTranspiler::emitGuardSpecificInt32(Int32OperandId numId,
   1162                                                   int32_t expected) {
   1163  MDefinition* num = getOperand(numId);
   1164 
   1165  auto* ins = MGuardSpecificInt32::New(alloc(), num, expected);
   1166  add(ins);
   1167 
   1168  setOperand(numId, ins);
   1169  return true;
   1170 }
   1171 
   1172 bool WarpCacheIRTranspiler::emitGuardSpecificValue(ValOperandId valId,
   1173                                                   uint32_t expectedOffset) {
   1174  MDefinition* val = getOperand(valId);
   1175  ValueOrNurseryValueIndex expected = valueStubField(expectedOffset);
   1176 
   1177  auto* ins = MGuardValue::New(alloc(), val, expected);
   1178  add(ins);
   1179 
   1180  setOperand(valId, ins);
   1181  return true;
   1182 }
   1183 
   1184 bool WarpCacheIRTranspiler::emitGuardSpecificObject(ObjOperandId objId,
   1185                                                    uint32_t expectedOffset) {
   1186  MDefinition* obj = getOperand(objId);
   1187  MDefinition* expected = objectStubField(expectedOffset);
   1188 
   1189  auto* ins = MGuardObjectIdentity::New(alloc(), obj, expected,
   1190                                        /* bailOnEquality = */ false);
   1191  add(ins);
   1192 
   1193  setOperand(objId, ins);
   1194  return true;
   1195 }
   1196 
   1197 bool WarpCacheIRTranspiler::emitGuardSpecificFunction(
   1198    ObjOperandId objId, uint32_t expectedOffset, uint32_t nargsAndFlagsOffset) {
   1199  MDefinition* obj = getOperand(objId);
   1200  MDefinition* expected = objectStubField(expectedOffset);
   1201  uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset);
   1202 
   1203  uint16_t nargs = nargsAndFlags >> 16;
   1204  FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
   1205 
   1206  auto* ins = MGuardSpecificFunction::New(alloc(), obj, expected, nargs, flags);
   1207  add(ins);
   1208 
   1209  setOperand(objId, ins);
   1210  return true;
   1211 }
   1212 
   1213 bool WarpCacheIRTranspiler::emitGuardFunctionScript(
   1214    ObjOperandId funId, uint32_t expectedOffset, uint32_t nargsAndFlagsOffset) {
   1215  MDefinition* fun = getOperand(funId);
   1216  BaseScript* expected = baseScriptStubField(expectedOffset);
   1217  uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset);
   1218 
   1219  uint16_t nargs = nargsAndFlags >> 16;
   1220  FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
   1221 
   1222  auto* ins = MGuardFunctionScript::New(alloc(), fun, expected, nargs, flags);
   1223  add(ins);
   1224 
   1225  setOperand(funId, ins);
   1226  return true;
   1227 }
   1228 
   1229 bool WarpCacheIRTranspiler::emitGuardStringToIndex(StringOperandId strId,
   1230                                                   Int32OperandId resultId) {
   1231  MDefinition* str = getOperand(strId);
   1232 
   1233  auto* ins = MGuardStringToIndex::New(alloc(), str);
   1234  add(ins);
   1235 
   1236  return defineOperand(resultId, ins);
   1237 }
   1238 
   1239 bool WarpCacheIRTranspiler::emitGuardStringToInt32(StringOperandId strId,
   1240                                                   Int32OperandId resultId) {
   1241  MDefinition* str = getOperand(strId);
   1242 
   1243  auto* ins = MGuardStringToInt32::New(alloc(), str);
   1244  add(ins);
   1245 
   1246  return defineOperand(resultId, ins);
   1247 }
   1248 
   1249 bool WarpCacheIRTranspiler::emitGuardStringToNumber(StringOperandId strId,
   1250                                                    NumberOperandId resultId) {
   1251  MDefinition* str = getOperand(strId);
   1252 
   1253  auto* ins = MGuardStringToDouble::New(alloc(), str);
   1254  add(ins);
   1255 
   1256  return defineOperand(resultId, ins);
   1257 }
   1258 
   1259 bool WarpCacheIRTranspiler::emitGuardNoDenseElements(ObjOperandId objId) {
   1260  MDefinition* obj = getOperand(objId);
   1261 
   1262  auto* ins = MGuardNoDenseElements::New(alloc(), obj);
   1263  add(ins);
   1264 
   1265  setOperand(objId, ins);
   1266  return true;
   1267 }
   1268 
   1269 bool WarpCacheIRTranspiler::emitGuardFunctionHasJitEntry(ObjOperandId funId) {
   1270  MDefinition* fun = getOperand(funId);
   1271  uint16_t expectedFlags = FunctionFlags::HasJitEntryFlags();
   1272  uint16_t unexpectedFlags = 0;
   1273 
   1274  auto* ins =
   1275      MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags);
   1276  add(ins);
   1277 
   1278  setOperand(funId, ins);
   1279  return true;
   1280 }
   1281 
   1282 bool WarpCacheIRTranspiler::emitGuardFunctionHasNoJitEntry(ObjOperandId funId) {
   1283  MDefinition* fun = getOperand(funId);
   1284  uint16_t expectedFlags = 0;
   1285  uint16_t unexpectedFlags = FunctionFlags::HasJitEntryFlags();
   1286 
   1287  auto* ins =
   1288      MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags);
   1289  add(ins);
   1290 
   1291  setOperand(funId, ins);
   1292  return true;
   1293 }
   1294 
   1295 bool WarpCacheIRTranspiler::emitGuardFunctionIsNonBuiltinCtor(
   1296    ObjOperandId funId) {
   1297  MDefinition* fun = getOperand(funId);
   1298 
   1299  auto* ins = MGuardFunctionIsNonBuiltinCtor::New(alloc(), fun);
   1300  add(ins);
   1301 
   1302  setOperand(funId, ins);
   1303  return true;
   1304 }
   1305 
   1306 bool WarpCacheIRTranspiler::emitGuardFunctionIsConstructor(ObjOperandId funId) {
   1307  MDefinition* fun = getOperand(funId);
   1308  uint16_t expectedFlags = FunctionFlags::CONSTRUCTOR;
   1309  uint16_t unexpectedFlags = 0;
   1310 
   1311  auto* ins =
   1312      MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags);
   1313  add(ins);
   1314 
   1315  setOperand(funId, ins);
   1316  return true;
   1317 }
   1318 
   1319 bool WarpCacheIRTranspiler::emitGuardNotClassConstructor(ObjOperandId funId) {
   1320  MDefinition* fun = getOperand(funId);
   1321 
   1322  auto* ins =
   1323      MGuardFunctionKind::New(alloc(), fun, FunctionFlags::ClassConstructor,
   1324                              /*bailOnEquality=*/true);
   1325  add(ins);
   1326 
   1327  setOperand(funId, ins);
   1328  return true;
   1329 }
   1330 
   1331 bool WarpCacheIRTranspiler::emitGuardArrayIsPacked(ObjOperandId arrayId) {
   1332  MDefinition* array = getOperand(arrayId);
   1333 
   1334  auto* ins = MGuardArrayIsPacked::New(alloc(), array);
   1335  add(ins);
   1336 
   1337  setOperand(arrayId, ins);
   1338  return true;
   1339 }
   1340 
   1341 bool WarpCacheIRTranspiler::emitGuardArgumentsObjectFlags(ObjOperandId objId,
   1342                                                          uint8_t flags) {
   1343  MDefinition* obj = getOperand(objId);
   1344 
   1345  auto* ins = MGuardArgumentsObjectFlags::New(alloc(), obj, flags);
   1346  add(ins);
   1347 
   1348  setOperand(objId, ins);
   1349  return true;
   1350 }
   1351 
   1352 bool WarpCacheIRTranspiler::emitGuardObjectHasSameRealm(ObjOperandId objId) {
   1353  MDefinition* obj = getOperand(objId);
   1354 
   1355  auto* ins = MGuardObjectHasSameRealm::New(alloc(), obj);
   1356  add(ins);
   1357 
   1358  setOperand(objId, ins);
   1359  return true;
   1360 }
   1361 
   1362 bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId,
   1363                                                   ValueType type) {
   1364  switch (type) {
   1365    case ValueType::String:
   1366    case ValueType::Symbol:
   1367    case ValueType::BigInt:
   1368    case ValueType::Int32:
   1369    case ValueType::Boolean:
   1370      return emitGuardTo(inputId, MIRTypeFromValueType(JSValueType(type)));
   1371    case ValueType::Undefined:
   1372      return emitGuardIsUndefined(inputId);
   1373    case ValueType::Null:
   1374      return emitGuardIsNull(inputId);
   1375    case ValueType::Double:
   1376    case ValueType::Magic:
   1377    case ValueType::PrivateGCThing:
   1378    case ValueType::Object:
   1379      break;
   1380  }
   1381 
   1382  MOZ_CRASH("unexpected type");
   1383 }
   1384 
   1385 bool WarpCacheIRTranspiler::emitGuardTo(ValOperandId inputId, MIRType type) {
   1386  MDefinition* def = getOperand(inputId);
   1387  if (def->type() == type) {
   1388    return true;
   1389  }
   1390 
   1391  auto* ins = MUnbox::New(alloc(), def, type, MUnbox::Fallible);
   1392  add(ins);
   1393 
   1394  setOperand(inputId, ins);
   1395  return true;
   1396 }
   1397 
   1398 bool WarpCacheIRTranspiler::emitGuardToObject(ValOperandId inputId) {
   1399  return emitGuardTo(inputId, MIRType::Object);
   1400 }
   1401 
   1402 bool WarpCacheIRTranspiler::emitGuardToString(ValOperandId inputId) {
   1403  return emitGuardTo(inputId, MIRType::String);
   1404 }
   1405 
   1406 bool WarpCacheIRTranspiler::emitGuardToSymbol(ValOperandId inputId) {
   1407  return emitGuardTo(inputId, MIRType::Symbol);
   1408 }
   1409 
   1410 bool WarpCacheIRTranspiler::emitGuardToBigInt(ValOperandId inputId) {
   1411  return emitGuardTo(inputId, MIRType::BigInt);
   1412 }
   1413 
   1414 bool WarpCacheIRTranspiler::emitGuardToBoolean(ValOperandId inputId) {
   1415  return emitGuardTo(inputId, MIRType::Boolean);
   1416 }
   1417 
   1418 bool WarpCacheIRTranspiler::emitGuardToInt32(ValOperandId inputId) {
   1419  return emitGuardTo(inputId, MIRType::Int32);
   1420 }
   1421 
   1422 bool WarpCacheIRTranspiler::emitGuardBooleanToInt32(ValOperandId inputId,
   1423                                                    Int32OperandId resultId) {
   1424  if (!emitGuardTo(inputId, MIRType::Boolean)) {
   1425    return false;
   1426  }
   1427 
   1428  MDefinition* input = getOperand(inputId);
   1429  MOZ_ASSERT(input->type() == MIRType::Boolean);
   1430 
   1431  auto* ins = MBooleanToInt32::New(alloc(), input);
   1432  add(ins);
   1433 
   1434  return defineOperand(resultId, ins);
   1435 }
   1436 
   1437 bool WarpCacheIRTranspiler::emitGuardIsNumber(ValOperandId inputId) {
   1438  MDefinition* def = getOperand(inputId);
   1439 
   1440  // No guard needed when the input is already a number type.
   1441  if (IsNumberType(def->type())) {
   1442    return true;
   1443  }
   1444 
   1445  // MIRType::Double also implies int32 in Ion.
   1446  return emitGuardTo(inputId, MIRType::Double);
   1447 }
   1448 
   1449 bool WarpCacheIRTranspiler::emitGuardIsNullOrUndefined(ValOperandId inputId) {
   1450  MDefinition* input = getOperand(inputId);
   1451  if (input->type() == MIRType::Null || input->type() == MIRType::Undefined) {
   1452    return true;
   1453  }
   1454 
   1455  auto* ins = MGuardNullOrUndefined::New(alloc(), input);
   1456  add(ins);
   1457 
   1458  setOperand(inputId, ins);
   1459  return true;
   1460 }
   1461 
   1462 bool WarpCacheIRTranspiler::emitGuardIsNull(ValOperandId inputId) {
   1463  MDefinition* input = getOperand(inputId);
   1464  if (input->type() == MIRType::Null) {
   1465    return true;
   1466  }
   1467 
   1468  auto* ins = MGuardValue::New(alloc(), input, NullValue());
   1469  add(ins);
   1470  setOperand(inputId, ins);
   1471  return true;
   1472 }
   1473 
   1474 bool WarpCacheIRTranspiler::emitGuardIsUndefined(ValOperandId inputId) {
   1475  MDefinition* input = getOperand(inputId);
   1476  if (input->type() == MIRType::Undefined) {
   1477    return true;
   1478  }
   1479 
   1480  auto* ins = MGuardValue::New(alloc(), input, UndefinedValue());
   1481  add(ins);
   1482  setOperand(inputId, ins);
   1483  return true;
   1484 }
   1485 
   1486 bool WarpCacheIRTranspiler::emitGuardIsExtensible(ObjOperandId objId) {
   1487  MDefinition* obj = getOperand(objId);
   1488 
   1489  auto* ins = MGuardIsExtensible::New(alloc(), obj);
   1490  add(ins);
   1491  setOperand(objId, ins);
   1492  return true;
   1493 }
   1494 
   1495 bool WarpCacheIRTranspiler::emitGuardInt32IsNonNegative(
   1496    Int32OperandId indexId) {
   1497  MDefinition* index = getOperand(indexId);
   1498 
   1499  auto* ins = MGuardInt32IsNonNegative::New(alloc(), index);
   1500  add(ins);
   1501  setOperand(indexId, ins);
   1502  return true;
   1503 }
   1504 
   1505 bool WarpCacheIRTranspiler::emitGuardIntPtrIsNonNegative(
   1506    IntPtrOperandId indexId) {
   1507  MDefinition* index = getOperand(indexId);
   1508 
   1509  auto* ins = MGuardIntPtrIsNonNegative::New(alloc(), index);
   1510  add(ins);
   1511  setOperand(indexId, ins);
   1512  return true;
   1513 }
   1514 
   1515 bool WarpCacheIRTranspiler::emitGuardIndexIsNotDenseElement(
   1516    ObjOperandId objId, Int32OperandId indexId) {
   1517  MDefinition* obj = getOperand(objId);
   1518  MDefinition* index = getOperand(indexId);
   1519 
   1520  auto* ins = MGuardIndexIsNotDenseElement::New(alloc(), obj, index);
   1521  add(ins);
   1522  setOperand(indexId, ins);
   1523  return true;
   1524 }
   1525 
   1526 bool WarpCacheIRTranspiler::emitGuardIndexIsValidUpdateOrAdd(
   1527    ObjOperandId objId, Int32OperandId indexId) {
   1528  MDefinition* obj = getOperand(objId);
   1529  MDefinition* index = getOperand(indexId);
   1530 
   1531  auto* ins = MGuardIndexIsValidUpdateOrAdd::New(alloc(), obj, index);
   1532  add(ins);
   1533  setOperand(indexId, ins);
   1534  return true;
   1535 }
   1536 
   1537 bool WarpCacheIRTranspiler::emitCallAddOrUpdateSparseElementHelper(
   1538    ObjOperandId objId, Int32OperandId idId, ValOperandId rhsId, bool strict) {
   1539  MDefinition* obj = getOperand(objId);
   1540  MDefinition* id = getOperand(idId);
   1541  MDefinition* rhs = getOperand(rhsId);
   1542 
   1543  auto* ins = MCallAddOrUpdateSparseElement::New(alloc(), obj, id, rhs, strict);
   1544  addEffectful(ins);
   1545 
   1546  return resumeAfter(ins);
   1547 }
   1548 
   1549 bool WarpCacheIRTranspiler::emitGuardTagNotEqual(ValueTagOperandId lhsId,
   1550                                                 ValueTagOperandId rhsId) {
   1551  MDefinition* lhs = getOperand(lhsId);
   1552  MDefinition* rhs = getOperand(rhsId);
   1553 
   1554  auto* ins = MGuardTagNotEqual::New(alloc(), lhs, rhs);
   1555  add(ins);
   1556 
   1557  return true;
   1558 }
   1559 
   1560 bool WarpCacheIRTranspiler::emitGuardToInt32Index(ValOperandId inputId,
   1561                                                  Int32OperandId resultId) {
   1562  MDefinition* input = getOperand(inputId);
   1563  auto* ins =
   1564      MToNumberInt32::New(alloc(), input, IntConversionInputKind::NumbersOnly);
   1565 
   1566  // ToPropertyKey(-0) is "0", so we can silently convert -0 to 0 here.
   1567  ins->setNeedsNegativeZeroCheck(false);
   1568  add(ins);
   1569 
   1570  return defineOperand(resultId, ins);
   1571 }
   1572 
   1573 bool WarpCacheIRTranspiler::emitTruncateDoubleToUInt32(
   1574    NumberOperandId inputId, Int32OperandId resultId) {
   1575  MDefinition* input = getOperand(inputId);
   1576  auto* ins = MTruncateToInt32::New(alloc(), input);
   1577  add(ins);
   1578 
   1579  return defineOperand(resultId, ins);
   1580 }
   1581 
   1582 bool WarpCacheIRTranspiler::emitDoubleToUint8Clamped(NumberOperandId inputId,
   1583                                                     Int32OperandId resultId) {
   1584  MDefinition* input = getOperand(inputId);
   1585  auto* ins = MClampToUint8::New(alloc(), input);
   1586  add(ins);
   1587 
   1588  return defineOperand(resultId, ins);
   1589 }
   1590 
   1591 bool WarpCacheIRTranspiler::emitGuardToInt32ModUint32(ValOperandId valId,
   1592                                                      Int32OperandId resultId) {
   1593  MDefinition* input = getOperand(valId);
   1594  auto* ins = MTruncateToInt32::New(alloc(), input);
   1595  add(ins);
   1596 
   1597  return defineOperand(resultId, ins);
   1598 }
   1599 
   1600 bool WarpCacheIRTranspiler::emitGuardToUint8Clamped(ValOperandId valId,
   1601                                                    Int32OperandId resultId) {
   1602  MDefinition* input = getOperand(valId);
   1603  auto* ins = MClampToUint8::New(alloc(), input);
   1604  add(ins);
   1605 
   1606  return defineOperand(resultId, ins);
   1607 }
   1608 
   1609 bool WarpCacheIRTranspiler::emitToString(OperandId inputId,
   1610                                         StringOperandId resultId) {
   1611  MDefinition* input = getOperand(inputId);
   1612  auto* ins =
   1613      MToString::New(alloc(), input, MToString::SideEffectHandling::Bailout);
   1614  add(ins);
   1615 
   1616  return defineOperand(resultId, ins);
   1617 }
   1618 
   1619 bool WarpCacheIRTranspiler::emitInt32ToIntPtr(Int32OperandId inputId,
   1620                                              IntPtrOperandId resultId) {
   1621  MDefinition* input = getOperand(inputId);
   1622  auto* ins = MInt32ToIntPtr::New(alloc(), input);
   1623  add(ins);
   1624  return defineOperand(resultId, ins);
   1625 }
   1626 
   1627 bool WarpCacheIRTranspiler::emitGuardNumberToIntPtrIndex(
   1628    NumberOperandId inputId, bool supportOOB, IntPtrOperandId resultId) {
   1629  MDefinition* input = getOperand(inputId);
   1630  auto* ins = MGuardNumberToIntPtrIndex::New(alloc(), input, supportOOB);
   1631  add(ins);
   1632  return defineOperand(resultId, ins);
   1633 }
   1634 
   1635 bool WarpCacheIRTranspiler::emitCallInt32ToString(Int32OperandId inputId,
   1636                                                  StringOperandId resultId) {
   1637  return emitToString(inputId, resultId);
   1638 }
   1639 
   1640 bool WarpCacheIRTranspiler::emitCallNumberToString(NumberOperandId inputId,
   1641                                                   StringOperandId resultId) {
   1642  return emitToString(inputId, resultId);
   1643 }
   1644 
   1645 bool WarpCacheIRTranspiler::emitInt32ToStringWithBaseResult(
   1646    Int32OperandId inputId, Int32OperandId baseId) {
   1647  MDefinition* input = getOperand(inputId);
   1648  MDefinition* base = getOperand(baseId);
   1649 
   1650  auto* guardedBase = MGuardInt32Range::New(alloc(), base, 2, 36);
   1651  add(guardedBase);
   1652 
   1653  // Use lower-case characters by default.
   1654  constexpr bool lower = true;
   1655 
   1656  auto* ins = MInt32ToStringWithBase::New(alloc(), input, guardedBase, lower);
   1657  add(ins);
   1658 
   1659  pushResult(ins);
   1660  return true;
   1661 }
   1662 
   1663 bool WarpCacheIRTranspiler::emitBooleanToString(BooleanOperandId inputId,
   1664                                                StringOperandId resultId) {
   1665  return emitToString(inputId, resultId);
   1666 }
   1667 
   1668 bool WarpCacheIRTranspiler::emitBooleanToNumber(BooleanOperandId inputId,
   1669                                                NumberOperandId resultId) {
   1670  MDefinition* input = getOperand(inputId);
   1671 
   1672  auto* ins = MToDouble::New(alloc(), input);
   1673  add(ins);
   1674 
   1675  return defineOperand(resultId, ins);
   1676 }
   1677 
   1678 bool WarpCacheIRTranspiler::emitStringToAtom(StringOperandId strId) {
   1679  MDefinition* str = getOperand(strId);
   1680 
   1681  auto* ins = MToHashableString::New(alloc(), str);
   1682  add(ins);
   1683 
   1684  setOperand(strId, ins);
   1685  return true;
   1686 }
   1687 
   1688 bool WarpCacheIRTranspiler::emitLoadInt32Result(Int32OperandId valId) {
   1689  MDefinition* val = getOperand(valId);
   1690  MOZ_ASSERT(val->type() == MIRType::Int32);
   1691  pushResult(val);
   1692  return true;
   1693 }
   1694 
   1695 bool WarpCacheIRTranspiler::emitLoadDoubleResult(NumberOperandId valId) {
   1696  MDefinition* val = getOperand(valId);
   1697  MOZ_ASSERT(IsNumberType(val->type()));
   1698 
   1699  if (val->type() != MIRType::Double) {
   1700    auto* ins = MToDouble::New(alloc(), val);
   1701    add(ins);
   1702 
   1703    val = ins;
   1704  }
   1705 
   1706  pushResult(val);
   1707  return true;
   1708 }
   1709 
   1710 bool WarpCacheIRTranspiler::emitLoadBigIntResult(BigIntOperandId valId) {
   1711  MDefinition* val = getOperand(valId);
   1712  MOZ_ASSERT(val->type() == MIRType::BigInt);
   1713  pushResult(val);
   1714  return true;
   1715 }
   1716 
   1717 bool WarpCacheIRTranspiler::emitLoadObjectResult(ObjOperandId objId) {
   1718  MDefinition* obj = getOperand(objId);
   1719  MOZ_ASSERT(obj->type() == MIRType::Object);
   1720  pushResult(obj);
   1721  return true;
   1722 }
   1723 
   1724 bool WarpCacheIRTranspiler::emitLoadStringResult(StringOperandId strId) {
   1725  MDefinition* str = getOperand(strId);
   1726  MOZ_ASSERT(str->type() == MIRType::String);
   1727  pushResult(str);
   1728  return true;
   1729 }
   1730 
   1731 bool WarpCacheIRTranspiler::emitLoadSymbolResult(SymbolOperandId symId) {
   1732  MDefinition* sym = getOperand(symId);
   1733  MOZ_ASSERT(sym->type() == MIRType::Symbol);
   1734  pushResult(sym);
   1735  return true;
   1736 }
   1737 
   1738 bool WarpCacheIRTranspiler::emitLoadUndefinedResult() {
   1739  pushResult(constant(UndefinedValue()));
   1740  return true;
   1741 }
   1742 
   1743 bool WarpCacheIRTranspiler::emitLoadBooleanResult(bool val) {
   1744  pushResult(constant(BooleanValue(val)));
   1745  return true;
   1746 }
   1747 
   1748 bool WarpCacheIRTranspiler::emitLoadValueResult(uint32_t valOffset) {
   1749  // This op is currently not used for nursery-allocated values.
   1750  ValueOrNurseryValueIndex val = valueStubField(valOffset);
   1751  MOZ_RELEASE_ASSERT(val.isValue(), "Unexpected nursery Value");
   1752  pushResult(constant(val.toValue()));
   1753  return true;
   1754 }
   1755 
   1756 bool WarpCacheIRTranspiler::emitUncheckedLoadWeakValueResult(
   1757    uint32_t valOffset) {
   1758  // This op is currently not used for nursery-allocated values.
   1759  ValueOrNurseryValueIndex val = valueStubField(valOffset);
   1760  MOZ_RELEASE_ASSERT(val.isValue(), "Unexpected nursery Value");
   1761  pushResult(constant(val.toValue()));
   1762  return true;
   1763 }
   1764 
   1765 bool WarpCacheIRTranspiler::emitUncheckedLoadWeakObjectResult(
   1766    uint32_t objOffset) {
   1767  MInstruction* ins = objectStubField(objOffset);
   1768  pushResult(ins);
   1769  return true;
   1770 }
   1771 
   1772 bool WarpCacheIRTranspiler::emitCheckWeakValueResultForFixedSlot(
   1773    ObjOperandId objId, uint32_t offsetOffset, uint32_t valOffset) {
   1774  // This is a no-op because we use strong references for weak BaselineIC stub
   1775  // fields in Warp.
   1776  return true;
   1777 }
   1778 
   1779 bool WarpCacheIRTranspiler::emitCheckWeakValueResultForDynamicSlot(
   1780    ObjOperandId objId, uint32_t offsetOffset, uint32_t valOffset) {
   1781  // This is a no-op because we use strong references for weak BaselineIC stub
   1782  // fields in Warp.
   1783  return true;
   1784 }
   1785 
   1786 bool WarpCacheIRTranspiler::emitLoadInt32Constant(uint32_t valOffset,
   1787                                                  Int32OperandId resultId) {
   1788  int32_t val = int32StubField(valOffset);
   1789  auto* valConst = constant(Int32Value(val));
   1790  return defineOperand(resultId, valConst);
   1791 }
   1792 
   1793 bool WarpCacheIRTranspiler::emitLoadInt32AsIntPtrConstant(
   1794    uint32_t valOffset, IntPtrOperandId resultId) {
   1795  int32_t val = int32StubField(valOffset);
   1796  auto* valConst = MConstant::NewIntPtr(alloc(), intptr_t(val));
   1797  add(valConst);
   1798  return defineOperand(resultId, valConst);
   1799 }
   1800 
   1801 bool WarpCacheIRTranspiler::emitLoadDoubleConstant(uint32_t valOffset,
   1802                                                   NumberOperandId resultId) {
   1803  double val = doubleStubField(valOffset);
   1804  auto* valConst = constant(DoubleValue(val));
   1805  return defineOperand(resultId, valConst);
   1806 }
   1807 
   1808 bool WarpCacheIRTranspiler::emitLoadBooleanConstant(bool val,
   1809                                                    BooleanOperandId resultId) {
   1810  auto* valConst = constant(BooleanValue(val));
   1811  return defineOperand(resultId, valConst);
   1812 }
   1813 
   1814 bool WarpCacheIRTranspiler::emitLoadUndefined(ValOperandId resultId) {
   1815  auto* valConst = constant(UndefinedValue());
   1816  return defineOperand(resultId, valConst);
   1817 }
   1818 
   1819 bool WarpCacheIRTranspiler::emitLoadConstantString(uint32_t strOffset,
   1820                                                   StringOperandId resultId) {
   1821  JSString* val = stringStubField(strOffset);
   1822  auto* valConst = constant(StringValue(val));
   1823  return defineOperand(resultId, valConst);
   1824 }
   1825 
   1826 bool WarpCacheIRTranspiler::emitLoadConstantStringResult(uint32_t strOffset) {
   1827  JSString* val = stringStubField(strOffset);
   1828  auto* valConst = constant(StringValue(val));
   1829  pushResult(valConst);
   1830  return true;
   1831 }
   1832 
   1833 bool WarpCacheIRTranspiler::emitLoadTypeOfObjectResult(ObjOperandId objId) {
   1834  MDefinition* obj = getOperand(objId);
   1835  auto* typeOf = MTypeOf::New(alloc(), obj);
   1836  add(typeOf);
   1837 
   1838  auto* ins = MTypeOfName::New(alloc(), typeOf);
   1839  add(ins);
   1840  pushResult(ins);
   1841  return true;
   1842 }
   1843 
   1844 bool WarpCacheIRTranspiler::emitLoadTypeOfEqObjectResult(
   1845    ObjOperandId objId, TypeofEqOperand operand) {
   1846  MDefinition* obj = getOperand(objId);
   1847  auto* typeOf = MTypeOf::New(alloc(), obj);
   1848  add(typeOf);
   1849 
   1850  auto* typeInt = MConstant::NewInt32(alloc(), operand.type());
   1851  add(typeInt);
   1852 
   1853  auto* ins = MCompare::New(alloc(), typeOf, typeInt, operand.compareOp(),
   1854                            MCompare::Compare_Int32);
   1855  add(ins);
   1856  pushResult(ins);
   1857  return true;
   1858 }
   1859 
   1860 bool WarpCacheIRTranspiler::emitLoadEnclosingEnvironment(
   1861    ObjOperandId objId, ObjOperandId resultId) {
   1862  MDefinition* env = getOperand(objId);
   1863  auto* ins = MEnclosingEnvironment::New(alloc(), env);
   1864  add(ins);
   1865 
   1866  return defineOperand(resultId, ins);
   1867 }
   1868 
   1869 bool WarpCacheIRTranspiler::emitLoadObject(ObjOperandId resultId,
   1870                                           uint32_t objOffset) {
   1871  MInstruction* ins = objectStubField(objOffset);
   1872 
   1873  return defineOperand(resultId, ins);
   1874 }
   1875 
   1876 bool WarpCacheIRTranspiler::emitLoadProtoObject(ObjOperandId resultId,
   1877                                                uint32_t objOffset,
   1878                                                ObjOperandId receiverObjId) {
   1879  MInstruction* ins = objectStubField(objOffset);
   1880  if (ins->isConstant()) {
   1881    MDefinition* receiverObj = getOperand(receiverObjId);
   1882 
   1883    ins = MConstantProto::New(alloc(), ins, receiverObj->skipObjectGuards());
   1884    add(ins);
   1885  }
   1886  return defineOperand(resultId, ins);
   1887 }
   1888 
   1889 bool WarpCacheIRTranspiler::emitLoadProto(ObjOperandId objId,
   1890                                          ObjOperandId resultId) {
   1891  MDefinition* obj = getOperand(objId);
   1892 
   1893  auto* ins = MObjectStaticProto::New(alloc(), obj);
   1894  add(ins);
   1895 
   1896  return defineOperand(resultId, ins);
   1897 }
   1898 
   1899 bool WarpCacheIRTranspiler::emitLoadInstanceOfObjectResult(
   1900    ValOperandId lhsId, ObjOperandId protoId) {
   1901  MDefinition* lhs = getOperand(lhsId);
   1902  MDefinition* proto = getOperand(protoId);
   1903 
   1904  auto* instanceOf = MInstanceOf::New(alloc(), lhs, proto);
   1905  addEffectful(instanceOf);
   1906 
   1907  pushResult(instanceOf);
   1908  return resumeAfter(instanceOf);
   1909 }
   1910 
   1911 bool WarpCacheIRTranspiler::emitLoadValueTag(ValOperandId valId,
   1912                                             ValueTagOperandId resultId) {
   1913  MDefinition* val = getOperand(valId);
   1914 
   1915  auto* ins = MLoadValueTag::New(alloc(), val);
   1916  add(ins);
   1917 
   1918  return defineOperand(resultId, ins);
   1919 }
   1920 
   1921 bool WarpCacheIRTranspiler::emitLoadDynamicSlotResult(ObjOperandId objId,
   1922                                                      uint32_t offsetOffset) {
   1923  int32_t offset = int32StubField(offsetOffset);
   1924 
   1925  MDefinition* obj = getOperand(objId);
   1926  size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset);
   1927 
   1928  auto* slots = MSlots::New(alloc(), obj);
   1929  add(slots);
   1930 
   1931  auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex);
   1932  add(load);
   1933 
   1934  pushResult(load);
   1935  return true;
   1936 }
   1937 
   1938 bool WarpCacheIRTranspiler::emitLoadFixedSlot(ValOperandId resultId,
   1939                                              ObjOperandId objId,
   1940                                              uint32_t offsetOffset) {
   1941  MDefinition* obj = getOperand(objId);
   1942 
   1943  size_t offset = int32StubField(offsetOffset);
   1944  uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   1945 
   1946  auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex);
   1947  add(load);
   1948 
   1949  return defineOperand(resultId, load);
   1950 }
   1951 
   1952 bool WarpCacheIRTranspiler::emitLoadFixedSlotFromOffsetResult(
   1953    ObjOperandId objId, Int32OperandId offsetId) {
   1954  MDefinition* obj = getOperand(objId);
   1955  MDefinition* offset = getOperand(offsetId);
   1956 
   1957  auto* ins = MLoadFixedSlotFromOffset::New(alloc(), obj, offset);
   1958  add(ins);
   1959 
   1960  pushResult(ins);
   1961  return true;
   1962 }
   1963 
   1964 bool WarpCacheIRTranspiler::emitStoreFixedSlotFromOffset(
   1965    ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) {
   1966  MDefinition* obj = getOperand(objId);
   1967  MDefinition* offset = getOperand(offsetId);
   1968  MDefinition* rhs = getOperand(rhsId);
   1969 
   1970  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   1971  add(barrier);
   1972 
   1973  auto* store =
   1974      MStoreFixedSlotFromOffset::NewBarriered(alloc(), obj, offset, rhs);
   1975  addEffectful(store);
   1976 
   1977  return resumeAfter(store);
   1978 }
   1979 
   1980 bool WarpCacheIRTranspiler::emitStoreDynamicSlotFromOffset(
   1981    ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) {
   1982  MDefinition* obj = getOperand(objId);
   1983  MDefinition* offset = getOperand(offsetId);
   1984  MDefinition* rhs = getOperand(rhsId);
   1985 
   1986  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   1987  add(barrier);
   1988 
   1989  auto* slots = MSlots::New(alloc(), obj);
   1990  add(slots);
   1991 
   1992  auto* store = MStoreDynamicSlotFromOffset::New(alloc(), slots, offset, rhs);
   1993  addEffectful(store);
   1994 
   1995  return resumeAfter(store);
   1996 }
   1997 
   1998 bool WarpCacheIRTranspiler::emitLoadFixedSlotResult(ObjOperandId objId,
   1999                                                    uint32_t offsetOffset) {
   2000  int32_t offset = int32StubField(offsetOffset);
   2001 
   2002  MDefinition* obj = getOperand(objId);
   2003  uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   2004 
   2005  auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex);
   2006  add(load);
   2007 
   2008  pushResult(load);
   2009  return true;
   2010 }
   2011 
   2012 bool WarpCacheIRTranspiler::emitLoadFixedSlotTypedResult(ObjOperandId objId,
   2013                                                         uint32_t offsetOffset,
   2014                                                         ValueType type) {
   2015  int32_t offset = int32StubField(offsetOffset);
   2016 
   2017  MDefinition* obj = getOperand(objId);
   2018  uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   2019 
   2020  auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex);
   2021  load->setResultType(MIRTypeFromValueType(JSValueType(type)));
   2022  add(load);
   2023 
   2024  pushResult(load);
   2025  return true;
   2026 }
   2027 
   2028 bool WarpCacheIRTranspiler::emitGuardIsNotUninitializedLexical(
   2029    ValOperandId valId) {
   2030  MDefinition* val = getOperand(valId);
   2031 
   2032  auto* lexicalCheck = MLexicalCheck::New(alloc(), val);
   2033  add(lexicalCheck);
   2034 
   2035  if (snapshot().bailoutInfo().failedLexicalCheck()) {
   2036    lexicalCheck->setNotMovable();
   2037  }
   2038 
   2039  setOperand(valId, lexicalCheck);
   2040  return true;
   2041 }
   2042 
   2043 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLengthResult(ObjOperandId objId) {
   2044  MDefinition* obj = getOperand(objId);
   2045 
   2046  auto* elements = MElements::New(alloc(), obj);
   2047  add(elements);
   2048 
   2049  auto* length = MArrayLength::New(alloc(), elements);
   2050  add(length);
   2051 
   2052  pushResult(length);
   2053  return true;
   2054 }
   2055 
   2056 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLength(ObjOperandId objId,
   2057                                                     Int32OperandId resultId) {
   2058  MDefinition* obj = getOperand(objId);
   2059 
   2060  auto* elements = MElements::New(alloc(), obj);
   2061  add(elements);
   2062 
   2063  auto* length = MArrayLength::New(alloc(), elements);
   2064  add(length);
   2065 
   2066  return defineOperand(resultId, length);
   2067 }
   2068 
   2069 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgResult(
   2070    ObjOperandId objId, Int32OperandId indexId) {
   2071  MDefinition* obj = getOperand(objId);
   2072  MDefinition* index = getOperand(indexId);
   2073 
   2074  auto* load = MLoadArgumentsObjectArg::New(alloc(), obj, index);
   2075  add(load);
   2076 
   2077  pushResult(load);
   2078  return true;
   2079 }
   2080 
   2081 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgHoleResult(
   2082    ObjOperandId objId, Int32OperandId indexId) {
   2083  MDefinition* obj = getOperand(objId);
   2084  MDefinition* index = getOperand(indexId);
   2085 
   2086  auto* load = MLoadArgumentsObjectArgHole::New(alloc(), obj, index);
   2087  add(load);
   2088 
   2089  pushResult(load);
   2090  return true;
   2091 }
   2092 
   2093 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgExistsResult(
   2094    ObjOperandId objId, Int32OperandId indexId) {
   2095  MDefinition* obj = getOperand(objId);
   2096  MDefinition* index = getOperand(indexId);
   2097 
   2098  auto* ins = MInArgumentsObjectArg::New(alloc(), obj, index);
   2099  add(ins);
   2100 
   2101  pushResult(ins);
   2102  return true;
   2103 }
   2104 
   2105 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLengthResult(
   2106    ObjOperandId objId) {
   2107  MDefinition* obj = getOperand(objId);
   2108 
   2109  auto* length = MArgumentsObjectLength::New(alloc(), obj);
   2110  add(length);
   2111 
   2112  pushResult(length);
   2113  return true;
   2114 }
   2115 
   2116 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLength(
   2117    ObjOperandId objId, Int32OperandId resultId) {
   2118  MDefinition* obj = getOperand(objId);
   2119 
   2120  auto* length = MArgumentsObjectLength::New(alloc(), obj);
   2121  add(length);
   2122 
   2123  return defineOperand(resultId, length);
   2124 }
   2125 
   2126 bool WarpCacheIRTranspiler::emitLoadBoundFunctionNumArgs(
   2127    ObjOperandId objId, Int32OperandId resultId) {
   2128  MDefinition* obj = getOperand(objId);
   2129 
   2130  auto* numArgs = MBoundFunctionNumArgs::New(alloc(), obj);
   2131  add(numArgs);
   2132 
   2133  return defineOperand(resultId, numArgs);
   2134 }
   2135 
   2136 bool WarpCacheIRTranspiler::emitLoadBoundFunctionTarget(ObjOperandId objId,
   2137                                                        ObjOperandId resultId) {
   2138  MDefinition* obj = getOperand(objId);
   2139 
   2140  auto* target = MLoadFixedSlotAndUnbox::New(
   2141      alloc(), obj, BoundFunctionObject::targetSlot(), MUnbox::Mode::Infallible,
   2142      MIRType::Object);
   2143  add(target);
   2144 
   2145  return defineOperand(resultId, target);
   2146 }
   2147 
   2148 bool WarpCacheIRTranspiler::emitLoadBoundFunctionArgument(
   2149    ObjOperandId objId, uint32_t index, ValOperandId resultId) {
   2150  MDefinition* obj = getOperand(objId);
   2151 
   2152  auto* boundArgs = MLoadFixedSlotAndUnbox::New(
   2153      alloc(), obj, BoundFunctionObject::firstInlineBoundArgSlot(),
   2154      MUnbox::Mode::Infallible, MIRType::Object);
   2155  add(boundArgs);
   2156 
   2157  auto* elements = MElements::New(alloc(), boundArgs);
   2158  add(elements);
   2159 
   2160  auto argIndex = constant(Int32Value(index));
   2161  auto* load = MLoadElement::New(alloc(), elements, argIndex,
   2162                                 /* needsHoleCheck */ false);
   2163  add(load);
   2164 
   2165  return defineOperand(resultId, load);
   2166 }
   2167 
   2168 bool WarpCacheIRTranspiler::emitGuardBoundFunctionIsConstructor(
   2169    ObjOperandId objId) {
   2170  MDefinition* obj = getOperand(objId);
   2171 
   2172  auto* guard = MGuardBoundFunctionIsConstructor::New(alloc(), obj);
   2173  add(guard);
   2174 
   2175  setOperand(objId, guard);
   2176  return true;
   2177 }
   2178 
   2179 bool WarpCacheIRTranspiler::emitGuardObjectIdentity(ObjOperandId obj1Id,
   2180                                                    ObjOperandId obj2Id) {
   2181  MDefinition* obj1 = getOperand(obj1Id);
   2182  MDefinition* obj2 = getOperand(obj2Id);
   2183 
   2184  auto* guard = MGuardObjectIdentity::New(alloc(), obj1, obj2,
   2185                                          /* bailOnEquality = */ false);
   2186  add(guard);
   2187  return true;
   2188 }
   2189 
   2190 bool WarpCacheIRTranspiler::emitArrayFromArgumentsObjectResult(
   2191    ObjOperandId objId, uint32_t shapeOffset) {
   2192  MDefinition* obj = getOperand(objId);
   2193  Shape* shape = shapeStubField(shapeOffset);
   2194  MOZ_ASSERT(shape);
   2195 
   2196  auto* array = MArrayFromArgumentsObject::New(alloc(), obj, shape);
   2197  addEffectful(array);
   2198 
   2199  pushResult(array);
   2200  return resumeAfter(array);
   2201 }
   2202 
   2203 bool WarpCacheIRTranspiler::emitLoadFunctionLengthResult(ObjOperandId objId) {
   2204  MDefinition* obj = getOperand(objId);
   2205 
   2206  auto* length = MFunctionLength::New(alloc(), obj);
   2207  add(length);
   2208 
   2209  pushResult(length);
   2210  return true;
   2211 }
   2212 
   2213 bool WarpCacheIRTranspiler::emitLoadFunctionNameResult(ObjOperandId objId) {
   2214  MDefinition* obj = getOperand(objId);
   2215 
   2216  auto* name = MFunctionName::New(alloc(), obj);
   2217  add(name);
   2218 
   2219  pushResult(name);
   2220  return true;
   2221 }
   2222 
   2223 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthInt32Result(
   2224    ObjOperandId objId) {
   2225  MDefinition* obj = getOperand(objId);
   2226 
   2227  auto* length = MArrayBufferByteLength::New(alloc(), obj);
   2228  add(length);
   2229 
   2230  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   2231  add(lengthInt32);
   2232 
   2233  pushResult(lengthInt32);
   2234  return true;
   2235 }
   2236 
   2237 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthDoubleResult(
   2238    ObjOperandId objId) {
   2239  MDefinition* obj = getOperand(objId);
   2240 
   2241  auto* length = MArrayBufferByteLength::New(alloc(), obj);
   2242  add(length);
   2243 
   2244  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   2245  add(lengthDouble);
   2246 
   2247  pushResult(lengthDouble);
   2248  return true;
   2249 }
   2250 
   2251 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthInt32Result(
   2252    ObjOperandId objId) {
   2253  MDefinition* obj = getOperand(objId);
   2254 
   2255  // Use a separate instruction for converting the length to Int32, so that we
   2256  // can fold the MArrayBufferViewLength instruction with length instructions
   2257  // added for bounds checks.
   2258 
   2259  auto* length = MArrayBufferViewLength::New(alloc(), obj);
   2260  add(length);
   2261 
   2262  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   2263  add(lengthInt32);
   2264 
   2265  pushResult(lengthInt32);
   2266  return true;
   2267 }
   2268 
   2269 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthDoubleResult(
   2270    ObjOperandId objId) {
   2271  MDefinition* obj = getOperand(objId);
   2272 
   2273  auto* length = MArrayBufferViewLength::New(alloc(), obj);
   2274  add(length);
   2275 
   2276  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   2277  add(lengthDouble);
   2278 
   2279  pushResult(lengthDouble);
   2280  return true;
   2281 }
   2282 
   2283 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLength(
   2284    ObjOperandId objId, IntPtrOperandId resultId) {
   2285  MDefinition* obj = getOperand(objId);
   2286 
   2287  auto* length = MArrayBufferViewLength::New(alloc(), obj);
   2288  add(length);
   2289 
   2290  return defineOperand(resultId, length);
   2291 }
   2292 
   2293 bool WarpCacheIRTranspiler::emitLoadStringLengthResult(StringOperandId strId) {
   2294  MDefinition* str = getOperand(strId);
   2295 
   2296  auto* length = MStringLength::New(alloc(), str);
   2297  add(length);
   2298 
   2299  pushResult(length);
   2300  return true;
   2301 }
   2302 
   2303 MInstruction* WarpCacheIRTranspiler::addBoundsCheck(MDefinition* index,
   2304                                                    MDefinition* length) {
   2305  MInstruction* check = MBoundsCheck::New(alloc(), index, length);
   2306  add(check);
   2307 
   2308  if (snapshot().bailoutInfo().failedBoundsCheck()) {
   2309    check->setNotMovable();
   2310  }
   2311 
   2312  if (JitOptions.spectreIndexMasking) {
   2313    // Use a separate MIR instruction for the index masking. Doing this as
   2314    // part of MBoundsCheck would be unsound because bounds checks can be
   2315    // optimized or eliminated completely. Consider this:
   2316    //
   2317    //   for (var i = 0; i < x; i++)
   2318    //        res = arr[i];
   2319    //
   2320    // If we can prove |x < arr.length|, we are able to eliminate the bounds
   2321    // check, but we should not get rid of the index masking because the
   2322    // |i < x| branch could still be mispredicted.
   2323    //
   2324    // Using a separate instruction lets us eliminate the bounds check
   2325    // without affecting the index masking.
   2326    check = MSpectreMaskIndex::New(alloc(), check, length);
   2327    add(check);
   2328  }
   2329 
   2330  return check;
   2331 }
   2332 
   2333 bool WarpCacheIRTranspiler::emitLoadDenseElementResult(
   2334    ObjOperandId objId, Int32OperandId indexId, bool expectPackedElements) {
   2335  MDefinition* obj = getOperand(objId);
   2336  MDefinition* index = getOperand(indexId);
   2337 
   2338  auto* elements = MElements::New(alloc(), obj);
   2339  add(elements);
   2340 
   2341  auto* length = MInitializedLength::New(alloc(), elements);
   2342  add(length);
   2343 
   2344  index = addBoundsCheck(index, length);
   2345 
   2346  if (expectPackedElements) {
   2347    auto* guardPacked = MGuardElementsArePacked::New(alloc(), elements);
   2348    add(guardPacked);
   2349  }
   2350 
   2351  bool needsHoleCheck = !expectPackedElements;
   2352  auto* load = MLoadElement::New(alloc(), elements, index, needsHoleCheck);
   2353  add(load);
   2354 
   2355  pushResult(load);
   2356  return true;
   2357 }
   2358 
   2359 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleResult(
   2360    ObjOperandId objId, Int32OperandId indexId) {
   2361  MDefinition* obj = getOperand(objId);
   2362  MDefinition* index = getOperand(indexId);
   2363 
   2364  auto* elements = MElements::New(alloc(), obj);
   2365  add(elements);
   2366 
   2367  auto* length = MInitializedLength::New(alloc(), elements);
   2368  add(length);
   2369 
   2370  auto* load = MLoadElementHole::New(alloc(), elements, index, length);
   2371  add(load);
   2372 
   2373  pushResult(load);
   2374  return true;
   2375 }
   2376 
   2377 bool WarpCacheIRTranspiler::emitCallGetSparseElementResult(
   2378    ObjOperandId objId, Int32OperandId indexId) {
   2379  MDefinition* obj = getOperand(objId);
   2380  MDefinition* index = getOperand(indexId);
   2381 
   2382  auto* call = MCallGetSparseElement::New(alloc(), obj, index);
   2383  addEffectful(call);
   2384 
   2385  pushResult(call);
   2386  return resumeAfter(call);
   2387 }
   2388 
   2389 bool WarpCacheIRTranspiler::emitCallNativeGetElementResult(
   2390    ObjOperandId objId, Int32OperandId indexId) {
   2391  MDefinition* obj = getOperand(objId);
   2392  MDefinition* index = getOperand(indexId);
   2393 
   2394  auto* call = MCallNativeGetElement::New(alloc(), obj, index);
   2395  addEffectful(call);
   2396 
   2397  pushResult(call);
   2398  return resumeAfter(call);
   2399 }
   2400 
   2401 bool WarpCacheIRTranspiler::emitCallNativeGetElementSuperResult(
   2402    ObjOperandId objId, Int32OperandId indexId, ValOperandId receiverId) {
   2403  MDefinition* obj = getOperand(objId);
   2404  MDefinition* index = getOperand(indexId);
   2405  MDefinition* receiver = getOperand(receiverId);
   2406 
   2407  auto* call = MCallNativeGetElementSuper::New(alloc(), obj, index, receiver);
   2408  addEffectful(call);
   2409 
   2410  pushResult(call);
   2411  return resumeAfter(call);
   2412 }
   2413 
   2414 bool WarpCacheIRTranspiler::emitLoadDenseElementExistsResult(
   2415    ObjOperandId objId, Int32OperandId indexId) {
   2416  MDefinition* obj = getOperand(objId);
   2417  MDefinition* index = getOperand(indexId);
   2418 
   2419  // Get the elements vector.
   2420  auto* elements = MElements::New(alloc(), obj);
   2421  add(elements);
   2422 
   2423  auto* length = MInitializedLength::New(alloc(), elements);
   2424  add(length);
   2425 
   2426  // Check if id < initLength.
   2427  index = addBoundsCheck(index, length);
   2428 
   2429  // And check elem[id] is not a hole.
   2430  auto* guard = MGuardElementNotHole::New(alloc(), elements, index);
   2431  add(guard);
   2432 
   2433  pushResult(constant(BooleanValue(true)));
   2434  return true;
   2435 }
   2436 
   2437 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleExistsResult(
   2438    ObjOperandId objId, Int32OperandId indexId) {
   2439  MDefinition* obj = getOperand(objId);
   2440  MDefinition* index = getOperand(indexId);
   2441 
   2442  // Get the elements vector.
   2443  auto* elements = MElements::New(alloc(), obj);
   2444  add(elements);
   2445 
   2446  auto* length = MInitializedLength::New(alloc(), elements);
   2447  add(length);
   2448 
   2449  // Check if id < initLength and elem[id] not a hole.
   2450  auto* ins = MInArray::New(alloc(), elements, index, length);
   2451  add(ins);
   2452 
   2453  pushResult(ins);
   2454  return true;
   2455 }
   2456 
   2457 bool WarpCacheIRTranspiler::emitCallObjectHasSparseElementResult(
   2458    ObjOperandId objId, Int32OperandId indexId) {
   2459  MDefinition* obj = getOperand(objId);
   2460  MDefinition* index = getOperand(indexId);
   2461 
   2462  auto* ins = MCallObjectHasSparseElement::New(alloc(), obj, index);
   2463  add(ins);
   2464 
   2465  pushResult(ins);
   2466  return true;
   2467 }
   2468 
   2469 MInstruction* WarpCacheIRTranspiler::emitTypedArrayLength(
   2470    ArrayBufferViewKind viewKind, MDefinition* obj) {
   2471  if (viewKind == ArrayBufferViewKind::FixedLength ||
   2472      viewKind == ArrayBufferViewKind::Immutable) {
   2473    auto* length = MArrayBufferViewLength::New(alloc(), obj);
   2474    add(length);
   2475 
   2476    return length;
   2477  }
   2478 
   2479  // Bounds check doesn't require a memory barrier. See IsValidIntegerIndex
   2480  // abstract operation which reads the underlying buffer byte length using
   2481  // "unordered" memory order.
   2482  auto barrier = MemoryBarrierRequirement::NotRequired;
   2483 
   2484  // Movable and removable because no memory barrier is needed.
   2485  auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier);
   2486  length->setMovable();
   2487  length->setNotGuard();
   2488  add(length);
   2489 
   2490  return length;
   2491 }
   2492 
   2493 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementExistsResult(
   2494    ObjOperandId objId, IntPtrOperandId indexId, ArrayBufferViewKind viewKind) {
   2495  MDefinition* obj = getOperand(objId);
   2496  MDefinition* index = getOperand(indexId);
   2497 
   2498  auto* length = emitTypedArrayLength(viewKind, obj);
   2499 
   2500  // Unsigned comparison to catch negative indices.
   2501  auto* ins = MCompare::New(alloc(), index, length, JSOp::Lt,
   2502                            MCompare::Compare_UIntPtr);
   2503  add(ins);
   2504 
   2505  pushResult(ins);
   2506  return true;
   2507 }
   2508 
   2509 static MIRType MIRTypeForArrayBufferViewRead(Scalar::Type arrayType,
   2510                                             bool forceDoubleForUint32) {
   2511  switch (arrayType) {
   2512    case Scalar::Int8:
   2513    case Scalar::Uint8:
   2514    case Scalar::Uint8Clamped:
   2515    case Scalar::Int16:
   2516    case Scalar::Uint16:
   2517    case Scalar::Int32:
   2518      return MIRType::Int32;
   2519    case Scalar::Uint32:
   2520      return forceDoubleForUint32 ? MIRType::Double : MIRType::Int32;
   2521    case Scalar::Float16:
   2522    case Scalar::Float32:
   2523      return MIRType::Float32;
   2524    case Scalar::Float64:
   2525      return MIRType::Double;
   2526    case Scalar::BigInt64:
   2527    case Scalar::BigUint64:
   2528      return MIRType::Int64;
   2529    default:
   2530      break;
   2531  }
   2532  MOZ_CRASH("Unknown typed array type");
   2533 }
   2534 
   2535 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementResult(
   2536    ObjOperandId objId, IntPtrOperandId indexId, Scalar::Type elementType,
   2537    bool handleOOB, bool forceDoubleForUint32, ArrayBufferViewKind viewKind) {
   2538  MDefinition* obj = getOperand(objId);
   2539  MDefinition* index = getOperand(indexId);
   2540 
   2541  auto* length = emitTypedArrayLength(viewKind, obj);
   2542 
   2543  if (!handleOOB) {
   2544    // MLoadTypedArrayElementHole does the bounds checking.
   2545    index = addBoundsCheck(index, length);
   2546  }
   2547 
   2548  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   2549  add(elements);
   2550 
   2551  if (handleOOB) {
   2552    auto* load = MLoadTypedArrayElementHole::New(
   2553        alloc(), elements, index, length, elementType, forceDoubleForUint32);
   2554    add(load);
   2555 
   2556    pushResult(load);
   2557    return true;
   2558  }
   2559 
   2560  auto* load = MLoadUnboxedScalar::New(alloc(), elements, index, elementType);
   2561  load->setResultType(
   2562      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32));
   2563  add(load);
   2564 
   2565  MInstruction* result = load;
   2566  if (Scalar::isBigIntType(elementType)) {
   2567    result = MInt64ToBigInt::New(alloc(), load,
   2568                                 Scalar::isSignedIntType(elementType));
   2569    add(result);
   2570  }
   2571 
   2572  pushResult(result);
   2573  return true;
   2574 }
   2575 
   2576 bool WarpCacheIRTranspiler::emitTypedArrayFillResult(ObjOperandId objId,
   2577                                                     uint32_t fillValueId,
   2578                                                     IntPtrOperandId startId,
   2579                                                     IntPtrOperandId endId,
   2580                                                     Scalar::Type elementType) {
   2581  MDefinition* obj = getOperand(objId);
   2582  MDefinition* fillValue = getOperand(ValOperandId(fillValueId));
   2583  MDefinition* start = getOperand(startId);
   2584  MDefinition* end = getOperand(endId);
   2585 
   2586  auto* ins =
   2587      MTypedArrayFill::New(alloc(), obj, fillValue, start, end, elementType);
   2588  addEffectful(ins);
   2589 
   2590  pushResult(obj);
   2591  return resumeAfter(ins);
   2592 }
   2593 
   2594 bool WarpCacheIRTranspiler::emitTypedArraySetResult(ObjOperandId targetId,
   2595                                                    ObjOperandId sourceId,
   2596                                                    IntPtrOperandId offsetId,
   2597                                                    bool canUseBitwiseCopy) {
   2598  MDefinition* target = getOperand(targetId);
   2599  MDefinition* source = getOperand(sourceId);
   2600  MDefinition* offset = getOperand(offsetId);
   2601 
   2602  auto* targetLength = MArrayBufferViewLength::New(alloc(), target);
   2603  add(targetLength);
   2604 
   2605  auto* sourceLength = MArrayBufferViewLength::New(alloc(), source);
   2606  add(sourceLength);
   2607 
   2608  auto* guardedOffset = MGuardTypedArraySetOffset::New(
   2609      alloc(), offset, targetLength, sourceLength);
   2610  add(guardedOffset);
   2611 
   2612  auto* ins = MTypedArraySet::New(alloc(), target, source, guardedOffset,
   2613                                  canUseBitwiseCopy);
   2614  addEffectful(ins);
   2615 
   2616  pushResult(constant(UndefinedValue()));
   2617  return resumeAfter(ins);
   2618 }
   2619 
   2620 bool WarpCacheIRTranspiler::emitTypedArraySubarrayResult(
   2621    uint32_t templateObjectOffset, ObjOperandId objId, IntPtrOperandId startId,
   2622    IntPtrOperandId endId) {
   2623  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2624  MDefinition* obj = getOperand(objId);
   2625  MDefinition* start = getOperand(startId);
   2626  MDefinition* end = getOperand(endId);
   2627 
   2628  auto* srcLength = MArrayBufferViewLength::New(alloc(), obj);
   2629  add(srcLength);
   2630 
   2631  auto* actualStart = MToIntegerIndex::New(alloc(), start, srcLength);
   2632  add(actualStart);
   2633 
   2634  auto* actualEnd = MToIntegerIndex::New(alloc(), end, srcLength);
   2635  add(actualEnd);
   2636 
   2637  auto* minStart =
   2638      MMinMax::NewMin(alloc(), actualStart, actualEnd, MIRType::IntPtr);
   2639  add(minStart);
   2640 
   2641  auto* length = MSub::New(alloc(), actualEnd, minStart, MIRType::IntPtr);
   2642  add(length);
   2643 
   2644  // TODO: support pre-tenuring.
   2645  gc::Heap heap = gc::Heap::Default;
   2646 
   2647  auto* ins = MTypedArraySubarray::New(alloc(), obj, actualStart, length,
   2648                                       templateObj, heap);
   2649  addEffectful(ins);
   2650 
   2651  pushResult(ins);
   2652  return resumeAfter(ins);
   2653 }
   2654 
   2655 bool WarpCacheIRTranspiler::emitLinearizeForCharAccess(
   2656    StringOperandId strId, Int32OperandId indexId, StringOperandId resultId) {
   2657  MDefinition* str = getOperand(strId);
   2658  MDefinition* index = getOperand(indexId);
   2659 
   2660  auto* ins = MLinearizeForCharAccess::New(alloc(), str, index);
   2661  add(ins);
   2662 
   2663  return defineOperand(resultId, ins);
   2664 }
   2665 
   2666 bool WarpCacheIRTranspiler::emitLinearizeForCodePointAccess(
   2667    StringOperandId strId, Int32OperandId indexId, StringOperandId resultId) {
   2668  MDefinition* str = getOperand(strId);
   2669  MDefinition* index = getOperand(indexId);
   2670 
   2671  auto* ins = MLinearizeForCodePointAccess::New(alloc(), str, index);
   2672  add(ins);
   2673 
   2674  return defineOperand(resultId, ins);
   2675 }
   2676 
   2677 bool WarpCacheIRTranspiler::emitToRelativeStringIndex(Int32OperandId indexId,
   2678                                                      StringOperandId strId,
   2679                                                      Int32OperandId resultId) {
   2680  MDefinition* str = getOperand(strId);
   2681  MDefinition* index = getOperand(indexId);
   2682 
   2683  auto* length = MStringLength::New(alloc(), str);
   2684  add(length);
   2685 
   2686  auto* ins = MToRelativeStringIndex::New(alloc(), index, length);
   2687  add(ins);
   2688 
   2689  return defineOperand(resultId, ins);
   2690 }
   2691 
   2692 bool WarpCacheIRTranspiler::emitLoadStringCharResult(StringOperandId strId,
   2693                                                     Int32OperandId indexId,
   2694                                                     bool handleOOB) {
   2695  MDefinition* str = getOperand(strId);
   2696  MDefinition* index = getOperand(indexId);
   2697 
   2698  if (handleOOB) {
   2699    auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index);
   2700    add(charCode);
   2701 
   2702    auto* fromCharCode = MFromCharCodeEmptyIfNegative::New(alloc(), charCode);
   2703    add(fromCharCode);
   2704 
   2705    pushResult(fromCharCode);
   2706    return true;
   2707  }
   2708 
   2709  auto* length = MStringLength::New(alloc(), str);
   2710  add(length);
   2711 
   2712  index = addBoundsCheck(index, length);
   2713 
   2714  auto* charCode = MCharCodeAt::New(alloc(), str, index);
   2715  add(charCode);
   2716 
   2717  auto* fromCharCode = MFromCharCode::New(alloc(), charCode);
   2718  add(fromCharCode);
   2719 
   2720  pushResult(fromCharCode);
   2721  return true;
   2722 }
   2723 
   2724 bool WarpCacheIRTranspiler::emitLoadStringAtResult(StringOperandId strId,
   2725                                                   Int32OperandId indexId,
   2726                                                   bool handleOOB) {
   2727  MDefinition* str = getOperand(strId);
   2728  MDefinition* index = getOperand(indexId);
   2729 
   2730  if (handleOOB) {
   2731    auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index);
   2732    add(charCode);
   2733 
   2734    auto* fromCharCode =
   2735        MFromCharCodeUndefinedIfNegative::New(alloc(), charCode);
   2736    add(fromCharCode);
   2737 
   2738    pushResult(fromCharCode);
   2739    return true;
   2740  }
   2741 
   2742  auto* length = MStringLength::New(alloc(), str);
   2743  add(length);
   2744 
   2745  index = addBoundsCheck(index, length);
   2746 
   2747  auto* charCode = MCharCodeAt::New(alloc(), str, index);
   2748  add(charCode);
   2749 
   2750  auto* fromCharCode = MFromCharCode::New(alloc(), charCode);
   2751  add(fromCharCode);
   2752 
   2753  pushResult(fromCharCode);
   2754  return true;
   2755 }
   2756 
   2757 bool WarpCacheIRTranspiler::emitLoadStringCharCodeResult(StringOperandId strId,
   2758                                                         Int32OperandId indexId,
   2759                                                         bool handleOOB) {
   2760  MDefinition* str = getOperand(strId);
   2761  MDefinition* index = getOperand(indexId);
   2762 
   2763  if (handleOOB) {
   2764    auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index);
   2765    add(charCode);
   2766 
   2767    auto* ins = MNegativeToNaN::New(alloc(), charCode);
   2768    add(ins);
   2769 
   2770    pushResult(ins);
   2771    return true;
   2772  }
   2773 
   2774  auto* length = MStringLength::New(alloc(), str);
   2775  add(length);
   2776 
   2777  index = addBoundsCheck(index, length);
   2778 
   2779  auto* charCode = MCharCodeAt::New(alloc(), str, index);
   2780  add(charCode);
   2781 
   2782  pushResult(charCode);
   2783  return true;
   2784 }
   2785 
   2786 bool WarpCacheIRTranspiler::emitLoadStringCodePointResult(
   2787    StringOperandId strId, Int32OperandId indexId, bool handleOOB) {
   2788  MDefinition* str = getOperand(strId);
   2789  MDefinition* index = getOperand(indexId);
   2790 
   2791  if (handleOOB) {
   2792    auto* codePoint = MCodePointAtOrNegative::New(alloc(), str, index);
   2793    add(codePoint);
   2794 
   2795    auto* ins = MNegativeToUndefined::New(alloc(), codePoint);
   2796    add(ins);
   2797 
   2798    pushResult(ins);
   2799    return true;
   2800  }
   2801 
   2802  auto* length = MStringLength::New(alloc(), str);
   2803  add(length);
   2804 
   2805  index = addBoundsCheck(index, length);
   2806 
   2807  auto* codePoint = MCodePointAt::New(alloc(), str, index);
   2808  add(codePoint);
   2809 
   2810  pushResult(codePoint);
   2811  return true;
   2812 }
   2813 
   2814 bool WarpCacheIRTranspiler::emitNewMapObjectResult(
   2815    uint32_t templateObjectOffset) {
   2816  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2817 
   2818  auto* obj = MNewMapObject::New(alloc(), templateObj);
   2819  addEffectful(obj);
   2820 
   2821  pushResult(obj);
   2822  return resumeAfter(obj);
   2823 }
   2824 
   2825 bool WarpCacheIRTranspiler::emitNewSetObjectResult(
   2826    uint32_t templateObjectOffset) {
   2827  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2828 
   2829  auto* obj = MNewSetObject::New(alloc(), templateObj);
   2830  addEffectful(obj);
   2831 
   2832  pushResult(obj);
   2833  return resumeAfter(obj);
   2834 }
   2835 
   2836 bool WarpCacheIRTranspiler::emitNewMapObjectFromIterableResult(
   2837    uint32_t templateObjectOffset, ValOperandId iterableId) {
   2838  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2839  MDefinition* iterable = getOperand(iterableId);
   2840 
   2841  auto* obj = MNewMapObjectFromIterable::New(alloc(), iterable, templateObj);
   2842  addEffectful(obj);
   2843 
   2844  pushResult(obj);
   2845  return resumeAfter(obj);
   2846 }
   2847 
   2848 bool WarpCacheIRTranspiler::emitNewSetObjectFromIterableResult(
   2849    uint32_t templateObjectOffset, ValOperandId iterableId) {
   2850  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2851  MDefinition* iterable = getOperand(iterableId);
   2852 
   2853  auto* obj = MNewSetObjectFromIterable::New(alloc(), iterable, templateObj);
   2854  addEffectful(obj);
   2855 
   2856  pushResult(obj);
   2857  return resumeAfter(obj);
   2858 }
   2859 
   2860 bool WarpCacheIRTranspiler::emitNewStringObjectResult(
   2861    uint32_t templateObjectOffset, StringOperandId strId) {
   2862  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   2863  MDefinition* string = getOperand(strId);
   2864 
   2865  auto* obj = MNewStringObject::New(alloc(), string, templateObj);
   2866  addEffectful(obj);
   2867 
   2868  pushResult(obj);
   2869  return resumeAfter(obj);
   2870 }
   2871 
   2872 bool WarpCacheIRTranspiler::emitStringFromCharCodeResult(
   2873    Int32OperandId codeId) {
   2874  MDefinition* code = getOperand(codeId);
   2875 
   2876  auto* fromCharCode = MFromCharCode::New(alloc(), code);
   2877  add(fromCharCode);
   2878 
   2879  pushResult(fromCharCode);
   2880  return true;
   2881 }
   2882 
   2883 bool WarpCacheIRTranspiler::emitStringFromCodePointResult(
   2884    Int32OperandId codeId) {
   2885  MDefinition* code = getOperand(codeId);
   2886 
   2887  auto* fromCodePoint = MFromCodePoint::New(alloc(), code);
   2888  add(fromCodePoint);
   2889 
   2890  pushResult(fromCodePoint);
   2891  return true;
   2892 }
   2893 
   2894 bool WarpCacheIRTranspiler::emitStringIncludesResult(
   2895    StringOperandId strId, StringOperandId searchStrId) {
   2896  MDefinition* str = getOperand(strId);
   2897  MDefinition* searchStr = getOperand(searchStrId);
   2898 
   2899  auto* includes = MStringIncludes::New(alloc(), str, searchStr);
   2900  add(includes);
   2901 
   2902  pushResult(includes);
   2903  return true;
   2904 }
   2905 
   2906 bool WarpCacheIRTranspiler::emitStringIndexOfResult(
   2907    StringOperandId strId, StringOperandId searchStrId) {
   2908  MDefinition* str = getOperand(strId);
   2909  MDefinition* searchStr = getOperand(searchStrId);
   2910 
   2911  auto* indexOf = MStringIndexOf::New(alloc(), str, searchStr);
   2912  add(indexOf);
   2913 
   2914  pushResult(indexOf);
   2915  return true;
   2916 }
   2917 
   2918 bool WarpCacheIRTranspiler::emitStringLastIndexOfResult(
   2919    StringOperandId strId, StringOperandId searchStrId) {
   2920  MDefinition* str = getOperand(strId);
   2921  MDefinition* searchStr = getOperand(searchStrId);
   2922 
   2923  auto* lastIndexOf = MStringLastIndexOf::New(alloc(), str, searchStr);
   2924  add(lastIndexOf);
   2925 
   2926  pushResult(lastIndexOf);
   2927  return true;
   2928 }
   2929 
   2930 bool WarpCacheIRTranspiler::emitStringStartsWithResult(
   2931    StringOperandId strId, StringOperandId searchStrId) {
   2932  MDefinition* str = getOperand(strId);
   2933  MDefinition* searchStr = getOperand(searchStrId);
   2934 
   2935  auto* startsWith = MStringStartsWith::New(alloc(), str, searchStr);
   2936  add(startsWith);
   2937 
   2938  pushResult(startsWith);
   2939  return true;
   2940 }
   2941 
   2942 bool WarpCacheIRTranspiler::emitStringEndsWithResult(
   2943    StringOperandId strId, StringOperandId searchStrId) {
   2944  MDefinition* str = getOperand(strId);
   2945  MDefinition* searchStr = getOperand(searchStrId);
   2946 
   2947  auto* endsWith = MStringEndsWith::New(alloc(), str, searchStr);
   2948  add(endsWith);
   2949 
   2950  pushResult(endsWith);
   2951  return true;
   2952 }
   2953 
   2954 bool WarpCacheIRTranspiler::emitStringToLowerCaseResult(StringOperandId strId) {
   2955  MDefinition* str = getOperand(strId);
   2956 
   2957  auto* convert =
   2958      MStringConvertCase::New(alloc(), str, MStringConvertCase::LowerCase);
   2959  add(convert);
   2960 
   2961  pushResult(convert);
   2962  return true;
   2963 }
   2964 
   2965 bool WarpCacheIRTranspiler::emitStringToUpperCaseResult(StringOperandId strId) {
   2966  MDefinition* str = getOperand(strId);
   2967 
   2968  auto* convert =
   2969      MStringConvertCase::New(alloc(), str, MStringConvertCase::UpperCase);
   2970  add(convert);
   2971 
   2972  pushResult(convert);
   2973  return true;
   2974 }
   2975 
   2976 bool WarpCacheIRTranspiler::emitStringTrimResult(StringOperandId strId) {
   2977  MDefinition* str = getOperand(strId);
   2978 
   2979  auto* linear = MLinearizeString::New(alloc(), str);
   2980  add(linear);
   2981 
   2982  auto* start = MStringTrimStartIndex::New(alloc(), linear);
   2983  add(start);
   2984 
   2985  auto* end = MStringTrimEndIndex::New(alloc(), linear, start);
   2986  add(end);
   2987 
   2988  // Safe to truncate because both operands are positive and end >= start.
   2989  auto* length = MSub::New(alloc(), end, start, MIRType::Int32);
   2990  length->setTruncateKind(TruncateKind::Truncate);
   2991  add(length);
   2992 
   2993  auto* substr = MSubstr::New(alloc(), linear, start, length);
   2994  add(substr);
   2995 
   2996  pushResult(substr);
   2997  return true;
   2998 }
   2999 
   3000 bool WarpCacheIRTranspiler::emitStringTrimStartResult(StringOperandId strId) {
   3001  MDefinition* str = getOperand(strId);
   3002 
   3003  auto* linear = MLinearizeString::New(alloc(), str);
   3004  add(linear);
   3005 
   3006  auto* start = MStringTrimStartIndex::New(alloc(), linear);
   3007  add(start);
   3008 
   3009  auto* end = MStringLength::New(alloc(), linear);
   3010  add(end);
   3011 
   3012  // Safe to truncate because both operands are positive and end >= start.
   3013  auto* length = MSub::New(alloc(), end, start, MIRType::Int32);
   3014  length->setTruncateKind(TruncateKind::Truncate);
   3015  add(length);
   3016 
   3017  auto* substr = MSubstr::New(alloc(), linear, start, length);
   3018  add(substr);
   3019 
   3020  pushResult(substr);
   3021  return true;
   3022 }
   3023 
   3024 bool WarpCacheIRTranspiler::emitStringTrimEndResult(StringOperandId strId) {
   3025  MDefinition* str = getOperand(strId);
   3026 
   3027  auto* linear = MLinearizeString::New(alloc(), str);
   3028  add(linear);
   3029 
   3030  auto* start = constant(Int32Value(0));
   3031 
   3032  auto* length = MStringTrimEndIndex::New(alloc(), linear, start);
   3033  add(length);
   3034 
   3035  auto* substr = MSubstr::New(alloc(), linear, start, length);
   3036  add(substr);
   3037 
   3038  pushResult(substr);
   3039  return true;
   3040 }
   3041 
   3042 bool WarpCacheIRTranspiler::emitStoreDynamicSlot(ObjOperandId objId,
   3043                                                 uint32_t offsetOffset,
   3044                                                 ValOperandId rhsId) {
   3045  int32_t offset = int32StubField(offsetOffset);
   3046 
   3047  MDefinition* obj = getOperand(objId);
   3048  size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset);
   3049  MDefinition* rhs = getOperand(rhsId);
   3050 
   3051  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   3052  add(barrier);
   3053 
   3054  auto* slots = MSlots::New(alloc(), obj);
   3055  add(slots);
   3056 
   3057  auto* store = MStoreDynamicSlot::NewBarriered(alloc(), slots, slotIndex, rhs);
   3058  addEffectful(store);
   3059  return resumeAfter(store);
   3060 }
   3061 
   3062 bool WarpCacheIRTranspiler::emitStoreFixedSlot(ObjOperandId objId,
   3063                                               uint32_t offsetOffset,
   3064                                               ValOperandId rhsId) {
   3065  int32_t offset = int32StubField(offsetOffset);
   3066 
   3067  MDefinition* obj = getOperand(objId);
   3068  size_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   3069  MDefinition* rhs = getOperand(rhsId);
   3070 
   3071  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   3072  add(barrier);
   3073 
   3074  auto* store = MStoreFixedSlot::NewBarriered(alloc(), obj, slotIndex, rhs);
   3075  addEffectful(store);
   3076  return resumeAfter(store);
   3077 }
   3078 
   3079 bool WarpCacheIRTranspiler::emitStoreFixedSlotUndefinedResult(
   3080    ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId) {
   3081  int32_t offset = int32StubField(offsetOffset);
   3082 
   3083  MDefinition* obj = getOperand(objId);
   3084  size_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset);
   3085  MDefinition* rhs = getOperand(rhsId);
   3086 
   3087  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   3088  add(barrier);
   3089 
   3090  auto* store = MStoreFixedSlot::NewBarriered(alloc(), obj, slotIndex, rhs);
   3091  addEffectful(store);
   3092 
   3093  auto* undef = constant(UndefinedValue());
   3094  pushResult(undef);
   3095 
   3096  return resumeAfter(store);
   3097 }
   3098 
   3099 bool WarpCacheIRTranspiler::emitAddAndStoreSlotShared(
   3100    MAddAndStoreSlot::Kind kind, ObjOperandId objId, uint32_t offsetOffset,
   3101    ValOperandId rhsId, uint32_t newShapeOffset, bool preserveWrapper) {
   3102  int32_t offset = int32StubField(offsetOffset);
   3103  Shape* shape = shapeStubField(newShapeOffset);
   3104 
   3105  MDefinition* obj = getOperand(objId);
   3106  MDefinition* rhs = getOperand(rhsId);
   3107 
   3108  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   3109  add(barrier);
   3110 
   3111  auto* addAndStore = MAddAndStoreSlot::New(alloc(), obj, rhs, kind, offset,
   3112                                            shape, preserveWrapper);
   3113  addEffectful(addAndStore);
   3114 
   3115  return resumeAfter(addAndStore);
   3116 }
   3117 
   3118 bool WarpCacheIRTranspiler::emitAddAndStoreFixedSlot(ObjOperandId objId,
   3119                                                     uint32_t offsetOffset,
   3120                                                     ValOperandId rhsId,
   3121                                                     uint32_t newShapeOffset,
   3122                                                     bool preserveWrapper) {
   3123  return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::FixedSlot, objId,
   3124                                   offsetOffset, rhsId, newShapeOffset,
   3125                                   preserveWrapper);
   3126 }
   3127 
   3128 bool WarpCacheIRTranspiler::emitAddAndStoreDynamicSlot(ObjOperandId objId,
   3129                                                       uint32_t offsetOffset,
   3130                                                       ValOperandId rhsId,
   3131                                                       uint32_t newShapeOffset,
   3132                                                       bool preserveWrapper) {
   3133  return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::DynamicSlot, objId,
   3134                                   offsetOffset, rhsId, newShapeOffset,
   3135                                   preserveWrapper);
   3136 }
   3137 
   3138 bool WarpCacheIRTranspiler::emitAllocateAndStoreDynamicSlot(
   3139    ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId,
   3140    uint32_t newShapeOffset, uint32_t numNewSlotsOffset, bool preserveWrapper) {
   3141  int32_t offset = int32StubField(offsetOffset);
   3142  Shape* shape = shapeStubField(newShapeOffset);
   3143  uint32_t numNewSlots = uint32StubField(numNewSlotsOffset);
   3144 
   3145  MDefinition* obj = getOperand(objId);
   3146  MDefinition* rhs = getOperand(rhsId);
   3147 
   3148  auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs);
   3149  add(barrier);
   3150 
   3151  auto* allocateAndStore = MAllocateAndStoreSlot::New(
   3152      alloc(), obj, rhs, offset, shape, numNewSlots, preserveWrapper);
   3153  addEffectful(allocateAndStore);
   3154 
   3155  return resumeAfter(allocateAndStore);
   3156 }
   3157 
   3158 bool WarpCacheIRTranspiler::emitAddSlotAndCallAddPropHook(
   3159    ObjOperandId objId, ValOperandId rhsId, uint32_t newShapeOffset) {
   3160  Shape* shape = shapeStubField(newShapeOffset);
   3161  MDefinition* obj = getOperand(objId);
   3162  MDefinition* rhs = getOperand(rhsId);
   3163 
   3164  auto* addProp = MAddSlotAndCallAddPropHook::New(alloc(), obj, rhs, shape);
   3165  addEffectful(addProp);
   3166 
   3167  return resumeAfter(addProp);
   3168 }
   3169 
   3170 bool WarpCacheIRTranspiler::emitStoreDenseElement(ObjOperandId objId,
   3171                                                  Int32OperandId indexId,
   3172                                                  ValOperandId rhsId,
   3173                                                  bool expectPackedElements) {
   3174  MDefinition* obj = getOperand(objId);
   3175  MDefinition* index = getOperand(indexId);
   3176  MDefinition* rhs = getOperand(rhsId);
   3177 
   3178  auto* elements = MElements::New(alloc(), obj);
   3179  add(elements);
   3180 
   3181  auto* length = MInitializedLength::New(alloc(), elements);
   3182  add(length);
   3183 
   3184  index = addBoundsCheck(index, length);
   3185 
   3186  if (expectPackedElements) {
   3187    auto* guardPacked = MGuardElementsArePacked::New(alloc(), elements);
   3188    add(guardPacked);
   3189  }
   3190 
   3191  auto* barrier = MPostWriteElementBarrier::New(alloc(), obj, rhs, index);
   3192  add(barrier);
   3193 
   3194  bool needsHoleCheck = !expectPackedElements;
   3195  auto* store = MStoreElement::NewBarriered(alloc(), elements, index, rhs,
   3196                                            needsHoleCheck);
   3197  addEffectful(store);
   3198  return resumeAfter(store);
   3199 }
   3200 
   3201 bool WarpCacheIRTranspiler::emitStoreDenseElementHole(ObjOperandId objId,
   3202                                                      Int32OperandId indexId,
   3203                                                      ValOperandId rhsId,
   3204                                                      bool handleAdd) {
   3205  MDefinition* obj = getOperand(objId);
   3206  MDefinition* index = getOperand(indexId);
   3207  MDefinition* rhs = getOperand(rhsId);
   3208 
   3209  auto* elements = MElements::New(alloc(), obj);
   3210  add(elements);
   3211 
   3212  MInstruction* store;
   3213  if (handleAdd) {
   3214    // TODO(post-Warp): Consider changing MStoreElementHole to match IC code.
   3215    store = MStoreElementHole::New(alloc(), obj, elements, index, rhs);
   3216  } else {
   3217    auto* length = MInitializedLength::New(alloc(), elements);
   3218    add(length);
   3219 
   3220    index = addBoundsCheck(index, length);
   3221 
   3222    auto* barrier = MPostWriteElementBarrier::New(alloc(), obj, rhs, index);
   3223    add(barrier);
   3224 
   3225    bool needsHoleCheck = false;
   3226    store = MStoreElement::NewBarriered(alloc(), elements, index, rhs,
   3227                                        needsHoleCheck);
   3228  }
   3229  addEffectful(store);
   3230 
   3231  return resumeAfter(store);
   3232 }
   3233 
   3234 bool WarpCacheIRTranspiler::emitStoreTypedArrayElement(
   3235    ObjOperandId objId, Scalar::Type elementType, IntPtrOperandId indexId,
   3236    uint32_t rhsId, bool handleOOB, ArrayBufferViewKind viewKind) {
   3237  MDefinition* obj = getOperand(objId);
   3238  MDefinition* index = getOperand(indexId);
   3239  MDefinition* rhs = getOperand(ValOperandId(rhsId));
   3240 
   3241  auto* length = emitTypedArrayLength(viewKind, obj);
   3242 
   3243  if (!handleOOB) {
   3244    // MStoreTypedArrayElementHole does the bounds checking.
   3245    index = addBoundsCheck(index, length);
   3246  }
   3247 
   3248  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   3249  add(elements);
   3250 
   3251  MInstruction* store;
   3252  if (handleOOB) {
   3253    store = MStoreTypedArrayElementHole::New(alloc(), elements, length, index,
   3254                                             rhs, elementType);
   3255  } else {
   3256    store =
   3257        MStoreUnboxedScalar::New(alloc(), elements, index, rhs, elementType);
   3258  }
   3259  addEffectful(store);
   3260  return resumeAfter(store);
   3261 }
   3262 
   3263 MInstruction* WarpCacheIRTranspiler::emitDataViewLength(
   3264    ArrayBufferViewKind viewKind, MDefinition* obj) {
   3265  if (viewKind == ArrayBufferViewKind::FixedLength ||
   3266      viewKind == ArrayBufferViewKind::Immutable) {
   3267    auto* length = MArrayBufferViewLength::New(alloc(), obj);
   3268    add(length);
   3269 
   3270    return length;
   3271  }
   3272 
   3273  // Bounds check doesn't require a memory barrier. See GetViewValue and
   3274  // SetViewValue abstract operations which read the underlying buffer byte
   3275  // length using "unordered" memory order.
   3276  auto barrier = MemoryBarrierRequirement::NotRequired;
   3277 
   3278  // Movable and removable because no memory barrier is needed.
   3279  auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier);
   3280  length->setMovable();
   3281  length->setNotGuard();
   3282  add(length);
   3283 
   3284  return length;
   3285 }
   3286 
   3287 void WarpCacheIRTranspiler::addDataViewData(ArrayBufferViewKind viewKind,
   3288                                            MDefinition* obj, Scalar::Type type,
   3289                                            MDefinition** offset,
   3290                                            MInstruction** elements) {
   3291  auto* length = emitDataViewLength(viewKind, obj);
   3292 
   3293  // Adjust the length to account for accesses near the end of the dataview.
   3294  if (size_t byteSize = Scalar::byteSize(type); byteSize > 1) {
   3295    // To ensure |0 <= offset && offset + byteSize <= length|, first adjust the
   3296    // length by subtracting |byteSize - 1| (bailing out if that becomes
   3297    // negative).
   3298    length = MAdjustDataViewLength::New(alloc(), length, byteSize);
   3299    add(length);
   3300  }
   3301 
   3302  *offset = addBoundsCheck(*offset, length);
   3303 
   3304  *elements = MArrayBufferViewElements::New(alloc(), obj);
   3305  add(*elements);
   3306 }
   3307 
   3308 bool WarpCacheIRTranspiler::emitLoadDataViewValueResult(
   3309    ObjOperandId objId, IntPtrOperandId offsetId,
   3310    BooleanOperandId littleEndianId, Scalar::Type elementType,
   3311    bool forceDoubleForUint32, ArrayBufferViewKind viewKind) {
   3312  MDefinition* obj = getOperand(objId);
   3313  MDefinition* offset = getOperand(offsetId);
   3314  MDefinition* littleEndian = getOperand(littleEndianId);
   3315 
   3316  // Add bounds check and get the DataViewObject's elements.
   3317  MInstruction* elements;
   3318  addDataViewData(viewKind, obj, elementType, &offset, &elements);
   3319 
   3320  // Load the element.
   3321  MInstruction* load;
   3322  if (Scalar::byteSize(elementType) == 1) {
   3323    load = MLoadUnboxedScalar::New(alloc(), elements, offset, elementType);
   3324  } else {
   3325    load = MLoadDataViewElement::New(alloc(), elements, offset, littleEndian,
   3326                                     elementType);
   3327  }
   3328  add(load);
   3329 
   3330  MIRType knownType =
   3331      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32);
   3332  load->setResultType(knownType);
   3333 
   3334  MInstruction* result = load;
   3335  if (Scalar::isBigIntType(elementType)) {
   3336    result = MInt64ToBigInt::New(alloc(), load,
   3337                                 Scalar::isSignedIntType(elementType));
   3338    add(result);
   3339  }
   3340 
   3341  pushResult(result);
   3342  return true;
   3343 }
   3344 
   3345 bool WarpCacheIRTranspiler::emitStoreDataViewValueResult(
   3346    ObjOperandId objId, IntPtrOperandId offsetId, uint32_t valueId,
   3347    BooleanOperandId littleEndianId, Scalar::Type elementType,
   3348    ArrayBufferViewKind viewKind) {
   3349  MDefinition* obj = getOperand(objId);
   3350  MDefinition* offset = getOperand(offsetId);
   3351  MDefinition* value = getOperand(ValOperandId(valueId));
   3352  MDefinition* littleEndian = getOperand(littleEndianId);
   3353 
   3354  // Add bounds check and get the DataViewObject's elements.
   3355  MInstruction* elements;
   3356  addDataViewData(viewKind, obj, elementType, &offset, &elements);
   3357 
   3358  // Store the element.
   3359  MInstruction* store;
   3360  if (Scalar::byteSize(elementType) == 1) {
   3361    store =
   3362        MStoreUnboxedScalar::New(alloc(), elements, offset, value, elementType);
   3363  } else {
   3364    store = MStoreDataViewElement::New(alloc(), elements, offset, value,
   3365                                       littleEndian, elementType);
   3366  }
   3367  addEffectful(store);
   3368 
   3369  pushResult(constant(UndefinedValue()));
   3370 
   3371  return resumeAfter(store);
   3372 }
   3373 
   3374 bool WarpCacheIRTranspiler::emitInt32IncResult(Int32OperandId inputId) {
   3375  MDefinition* input = getOperand(inputId);
   3376 
   3377  auto* constOne = MConstant::NewInt32(alloc(), 1);
   3378  add(constOne);
   3379 
   3380  auto* ins = MAdd::New(alloc(), input, constOne, MIRType::Int32);
   3381  add(ins);
   3382 
   3383  pushResult(ins);
   3384  return true;
   3385 }
   3386 
   3387 bool WarpCacheIRTranspiler::emitDoubleIncResult(NumberOperandId inputId) {
   3388  MDefinition* input = getOperand(inputId);
   3389 
   3390  auto* constOne = MConstant::NewDouble(alloc(), 1.0);
   3391  add(constOne);
   3392 
   3393  auto* ins = MAdd::New(alloc(), input, constOne, MIRType::Double);
   3394  add(ins);
   3395 
   3396  pushResult(ins);
   3397  return true;
   3398 }
   3399 
   3400 bool WarpCacheIRTranspiler::emitInt32DecResult(Int32OperandId inputId) {
   3401  MDefinition* input = getOperand(inputId);
   3402 
   3403  auto* constOne = MConstant::NewInt32(alloc(), 1);
   3404  add(constOne);
   3405 
   3406  auto* ins = MSub::New(alloc(), input, constOne, MIRType::Int32);
   3407  add(ins);
   3408 
   3409  pushResult(ins);
   3410  return true;
   3411 }
   3412 
   3413 bool WarpCacheIRTranspiler::emitDoubleDecResult(NumberOperandId inputId) {
   3414  MDefinition* input = getOperand(inputId);
   3415 
   3416  auto* constOne = MConstant::NewDouble(alloc(), 1.0);
   3417  add(constOne);
   3418 
   3419  auto* ins = MSub::New(alloc(), input, constOne, MIRType::Double);
   3420  add(ins);
   3421 
   3422  pushResult(ins);
   3423  return true;
   3424 }
   3425 
   3426 bool WarpCacheIRTranspiler::emitInt32NegationResult(Int32OperandId inputId) {
   3427  MDefinition* input = getOperand(inputId);
   3428 
   3429  auto* constNegOne = MConstant::NewInt32(alloc(), -1);
   3430  add(constNegOne);
   3431 
   3432  auto* ins = MMul::New(alloc(), input, constNegOne, MIRType::Int32);
   3433  add(ins);
   3434 
   3435  pushResult(ins);
   3436  return true;
   3437 }
   3438 
   3439 bool WarpCacheIRTranspiler::emitDoubleNegationResult(NumberOperandId inputId) {
   3440  MDefinition* input = getOperand(inputId);
   3441 
   3442  auto* constNegOne = MConstant::NewDouble(alloc(), -1.0);
   3443  add(constNegOne);
   3444 
   3445  auto* ins = MMul::New(alloc(), input, constNegOne, MIRType::Double);
   3446  add(ins);
   3447 
   3448  pushResult(ins);
   3449  return true;
   3450 }
   3451 
   3452 bool WarpCacheIRTranspiler::emitInt32NotResult(Int32OperandId inputId) {
   3453  MDefinition* input = getOperand(inputId);
   3454 
   3455  auto* ins = MBitNot::New(alloc(), input, MIRType::Int32);
   3456  add(ins);
   3457 
   3458  pushResult(ins);
   3459  return true;
   3460 }
   3461 
   3462 template <typename T>
   3463 bool WarpCacheIRTranspiler::emitDoubleBinaryArithResult(NumberOperandId lhsId,
   3464                                                        NumberOperandId rhsId) {
   3465  MDefinition* lhs = getOperand(lhsId);
   3466  MDefinition* rhs = getOperand(rhsId);
   3467 
   3468  auto* ins = T::New(alloc(), lhs, rhs, MIRType::Double);
   3469  add(ins);
   3470 
   3471  pushResult(ins);
   3472  return true;
   3473 }
   3474 
   3475 bool WarpCacheIRTranspiler::emitDoubleAddResult(NumberOperandId lhsId,
   3476                                                NumberOperandId rhsId) {
   3477  return emitDoubleBinaryArithResult<MAdd>(lhsId, rhsId);
   3478 }
   3479 
   3480 bool WarpCacheIRTranspiler::emitDoubleSubResult(NumberOperandId lhsId,
   3481                                                NumberOperandId rhsId) {
   3482  return emitDoubleBinaryArithResult<MSub>(lhsId, rhsId);
   3483 }
   3484 
   3485 bool WarpCacheIRTranspiler::emitDoubleMulResult(NumberOperandId lhsId,
   3486                                                NumberOperandId rhsId) {
   3487  return emitDoubleBinaryArithResult<MMul>(lhsId, rhsId);
   3488 }
   3489 
   3490 bool WarpCacheIRTranspiler::emitDoubleDivResult(NumberOperandId lhsId,
   3491                                                NumberOperandId rhsId) {
   3492  return emitDoubleBinaryArithResult<MDiv>(lhsId, rhsId);
   3493 }
   3494 
   3495 bool WarpCacheIRTranspiler::emitDoubleModResult(NumberOperandId lhsId,
   3496                                                NumberOperandId rhsId) {
   3497  return emitDoubleBinaryArithResult<MMod>(lhsId, rhsId);
   3498 }
   3499 
   3500 bool WarpCacheIRTranspiler::emitDoublePowResult(NumberOperandId lhsId,
   3501                                                NumberOperandId rhsId) {
   3502  return emitDoubleBinaryArithResult<MPow>(lhsId, rhsId);
   3503 }
   3504 
   3505 template <typename T>
   3506 bool WarpCacheIRTranspiler::emitInt32BinaryArithResult(Int32OperandId lhsId,
   3507                                                       Int32OperandId rhsId) {
   3508  MDefinition* lhs = getOperand(lhsId);
   3509  MDefinition* rhs = getOperand(rhsId);
   3510 
   3511  auto* ins = T::New(alloc(), lhs, rhs, MIRType::Int32);
   3512  add(ins);
   3513 
   3514  pushResult(ins);
   3515  return true;
   3516 }
   3517 
   3518 bool WarpCacheIRTranspiler::emitInt32AddResult(Int32OperandId lhsId,
   3519                                               Int32OperandId rhsId) {
   3520  return emitInt32BinaryArithResult<MAdd>(lhsId, rhsId);
   3521 }
   3522 
   3523 bool WarpCacheIRTranspiler::emitInt32SubResult(Int32OperandId lhsId,
   3524                                               Int32OperandId rhsId) {
   3525  return emitInt32BinaryArithResult<MSub>(lhsId, rhsId);
   3526 }
   3527 
   3528 bool WarpCacheIRTranspiler::emitInt32MulResult(Int32OperandId lhsId,
   3529                                               Int32OperandId rhsId) {
   3530  return emitInt32BinaryArithResult<MMul>(lhsId, rhsId);
   3531 }
   3532 
   3533 bool WarpCacheIRTranspiler::emitInt32DivResult(Int32OperandId lhsId,
   3534                                               Int32OperandId rhsId) {
   3535  return emitInt32BinaryArithResult<MDiv>(lhsId, rhsId);
   3536 }
   3537 
   3538 bool WarpCacheIRTranspiler::emitInt32ModResult(Int32OperandId lhsId,
   3539                                               Int32OperandId rhsId) {
   3540  return emitInt32BinaryArithResult<MMod>(lhsId, rhsId);
   3541 }
   3542 
   3543 bool WarpCacheIRTranspiler::emitInt32PowResult(Int32OperandId lhsId,
   3544                                               Int32OperandId rhsId) {
   3545  return emitInt32BinaryArithResult<MPow>(lhsId, rhsId);
   3546 }
   3547 
   3548 bool WarpCacheIRTranspiler::emitInt32BitOrResult(Int32OperandId lhsId,
   3549                                                 Int32OperandId rhsId) {
   3550  return emitInt32BinaryArithResult<MBitOr>(lhsId, rhsId);
   3551 }
   3552 
   3553 bool WarpCacheIRTranspiler::emitInt32BitXorResult(Int32OperandId lhsId,
   3554                                                  Int32OperandId rhsId) {
   3555  return emitInt32BinaryArithResult<MBitXor>(lhsId, rhsId);
   3556 }
   3557 
   3558 bool WarpCacheIRTranspiler::emitInt32BitAndResult(Int32OperandId lhsId,
   3559                                                  Int32OperandId rhsId) {
   3560  return emitInt32BinaryArithResult<MBitAnd>(lhsId, rhsId);
   3561 }
   3562 
   3563 bool WarpCacheIRTranspiler::emitInt32LeftShiftResult(Int32OperandId lhsId,
   3564                                                     Int32OperandId rhsId) {
   3565  return emitInt32BinaryArithResult<MLsh>(lhsId, rhsId);
   3566 }
   3567 
   3568 bool WarpCacheIRTranspiler::emitInt32RightShiftResult(Int32OperandId lhsId,
   3569                                                      Int32OperandId rhsId) {
   3570  return emitInt32BinaryArithResult<MRsh>(lhsId, rhsId);
   3571 }
   3572 
   3573 bool WarpCacheIRTranspiler::emitInt32URightShiftResult(Int32OperandId lhsId,
   3574                                                       Int32OperandId rhsId,
   3575                                                       bool forceDouble) {
   3576  MDefinition* lhs = getOperand(lhsId);
   3577  MDefinition* rhs = getOperand(rhsId);
   3578 
   3579  MIRType specialization = forceDouble ? MIRType::Double : MIRType::Int32;
   3580  auto* ins = MUrsh::New(alloc(), lhs, rhs, specialization);
   3581  add(ins);
   3582 
   3583  pushResult(ins);
   3584  return true;
   3585 }
   3586 
   3587 template <typename T>
   3588 bool WarpCacheIRTranspiler::emitBigIntBinaryArithResult(BigIntOperandId lhsId,
   3589                                                        BigIntOperandId rhsId) {
   3590  MDefinition* lhs = getOperand(lhsId);
   3591  MDefinition* rhs = getOperand(rhsId);
   3592 
   3593  auto* ins = T::New(alloc(), lhs, rhs);
   3594  add(ins);
   3595 
   3596  pushResult(ins);
   3597  return true;
   3598 }
   3599 
   3600 bool WarpCacheIRTranspiler::emitBigIntAddResult(BigIntOperandId lhsId,
   3601                                                BigIntOperandId rhsId) {
   3602  return emitBigIntBinaryArithResult<MBigIntAdd>(lhsId, rhsId);
   3603 }
   3604 
   3605 bool WarpCacheIRTranspiler::emitBigIntSubResult(BigIntOperandId lhsId,
   3606                                                BigIntOperandId rhsId) {
   3607  return emitBigIntBinaryArithResult<MBigIntSub>(lhsId, rhsId);
   3608 }
   3609 
   3610 bool WarpCacheIRTranspiler::emitBigIntMulResult(BigIntOperandId lhsId,
   3611                                                BigIntOperandId rhsId) {
   3612  return emitBigIntBinaryArithResult<MBigIntMul>(lhsId, rhsId);
   3613 }
   3614 
   3615 template <typename T>
   3616 bool WarpCacheIRTranspiler::emitBigIntBinaryArithEffectfulResult(
   3617    BigIntOperandId lhsId, BigIntOperandId rhsId) {
   3618  MDefinition* lhs = getOperand(lhsId);
   3619  MDefinition* rhs = getOperand(rhsId);
   3620 
   3621  auto* ins = T::New(alloc(), lhs, rhs);
   3622 
   3623  if (ins->isEffectful()) {
   3624    addEffectful(ins);
   3625 
   3626    pushResult(ins);
   3627    return resumeAfter(ins);
   3628  }
   3629 
   3630  add(ins);
   3631 
   3632  pushResult(ins);
   3633  return true;
   3634 }
   3635 
   3636 bool WarpCacheIRTranspiler::emitBigIntDivResult(BigIntOperandId lhsId,
   3637                                                BigIntOperandId rhsId) {
   3638  return emitBigIntBinaryArithEffectfulResult<MBigIntDiv>(lhsId, rhsId);
   3639 }
   3640 
   3641 bool WarpCacheIRTranspiler::emitBigIntModResult(BigIntOperandId lhsId,
   3642                                                BigIntOperandId rhsId) {
   3643  return emitBigIntBinaryArithEffectfulResult<MBigIntMod>(lhsId, rhsId);
   3644 }
   3645 
   3646 bool WarpCacheIRTranspiler::emitBigIntPowResult(BigIntOperandId lhsId,
   3647                                                BigIntOperandId rhsId) {
   3648  return emitBigIntBinaryArithEffectfulResult<MBigIntPow>(lhsId, rhsId);
   3649 }
   3650 
   3651 bool WarpCacheIRTranspiler::emitBigIntBitAndResult(BigIntOperandId lhsId,
   3652                                                   BigIntOperandId rhsId) {
   3653  return emitBigIntBinaryArithResult<MBigIntBitAnd>(lhsId, rhsId);
   3654 }
   3655 
   3656 bool WarpCacheIRTranspiler::emitBigIntBitOrResult(BigIntOperandId lhsId,
   3657                                                  BigIntOperandId rhsId) {
   3658  return emitBigIntBinaryArithResult<MBigIntBitOr>(lhsId, rhsId);
   3659 }
   3660 
   3661 bool WarpCacheIRTranspiler::emitBigIntBitXorResult(BigIntOperandId lhsId,
   3662                                                   BigIntOperandId rhsId) {
   3663  return emitBigIntBinaryArithResult<MBigIntBitXor>(lhsId, rhsId);
   3664 }
   3665 
   3666 bool WarpCacheIRTranspiler::emitBigIntLeftShiftResult(BigIntOperandId lhsId,
   3667                                                      BigIntOperandId rhsId) {
   3668  return emitBigIntBinaryArithResult<MBigIntLsh>(lhsId, rhsId);
   3669 }
   3670 
   3671 bool WarpCacheIRTranspiler::emitBigIntRightShiftResult(BigIntOperandId lhsId,
   3672                                                       BigIntOperandId rhsId) {
   3673  return emitBigIntBinaryArithResult<MBigIntRsh>(lhsId, rhsId);
   3674 }
   3675 
   3676 template <typename T>
   3677 bool WarpCacheIRTranspiler::emitBigIntUnaryArithResult(
   3678    BigIntOperandId inputId) {
   3679  MDefinition* input = getOperand(inputId);
   3680 
   3681  auto* ins = T::New(alloc(), input);
   3682  add(ins);
   3683 
   3684  pushResult(ins);
   3685  return true;
   3686 }
   3687 
   3688 bool WarpCacheIRTranspiler::emitBigIntIncResult(BigIntOperandId inputId) {
   3689  return emitBigIntUnaryArithResult<MBigIntIncrement>(inputId);
   3690 }
   3691 
   3692 bool WarpCacheIRTranspiler::emitBigIntDecResult(BigIntOperandId inputId) {
   3693  return emitBigIntUnaryArithResult<MBigIntDecrement>(inputId);
   3694 }
   3695 
   3696 bool WarpCacheIRTranspiler::emitBigIntNegationResult(BigIntOperandId inputId) {
   3697  return emitBigIntUnaryArithResult<MBigIntNegate>(inputId);
   3698 }
   3699 
   3700 bool WarpCacheIRTranspiler::emitBigIntNotResult(BigIntOperandId inputId) {
   3701  return emitBigIntUnaryArithResult<MBigIntBitNot>(inputId);
   3702 }
   3703 
   3704 bool WarpCacheIRTranspiler::emitBigIntToIntPtr(BigIntOperandId inputId,
   3705                                               IntPtrOperandId resultId) {
   3706  MDefinition* input = getOperand(inputId);
   3707 
   3708  auto* ins = MBigIntToIntPtr::New(alloc(), input);
   3709  add(ins);
   3710 
   3711  return defineOperand(resultId, ins);
   3712 }
   3713 
   3714 bool WarpCacheIRTranspiler::emitIntPtrToBigIntResult(IntPtrOperandId inputId) {
   3715  MDefinition* input = getOperand(inputId);
   3716 
   3717  auto* ins = MIntPtrToBigInt::New(alloc(), input);
   3718  add(ins);
   3719 
   3720  pushResult(ins);
   3721  return true;
   3722 }
   3723 
   3724 template <typename T>
   3725 bool WarpCacheIRTranspiler::emitBigIntPtrBinaryArith(IntPtrOperandId lhsId,
   3726                                                     IntPtrOperandId rhsId,
   3727                                                     IntPtrOperandId resultId) {
   3728  MDefinition* lhs = getOperand(lhsId);
   3729  MDefinition* rhs = getOperand(rhsId);
   3730 
   3731  auto* ins = T::New(alloc(), lhs, rhs);
   3732  add(ins);
   3733 
   3734  return defineOperand(resultId, ins);
   3735 }
   3736 
   3737 bool WarpCacheIRTranspiler::emitBigIntPtrAdd(IntPtrOperandId lhsId,
   3738                                             IntPtrOperandId rhsId,
   3739                                             IntPtrOperandId resultId) {
   3740  return emitBigIntPtrBinaryArith<MBigIntPtrAdd>(lhsId, rhsId, resultId);
   3741 }
   3742 
   3743 bool WarpCacheIRTranspiler::emitBigIntPtrSub(IntPtrOperandId lhsId,
   3744                                             IntPtrOperandId rhsId,
   3745                                             IntPtrOperandId resultId) {
   3746  return emitBigIntPtrBinaryArith<MBigIntPtrSub>(lhsId, rhsId, resultId);
   3747 }
   3748 
   3749 bool WarpCacheIRTranspiler::emitBigIntPtrMul(IntPtrOperandId lhsId,
   3750                                             IntPtrOperandId rhsId,
   3751                                             IntPtrOperandId resultId) {
   3752  return emitBigIntPtrBinaryArith<MBigIntPtrMul>(lhsId, rhsId, resultId);
   3753 }
   3754 
   3755 bool WarpCacheIRTranspiler::emitBigIntPtrDiv(IntPtrOperandId lhsId,
   3756                                             IntPtrOperandId rhsId,
   3757                                             IntPtrOperandId resultId) {
   3758  return emitBigIntPtrBinaryArith<MBigIntPtrDiv>(lhsId, rhsId, resultId);
   3759 }
   3760 
   3761 bool WarpCacheIRTranspiler::emitBigIntPtrMod(IntPtrOperandId lhsId,
   3762                                             IntPtrOperandId rhsId,
   3763                                             IntPtrOperandId resultId) {
   3764  return emitBigIntPtrBinaryArith<MBigIntPtrMod>(lhsId, rhsId, resultId);
   3765 }
   3766 
   3767 bool WarpCacheIRTranspiler::emitBigIntPtrPow(IntPtrOperandId lhsId,
   3768                                             IntPtrOperandId rhsId,
   3769                                             IntPtrOperandId resultId) {
   3770  return emitBigIntPtrBinaryArith<MBigIntPtrPow>(lhsId, rhsId, resultId);
   3771 }
   3772 
   3773 bool WarpCacheIRTranspiler::emitBigIntPtrBitOr(IntPtrOperandId lhsId,
   3774                                               IntPtrOperandId rhsId,
   3775                                               IntPtrOperandId resultId) {
   3776  return emitBigIntPtrBinaryArith<MBigIntPtrBitOr>(lhsId, rhsId, resultId);
   3777 }
   3778 
   3779 bool WarpCacheIRTranspiler::emitBigIntPtrBitXor(IntPtrOperandId lhsId,
   3780                                                IntPtrOperandId rhsId,
   3781                                                IntPtrOperandId resultId) {
   3782  return emitBigIntPtrBinaryArith<MBigIntPtrBitXor>(lhsId, rhsId, resultId);
   3783 }
   3784 
   3785 bool WarpCacheIRTranspiler::emitBigIntPtrBitAnd(IntPtrOperandId lhsId,
   3786                                                IntPtrOperandId rhsId,
   3787                                                IntPtrOperandId resultId) {
   3788  return emitBigIntPtrBinaryArith<MBigIntPtrBitAnd>(lhsId, rhsId, resultId);
   3789 }
   3790 
   3791 bool WarpCacheIRTranspiler::emitBigIntPtrLeftShift(IntPtrOperandId lhsId,
   3792                                                   IntPtrOperandId rhsId,
   3793                                                   IntPtrOperandId resultId) {
   3794  return emitBigIntPtrBinaryArith<MBigIntPtrLsh>(lhsId, rhsId, resultId);
   3795 }
   3796 
   3797 bool WarpCacheIRTranspiler::emitBigIntPtrRightShift(IntPtrOperandId lhsId,
   3798                                                    IntPtrOperandId rhsId,
   3799                                                    IntPtrOperandId resultId) {
   3800  return emitBigIntPtrBinaryArith<MBigIntPtrRsh>(lhsId, rhsId, resultId);
   3801 }
   3802 
   3803 bool WarpCacheIRTranspiler::emitBigIntPtrInc(IntPtrOperandId inputId,
   3804                                             IntPtrOperandId resultId) {
   3805  MDefinition* input = getOperand(inputId);
   3806 
   3807  auto* constOne = MConstant::NewIntPtr(alloc(), 1);
   3808  add(constOne);
   3809 
   3810  auto* ins = MBigIntPtrAdd::New(alloc(), input, constOne);
   3811  add(ins);
   3812 
   3813  return defineOperand(resultId, ins);
   3814 }
   3815 
   3816 bool WarpCacheIRTranspiler::emitBigIntPtrDec(IntPtrOperandId inputId,
   3817                                             IntPtrOperandId resultId) {
   3818  MDefinition* input = getOperand(inputId);
   3819 
   3820  auto* constOne = MConstant::NewIntPtr(alloc(), 1);
   3821  add(constOne);
   3822 
   3823  auto* ins = MBigIntPtrSub::New(alloc(), input, constOne);
   3824  add(ins);
   3825 
   3826  return defineOperand(resultId, ins);
   3827 }
   3828 
   3829 bool WarpCacheIRTranspiler::emitBigIntPtrNegation(IntPtrOperandId inputId,
   3830                                                  IntPtrOperandId resultId) {
   3831  MDefinition* input = getOperand(inputId);
   3832 
   3833  auto* constNegOne = MConstant::NewIntPtr(alloc(), -1);
   3834  add(constNegOne);
   3835 
   3836  auto* ins = MBigIntPtrMul::New(alloc(), input, constNegOne);
   3837  add(ins);
   3838 
   3839  return defineOperand(resultId, ins);
   3840 }
   3841 
   3842 bool WarpCacheIRTranspiler::emitBigIntPtrNot(IntPtrOperandId inputId,
   3843                                             IntPtrOperandId resultId) {
   3844  MDefinition* input = getOperand(inputId);
   3845 
   3846  auto* ins = MBigIntPtrBitNot::New(alloc(), input);
   3847  add(ins);
   3848 
   3849  return defineOperand(resultId, ins);
   3850 }
   3851 
   3852 bool WarpCacheIRTranspiler::emitConcatStringsResult(StringOperandId lhsId,
   3853                                                    StringOperandId rhsId,
   3854                                                    uint32_t stubOffset) {
   3855  MDefinition* lhs = getOperand(lhsId);
   3856  MDefinition* rhs = getOperand(rhsId);
   3857 
   3858  auto* ins = MConcat::New(alloc(), lhs, rhs);
   3859  add(ins);
   3860 
   3861  pushResult(ins);
   3862  return true;
   3863 }
   3864 
   3865 bool WarpCacheIRTranspiler::emitCompareResult(
   3866    JSOp op, OperandId lhsId, OperandId rhsId,
   3867    MCompare::CompareType compareType) {
   3868  MDefinition* lhs = getOperand(lhsId);
   3869  MDefinition* rhs = getOperand(rhsId);
   3870 
   3871  auto* ins = MCompare::New(alloc(), lhs, rhs, op, compareType);
   3872  add(ins);
   3873 
   3874  pushResult(ins);
   3875  return true;
   3876 }
   3877 
   3878 bool WarpCacheIRTranspiler::emitCompareInt32Result(JSOp op,
   3879                                                   Int32OperandId lhsId,
   3880                                                   Int32OperandId rhsId) {
   3881  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Int32);
   3882 }
   3883 
   3884 bool WarpCacheIRTranspiler::emitCompareDoubleResult(JSOp op,
   3885                                                    NumberOperandId lhsId,
   3886                                                    NumberOperandId rhsId) {
   3887  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Double);
   3888 }
   3889 
   3890 bool WarpCacheIRTranspiler::emitCompareObjectResult(JSOp op, ObjOperandId lhsId,
   3891                                                    ObjOperandId rhsId) {
   3892  MOZ_ASSERT(IsEqualityOp(op));
   3893  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Object);
   3894 }
   3895 
   3896 bool WarpCacheIRTranspiler::emitCompareStringResult(JSOp op,
   3897                                                    StringOperandId lhsId,
   3898                                                    StringOperandId rhsId) {
   3899  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_String);
   3900 }
   3901 
   3902 bool WarpCacheIRTranspiler::emitCompareSymbolResult(JSOp op,
   3903                                                    SymbolOperandId lhsId,
   3904                                                    SymbolOperandId rhsId) {
   3905  MOZ_ASSERT(IsEqualityOp(op));
   3906  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Symbol);
   3907 }
   3908 
   3909 bool WarpCacheIRTranspiler::emitCompareBigIntResult(JSOp op,
   3910                                                    BigIntOperandId lhsId,
   3911                                                    BigIntOperandId rhsId) {
   3912  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt);
   3913 }
   3914 
   3915 bool WarpCacheIRTranspiler::emitCompareBigIntInt32Result(JSOp op,
   3916                                                         BigIntOperandId lhsId,
   3917                                                         Int32OperandId rhsId) {
   3918  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_Int32);
   3919 }
   3920 
   3921 bool WarpCacheIRTranspiler::emitCompareBigIntNumberResult(
   3922    JSOp op, BigIntOperandId lhsId, NumberOperandId rhsId) {
   3923  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_Double);
   3924 }
   3925 
   3926 bool WarpCacheIRTranspiler::emitCompareBigIntStringResult(
   3927    JSOp op, BigIntOperandId lhsId, StringOperandId rhsId) {
   3928  return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_String);
   3929 }
   3930 
   3931 bool WarpCacheIRTranspiler::emitCompareNullUndefinedResult(
   3932    JSOp op, bool isUndefined, ValOperandId inputId) {
   3933  MDefinition* input = getOperand(inputId);
   3934 
   3935  MOZ_ASSERT(IsEqualityOp(op));
   3936 
   3937  // A previously emitted guard ensures that one side of the comparison
   3938  // is null or undefined.
   3939  MDefinition* cst =
   3940      isUndefined ? constant(UndefinedValue()) : constant(NullValue());
   3941  auto compareType =
   3942      isUndefined ? MCompare::Compare_Undefined : MCompare::Compare_Null;
   3943  auto* ins = MCompare::New(alloc(), input, cst, op, compareType);
   3944  add(ins);
   3945 
   3946  pushResult(ins);
   3947  return true;
   3948 }
   3949 
   3950 bool WarpCacheIRTranspiler::emitCompareDoubleSameValueResult(
   3951    NumberOperandId lhsId, NumberOperandId rhsId) {
   3952  MDefinition* lhs = getOperand(lhsId);
   3953  MDefinition* rhs = getOperand(rhsId);
   3954 
   3955  auto* sameValue = MSameValueDouble::New(alloc(), lhs, rhs);
   3956  add(sameValue);
   3957 
   3958  pushResult(sameValue);
   3959  return true;
   3960 }
   3961 
   3962 bool WarpCacheIRTranspiler::emitSameValueResult(ValOperandId lhsId,
   3963                                                ValOperandId rhsId) {
   3964  MDefinition* lhs = getOperand(lhsId);
   3965  MDefinition* rhs = getOperand(rhsId);
   3966 
   3967  auto* sameValue = MSameValue::New(alloc(), lhs, rhs);
   3968  add(sameValue);
   3969 
   3970  pushResult(sameValue);
   3971  return true;
   3972 }
   3973 
   3974 bool WarpCacheIRTranspiler::emitIndirectTruncateInt32Result(
   3975    Int32OperandId valId) {
   3976  MDefinition* val = getOperand(valId);
   3977  MOZ_ASSERT(val->type() == MIRType::Int32);
   3978 
   3979  auto* truncate =
   3980      MLimitedTruncate::New(alloc(), val, TruncateKind::IndirectTruncate);
   3981  add(truncate);
   3982 
   3983  pushResult(truncate);
   3984  return true;
   3985 }
   3986 
   3987 bool WarpCacheIRTranspiler::emitMathHypot2NumberResult(
   3988    NumberOperandId firstId, NumberOperandId secondId) {
   3989  MDefinitionVector vector(alloc());
   3990  if (!vector.reserve(2)) {
   3991    return false;
   3992  }
   3993 
   3994  vector.infallibleAppend(getOperand(firstId));
   3995  vector.infallibleAppend(getOperand(secondId));
   3996 
   3997  auto* ins = MHypot::New(alloc(), vector);
   3998  if (!ins) {
   3999    return false;
   4000  }
   4001  add(ins);
   4002 
   4003  pushResult(ins);
   4004  return true;
   4005 }
   4006 
   4007 bool WarpCacheIRTranspiler::emitMathHypot3NumberResult(
   4008    NumberOperandId firstId, NumberOperandId secondId,
   4009    NumberOperandId thirdId) {
   4010  MDefinitionVector vector(alloc());
   4011  if (!vector.reserve(3)) {
   4012    return false;
   4013  }
   4014 
   4015  vector.infallibleAppend(getOperand(firstId));
   4016  vector.infallibleAppend(getOperand(secondId));
   4017  vector.infallibleAppend(getOperand(thirdId));
   4018 
   4019  auto* ins = MHypot::New(alloc(), vector);
   4020  if (!ins) {
   4021    return false;
   4022  }
   4023  add(ins);
   4024 
   4025  pushResult(ins);
   4026  return true;
   4027 }
   4028 
   4029 bool WarpCacheIRTranspiler::emitMathHypot4NumberResult(
   4030    NumberOperandId firstId, NumberOperandId secondId, NumberOperandId thirdId,
   4031    NumberOperandId fourthId) {
   4032  MDefinitionVector vector(alloc());
   4033  if (!vector.reserve(4)) {
   4034    return false;
   4035  }
   4036 
   4037  vector.infallibleAppend(getOperand(firstId));
   4038  vector.infallibleAppend(getOperand(secondId));
   4039  vector.infallibleAppend(getOperand(thirdId));
   4040  vector.infallibleAppend(getOperand(fourthId));
   4041 
   4042  auto* ins = MHypot::New(alloc(), vector);
   4043  if (!ins) {
   4044    return false;
   4045  }
   4046  add(ins);
   4047 
   4048  pushResult(ins);
   4049  return true;
   4050 }
   4051 
   4052 bool WarpCacheIRTranspiler::emitMathRandomResult(uint32_t rngOffset) {
   4053 #ifdef DEBUG
   4054  // CodeGenerator uses CompileRealm::addressOfRandomNumberGenerator. Assert it
   4055  // matches the RNG pointer stored in the stub field.
   4056  const void* rng = rawPointerField(rngOffset);
   4057  MOZ_ASSERT(rng == mirGen().realm->addressOfRandomNumberGenerator());
   4058 #endif
   4059 
   4060  auto* ins = MRandom::New(alloc());
   4061  addEffectful(ins);
   4062 
   4063  pushResult(ins);
   4064  return resumeAfter(ins);
   4065 }
   4066 
   4067 bool WarpCacheIRTranspiler::emitInt32MinMax(bool isMax, Int32OperandId firstId,
   4068                                            Int32OperandId secondId,
   4069                                            Int32OperandId resultId) {
   4070  MDefinition* first = getOperand(firstId);
   4071  MDefinition* second = getOperand(secondId);
   4072 
   4073  auto* ins = MMinMax::New(alloc(), first, second, MIRType::Int32, isMax);
   4074  add(ins);
   4075 
   4076  return defineOperand(resultId, ins);
   4077 }
   4078 
   4079 bool WarpCacheIRTranspiler::emitNumberMinMax(bool isMax,
   4080                                             NumberOperandId firstId,
   4081                                             NumberOperandId secondId,
   4082                                             NumberOperandId resultId) {
   4083  MDefinition* first = getOperand(firstId);
   4084  MDefinition* second = getOperand(secondId);
   4085 
   4086  auto* ins = MMinMax::New(alloc(), first, second, MIRType::Double, isMax);
   4087  add(ins);
   4088 
   4089  return defineOperand(resultId, ins);
   4090 }
   4091 
   4092 bool WarpCacheIRTranspiler::emitInt32MinMaxArrayResult(ObjOperandId arrayId,
   4093                                                       bool isMax) {
   4094  MDefinition* array = getOperand(arrayId);
   4095 
   4096  auto* ins = MMinMaxArray::New(alloc(), array, MIRType::Int32, isMax);
   4097  add(ins);
   4098 
   4099  pushResult(ins);
   4100  return true;
   4101 }
   4102 
   4103 bool WarpCacheIRTranspiler::emitNumberMinMaxArrayResult(ObjOperandId arrayId,
   4104                                                        bool isMax) {
   4105  MDefinition* array = getOperand(arrayId);
   4106 
   4107  auto* ins = MMinMaxArray::New(alloc(), array, MIRType::Double, isMax);
   4108  add(ins);
   4109 
   4110  pushResult(ins);
   4111  return true;
   4112 }
   4113 
   4114 bool WarpCacheIRTranspiler::emitMathAbsInt32Result(Int32OperandId inputId) {
   4115  MDefinition* input = getOperand(inputId);
   4116 
   4117  auto* ins = MAbs::New(alloc(), input, MIRType::Int32);
   4118  add(ins);
   4119 
   4120  pushResult(ins);
   4121  return true;
   4122 }
   4123 
   4124 bool WarpCacheIRTranspiler::emitMathAbsNumberResult(NumberOperandId inputId) {
   4125  MDefinition* input = getOperand(inputId);
   4126 
   4127  auto* ins = MAbs::New(alloc(), input, MIRType::Double);
   4128  add(ins);
   4129 
   4130  pushResult(ins);
   4131  return true;
   4132 }
   4133 
   4134 bool WarpCacheIRTranspiler::emitMathClz32Result(Int32OperandId inputId) {
   4135  MDefinition* input = getOperand(inputId);
   4136 
   4137  auto* ins = MClz::New(alloc(), input, MIRType::Int32);
   4138  add(ins);
   4139 
   4140  pushResult(ins);
   4141  return true;
   4142 }
   4143 
   4144 bool WarpCacheIRTranspiler::emitMathSignInt32Result(Int32OperandId inputId) {
   4145  MDefinition* input = getOperand(inputId);
   4146 
   4147  auto* ins = MSign::New(alloc(), input, MIRType::Int32);
   4148  add(ins);
   4149 
   4150  pushResult(ins);
   4151  return true;
   4152 }
   4153 
   4154 bool WarpCacheIRTranspiler::emitMathSignNumberResult(NumberOperandId inputId) {
   4155  MDefinition* input = getOperand(inputId);
   4156 
   4157  auto* ins = MSign::New(alloc(), input, MIRType::Double);
   4158  add(ins);
   4159 
   4160  pushResult(ins);
   4161  return true;
   4162 }
   4163 
   4164 bool WarpCacheIRTranspiler::emitMathSignNumberToInt32Result(
   4165    NumberOperandId inputId) {
   4166  MDefinition* input = getOperand(inputId);
   4167 
   4168  auto* ins = MSign::New(alloc(), input, MIRType::Int32);
   4169  add(ins);
   4170 
   4171  pushResult(ins);
   4172  return true;
   4173 }
   4174 
   4175 bool WarpCacheIRTranspiler::emitMathImulResult(Int32OperandId lhsId,
   4176                                               Int32OperandId rhsId) {
   4177  MDefinition* lhs = getOperand(lhsId);
   4178  MDefinition* rhs = getOperand(rhsId);
   4179 
   4180  auto* ins = MMul::New(alloc(), lhs, rhs, MIRType::Int32, MMul::Integer);
   4181  add(ins);
   4182 
   4183  pushResult(ins);
   4184  return true;
   4185 }
   4186 
   4187 bool WarpCacheIRTranspiler::emitMathFloorToInt32Result(
   4188    NumberOperandId inputId) {
   4189  MDefinition* input = getOperand(inputId);
   4190 
   4191  auto* ins = MFloor::New(alloc(), input);
   4192  add(ins);
   4193 
   4194  pushResult(ins);
   4195  return true;
   4196 }
   4197 
   4198 bool WarpCacheIRTranspiler::emitMathCeilToInt32Result(NumberOperandId inputId) {
   4199  MDefinition* input = getOperand(inputId);
   4200 
   4201  auto* ins = MCeil::New(alloc(), input);
   4202  add(ins);
   4203 
   4204  pushResult(ins);
   4205  return true;
   4206 }
   4207 
   4208 bool WarpCacheIRTranspiler::emitMathTruncToInt32Result(
   4209    NumberOperandId inputId) {
   4210  MDefinition* input = getOperand(inputId);
   4211 
   4212  auto* ins = MTrunc::New(alloc(), input);
   4213  add(ins);
   4214 
   4215  pushResult(ins);
   4216  return true;
   4217 }
   4218 
   4219 bool WarpCacheIRTranspiler::emitMathRoundToInt32Result(
   4220    NumberOperandId inputId) {
   4221  MDefinition* input = getOperand(inputId);
   4222 
   4223  auto* ins = MRound::New(alloc(), input);
   4224  add(ins);
   4225 
   4226  pushResult(ins);
   4227  return true;
   4228 }
   4229 
   4230 bool WarpCacheIRTranspiler::emitMathSqrtNumberResult(NumberOperandId inputId) {
   4231  MDefinition* input = getOperand(inputId);
   4232 
   4233  auto* ins = MSqrt::New(alloc(), input, MIRType::Double);
   4234  add(ins);
   4235 
   4236  pushResult(ins);
   4237  return true;
   4238 }
   4239 
   4240 bool WarpCacheIRTranspiler::emitMathFRoundNumberResult(
   4241    NumberOperandId inputId) {
   4242  MDefinition* input = getOperand(inputId);
   4243 
   4244  auto* ins = MToFloat32::New(alloc(), input);
   4245  add(ins);
   4246 
   4247  pushResult(ins);
   4248  return true;
   4249 }
   4250 
   4251 bool WarpCacheIRTranspiler::emitMathF16RoundNumberResult(
   4252    NumberOperandId inputId) {
   4253  MDefinition* input = getOperand(inputId);
   4254 
   4255  auto* ins = MToFloat16::New(alloc(), input);
   4256  add(ins);
   4257 
   4258  pushResult(ins);
   4259  return true;
   4260 }
   4261 
   4262 bool WarpCacheIRTranspiler::emitMathAtan2NumberResult(NumberOperandId yId,
   4263                                                      NumberOperandId xId) {
   4264  MDefinition* y = getOperand(yId);
   4265  MDefinition* x = getOperand(xId);
   4266 
   4267  auto* ins = MAtan2::New(alloc(), y, x);
   4268  add(ins);
   4269 
   4270  pushResult(ins);
   4271  return true;
   4272 }
   4273 
   4274 bool WarpCacheIRTranspiler::emitMathFunctionNumberResult(
   4275    NumberOperandId inputId, UnaryMathFunction fun) {
   4276  MDefinition* input = getOperand(inputId);
   4277 
   4278  auto* ins = MMathFunction::New(alloc(), input, fun);
   4279  add(ins);
   4280 
   4281  pushResult(ins);
   4282  return true;
   4283 }
   4284 
   4285 bool WarpCacheIRTranspiler::emitMathFloorNumberResult(NumberOperandId inputId) {
   4286  MDefinition* input = getOperand(inputId);
   4287 
   4288  MInstruction* ins;
   4289  if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down)) {
   4290    ins = MNearbyInt::New(alloc(), input, MIRType::Double, RoundingMode::Down);
   4291  } else {
   4292    ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Floor);
   4293  }
   4294  add(ins);
   4295 
   4296  pushResult(ins);
   4297  return true;
   4298 }
   4299 
   4300 bool WarpCacheIRTranspiler::emitMathCeilNumberResult(NumberOperandId inputId) {
   4301  MDefinition* input = getOperand(inputId);
   4302 
   4303  MInstruction* ins;
   4304  if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up)) {
   4305    ins = MNearbyInt::New(alloc(), input, MIRType::Double, RoundingMode::Up);
   4306  } else {
   4307    ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Ceil);
   4308  }
   4309  add(ins);
   4310 
   4311  pushResult(ins);
   4312  return true;
   4313 }
   4314 
   4315 bool WarpCacheIRTranspiler::emitMathTruncNumberResult(NumberOperandId inputId) {
   4316  MDefinition* input = getOperand(inputId);
   4317 
   4318  MInstruction* ins;
   4319  if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero)) {
   4320    ins = MNearbyInt::New(alloc(), input, MIRType::Double,
   4321                          RoundingMode::TowardsZero);
   4322  } else {
   4323    ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Trunc);
   4324  }
   4325  add(ins);
   4326 
   4327  pushResult(ins);
   4328  return true;
   4329 }
   4330 
   4331 bool WarpCacheIRTranspiler::emitMathRoundNumberResult(NumberOperandId inputId) {
   4332  MDefinition* input = getOperand(inputId);
   4333 
   4334  MInstruction* ins;
   4335  if (MRoundToDouble::HasAssemblerSupport()) {
   4336    ins = MRoundToDouble::New(alloc(), input);
   4337  } else {
   4338    ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Round);
   4339  }
   4340  add(ins);
   4341 
   4342  pushResult(ins);
   4343  return true;
   4344 }
   4345 
   4346 bool WarpCacheIRTranspiler::emitNumberParseIntResult(StringOperandId strId,
   4347                                                     Int32OperandId radixId) {
   4348  MDefinition* str = getOperand(strId);
   4349  MDefinition* radix = getOperand(radixId);
   4350 
   4351  auto* ins = MNumberParseInt::New(alloc(), str, radix);
   4352  add(ins);
   4353 
   4354  pushResult(ins);
   4355  return true;
   4356 }
   4357 
   4358 bool WarpCacheIRTranspiler::emitDoubleParseIntResult(NumberOperandId numId) {
   4359  MDefinition* num = getOperand(numId);
   4360 
   4361  auto* ins = MDoubleParseInt::New(alloc(), num);
   4362  add(ins);
   4363 
   4364  pushResult(ins);
   4365  return true;
   4366 }
   4367 
   4368 bool WarpCacheIRTranspiler::emitObjectToStringResult(ObjOperandId objId) {
   4369  MDefinition* obj = getOperand(objId);
   4370 
   4371  auto* ins = MObjectClassToString::New(alloc(), obj);
   4372  add(ins);
   4373 
   4374  pushResult(ins);
   4375  return true;
   4376 }
   4377 
   4378 bool WarpCacheIRTranspiler::emitReflectGetPrototypeOfResult(
   4379    ObjOperandId objId) {
   4380  MDefinition* obj = getOperand(objId);
   4381 
   4382  auto* ins = MGetPrototypeOf::New(alloc(), obj);
   4383  addEffectful(ins);
   4384  pushResult(ins);
   4385 
   4386  return resumeAfter(ins);
   4387 }
   4388 
   4389 bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId,
   4390                                          ValOperandId rhsId) {
   4391  MDefinition* obj = getOperand(objId);
   4392  MDefinition* value = getOperand(rhsId);
   4393 
   4394  auto* ins = MArrayPush::New(alloc(), obj, value);
   4395  addEffectful(ins);
   4396  pushResult(ins);
   4397 
   4398  return resumeAfter(ins);
   4399 }
   4400 
   4401 bool WarpCacheIRTranspiler::emitArrayJoinResult(ObjOperandId objId,
   4402                                                StringOperandId sepId) {
   4403  MDefinition* obj = getOperand(objId);
   4404  MDefinition* sep = getOperand(sepId);
   4405 
   4406  auto* join = MArrayJoin::New(alloc(), obj, sep);
   4407  addEffectful(join);
   4408 
   4409  pushResult(join);
   4410  return resumeAfter(join);
   4411 }
   4412 
   4413 bool WarpCacheIRTranspiler::emitObjectKeysResult(ObjOperandId objId,
   4414                                                 uint32_t resultShapeOffset) {
   4415  MDefinition* obj = getOperand(objId);
   4416  Shape* resultShape = shapeStubField(resultShapeOffset);
   4417 
   4418  auto* join = MObjectKeys::New(alloc(), obj, resultShape);
   4419  addEffectful(join);
   4420 
   4421  pushResult(join);
   4422  return resumeAfter(join);
   4423 }
   4424 
   4425 bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId) {
   4426  MDefinition* array = getOperand(arrayId);
   4427 
   4428  auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Pop);
   4429  addEffectful(ins);
   4430 
   4431  pushResult(ins);
   4432  return resumeAfter(ins);
   4433 }
   4434 
   4435 bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId) {
   4436  MDefinition* array = getOperand(arrayId);
   4437 
   4438  auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Shift);
   4439  addEffectful(ins);
   4440 
   4441  pushResult(ins);
   4442  return resumeAfter(ins);
   4443 }
   4444 
   4445 bool WarpCacheIRTranspiler::emitPackedArraySliceResult(
   4446    uint32_t templateObjectOffset, ObjOperandId arrayId, Int32OperandId beginId,
   4447    Int32OperandId endId) {
   4448  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   4449 
   4450  MDefinition* array = getOperand(arrayId);
   4451  MDefinition* begin = getOperand(beginId);
   4452  MDefinition* end = getOperand(endId);
   4453 
   4454  // TODO: support pre-tenuring.
   4455  gc::Heap heap = gc::Heap::Default;
   4456 
   4457  auto* ins = MArraySlice::New(alloc(), array, begin, end, templateObj, heap);
   4458  addEffectful(ins);
   4459 
   4460  pushResult(ins);
   4461  return resumeAfter(ins);
   4462 }
   4463 
   4464 bool WarpCacheIRTranspiler::emitArgumentsSliceResult(
   4465    uint32_t templateObjectOffset, ObjOperandId argsId, Int32OperandId beginId,
   4466    Int32OperandId endId) {
   4467  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   4468 
   4469  MDefinition* args = getOperand(argsId);
   4470  MDefinition* begin = getOperand(beginId);
   4471  MDefinition* end = getOperand(endId);
   4472 
   4473  // TODO: support pre-tenuring.
   4474  gc::Heap heap = gc::Heap::Default;
   4475 
   4476  auto* ins =
   4477      MArgumentsSlice::New(alloc(), args, begin, end, templateObj, heap);
   4478  addEffectful(ins);
   4479 
   4480  pushResult(ins);
   4481  return resumeAfter(ins);
   4482 }
   4483 
   4484 bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId,
   4485                                               uint32_t claspOffset) {
   4486  MDefinition* obj = getOperand(objId);
   4487  const JSClass* clasp = classStubField(claspOffset);
   4488 
   4489  auto* hasClass = MHasClass::New(alloc(), obj, clasp);
   4490  add(hasClass);
   4491 
   4492  pushResult(hasClass);
   4493  return true;
   4494 }
   4495 
   4496 bool WarpCacheIRTranspiler::emitHasShapeResult(ObjOperandId objId,
   4497                                               uint32_t shapeOffset) {
   4498  MDefinition* obj = getOperand(objId);
   4499  Shape* shape = shapeStubField(shapeOffset);
   4500 
   4501  auto* hasShape = MHasShape::New(alloc(), obj, shape);
   4502  add(hasShape);
   4503 
   4504  pushResult(hasShape);
   4505  return true;
   4506 }
   4507 
   4508 bool WarpCacheIRTranspiler::emitCallRegExpMatcherResult(
   4509    ObjOperandId regexpId, StringOperandId inputId, Int32OperandId lastIndexId,
   4510    uint32_t stubOffset) {
   4511  MDefinition* regexp = getOperand(regexpId);
   4512  MDefinition* input = getOperand(inputId);
   4513  MDefinition* lastIndex = getOperand(lastIndexId);
   4514 
   4515  auto* matcher = MRegExpMatcher::New(alloc(), regexp, input, lastIndex);
   4516  addEffectful(matcher);
   4517  pushResult(matcher);
   4518 
   4519  return resumeAfter(matcher);
   4520 }
   4521 
   4522 bool WarpCacheIRTranspiler::emitCallRegExpSearcherResult(
   4523    ObjOperandId regexpId, StringOperandId inputId, Int32OperandId lastIndexId,
   4524    uint32_t stubOffset) {
   4525  MDefinition* regexp = getOperand(regexpId);
   4526  MDefinition* input = getOperand(inputId);
   4527  MDefinition* lastIndex = getOperand(lastIndexId);
   4528 
   4529  auto* searcher = MRegExpSearcher::New(alloc(), regexp, input, lastIndex);
   4530  addEffectful(searcher);
   4531  pushResult(searcher);
   4532 
   4533  return resumeAfter(searcher);
   4534 }
   4535 
   4536 bool WarpCacheIRTranspiler::emitRegExpSearcherLastLimitResult() {
   4537  auto* limit = MRegExpSearcherLastLimit::New(alloc());
   4538  addEffectful(limit);
   4539  pushResult(limit);
   4540 
   4541  return resumeAfter(limit);
   4542 }
   4543 
   4544 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecMatchResult(
   4545    ObjOperandId regexpId, StringOperandId inputId, uint32_t stubOffset) {
   4546  MDefinition* regexp = getOperand(regexpId);
   4547  MDefinition* input = getOperand(inputId);
   4548 
   4549  auto* ins = MRegExpExecMatch::New(alloc(), regexp, input);
   4550  addEffectful(ins);
   4551  pushResult(ins);
   4552 
   4553  return resumeAfter(ins);
   4554 }
   4555 
   4556 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecTestResult(
   4557    ObjOperandId regexpId, StringOperandId inputId, uint32_t stubOffset) {
   4558  MDefinition* regexp = getOperand(regexpId);
   4559  MDefinition* input = getOperand(inputId);
   4560 
   4561  auto* ins = MRegExpExecTest::New(alloc(), regexp, input);
   4562  addEffectful(ins);
   4563  pushResult(ins);
   4564 
   4565  return resumeAfter(ins);
   4566 }
   4567 
   4568 bool WarpCacheIRTranspiler::emitRegExpHasCaptureGroupsResult(
   4569    ObjOperandId regexpId, StringOperandId inputId) {
   4570  MDefinition* regexp = getOperand(regexpId);
   4571  MDefinition* input = getOperand(inputId);
   4572 
   4573  auto* result = MRegExpHasCaptureGroups::New(alloc(), regexp, input);
   4574  addEffectful(result);
   4575  pushResult(result);
   4576 
   4577  return resumeAfter(result);
   4578 }
   4579 
   4580 MInstruction* WarpCacheIRTranspiler::convertToBoolean(MDefinition* input) {
   4581  // Convert to bool with the '!!' idiom.
   4582  //
   4583  // The FoldTests and GVN passes both specifically handle this pattern. If you
   4584  // change this code, make sure to update FoldTests and GVN, too.
   4585 
   4586  auto* resultInverted = MNot::New(alloc(), input);
   4587  add(resultInverted);
   4588  auto* result = MNot::New(alloc(), resultInverted);
   4589  add(result);
   4590 
   4591  return result;
   4592 }
   4593 
   4594 bool WarpCacheIRTranspiler::emitRegExpFlagResult(ObjOperandId regexpId,
   4595                                                 int32_t flagsMask) {
   4596  MDefinition* regexp = getOperand(regexpId);
   4597 
   4598  auto* flags = MLoadFixedSlot::New(alloc(), regexp, RegExpObject::flagsSlot());
   4599  flags->setResultType(MIRType::Int32);
   4600  add(flags);
   4601 
   4602  auto* mask = MConstant::NewInt32(alloc(), flagsMask);
   4603  add(mask);
   4604 
   4605  auto* maskedFlag = MBitAnd::New(alloc(), flags, mask, MIRType::Int32);
   4606  add(maskedFlag);
   4607 
   4608  auto* result = convertToBoolean(maskedFlag);
   4609 
   4610  pushResult(result);
   4611  return true;
   4612 }
   4613 
   4614 bool WarpCacheIRTranspiler::emitCallSubstringKernelResult(
   4615    StringOperandId strId, Int32OperandId beginId, Int32OperandId lengthId) {
   4616  MDefinition* str = getOperand(strId);
   4617  MDefinition* begin = getOperand(beginId);
   4618  MDefinition* length = getOperand(lengthId);
   4619 
   4620  auto* substr = MSubstr::New(alloc(), str, begin, length);
   4621  add(substr);
   4622 
   4623  pushResult(substr);
   4624  return true;
   4625 }
   4626 
   4627 bool WarpCacheIRTranspiler::emitStringReplaceStringResult(
   4628    StringOperandId strId, StringOperandId patternId,
   4629    StringOperandId replacementId) {
   4630  MDefinition* str = getOperand(strId);
   4631  MDefinition* pattern = getOperand(patternId);
   4632  MDefinition* replacement = getOperand(replacementId);
   4633 
   4634  auto* replace = MStringReplace::New(alloc(), str, pattern, replacement);
   4635  add(replace);
   4636 
   4637  pushResult(replace);
   4638  return true;
   4639 }
   4640 
   4641 bool WarpCacheIRTranspiler::emitStringSplitStringResult(
   4642    StringOperandId strId, StringOperandId separatorId) {
   4643  MDefinition* str = getOperand(strId);
   4644  MDefinition* separator = getOperand(separatorId);
   4645 
   4646  auto* split = MStringSplit::New(alloc(), str, separator);
   4647  add(split);
   4648 
   4649  pushResult(split);
   4650  return true;
   4651 }
   4652 
   4653 bool WarpCacheIRTranspiler::emitGetFirstDollarIndexResult(
   4654    StringOperandId strId) {
   4655  MDefinition* str = getOperand(strId);
   4656 
   4657  auto* firstDollarIndex = MGetFirstDollarIndex::New(alloc(), str);
   4658  add(firstDollarIndex);
   4659 
   4660  pushResult(firstDollarIndex);
   4661  return true;
   4662 }
   4663 
   4664 bool WarpCacheIRTranspiler::emitIsArrayResult(ValOperandId inputId) {
   4665  MDefinition* value = getOperand(inputId);
   4666 
   4667  auto* isArray = MIsArray::New(alloc(), value);
   4668  addEffectful(isArray);
   4669  pushResult(isArray);
   4670 
   4671  return resumeAfter(isArray);
   4672 }
   4673 
   4674 bool WarpCacheIRTranspiler::emitIsObjectResult(ValOperandId inputId) {
   4675  MDefinition* value = getOperand(inputId);
   4676 
   4677  if (value->type() == MIRType::Object) {
   4678    pushResult(constant(BooleanValue(true)));
   4679  } else {
   4680    auto* isObject = MIsObject::New(alloc(), value);
   4681    add(isObject);
   4682    pushResult(isObject);
   4683  }
   4684 
   4685  return true;
   4686 }
   4687 
   4688 bool WarpCacheIRTranspiler::emitIsPackedArrayResult(ObjOperandId objId) {
   4689  MDefinition* obj = getOperand(objId);
   4690 
   4691  auto* isPackedArray = MIsPackedArray::New(alloc(), obj);
   4692  add(isPackedArray);
   4693 
   4694  pushResult(isPackedArray);
   4695  return true;
   4696 }
   4697 
   4698 bool WarpCacheIRTranspiler::emitIsCallableResult(ValOperandId inputId) {
   4699  MDefinition* value = getOperand(inputId);
   4700 
   4701  auto* isCallable = MIsCallable::New(alloc(), value);
   4702  add(isCallable);
   4703 
   4704  pushResult(isCallable);
   4705  return true;
   4706 }
   4707 
   4708 bool WarpCacheIRTranspiler::emitIsConstructorResult(ObjOperandId objId) {
   4709  MDefinition* obj = getOperand(objId);
   4710 
   4711  auto* isConstructor = MIsConstructor::New(alloc(), obj);
   4712  add(isConstructor);
   4713 
   4714  pushResult(isConstructor);
   4715  return true;
   4716 }
   4717 
   4718 bool WarpCacheIRTranspiler::emitIsCrossRealmArrayConstructorResult(
   4719    ObjOperandId objId) {
   4720  MDefinition* obj = getOperand(objId);
   4721 
   4722  auto* ins = MIsCrossRealmArrayConstructor::New(alloc(), obj);
   4723  add(ins);
   4724 
   4725  pushResult(ins);
   4726  return true;
   4727 }
   4728 
   4729 bool WarpCacheIRTranspiler::emitIsTypedArrayResult(ObjOperandId objId,
   4730                                                   bool isPossiblyWrapped) {
   4731  MDefinition* obj = getOperand(objId);
   4732 
   4733  auto* ins = MIsTypedArray::New(alloc(), obj, isPossiblyWrapped);
   4734  if (isPossiblyWrapped) {
   4735    addEffectful(ins);
   4736  } else {
   4737    add(ins);
   4738  }
   4739 
   4740  pushResult(ins);
   4741 
   4742  if (isPossiblyWrapped) {
   4743    if (!resumeAfter(ins)) {
   4744      return false;
   4745    }
   4746  }
   4747 
   4748  return true;
   4749 }
   4750 
   4751 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetInt32Result(
   4752    ObjOperandId objId) {
   4753  MDefinition* obj = getOperand(objId);
   4754 
   4755  auto* byteOffset = MArrayBufferViewByteOffset::New(alloc(), obj);
   4756  add(byteOffset);
   4757 
   4758  auto* byteOffsetInt32 = MNonNegativeIntPtrToInt32::New(alloc(), byteOffset);
   4759  add(byteOffsetInt32);
   4760 
   4761  pushResult(byteOffsetInt32);
   4762  return true;
   4763 }
   4764 
   4765 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetDoubleResult(
   4766    ObjOperandId objId) {
   4767  MDefinition* obj = getOperand(objId);
   4768 
   4769  auto* byteOffset = MArrayBufferViewByteOffset::New(alloc(), obj);
   4770  add(byteOffset);
   4771 
   4772  auto* byteOffsetDouble = MIntPtrToDouble::New(alloc(), byteOffset);
   4773  add(byteOffsetDouble);
   4774 
   4775  pushResult(byteOffsetDouble);
   4776  return true;
   4777 }
   4778 
   4779 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthInt32Result(
   4780    ObjOperandId objId) {
   4781  MDefinition* obj = getOperand(objId);
   4782 
   4783  // Explicit |length| accesses are seq-consistent atomic loads.
   4784  auto barrier = MemoryBarrierRequirement::Required;
   4785 
   4786  auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier);
   4787  addEffectful(length);
   4788 
   4789  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   4790  add(lengthInt32);
   4791 
   4792  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32);
   4793  add(postConversion);
   4794 
   4795  pushResult(postConversion);
   4796  return resumeAfterUnchecked(postConversion);
   4797 }
   4798 
   4799 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthDoubleResult(
   4800    ObjOperandId objId) {
   4801  MDefinition* obj = getOperand(objId);
   4802 
   4803  // Explicit |length| accesses are seq-consistent atomic loads.
   4804  auto barrier = MemoryBarrierRequirement::Required;
   4805 
   4806  auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier);
   4807  addEffectful(length);
   4808 
   4809  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   4810  add(lengthDouble);
   4811 
   4812  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble);
   4813  add(postConversion);
   4814 
   4815  pushResult(postConversion);
   4816  return resumeAfterUnchecked(postConversion);
   4817 }
   4818 
   4819 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthInt32Result(
   4820    ObjOperandId objId) {
   4821  MDefinition* obj = getOperand(objId);
   4822 
   4823  auto* length = MArrayBufferViewLength::New(alloc(), obj);
   4824  add(length);
   4825 
   4826  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   4827  add(lengthInt32);
   4828 
   4829  auto* size = MTypedArrayElementSize::New(alloc(), obj);
   4830  add(size);
   4831 
   4832  auto* mul = MMul::New(alloc(), lengthInt32, size, MIRType::Int32);
   4833  mul->setCanBeNegativeZero(false);
   4834  add(mul);
   4835 
   4836  pushResult(mul);
   4837  return true;
   4838 }
   4839 
   4840 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthDoubleResult(
   4841    ObjOperandId objId) {
   4842  MDefinition* obj = getOperand(objId);
   4843 
   4844  auto* length = MArrayBufferViewLength::New(alloc(), obj);
   4845  add(length);
   4846 
   4847  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   4848  add(lengthDouble);
   4849 
   4850  auto* size = MTypedArrayElementSize::New(alloc(), obj);
   4851  add(size);
   4852 
   4853  auto* sizeDouble = MToDouble::New(alloc(), size);
   4854  add(sizeDouble);
   4855 
   4856  auto* mul = MMul::New(alloc(), lengthDouble, sizeDouble, MIRType::Double);
   4857  mul->setCanBeNegativeZero(false);
   4858  add(mul);
   4859 
   4860  pushResult(mul);
   4861  return true;
   4862 }
   4863 
   4864 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthInt32Result(
   4865    ObjOperandId objId) {
   4866  MDefinition* obj = getOperand(objId);
   4867 
   4868  // Explicit |byteLength| accesses are seq-consistent atomic loads.
   4869  auto barrier = MemoryBarrierRequirement::Required;
   4870 
   4871  auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier);
   4872  addEffectful(length);
   4873 
   4874  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   4875  add(lengthInt32);
   4876 
   4877  auto* size = MTypedArrayElementSize::New(alloc(), obj);
   4878  add(size);
   4879 
   4880  auto* mul = MMul::New(alloc(), lengthInt32, size, MIRType::Int32);
   4881  mul->setCanBeNegativeZero(false);
   4882  add(mul);
   4883 
   4884  auto* postConversion = MPostIntPtrConversion::New(alloc(), mul);
   4885  add(postConversion);
   4886 
   4887  pushResult(postConversion);
   4888  return resumeAfterUnchecked(postConversion);
   4889 }
   4890 
   4891 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthDoubleResult(
   4892    ObjOperandId objId) {
   4893  MDefinition* obj = getOperand(objId);
   4894 
   4895  // Explicit |byteLength| accesses are seq-consistent atomic loads.
   4896  auto barrier = MemoryBarrierRequirement::Required;
   4897 
   4898  auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier);
   4899  addEffectful(length);
   4900 
   4901  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   4902  add(lengthDouble);
   4903 
   4904  auto* size = MTypedArrayElementSize::New(alloc(), obj);
   4905  add(size);
   4906 
   4907  auto* sizeDouble = MToDouble::New(alloc(), size);
   4908  add(sizeDouble);
   4909 
   4910  auto* mul = MMul::New(alloc(), lengthDouble, sizeDouble, MIRType::Double);
   4911  mul->setCanBeNegativeZero(false);
   4912  add(mul);
   4913 
   4914  auto* postConversion = MPostIntPtrConversion::New(alloc(), mul);
   4915  add(postConversion);
   4916 
   4917  pushResult(postConversion);
   4918  return resumeAfterUnchecked(postConversion);
   4919 }
   4920 
   4921 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthInt32Result(
   4922    ObjOperandId objId) {
   4923  MDefinition* obj = getOperand(objId);
   4924 
   4925  // Explicit |byteLength| accesses are seq-consistent atomic loads.
   4926  auto barrier = MemoryBarrierRequirement::Required;
   4927 
   4928  auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier);
   4929  addEffectful(length);
   4930 
   4931  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   4932  add(lengthInt32);
   4933 
   4934  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32);
   4935  add(postConversion);
   4936 
   4937  pushResult(postConversion);
   4938  return resumeAfterUnchecked(postConversion);
   4939 }
   4940 
   4941 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthDoubleResult(
   4942    ObjOperandId objId) {
   4943  MDefinition* obj = getOperand(objId);
   4944 
   4945  // Explicit |byteLength| accesses are seq-consistent atomic loads.
   4946  auto barrier = MemoryBarrierRequirement::Required;
   4947 
   4948  auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier);
   4949  addEffectful(length);
   4950 
   4951  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   4952  add(lengthDouble);
   4953 
   4954  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble);
   4955  add(postConversion);
   4956 
   4957  pushResult(postConversion);
   4958  return resumeAfterUnchecked(postConversion);
   4959 }
   4960 
   4961 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthInt32Result(
   4962    ObjOperandId objId) {
   4963  MDefinition* obj = getOperand(objId);
   4964 
   4965  auto* length = MGrowableSharedArrayBufferByteLength::New(alloc(), obj);
   4966  addEffectful(length);
   4967 
   4968  auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length);
   4969  add(lengthInt32);
   4970 
   4971  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32);
   4972  add(postConversion);
   4973 
   4974  pushResult(postConversion);
   4975  return resumeAfterUnchecked(postConversion);
   4976 }
   4977 
   4978 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthDoubleResult(
   4979    ObjOperandId objId) {
   4980  MDefinition* obj = getOperand(objId);
   4981 
   4982  auto* length = MGrowableSharedArrayBufferByteLength::New(alloc(), obj);
   4983  addEffectful(length);
   4984 
   4985  auto* lengthDouble = MIntPtrToDouble::New(alloc(), length);
   4986  add(lengthDouble);
   4987 
   4988  auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble);
   4989  add(postConversion);
   4990 
   4991  pushResult(postConversion);
   4992  return resumeAfterUnchecked(postConversion);
   4993 }
   4994 
   4995 bool WarpCacheIRTranspiler::emitGuardHasAttachedArrayBuffer(
   4996    ObjOperandId objId) {
   4997  MDefinition* obj = getOperand(objId);
   4998 
   4999  auto* ins = MGuardHasAttachedArrayBuffer::New(alloc(), obj);
   5000  add(ins);
   5001 
   5002  setOperand(objId, ins);
   5003  return true;
   5004 }
   5005 
   5006 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBounds(
   5007    ObjOperandId objId) {
   5008  MDefinition* obj = getOperand(objId);
   5009 
   5010  auto* ins = MGuardResizableArrayBufferViewInBounds::New(alloc(), obj);
   5011  add(ins);
   5012 
   5013  setOperand(objId, ins);
   5014  return true;
   5015 }
   5016 
   5017 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBoundsOrDetached(
   5018    ObjOperandId objId) {
   5019  MDefinition* obj = getOperand(objId);
   5020 
   5021  auto* ins =
   5022      MGuardResizableArrayBufferViewInBoundsOrDetached::New(alloc(), obj);
   5023  add(ins);
   5024 
   5025  setOperand(objId, ins);
   5026  return true;
   5027 }
   5028 
   5029 bool WarpCacheIRTranspiler::emitIsTypedArrayConstructorResult(
   5030    ObjOperandId objId) {
   5031  MDefinition* obj = getOperand(objId);
   5032 
   5033  auto* ins = MIsTypedArrayConstructor::New(alloc(), obj);
   5034  add(ins);
   5035 
   5036  pushResult(ins);
   5037  return true;
   5038 }
   5039 
   5040 bool WarpCacheIRTranspiler::emitGetNextMapSetEntryForIteratorResult(
   5041    ObjOperandId iterId, ObjOperandId resultArrId, bool isMap) {
   5042  MDefinition* iter = getOperand(iterId);
   5043  MDefinition* resultArr = getOperand(resultArrId);
   5044 
   5045  MGetNextEntryForIterator::Mode mode =
   5046      isMap ? MGetNextEntryForIterator::Map : MGetNextEntryForIterator::Set;
   5047  auto* ins = MGetNextEntryForIterator::New(alloc(), iter, resultArr, mode);
   5048  addEffectful(ins);
   5049  pushResult(ins);
   5050 
   5051  return resumeAfter(ins);
   5052 }
   5053 
   5054 bool WarpCacheIRTranspiler::emitFrameIsConstructingResult() {
   5055  if (const CallInfo* callInfo = builder_->inlineCallInfo()) {
   5056    auto* ins = constant(BooleanValue(callInfo->constructing()));
   5057    pushResult(ins);
   5058    return true;
   5059  }
   5060 
   5061  auto* ins = MIsConstructing::New(alloc());
   5062  add(ins);
   5063  pushResult(ins);
   5064  return true;
   5065 }
   5066 
   5067 bool WarpCacheIRTranspiler::emitNewIteratorResult(
   5068    MNewIterator::Type type, uint32_t templateObjectOffset) {
   5069  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   5070 
   5071  auto* templateConst = constant(ObjectValue(*templateObj));
   5072  auto* iter = MNewIterator::New(alloc(), templateConst, type);
   5073  add(iter);
   5074 
   5075  pushResult(iter);
   5076  return true;
   5077 }
   5078 
   5079 bool WarpCacheIRTranspiler::emitNewArrayIteratorResult(
   5080    uint32_t templateObjectOffset) {
   5081  return emitNewIteratorResult(MNewIterator::ArrayIterator,
   5082                               templateObjectOffset);
   5083 }
   5084 
   5085 bool WarpCacheIRTranspiler::emitNewStringIteratorResult(
   5086    uint32_t templateObjectOffset) {
   5087  return emitNewIteratorResult(MNewIterator::StringIterator,
   5088                               templateObjectOffset);
   5089 }
   5090 
   5091 bool WarpCacheIRTranspiler::emitNewRegExpStringIteratorResult(
   5092    uint32_t templateObjectOffset) {
   5093  return emitNewIteratorResult(MNewIterator::RegExpStringIterator,
   5094                               templateObjectOffset);
   5095 }
   5096 
   5097 bool WarpCacheIRTranspiler::emitObjectCreateResult(
   5098    uint32_t templateObjectOffset) {
   5099  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   5100 
   5101  auto* templateConst = constant(ObjectValue(*templateObj));
   5102 
   5103  // TODO: support pre-tenuring.
   5104  gc::Heap heap = gc::Heap::Default;
   5105  auto* obj =
   5106      MNewObject::New(alloc(), templateConst, heap, MNewObject::ObjectCreate);
   5107  addEffectful(obj);
   5108 
   5109  pushResult(obj);
   5110  return resumeAfter(obj);
   5111 }
   5112 
   5113 bool WarpCacheIRTranspiler::emitNewArrayFromLengthResult(
   5114    uint32_t templateObjectOffset, Int32OperandId lengthId,
   5115    uint32_t siteOffset) {
   5116  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   5117  MDefinition* length = getOperand(lengthId);
   5118  gc::Heap heap = allocSiteInitialHeapField(siteOffset);
   5119 
   5120  if (length->isConstant()) {
   5121    int32_t lenInt32 = length->toConstant()->toInt32();
   5122    if (lenInt32 >= 0 &&
   5123        uint32_t(lenInt32) == templateObj->as<ArrayObject>().length()) {
   5124      uint32_t len = uint32_t(lenInt32);
   5125      auto* templateConst = constant(ObjectValue(*templateObj));
   5126 
   5127      size_t inlineLength =
   5128          gc::GetGCKindSlots(templateObj->asTenured().getAllocKind()) -
   5129          ObjectElements::VALUES_PER_HEADER;
   5130 
   5131      MNewArray* obj;
   5132      if (len > inlineLength) {
   5133        obj = MNewArray::NewVM(alloc(), len, templateConst, heap);
   5134      } else {
   5135        obj = MNewArray::New(alloc(), len, templateConst, heap);
   5136      }
   5137      add(obj);
   5138      pushResult(obj);
   5139      return true;
   5140    }
   5141  }
   5142 
   5143  auto* obj = MNewArrayDynamicLength::New(alloc(), length, templateObj, heap);
   5144  addEffectful(obj);
   5145  pushResult(obj);
   5146  return resumeAfter(obj);
   5147 }
   5148 
   5149 bool WarpCacheIRTranspiler::emitNewTypedArrayFromLengthResult(
   5150    uint32_t templateObjectOffset, Int32OperandId lengthId) {
   5151  auto* templateObj = &tenuredObjectStubField(templateObjectOffset)
   5152                           ->as<FixedLengthTypedArrayObject>();
   5153  MDefinition* length = getOperand(lengthId);
   5154 
   5155  // TODO: support pre-tenuring.
   5156  gc::Heap heap = gc::Heap::Default;
   5157 
   5158  if (length->isConstant()) {
   5159    int32_t len = length->toConstant()->toInt32();
   5160    if (len >= 0 && uint32_t(len) == templateObj->length()) {
   5161      auto* templateConst = constant(ObjectValue(*templateObj));
   5162      auto* obj = MNewTypedArray::New(alloc(), templateConst, heap);
   5163      add(obj);
   5164      pushResult(obj);
   5165      return true;
   5166    }
   5167  }
   5168 
   5169  auto* obj =
   5170      MNewTypedArrayDynamicLength::New(alloc(), length, templateObj, heap);
   5171  addEffectful(obj);
   5172  pushResult(obj);
   5173  return resumeAfter(obj);
   5174 }
   5175 
   5176 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayBufferResult(
   5177    uint32_t templateObjectOffset, ObjOperandId bufferId,
   5178    ValOperandId byteOffsetId, ValOperandId lengthId) {
   5179  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   5180  MDefinition* buffer = getOperand(bufferId);
   5181  MDefinition* byteOffset = getOperand(byteOffsetId);
   5182  MDefinition* length = getOperand(lengthId);
   5183 
   5184  // TODO: support pre-tenuring.
   5185  gc::Heap heap = gc::Heap::Default;
   5186 
   5187  auto* obj = MNewTypedArrayFromArrayBuffer::New(alloc(), buffer, byteOffset,
   5188                                                 length, templateObj, heap);
   5189  addEffectful(obj);
   5190 
   5191  pushResult(obj);
   5192  return resumeAfter(obj);
   5193 }
   5194 
   5195 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayResult(
   5196    uint32_t templateObjectOffset, ObjOperandId arrayId) {
   5197  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   5198  MDefinition* array = getOperand(arrayId);
   5199 
   5200  // TODO: support pre-tenuring.
   5201  gc::Heap heap = gc::Heap::Default;
   5202 
   5203  auto* obj = MNewTypedArrayFromArray::New(alloc(), array, templateObj, heap);
   5204  addEffectful(obj);
   5205 
   5206  pushResult(obj);
   5207  return resumeAfter(obj);
   5208 }
   5209 
   5210 bool WarpCacheIRTranspiler::emitAtomicsCompareExchangeResult(
   5211    ObjOperandId objId, IntPtrOperandId indexId, uint32_t expectedId,
   5212    uint32_t replacementId, Scalar::Type elementType,
   5213    ArrayBufferViewKind viewKind) {
   5214  MDefinition* obj = getOperand(objId);
   5215  MDefinition* index = getOperand(indexId);
   5216  MDefinition* expected = getOperand(ValOperandId(expectedId));
   5217  MDefinition* replacement = getOperand(ValOperandId(replacementId));
   5218 
   5219  auto* length = emitTypedArrayLength(viewKind, obj);
   5220 
   5221  index = addBoundsCheck(index, length);
   5222 
   5223  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   5224  add(elements);
   5225 
   5226  bool forceDoubleForUint32 = true;
   5227  MIRType knownType =
   5228      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32);
   5229 
   5230  auto* cas = MCompareExchangeTypedArrayElement::New(
   5231      alloc(), elements, index, elementType, expected, replacement);
   5232  cas->setResultType(knownType);
   5233  addEffectful(cas);
   5234 
   5235  MInstruction* result = cas;
   5236  if (Scalar::isBigIntType(elementType)) {
   5237    result =
   5238        MInt64ToBigInt::New(alloc(), cas, Scalar::isSignedIntType(elementType));
   5239 
   5240    // Make non-movable so we can attach a resume point.
   5241    result->setNotMovable();
   5242 
   5243    add(result);
   5244  }
   5245 
   5246  pushResult(result);
   5247  return resumeAfterUnchecked(result);
   5248 }
   5249 
   5250 bool WarpCacheIRTranspiler::emitAtomicsExchangeResult(
   5251    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5252    Scalar::Type elementType, ArrayBufferViewKind viewKind) {
   5253  MDefinition* obj = getOperand(objId);
   5254  MDefinition* index = getOperand(indexId);
   5255  MDefinition* value = getOperand(ValOperandId(valueId));
   5256 
   5257  auto* length = emitTypedArrayLength(viewKind, obj);
   5258 
   5259  index = addBoundsCheck(index, length);
   5260 
   5261  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   5262  add(elements);
   5263 
   5264  bool forceDoubleForUint32 = true;
   5265  MIRType knownType =
   5266      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32);
   5267 
   5268  auto* exchange = MAtomicExchangeTypedArrayElement::New(
   5269      alloc(), elements, index, value, elementType);
   5270  exchange->setResultType(knownType);
   5271  addEffectful(exchange);
   5272 
   5273  MInstruction* result = exchange;
   5274  if (Scalar::isBigIntType(elementType)) {
   5275    result = MInt64ToBigInt::New(alloc(), exchange,
   5276                                 Scalar::isSignedIntType(elementType));
   5277 
   5278    // Make non-movable so we can attach a resume point.
   5279    result->setNotMovable();
   5280 
   5281    add(result);
   5282  }
   5283 
   5284  pushResult(result);
   5285  return resumeAfterUnchecked(result);
   5286 }
   5287 
   5288 bool WarpCacheIRTranspiler::emitAtomicsBinaryOp(
   5289    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5290    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind,
   5291    AtomicOp op) {
   5292  MDefinition* obj = getOperand(objId);
   5293  MDefinition* index = getOperand(indexId);
   5294  MDefinition* value = getOperand(ValOperandId(valueId));
   5295 
   5296  auto* length = emitTypedArrayLength(viewKind, obj);
   5297 
   5298  index = addBoundsCheck(index, length);
   5299 
   5300  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   5301  add(elements);
   5302 
   5303  bool forceDoubleForUint32 = true;
   5304  MIRType knownType =
   5305      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32);
   5306 
   5307  auto* binop = MAtomicTypedArrayElementBinop::New(
   5308      alloc(), op, elements, index, elementType, value, forEffect);
   5309  if (!forEffect) {
   5310    binop->setResultType(knownType);
   5311  }
   5312  addEffectful(binop);
   5313 
   5314  if (forEffect) {
   5315    pushResult(constant(UndefinedValue()));
   5316    return resumeAfter(binop);
   5317  }
   5318 
   5319  MInstruction* result = binop;
   5320  if (Scalar::isBigIntType(elementType)) {
   5321    result = MInt64ToBigInt::New(alloc(), binop,
   5322                                 Scalar::isSignedIntType(elementType));
   5323 
   5324    // Make non-movable so we can attach a resume point.
   5325    result->setNotMovable();
   5326 
   5327    add(result);
   5328  }
   5329 
   5330  pushResult(result);
   5331  return resumeAfterUnchecked(result);
   5332 }
   5333 
   5334 bool WarpCacheIRTranspiler::emitAtomicsAddResult(
   5335    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5336    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) {
   5337  return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect,
   5338                             viewKind, AtomicOp::Add);
   5339 }
   5340 
   5341 bool WarpCacheIRTranspiler::emitAtomicsSubResult(
   5342    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5343    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) {
   5344  return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect,
   5345                             viewKind, AtomicOp::Sub);
   5346 }
   5347 
   5348 bool WarpCacheIRTranspiler::emitAtomicsAndResult(
   5349    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5350    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) {
   5351  return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect,
   5352                             viewKind, AtomicOp::And);
   5353 }
   5354 
   5355 bool WarpCacheIRTranspiler::emitAtomicsOrResult(
   5356    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5357    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) {
   5358  return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect,
   5359                             viewKind, AtomicOp::Or);
   5360 }
   5361 
   5362 bool WarpCacheIRTranspiler::emitAtomicsXorResult(
   5363    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5364    Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) {
   5365  return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect,
   5366                             viewKind, AtomicOp::Xor);
   5367 }
   5368 
   5369 bool WarpCacheIRTranspiler::emitAtomicsLoadResult(
   5370    ObjOperandId objId, IntPtrOperandId indexId, Scalar::Type elementType,
   5371    ArrayBufferViewKind viewKind) {
   5372  MDefinition* obj = getOperand(objId);
   5373  MDefinition* index = getOperand(indexId);
   5374 
   5375  auto* length = emitTypedArrayLength(viewKind, obj);
   5376 
   5377  index = addBoundsCheck(index, length);
   5378 
   5379  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   5380  add(elements);
   5381 
   5382  bool forceDoubleForUint32 = true;
   5383  MIRType knownType =
   5384      MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32);
   5385 
   5386  auto* load = MLoadUnboxedScalar::New(alloc(), elements, index, elementType,
   5387                                       MemoryBarrierRequirement::Required);
   5388  load->setResultType(knownType);
   5389  addEffectful(load);
   5390 
   5391  MInstruction* result = load;
   5392  if (Scalar::isBigIntType(elementType)) {
   5393    result = MInt64ToBigInt::New(alloc(), load,
   5394                                 Scalar::isSignedIntType(elementType));
   5395 
   5396    // Make non-movable so we can attach a resume point.
   5397    result->setNotMovable();
   5398 
   5399    add(result);
   5400  }
   5401 
   5402  pushResult(result);
   5403  return resumeAfterUnchecked(result);
   5404 }
   5405 
   5406 bool WarpCacheIRTranspiler::emitAtomicsStoreResult(
   5407    ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId,
   5408    Scalar::Type elementType, ArrayBufferViewKind viewKind) {
   5409  MDefinition* obj = getOperand(objId);
   5410  MDefinition* index = getOperand(indexId);
   5411  MDefinition* value = getOperand(ValOperandId(valueId));
   5412 
   5413  auto* length = emitTypedArrayLength(viewKind, obj);
   5414 
   5415  index = addBoundsCheck(index, length);
   5416 
   5417  auto* elements = MArrayBufferViewElements::New(alloc(), obj);
   5418  add(elements);
   5419 
   5420  auto* store =
   5421      MStoreUnboxedScalar::New(alloc(), elements, index, value, elementType,
   5422                               MemoryBarrierRequirement::Required);
   5423  addEffectful(store);
   5424 
   5425  pushResult(value);
   5426  return resumeAfter(store);
   5427 }
   5428 
   5429 bool WarpCacheIRTranspiler::emitAtomicsIsLockFreeResult(
   5430    Int32OperandId valueId) {
   5431  MDefinition* value = getOperand(valueId);
   5432 
   5433  auto* ilf = MAtomicIsLockFree::New(alloc(), value);
   5434  add(ilf);
   5435 
   5436  pushResult(ilf);
   5437  return true;
   5438 }
   5439 
   5440 bool WarpCacheIRTranspiler::emitAtomicsPauseResult() {
   5441  auto* ins = MAtomicPause::New(alloc());
   5442  add(ins);
   5443 
   5444  pushResult(constant(UndefinedValue()));
   5445  return true;
   5446 }
   5447 
   5448 bool WarpCacheIRTranspiler::emitBigIntAsIntNResult(Int32OperandId bitsId,
   5449                                                   BigIntOperandId bigIntId) {
   5450  MDefinition* bits = getOperand(bitsId);
   5451  MDefinition* bigInt = getOperand(bigIntId);
   5452 
   5453  auto* ins = MBigIntAsIntN::New(alloc(), bits, bigInt);
   5454  add(ins);
   5455 
   5456  pushResult(ins);
   5457  return true;
   5458 }
   5459 
   5460 bool WarpCacheIRTranspiler::emitBigIntAsUintNResult(Int32OperandId bitsId,
   5461                                                    BigIntOperandId bigIntId) {
   5462  MDefinition* bits = getOperand(bitsId);
   5463  MDefinition* bigInt = getOperand(bigIntId);
   5464 
   5465  auto* ins = MBigIntAsUintN::New(alloc(), bits, bigInt);
   5466  add(ins);
   5467 
   5468  pushResult(ins);
   5469  return true;
   5470 }
   5471 
   5472 bool WarpCacheIRTranspiler::emitGuardToNonGCThing(ValOperandId inputId) {
   5473  MDefinition* def = getOperand(inputId);
   5474  if (IsNonGCThing(def->type())) {
   5475    return true;
   5476  }
   5477 
   5478  auto* ins = MGuardNonGCThing::New(alloc(), def);
   5479  add(ins);
   5480 
   5481  setOperand(inputId, ins);
   5482  return true;
   5483 }
   5484 
   5485 bool WarpCacheIRTranspiler::emitSetHasNonGCThingResult(ObjOperandId setId,
   5486                                                       ValOperandId valId) {
   5487  MDefinition* set = getOperand(setId);
   5488  MDefinition* val = getOperand(valId);
   5489 
   5490  auto* hashValue = MToHashableNonGCThing::New(alloc(), val);
   5491  add(hashValue);
   5492 
   5493  auto* hash = MHashNonGCThing::New(alloc(), hashValue);
   5494  add(hash);
   5495 
   5496  auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, hashValue, hash);
   5497  add(ins);
   5498 
   5499  pushResult(ins);
   5500  return true;
   5501 }
   5502 
   5503 bool WarpCacheIRTranspiler::emitSetHasStringResult(ObjOperandId setId,
   5504                                                   StringOperandId strId) {
   5505  MDefinition* set = getOperand(setId);
   5506  MDefinition* str = getOperand(strId);
   5507 
   5508  auto* hashValue = MToHashableString::New(alloc(), str);
   5509  add(hashValue);
   5510 
   5511  auto* hash = MHashString::New(alloc(), hashValue);
   5512  add(hash);
   5513 
   5514  auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, hashValue, hash);
   5515  add(ins);
   5516 
   5517  pushResult(ins);
   5518  return true;
   5519 }
   5520 
   5521 bool WarpCacheIRTranspiler::emitSetHasSymbolResult(ObjOperandId setId,
   5522                                                   SymbolOperandId symId) {
   5523  MDefinition* set = getOperand(setId);
   5524  MDefinition* sym = getOperand(symId);
   5525 
   5526  auto* hash = MHashSymbol::New(alloc(), sym);
   5527  add(hash);
   5528 
   5529  auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, sym, hash);
   5530  add(ins);
   5531 
   5532  pushResult(ins);
   5533  return true;
   5534 }
   5535 
   5536 bool WarpCacheIRTranspiler::emitSetHasBigIntResult(ObjOperandId setId,
   5537                                                   BigIntOperandId bigIntId) {
   5538  MDefinition* set = getOperand(setId);
   5539  MDefinition* bigInt = getOperand(bigIntId);
   5540 
   5541  auto* hash = MHashBigInt::New(alloc(), bigInt);
   5542  add(hash);
   5543 
   5544  auto* ins = MSetObjectHasBigInt::New(alloc(), set, bigInt, hash);
   5545  add(ins);
   5546 
   5547  pushResult(ins);
   5548  return true;
   5549 }
   5550 
   5551 bool WarpCacheIRTranspiler::emitSetHasObjectResult(ObjOperandId setId,
   5552                                                   ObjOperandId objId) {
   5553  MDefinition* set = getOperand(setId);
   5554  MDefinition* obj = getOperand(objId);
   5555 
   5556  auto* hash = MHashObject::New(alloc(), set, obj);
   5557  add(hash);
   5558 
   5559  auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, obj, hash);
   5560  add(ins);
   5561 
   5562  pushResult(ins);
   5563  return true;
   5564 }
   5565 
   5566 bool WarpCacheIRTranspiler::emitSetHasResult(ObjOperandId setId,
   5567                                             ValOperandId valId) {
   5568  MDefinition* set = getOperand(setId);
   5569  MDefinition* val = getOperand(valId);
   5570 
   5571 #ifdef JS_PUNBOX64
   5572  auto* hashValue = MToHashableValue::New(alloc(), val);
   5573  add(hashValue);
   5574 
   5575  auto* hash = MHashValue::New(alloc(), set, hashValue);
   5576  add(hash);
   5577 
   5578  auto* ins = MSetObjectHasValue::New(alloc(), set, hashValue, hash);
   5579  add(ins);
   5580 #else
   5581  auto* ins = MSetObjectHasValueVMCall::New(alloc(), set, val);
   5582  add(ins);
   5583 #endif
   5584 
   5585  pushResult(ins);
   5586  return true;
   5587 }
   5588 
   5589 bool WarpCacheIRTranspiler::emitSetDeleteResult(ObjOperandId setId,
   5590                                                ValOperandId keyId) {
   5591  MDefinition* set = getOperand(setId);
   5592  MDefinition* key = getOperand(keyId);
   5593 
   5594  auto* ins = MSetObjectDelete::New(alloc(), set, key);
   5595  addEffectful(ins);
   5596 
   5597  pushResult(ins);
   5598  return resumeAfter(ins);
   5599 }
   5600 
   5601 bool WarpCacheIRTranspiler::emitSetAddResult(ObjOperandId setId,
   5602                                             ValOperandId keyId) {
   5603  MDefinition* set = getOperand(setId);
   5604  MDefinition* key = getOperand(keyId);
   5605 
   5606  auto* ins = MSetObjectAdd::New(alloc(), set, key);
   5607  addEffectful(ins);
   5608 
   5609  pushResult(set);
   5610  return resumeAfter(ins);
   5611 }
   5612 
   5613 bool WarpCacheIRTranspiler::emitSetSizeResult(ObjOperandId setId) {
   5614  MDefinition* set = getOperand(setId);
   5615 
   5616  auto* ins = MSetObjectSize::New(alloc(), set);
   5617  add(ins);
   5618 
   5619  pushResult(ins);
   5620  return true;
   5621 }
   5622 
   5623 bool WarpCacheIRTranspiler::emitMapHasNonGCThingResult(ObjOperandId mapId,
   5624                                                       ValOperandId valId) {
   5625  MDefinition* map = getOperand(mapId);
   5626  MDefinition* val = getOperand(valId);
   5627 
   5628  auto* hashValue = MToHashableNonGCThing::New(alloc(), val);
   5629  add(hashValue);
   5630 
   5631  auto* hash = MHashNonGCThing::New(alloc(), hashValue);
   5632  add(hash);
   5633 
   5634  auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, hashValue, hash);
   5635  add(ins);
   5636 
   5637  pushResult(ins);
   5638  return true;
   5639 }
   5640 
   5641 bool WarpCacheIRTranspiler::emitMapHasStringResult(ObjOperandId mapId,
   5642                                                   StringOperandId strId) {
   5643  MDefinition* map = getOperand(mapId);
   5644  MDefinition* str = getOperand(strId);
   5645 
   5646  auto* hashValue = MToHashableString::New(alloc(), str);
   5647  add(hashValue);
   5648 
   5649  auto* hash = MHashString::New(alloc(), hashValue);
   5650  add(hash);
   5651 
   5652  auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, hashValue, hash);
   5653  add(ins);
   5654 
   5655  pushResult(ins);
   5656  return true;
   5657 }
   5658 
   5659 bool WarpCacheIRTranspiler::emitMapHasSymbolResult(ObjOperandId mapId,
   5660                                                   SymbolOperandId symId) {
   5661  MDefinition* map = getOperand(mapId);
   5662  MDefinition* sym = getOperand(symId);
   5663 
   5664  auto* hash = MHashSymbol::New(alloc(), sym);
   5665  add(hash);
   5666 
   5667  auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, sym, hash);
   5668  add(ins);
   5669 
   5670  pushResult(ins);
   5671  return true;
   5672 }
   5673 
   5674 bool WarpCacheIRTranspiler::emitMapHasBigIntResult(ObjOperandId mapId,
   5675                                                   BigIntOperandId bigIntId) {
   5676  MDefinition* map = getOperand(mapId);
   5677  MDefinition* bigInt = getOperand(bigIntId);
   5678 
   5679  auto* hash = MHashBigInt::New(alloc(), bigInt);
   5680  add(hash);
   5681 
   5682  auto* ins = MMapObjectHasBigInt::New(alloc(), map, bigInt, hash);
   5683  add(ins);
   5684 
   5685  pushResult(ins);
   5686  return true;
   5687 }
   5688 
   5689 bool WarpCacheIRTranspiler::emitMapHasObjectResult(ObjOperandId mapId,
   5690                                                   ObjOperandId objId) {
   5691  MDefinition* map = getOperand(mapId);
   5692  MDefinition* obj = getOperand(objId);
   5693 
   5694  auto* hash = MHashObject::New(alloc(), map, obj);
   5695  add(hash);
   5696 
   5697  auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, obj, hash);
   5698  add(ins);
   5699 
   5700  pushResult(ins);
   5701  return true;
   5702 }
   5703 
   5704 bool WarpCacheIRTranspiler::emitMapHasResult(ObjOperandId mapId,
   5705                                             ValOperandId valId) {
   5706  MDefinition* map = getOperand(mapId);
   5707  MDefinition* val = getOperand(valId);
   5708 
   5709 #ifdef JS_PUNBOX64
   5710  auto* hashValue = MToHashableValue::New(alloc(), val);
   5711  add(hashValue);
   5712 
   5713  auto* hash = MHashValue::New(alloc(), map, hashValue);
   5714  add(hash);
   5715 
   5716  auto* ins = MMapObjectHasValue::New(alloc(), map, hashValue, hash);
   5717  add(ins);
   5718 #else
   5719  auto* ins = MMapObjectHasValueVMCall::New(alloc(), map, val);
   5720  add(ins);
   5721 #endif
   5722 
   5723  pushResult(ins);
   5724  return true;
   5725 }
   5726 
   5727 bool WarpCacheIRTranspiler::emitMapGetNonGCThingResult(ObjOperandId mapId,
   5728                                                       ValOperandId valId) {
   5729  MDefinition* map = getOperand(mapId);
   5730  MDefinition* val = getOperand(valId);
   5731 
   5732  auto* hashValue = MToHashableNonGCThing::New(alloc(), val);
   5733  add(hashValue);
   5734 
   5735  auto* hash = MHashNonGCThing::New(alloc(), hashValue);
   5736  add(hash);
   5737 
   5738  auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, hashValue, hash);
   5739  add(ins);
   5740 
   5741  pushResult(ins);
   5742  return true;
   5743 }
   5744 
   5745 bool WarpCacheIRTranspiler::emitMapGetStringResult(ObjOperandId mapId,
   5746                                                   StringOperandId strId) {
   5747  MDefinition* map = getOperand(mapId);
   5748  MDefinition* str = getOperand(strId);
   5749 
   5750  auto* hashValue = MToHashableString::New(alloc(), str);
   5751  add(hashValue);
   5752 
   5753  auto* hash = MHashString::New(alloc(), hashValue);
   5754  add(hash);
   5755 
   5756  auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, hashValue, hash);
   5757  add(ins);
   5758 
   5759  pushResult(ins);
   5760  return true;
   5761 }
   5762 
   5763 bool WarpCacheIRTranspiler::emitMapGetSymbolResult(ObjOperandId mapId,
   5764                                                   SymbolOperandId symId) {
   5765  MDefinition* map = getOperand(mapId);
   5766  MDefinition* sym = getOperand(symId);
   5767 
   5768  auto* hash = MHashSymbol::New(alloc(), sym);
   5769  add(hash);
   5770 
   5771  auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, sym, hash);
   5772  add(ins);
   5773 
   5774  pushResult(ins);
   5775  return true;
   5776 }
   5777 
   5778 bool WarpCacheIRTranspiler::emitMapGetBigIntResult(ObjOperandId mapId,
   5779                                                   BigIntOperandId bigIntId) {
   5780  MDefinition* map = getOperand(mapId);
   5781  MDefinition* bigInt = getOperand(bigIntId);
   5782 
   5783  auto* hash = MHashBigInt::New(alloc(), bigInt);
   5784  add(hash);
   5785 
   5786  auto* ins = MMapObjectGetBigInt::New(alloc(), map, bigInt, hash);
   5787  add(ins);
   5788 
   5789  pushResult(ins);
   5790  return true;
   5791 }
   5792 
   5793 bool WarpCacheIRTranspiler::emitMapGetObjectResult(ObjOperandId mapId,
   5794                                                   ObjOperandId objId) {
   5795  MDefinition* map = getOperand(mapId);
   5796  MDefinition* obj = getOperand(objId);
   5797 
   5798  auto* hash = MHashObject::New(alloc(), map, obj);
   5799  add(hash);
   5800 
   5801  auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, obj, hash);
   5802  add(ins);
   5803 
   5804  pushResult(ins);
   5805  return true;
   5806 }
   5807 
   5808 bool WarpCacheIRTranspiler::emitMapGetResult(ObjOperandId mapId,
   5809                                             ValOperandId valId) {
   5810  MDefinition* map = getOperand(mapId);
   5811  MDefinition* val = getOperand(valId);
   5812 
   5813 #ifdef JS_PUNBOX64
   5814  auto* hashValue = MToHashableValue::New(alloc(), val);
   5815  add(hashValue);
   5816 
   5817  auto* hash = MHashValue::New(alloc(), map, hashValue);
   5818  add(hash);
   5819 
   5820  auto* ins = MMapObjectGetValue::New(alloc(), map, hashValue, hash);
   5821  add(ins);
   5822 #else
   5823  auto* ins = MMapObjectGetValueVMCall::New(alloc(), map, val);
   5824  add(ins);
   5825 #endif
   5826 
   5827  pushResult(ins);
   5828  return true;
   5829 }
   5830 
   5831 bool WarpCacheIRTranspiler::emitMapDeleteResult(ObjOperandId mapId,
   5832                                                ValOperandId keyId) {
   5833  MDefinition* map = getOperand(mapId);
   5834  MDefinition* key = getOperand(keyId);
   5835 
   5836  auto* ins = MMapObjectDelete::New(alloc(), map, key);
   5837  addEffectful(ins);
   5838 
   5839  pushResult(ins);
   5840  return resumeAfter(ins);
   5841 }
   5842 
   5843 bool WarpCacheIRTranspiler::emitMapSetResult(ObjOperandId mapId,
   5844                                             ValOperandId keyId,
   5845                                             ValOperandId valId) {
   5846  MDefinition* map = getOperand(mapId);
   5847  MDefinition* key = getOperand(keyId);
   5848  MDefinition* val = getOperand(valId);
   5849 
   5850  auto* ins = MMapObjectSet::New(alloc(), map, key, val);
   5851  addEffectful(ins);
   5852 
   5853  pushResult(map);
   5854  return resumeAfter(ins);
   5855 }
   5856 
   5857 bool WarpCacheIRTranspiler::emitMapSizeResult(ObjOperandId mapId) {
   5858  MDefinition* map = getOperand(mapId);
   5859 
   5860  auto* ins = MMapObjectSize::New(alloc(), map);
   5861  add(ins);
   5862 
   5863  pushResult(ins);
   5864  return true;
   5865 }
   5866 
   5867 bool WarpCacheIRTranspiler::emitWeakMapGetObjectResult(ObjOperandId weakMapId,
   5868                                                       ObjOperandId objId) {
   5869  MDefinition* weakMap = getOperand(weakMapId);
   5870  MDefinition* obj = getOperand(objId);
   5871 
   5872  auto* ins = MWeakMapGetObject::New(alloc(), weakMap, obj);
   5873  add(ins);
   5874 
   5875  pushResult(ins);
   5876  return true;
   5877 }
   5878 
   5879 bool WarpCacheIRTranspiler::emitWeakMapHasObjectResult(ObjOperandId weakMapId,
   5880                                                       ObjOperandId objId) {
   5881  MDefinition* weakMap = getOperand(weakMapId);
   5882  MDefinition* obj = getOperand(objId);
   5883 
   5884  auto* ins = MWeakMapHasObject::New(alloc(), weakMap, obj);
   5885  add(ins);
   5886 
   5887  pushResult(ins);
   5888  return true;
   5889 }
   5890 
   5891 bool WarpCacheIRTranspiler::emitWeakSetHasObjectResult(ObjOperandId weakSetId,
   5892                                                       ObjOperandId objId) {
   5893  MDefinition* weakSet = getOperand(weakSetId);
   5894  MDefinition* obj = getOperand(objId);
   5895 
   5896  auto* ins = MWeakSetHasObject::New(alloc(), weakSet, obj);
   5897  add(ins);
   5898 
   5899  pushResult(ins);
   5900  return true;
   5901 }
   5902 
   5903 bool WarpCacheIRTranspiler::emitDateFillLocalTimeSlots(ObjOperandId dateId) {
   5904  MDefinition* date = getOperand(dateId);
   5905 
   5906  // MDateFillLocalTimeSlots is effectful because it can store into fixed slots,
   5907  // but it's safe to repeat this action after a bailout, therefore it's okay to
   5908  // use |addEffectfulUnsafe|.
   5909  auto* ins = MDateFillLocalTimeSlots::New(alloc(), date);
   5910  addEffectfulUnsafe(ins);
   5911 
   5912  return true;
   5913 }
   5914 
   5915 bool WarpCacheIRTranspiler::emitDateHoursFromSecondsIntoYearResult(
   5916    ValOperandId secondsIntoYearId) {
   5917  MDefinition* secondsIntoYear = getOperand(secondsIntoYearId);
   5918 
   5919  auto* ins = MDateHoursFromSecondsIntoYear::New(alloc(), secondsIntoYear);
   5920  add(ins);
   5921 
   5922  pushResult(ins);
   5923  return true;
   5924 }
   5925 
   5926 bool WarpCacheIRTranspiler::emitDateMinutesFromSecondsIntoYearResult(
   5927    ValOperandId secondsIntoYearId) {
   5928  MDefinition* secondsIntoYear = getOperand(secondsIntoYearId);
   5929 
   5930  auto* ins = MDateMinutesFromSecondsIntoYear::New(alloc(), secondsIntoYear);
   5931  add(ins);
   5932 
   5933  pushResult(ins);
   5934  return true;
   5935 }
   5936 
   5937 bool WarpCacheIRTranspiler::emitDateSecondsFromSecondsIntoYearResult(
   5938    ValOperandId secondsIntoYearId) {
   5939  MDefinition* secondsIntoYear = getOperand(secondsIntoYearId);
   5940 
   5941  auto* ins = MDateSecondsFromSecondsIntoYear::New(alloc(), secondsIntoYear);
   5942  add(ins);
   5943 
   5944  pushResult(ins);
   5945  return true;
   5946 }
   5947 
   5948 bool WarpCacheIRTranspiler::emitTruthyResult(OperandId inputId) {
   5949  MDefinition* input = getOperand(inputId);
   5950 
   5951  auto* result = convertToBoolean(input);
   5952 
   5953  pushResult(result);
   5954  return true;
   5955 }
   5956 
   5957 bool WarpCacheIRTranspiler::emitLoadInt32TruthyResult(ValOperandId inputId) {
   5958  return emitTruthyResult(inputId);
   5959 }
   5960 
   5961 bool WarpCacheIRTranspiler::emitLoadDoubleTruthyResult(
   5962    NumberOperandId inputId) {
   5963  return emitTruthyResult(inputId);
   5964 }
   5965 
   5966 bool WarpCacheIRTranspiler::emitLoadStringTruthyResult(
   5967    StringOperandId inputId) {
   5968  return emitTruthyResult(inputId);
   5969 }
   5970 
   5971 bool WarpCacheIRTranspiler::emitLoadObjectTruthyResult(ObjOperandId inputId) {
   5972  return emitTruthyResult(inputId);
   5973 }
   5974 
   5975 bool WarpCacheIRTranspiler::emitLoadBigIntTruthyResult(
   5976    BigIntOperandId inputId) {
   5977  return emitTruthyResult(inputId);
   5978 }
   5979 
   5980 bool WarpCacheIRTranspiler::emitLoadValueTruthyResult(ValOperandId inputId) {
   5981  return emitTruthyResult(inputId);
   5982 }
   5983 
   5984 bool WarpCacheIRTranspiler::emitLoadOperandResult(ValOperandId inputId) {
   5985  MDefinition* input = getOperand(inputId);
   5986  pushResult(input);
   5987  return true;
   5988 }
   5989 
   5990 bool WarpCacheIRTranspiler::emitLoadWrapperTarget(ObjOperandId objId,
   5991                                                  ObjOperandId resultId,
   5992                                                  bool fallible) {
   5993  MDefinition* obj = getOperand(objId);
   5994 
   5995  auto* ins = MLoadWrapperTarget::New(alloc(), obj, fallible);
   5996  if (fallible) {
   5997    ins->setGuard();
   5998  }
   5999  add(ins);
   6000 
   6001  return defineOperand(resultId, ins);
   6002 }
   6003 
   6004 // When we transpile a call, we may generate guards for some
   6005 // arguments.  To make sure the call instruction depends on those
   6006 // guards, when the transpiler creates an operand for an argument, we
   6007 // register the OperandId of that argument in argumentIds_. (See
   6008 // emitLoadArgumentSlot.) Before generating the call, we update the
   6009 // CallInfo to use the appropriate value from operands_.
   6010 // Note: The callee is an explicit argument to the call op, and is
   6011 // tracked separately.
   6012 void WarpCacheIRTranspiler::updateArgumentsFromOperands() {
   6013  for (uint32_t i = 0; i < uint32_t(ArgumentKind::NumKinds); i++) {
   6014    ArgumentKind kind = ArgumentKind(i);
   6015    OperandId id = argumentOperandIds_[kind];
   6016    if (id.valid()) {
   6017      switch (kind) {
   6018        case ArgumentKind::This:
   6019          callInfo_->setThis(getOperand(id));
   6020          break;
   6021        case ArgumentKind::NewTarget:
   6022          callInfo_->setNewTarget(getOperand(id));
   6023          break;
   6024        case ArgumentKind::Arg0:
   6025          callInfo_->setArg(0, getOperand(id));
   6026          break;
   6027        case ArgumentKind::Arg1:
   6028          callInfo_->setArg(1, getOperand(id));
   6029          break;
   6030        case ArgumentKind::Arg2:
   6031          callInfo_->setArg(2, getOperand(id));
   6032          break;
   6033        case ArgumentKind::Arg3:
   6034          callInfo_->setArg(3, getOperand(id));
   6035          break;
   6036        case ArgumentKind::Arg4:
   6037          callInfo_->setArg(4, getOperand(id));
   6038          break;
   6039        case ArgumentKind::Arg5:
   6040          callInfo_->setArg(5, getOperand(id));
   6041          break;
   6042        case ArgumentKind::Arg6:
   6043          callInfo_->setArg(6, getOperand(id));
   6044          break;
   6045        case ArgumentKind::Arg7:
   6046          callInfo_->setArg(7, getOperand(id));
   6047          break;
   6048        case ArgumentKind::Callee:
   6049        case ArgumentKind::NumKinds:
   6050          MOZ_CRASH("Unexpected argument kind");
   6051      }
   6052    }
   6053  }
   6054 }
   6055 
   6056 bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId,
   6057                                                 uint32_t slotIndex) {
   6058  // Reverse of GetIndexOfArgument.
   6059 
   6060  // Layout:
   6061  // NewTarget | Args.. (reversed)      | ThisValue | Callee
   6062  // 0         | ArgC .. Arg1 Arg0 (+1) | argc (+1) | argc + 1 (+ 1)
   6063  // ^ (if constructing)
   6064 
   6065  // NewTarget (optional)
   6066  if (callInfo_->constructing()) {
   6067    if (slotIndex == 0) {
   6068      setArgumentId(ArgumentKind::NewTarget, resultId);
   6069      return defineOperand(resultId, callInfo_->getNewTarget());
   6070    }
   6071 
   6072    slotIndex -= 1;  // Adjust slot index to match non-constructing calls.
   6073  }
   6074 
   6075  // Args..
   6076  if (slotIndex < callInfo_->argc()) {
   6077    uint32_t arg = callInfo_->argc() - 1 - slotIndex;
   6078    ArgumentKind kind = ArgumentKindForArgIndex(arg);
   6079    MOZ_ASSERT(kind < ArgumentKind::NumKinds);
   6080    setArgumentId(kind, resultId);
   6081    return defineOperand(resultId, callInfo_->getArg(arg));
   6082  }
   6083 
   6084  // ThisValue
   6085  if (slotIndex == callInfo_->argc()) {
   6086    setArgumentId(ArgumentKind::This, resultId);
   6087    return defineOperand(resultId, callInfo_->thisArg());
   6088  }
   6089 
   6090  // Callee
   6091  MOZ_ASSERT(slotIndex == callInfo_->argc() + 1);
   6092  return defineOperand(resultId, callInfo_->callee());
   6093 }
   6094 
   6095 bool WarpCacheIRTranspiler::emitLoadArgumentFixedSlot(ValOperandId resultId,
   6096                                                      uint8_t slotIndex) {
   6097  return emitLoadArgumentSlot(resultId, slotIndex);
   6098 }
   6099 
   6100 bool WarpCacheIRTranspiler::emitLoadArgumentDynamicSlot(ValOperandId resultId,
   6101                                                        Int32OperandId argcId,
   6102                                                        uint8_t slotIndex) {
   6103 #ifdef DEBUG
   6104  MDefinition* argc = getOperand(argcId);
   6105  MOZ_ASSERT(argc->toConstant()->toInt32() ==
   6106             static_cast<int32_t>(callInfo_->argc()));
   6107 #endif
   6108 
   6109  return emitLoadArgumentSlot(resultId, callInfo_->argc() + slotIndex);
   6110 }
   6111 
   6112 WrappedFunction* WarpCacheIRTranspiler::maybeWrappedFunction(
   6113    MDefinition* callee, CallKind kind, uint16_t nargs, FunctionFlags flags) {
   6114  MOZ_ASSERT(callee->isConstant() || callee->isNurseryObject());
   6115 
   6116  // If this is a native without a JitEntry, WrappedFunction needs to know the
   6117  // target JSFunction.
   6118  // TODO: support nursery-allocated natives with WrappedFunction, maybe by
   6119  // storing the JSNative in the Baseline stub like flags/nargs.
   6120  bool isNative = flags.isNativeWithoutJitEntry();
   6121  if (isNative && !callee->isConstant()) {
   6122    return nullptr;
   6123  }
   6124 
   6125  JSFunction* nativeTarget = nullptr;
   6126  if (isNative) {
   6127    nativeTarget = &callee->toConstant()->toObject().as<JSFunction>();
   6128  }
   6129 
   6130  WrappedFunction* wrappedTarget =
   6131      new (alloc()) WrappedFunction(nativeTarget, nargs, flags);
   6132  MOZ_ASSERT_IF(kind == CallKind::Native || kind == CallKind::DOM,
   6133                wrappedTarget->isNativeWithoutJitEntry());
   6134  MOZ_ASSERT_IF(kind == CallKind::Scripted, wrappedTarget->hasJitEntry());
   6135  return wrappedTarget;
   6136 }
   6137 
   6138 WrappedFunction* WarpCacheIRTranspiler::maybeCallTarget(MDefinition* callee,
   6139                                                        CallKind kind) {
   6140  // CacheIR emits the following for specialized calls:
   6141  //     GuardSpecificFunction <callee> <func> ..
   6142  //     Call(Native|Scripted)Function <callee> ..
   6143  // or:
   6144  //     GuardClass <callee> ..
   6145  //     GuardFunctionScript <callee> <script> ..
   6146  //     CallScriptedFunction <callee> ..
   6147  //
   6148  // We can use the <func> JSFunction or <script> BaseScript to specialize this
   6149  // call.
   6150  if (callee->isGuardSpecificFunction()) {
   6151    auto* guard = callee->toGuardSpecificFunction();
   6152    return maybeWrappedFunction(guard->expected(), kind, guard->nargs(),
   6153                                guard->flags());
   6154  }
   6155  if (callee->isGuardFunctionScript()) {
   6156    MOZ_ASSERT(kind == CallKind::Scripted);
   6157    auto* guard = callee->toGuardFunctionScript();
   6158    WrappedFunction* wrappedTarget = new (alloc()) WrappedFunction(
   6159        /* nativeFun = */ nullptr, guard->nargs(), guard->flags());
   6160    MOZ_ASSERT(wrappedTarget->hasJitEntry());
   6161    return wrappedTarget;
   6162  }
   6163  return nullptr;
   6164 }
   6165 
   6166 WrappedFunction* WarpCacheIRTranspiler::maybeGetterSetterTarget(
   6167    MDefinition* callee, CallKind kind, uint16_t nargs, FunctionFlags flags) {
   6168  // CacheIR has two representations for the callee of a getter/setter:
   6169  // 1. If it is always the same function, guard the GetterSetter pair,
   6170  //    then load a constant callee:
   6171  //       GuardDynamicSlotValue <holder> ... <GetterSetter>
   6172  //       LoadObject <callee>
   6173  //       CallScripted(Setter|GetterResult) <receiver> <callee> ...
   6174  // 2. If it is different functions sharing a single script, load
   6175  //    the callee out of the GetterSetter pair, then guard that it
   6176  //    has the correct script:
   6177  //     Load(Fixed|Dynamic)Slot <GetterSetter> ...
   6178  //     LoadGetterSetterFunction <GetterSetter> <callee>
   6179  //     GuardFunctionScript <callee> <script>
   6180  //     CallScripted(Setter|GetterResult) <receiver> <callee> ...
   6181  //
   6182  // We can use <callee> from the first case, or <script> from the second.
   6183  if (callee->isGuardFunctionScript()) {
   6184    MOZ_ASSERT(kind == CallKind::Scripted);
   6185    auto* guard = callee->toGuardFunctionScript();
   6186    WrappedFunction* wrappedTarget = new (alloc()) WrappedFunction(
   6187        /* nativeFun = */ nullptr, guard->nargs(), guard->flags());
   6188    MOZ_ASSERT(wrappedTarget->hasJitEntry());
   6189    return wrappedTarget;
   6190  }
   6191  return maybeWrappedFunction(callee, kind, nargs, flags);
   6192 }
   6193 
   6194 // If it is possible to use MCall for this call, update callInfo_ to use
   6195 // the correct arguments. Otherwise, update the ArgFormat of callInfo_.
   6196 bool WarpCacheIRTranspiler::updateCallInfo(MDefinition* callee,
   6197                                           CallFlags flags) {
   6198  // The transpilation will add various guards to the callee.
   6199  // We replace the callee referenced by the CallInfo, so that
   6200  // the resulting call instruction depends on these guards.
   6201  callInfo_->setCallee(callee);
   6202 
   6203  // The transpilation may also add guards to other arguments.
   6204  // We replace those arguments in the CallInfo here.
   6205  updateArgumentsFromOperands();
   6206 
   6207  switch (flags.getArgFormat()) {
   6208    case CallFlags::Standard:
   6209      MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6210      break;
   6211    case CallFlags::Spread:
   6212      MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Array);
   6213      break;
   6214    case CallFlags::FunCall:
   6215      // Note: We already changed the callee to the target
   6216      // function instead of the |call| function.
   6217      MOZ_ASSERT(!callInfo_->constructing());
   6218      MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6219 
   6220      if (callInfo_->argc() == 0) {
   6221        // Special case for fun.call() with no arguments.
   6222        auto* undef = constant(UndefinedValue());
   6223        callInfo_->setThis(undef);
   6224      } else {
   6225        // The first argument for |call| is the new this value.
   6226        callInfo_->setThis(callInfo_->getArg(0));
   6227 
   6228        // Shift down all other arguments by removing the first.
   6229        callInfo_->removeArg(0);
   6230      }
   6231      break;
   6232    case CallFlags::FunApplyArgsObj:
   6233      MOZ_ASSERT(!callInfo_->constructing());
   6234      MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6235 
   6236      callInfo_->setArgFormat(CallInfo::ArgFormat::FunApplyArgsObj);
   6237      break;
   6238    case CallFlags::FunApplyArray: {
   6239      MDefinition* argFunc = callInfo_->thisArg();
   6240      MDefinition* argThis = callInfo_->getArg(0);
   6241      callInfo_->setCallee(argFunc);
   6242      callInfo_->setThis(argThis);
   6243      callInfo_->setArgFormat(CallInfo::ArgFormat::Array);
   6244      break;
   6245    }
   6246    case CallFlags::FunApplyNullUndefined:
   6247      // Note: We already changed the callee to the target
   6248      // function instead of the |apply| function.
   6249      MOZ_ASSERT(callInfo_->argc() == 2);
   6250      MOZ_ASSERT(!callInfo_->constructing());
   6251      MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6252      callInfo_->setThis(callInfo_->getArg(0));
   6253      callInfo_->getArg(1)->setImplicitlyUsedUnchecked();
   6254      callInfo_->removeArg(1);
   6255      callInfo_->removeArg(0);
   6256      break;
   6257    default:
   6258      MOZ_CRASH("Unsupported arg format");
   6259  }
   6260  return true;
   6261 }
   6262 
   6263 // Returns true if we are generating a call to CreateThisFromIon and
   6264 // must check its return value.
   6265 bool WarpCacheIRTranspiler::maybeCreateThis(MDefinition* callee,
   6266                                            CallFlags flags, CallKind kind) {
   6267  MOZ_ASSERT(kind != CallKind::DOM, "DOM functions are not constructors");
   6268  MDefinition* thisArg = callInfo_->thisArg();
   6269 
   6270  if (kind == CallKind::Native) {
   6271    // Native functions keep the is-constructing MagicValue as |this|.
   6272    // If one of the arguments uses spread syntax this can be a loop phi with
   6273    // MIRType::Value.
   6274    MOZ_ASSERT(thisArg->type() == MIRType::MagicIsConstructing ||
   6275               thisArg->isPhi());
   6276    return false;
   6277  }
   6278  MOZ_ASSERT(kind == CallKind::Scripted);
   6279 
   6280  if (thisArg->isNewPlainObject()) {
   6281    // We have already updated |this| based on MetaScriptedThisShape. We do
   6282    // not need to generate a check.
   6283    return false;
   6284  }
   6285  if (flags.needsUninitializedThis()) {
   6286    MConstant* uninit = constant(MagicValue(JS_UNINITIALIZED_LEXICAL));
   6287    thisArg->setImplicitlyUsedUnchecked();
   6288    callInfo_->setThis(uninit);
   6289    return false;
   6290  }
   6291  // See the Native case above.
   6292  MOZ_ASSERT(thisArg->type() == MIRType::MagicIsConstructing ||
   6293             thisArg->isPhi());
   6294 
   6295  auto* newTarget = unboxObjectInfallible(callInfo_->getNewTarget());
   6296  auto* createThis = MCreateThis::New(alloc(), callee, newTarget);
   6297  add(createThis);
   6298 
   6299  thisArg->setImplicitlyUsedUnchecked();
   6300  callInfo_->setThis(createThis);
   6301 
   6302  return true;
   6303 }
   6304 
   6305 bool WarpCacheIRTranspiler::emitCallFunction(
   6306    ObjOperandId calleeId, Int32OperandId argcId,
   6307    mozilla::Maybe<ObjOperandId> thisObjId, CallFlags flags, CallKind kind,
   6308    mozilla::Maybe<uint32_t> siteOffset) {
   6309  MDefinition* callee = getOperand(calleeId);
   6310  if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) {
   6311    // We are transpiling to generate the correct guards. We also
   6312    // update the CallInfo to use the correct arguments. Code for the
   6313    // inlined function itself will be generated in
   6314    // WarpBuilder::buildInlinedCall.
   6315    if (!updateCallInfo(callee, flags)) {
   6316      return false;
   6317    }
   6318    if (callInfo_->constructing()) {
   6319      MOZ_ASSERT(flags.isConstructing());
   6320 
   6321      // We call maybeCreateThis to update |this|, but inlined constructors
   6322      // never need a VM call. CallIRGenerator::getThisForScripted ensures that
   6323      // we don't attach a specialized stub unless we have a template object or
   6324      // know that the constructor needs uninitialized this.
   6325      MOZ_ALWAYS_FALSE(maybeCreateThis(callee, flags, CallKind::Scripted));
   6326      mozilla::DebugOnly<MDefinition*> thisArg = callInfo_->thisArg();
   6327      MOZ_ASSERT(thisArg->isNewPlainObject() ||
   6328                 thisArg->type() == MIRType::MagicUninitializedLexical);
   6329    }
   6330 
   6331    if (flags.getArgFormat() == CallFlags::FunCall) {
   6332      callInfo_->setInliningResumeMode(ResumeMode::InlinedFunCall);
   6333    } else {
   6334      MOZ_ASSERT(flags.getArgFormat() == CallFlags::Standard);
   6335      callInfo_->setInliningResumeMode(ResumeMode::InlinedStandardCall);
   6336    }
   6337 
   6338    switch (callInfo_->argFormat()) {
   6339      case CallInfo::ArgFormat::Standard:
   6340        break;
   6341      default:
   6342        MOZ_CRASH("Unsupported arg format");
   6343    }
   6344    return true;
   6345  }
   6346 
   6347 #ifdef DEBUG
   6348  MDefinition* argc = getOperand(argcId);
   6349  MOZ_ASSERT(argc->toConstant()->toInt32() ==
   6350             static_cast<int32_t>(callInfo_->argc()));
   6351 #endif
   6352 
   6353  if (!updateCallInfo(callee, flags)) {
   6354    return false;
   6355  }
   6356 
   6357  if (kind == CallKind::DOM) {
   6358    MOZ_ASSERT(flags.getArgFormat() == CallFlags::Standard);
   6359    // For DOM calls |this| has a class guard.
   6360    MDefinition* thisObj = getOperand(*thisObjId);
   6361    callInfo_->setThis(thisObj);
   6362  }
   6363 
   6364  WrappedFunction* wrappedTarget = maybeCallTarget(callee, kind);
   6365 
   6366  bool needsThisCheck = false;
   6367  if (callInfo_->constructing()) {
   6368    MOZ_ASSERT(flags.isConstructing());
   6369    needsThisCheck = maybeCreateThis(callee, flags, kind);
   6370    if (needsThisCheck) {
   6371      wrappedTarget = nullptr;
   6372    }
   6373  }
   6374 
   6375  switch (callInfo_->argFormat()) {
   6376    case CallInfo::ArgFormat::Standard: {
   6377      gc::Heap initialHeap = gc::Heap::Default;
   6378      if (siteOffset) {
   6379        MOZ_ASSERT(kind == CallKind::DOM);
   6380        MOZ_ASSERT(readStubWord(*siteOffset) <= (uintptr_t)(gc::Heap::Tenured));
   6381        initialHeap = static_cast<gc::Heap>(readStubWord(*siteOffset));
   6382      }
   6383      MCall* call = makeCall(*callInfo_, needsThisCheck, wrappedTarget,
   6384                             kind == CallKind::DOM, initialHeap);
   6385      if (!call) {
   6386        return false;
   6387      }
   6388 
   6389      if (flags.isSameRealm()) {
   6390        call->setNotCrossRealm();
   6391      }
   6392 
   6393      if (call->isEffectful()) {
   6394        addEffectful(call);
   6395        pushResult(call);
   6396        return resumeAfter(call);
   6397      }
   6398 
   6399      MOZ_ASSERT(kind == CallKind::DOM);
   6400      add(call);
   6401      pushResult(call);
   6402      return true;
   6403    }
   6404    case CallInfo::ArgFormat::Array: {
   6405      MInstruction* call = makeSpreadCall(*callInfo_, needsThisCheck,
   6406                                          flags.isSameRealm(), wrappedTarget);
   6407      if (!call) {
   6408        return false;
   6409      }
   6410      addEffectful(call);
   6411      pushResult(call);
   6412 
   6413      return resumeAfter(call);
   6414    }
   6415    case CallInfo::ArgFormat::FunApplyArgsObj: {
   6416      return emitFunApplyArgsObj(wrappedTarget, flags);
   6417    }
   6418  }
   6419  MOZ_CRASH("unreachable");
   6420 }
   6421 
   6422 bool WarpCacheIRTranspiler::emitFunApplyArgsObj(WrappedFunction* wrappedTarget,
   6423                                                CallFlags flags) {
   6424  MOZ_ASSERT(!callInfo_->constructing());
   6425 
   6426  MDefinition* callee = callInfo_->thisArg();
   6427  MDefinition* thisArg = callInfo_->getArg(0);
   6428  MDefinition* argsObj = callInfo_->getArg(1);
   6429 
   6430  MApplyArgsObj* apply =
   6431      MApplyArgsObj::New(alloc(), wrappedTarget, callee, argsObj, thisArg);
   6432 
   6433  if (flags.isSameRealm()) {
   6434    apply->setNotCrossRealm();
   6435  }
   6436  if (callInfo_->ignoresReturnValue()) {
   6437    apply->setIgnoresReturnValue();
   6438  }
   6439 
   6440  addEffectful(apply);
   6441  pushResult(apply);
   6442 
   6443  return resumeAfter(apply);
   6444 }
   6445 
   6446 #ifndef JS_SIMULATOR
   6447 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId,
   6448                                                   Int32OperandId argcId,
   6449                                                   CallFlags flags,
   6450                                                   uint32_t argcFixed,
   6451                                                   bool ignoresReturnValue) {
   6452  // Instead of ignoresReturnValue we use CallInfo::ignoresReturnValue.
   6453  return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags,
   6454                          CallKind::Native);
   6455 }
   6456 
   6457 bool WarpCacheIRTranspiler::emitCallDOMFunction(ObjOperandId calleeId,
   6458                                                Int32OperandId argcId,
   6459                                                ObjOperandId thisObjId,
   6460                                                CallFlags flags,
   6461                                                uint32_t argcFixed) {
   6462  return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags,
   6463                          CallKind::DOM);
   6464 }
   6465 
   6466 bool WarpCacheIRTranspiler::emitCallDOMFunctionWithAllocSite(
   6467    ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId,
   6468    CallFlags flags, uint32_t argcFixed, uint32_t siteOffset) {
   6469  return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags,
   6470                          CallKind::DOM, mozilla::Some(siteOffset));
   6471 }
   6472 #else
   6473 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId,
   6474                                                   Int32OperandId argcId,
   6475                                                   CallFlags flags,
   6476                                                   uint32_t argcFixed,
   6477                                                   uint32_t targetOffset) {
   6478  return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags,
   6479                          CallKind::Native);
   6480 }
   6481 
   6482 bool WarpCacheIRTranspiler::emitCallDOMFunction(
   6483    ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId,
   6484    CallFlags flags, uint32_t argcFixed, uint32_t targetOffset) {
   6485  return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags,
   6486                          CallKind::DOM);
   6487 }
   6488 
   6489 bool WarpCacheIRTranspiler::emitCallDOMFunctionWithAllocSite(
   6490    ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId,
   6491    CallFlags flags, uint32_t argcFixed, uint32_t siteOffset,
   6492    uint32_t targetOffset) {
   6493  return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags,
   6494                          CallKind::DOM, mozilla::Some(siteOffset));
   6495 }
   6496 #endif
   6497 
   6498 bool WarpCacheIRTranspiler::emitCallScriptedFunction(ObjOperandId calleeId,
   6499                                                     Int32OperandId argcId,
   6500                                                     CallFlags flags,
   6501                                                     uint32_t argcFixed) {
   6502  return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags,
   6503                          CallKind::Scripted);
   6504 }
   6505 
   6506 bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId,
   6507                                                    Int32OperandId argcId,
   6508                                                    uint32_t icScriptOffset,
   6509                                                    CallFlags flags,
   6510                                                    uint32_t argcFixed) {
   6511  return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags,
   6512                          CallKind::Scripted);
   6513 }
   6514 
   6515 #ifdef JS_PUNBOX64
   6516 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetShared(
   6517    MDefinition* target, MDefinition* receiver, MDefinition* handler,
   6518    MDefinition* id, MDefinition* trapDef, WrappedFunction* trap) {
   6519  CallInfo callInfo(alloc(), /* constructing = */ false,
   6520                    /* ignoresRval = */ false);
   6521  callInfo.initForProxyGet(trapDef, handler, target, id, receiver);
   6522 
   6523  MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, trap);
   6524  if (!call) {
   6525    return false;
   6526  }
   6527 
   6528  addEffectful(call);
   6529 
   6530  if (!current->ensureHasSlots(3)) {
   6531    return false;
   6532  }
   6533  current->push(call);
   6534  current->push(id);
   6535  current->push(target);
   6536 
   6537  MResumePoint* resumePoint =
   6538      MResumePoint::New(alloc(), current, loc_.toRawBytecode(),
   6539                        ResumeMode::ResumeAfterCheckProxyGetResult);
   6540  if (!resumePoint) {
   6541    return false;
   6542  }
   6543  call->setResumePoint(resumePoint);
   6544 
   6545  current->pop();
   6546  current->pop();
   6547 
   6548  MCheckScriptedProxyGetResult* check =
   6549      MCheckScriptedProxyGetResult::New(alloc(), target, id, call);
   6550  addEffectfulUnsafe(check);
   6551 
   6552  return resumeAfterUnchecked(check);
   6553 }
   6554 
   6555 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetResult(
   6556    ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
   6557    ObjOperandId trapId, uint32_t idOffset, uint32_t nargsAndFlags) {
   6558  MDefinition* target = getOperand(targetId);
   6559  MDefinition* receiver = getOperand(receiverId);
   6560  MDefinition* handler = getOperand(handlerId);
   6561  MDefinition* trap = getOperand(trapId);
   6562  jsid id = idStubField(idOffset);
   6563  MDefinition* idDef = constant(StringValue(id.toAtom()));
   6564  WrappedFunction* wrappedTarget = maybeCallTarget(trap, CallKind::Scripted);
   6565  MOZ_RELEASE_ASSERT(wrappedTarget);
   6566  return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap,
   6567                                        wrappedTarget);
   6568 }
   6569 
   6570 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetByValueResult(
   6571    ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId,
   6572    ValOperandId idId, ObjOperandId trapId, uint32_t nargsAndFlags) {
   6573  MDefinition* target = getOperand(targetId);
   6574  MDefinition* receiver = getOperand(receiverId);
   6575  MDefinition* handler = getOperand(handlerId);
   6576  MDefinition* trap = getOperand(trapId);
   6577  MDefinition* idDef = getOperand(idId);
   6578  WrappedFunction* wrappedTarget = maybeCallTarget(trap, CallKind::Scripted);
   6579  MOZ_RELEASE_ASSERT(wrappedTarget);
   6580  return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap,
   6581                                        wrappedTarget);
   6582 }
   6583 #endif
   6584 
   6585 bool WarpCacheIRTranspiler::emitCallClassHook(ObjOperandId calleeId,
   6586                                              Int32OperandId argcId,
   6587                                              CallFlags flags,
   6588                                              uint32_t argcFixed,
   6589                                              uint32_t targetOffset) {
   6590  MDefinition* callee = getOperand(calleeId);
   6591  JSNative target = jsnativeStubField(targetOffset);
   6592 
   6593 #ifdef DEBUG
   6594  MDefinition* argc = getOperand(argcId);
   6595  MOZ_ASSERT(argc->toConstant()->toInt32() ==
   6596             static_cast<int32_t>(callInfo_->argc()));
   6597 #endif
   6598 
   6599  if (!updateCallInfo(callee, flags)) {
   6600    return false;
   6601  }
   6602 
   6603  MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6604  MOZ_ASSERT(flags.getArgFormat() == CallFlags::ArgFormat::Standard);
   6605 
   6606  // Callees can be from any realm. If this changes, we should update
   6607  // MCallClassHook::maybeCrossRealm.
   6608  MOZ_ASSERT(!flags.isSameRealm());
   6609 
   6610  auto* call = MCallClassHook::New(alloc(), target, callInfo_->argc(),
   6611                                   callInfo_->constructing());
   6612  if (!call) {
   6613    return false;
   6614  }
   6615 
   6616  if (callInfo_->ignoresReturnValue()) {
   6617    call->setIgnoresReturnValue();
   6618  }
   6619 
   6620  call->initCallee(callInfo_->callee());
   6621  call->addArg(0, callInfo_->thisArg());
   6622 
   6623  for (uint32_t i = 0; i < callInfo_->argc(); i++) {
   6624    call->addArg(i + 1, callInfo_->getArg(i));
   6625  }
   6626 
   6627  if (callInfo_->constructing()) {
   6628    call->addArg(1 + callInfo_->argc(), callInfo_->getNewTarget());
   6629  }
   6630 
   6631  addEffectful(call);
   6632  pushResult(call);
   6633 
   6634  return resumeAfter(call);
   6635 }
   6636 
   6637 bool WarpCacheIRTranspiler::emitCallBoundScriptedFunction(
   6638    ObjOperandId calleeId, ObjOperandId targetId, Int32OperandId argcId,
   6639    CallFlags flags, uint32_t numBoundArgs) {
   6640  MDefinition* callee = getOperand(calleeId);
   6641  MDefinition* target = getOperand(targetId);
   6642 
   6643  MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6644  MOZ_ASSERT(callInfo_->constructing() == flags.isConstructing());
   6645 
   6646  callInfo_->setCallee(target);
   6647  updateArgumentsFromOperands();
   6648 
   6649  WrappedFunction* wrappedTarget = maybeCallTarget(target, CallKind::Scripted);
   6650 
   6651  bool needsThisCheck = false;
   6652  if (callInfo_->constructing()) {
   6653    callInfo_->setNewTarget(target);
   6654    needsThisCheck = maybeCreateThis(target, flags, CallKind::Scripted);
   6655    if (needsThisCheck) {
   6656      wrappedTarget = nullptr;
   6657    }
   6658  } else {
   6659    auto* thisv = MLoadFixedSlot::New(alloc(), callee,
   6660                                      BoundFunctionObject::boundThisSlot());
   6661    add(thisv);
   6662    callInfo_->thisArg()->setImplicitlyUsedUnchecked();
   6663    callInfo_->setThis(thisv);
   6664  }
   6665 
   6666  bool usingInlineBoundArgs =
   6667      numBoundArgs <= BoundFunctionObject::MaxInlineBoundArgs;
   6668 
   6669  MElements* elements = nullptr;
   6670  if (!usingInlineBoundArgs) {
   6671    auto* boundArgs = MLoadFixedSlot::New(
   6672        alloc(), callee, BoundFunctionObject::firstInlineBoundArgSlot());
   6673    add(boundArgs);
   6674    auto* boundArgsObj = unboxObjectInfallible(boundArgs, IsMovable::Yes);
   6675    elements = MElements::New(alloc(), boundArgsObj);
   6676    add(elements);
   6677  }
   6678 
   6679  auto loadBoundArg = [&](size_t index) {
   6680    MInstruction* arg;
   6681    if (usingInlineBoundArgs) {
   6682      size_t slot = BoundFunctionObject::firstInlineBoundArgSlot() + index;
   6683      arg = MLoadFixedSlot::New(alloc(), callee, slot);
   6684    } else {
   6685      arg = MLoadElement::New(alloc(), elements, constant(Int32Value(index)),
   6686                              /*needsHoleCheck*/ false);
   6687    }
   6688    add(arg);
   6689    return arg;
   6690  };
   6691  if (!callInfo_->prependArgs(numBoundArgs, loadBoundArg)) {
   6692    return false;
   6693  }
   6694 
   6695  MCall* call = makeCall(*callInfo_, needsThisCheck, wrappedTarget);
   6696  if (!call) {
   6697    return false;
   6698  }
   6699 
   6700  if (flags.isSameRealm()) {
   6701    call->setNotCrossRealm();
   6702  }
   6703 
   6704  addEffectful(call);
   6705  pushResult(call);
   6706  return resumeAfter(call);
   6707 }
   6708 
   6709 bool WarpCacheIRTranspiler::emitBindFunctionResult(
   6710    ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
   6711  MDefinition* target = getOperand(targetId);
   6712  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   6713 
   6714  // callInfo_ can be null when `bind` is inlined through a getter access, but
   6715  // in that case `argc` is guaranteed to be zero.
   6716  MOZ_ASSERT_IF(callInfo_, callInfo_->argc() == argc);
   6717  MOZ_ASSERT_IF(!callInfo_, argc == 0);
   6718 
   6719  auto* bound = MBindFunction::New(alloc(), target, argc, templateObj);
   6720  if (!bound) {
   6721    return false;
   6722  }
   6723  addEffectful(bound);
   6724 
   6725  for (uint32_t i = 0; i < argc; i++) {
   6726    bound->initArg(i, callInfo_->getArg(i));
   6727  }
   6728 
   6729  pushResult(bound);
   6730  return resumeAfter(bound);
   6731 }
   6732 
   6733 bool WarpCacheIRTranspiler::emitSpecializedBindFunctionResult(
   6734    ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) {
   6735  MDefinition* target = getOperand(targetId);
   6736  JSObject* templateObj = tenuredObjectStubField(templateObjectOffset);
   6737 
   6738  // callInfo_ can be null when `bind` is inlined through a getter access, but
   6739  // in that case `argc` is guaranteed to be zero.
   6740  MOZ_ASSERT_IF(callInfo_, callInfo_->argc() == argc);
   6741  MOZ_ASSERT_IF(!callInfo_, argc == 0);
   6742 
   6743  auto* bound = MNewBoundFunction::New(alloc(), templateObj);
   6744  add(bound);
   6745 
   6746  size_t numBoundArgs = argc > 0 ? argc - 1 : 0;
   6747  MOZ_ASSERT(numBoundArgs <= BoundFunctionObject::MaxInlineBoundArgs);
   6748 
   6749  auto initSlot = [&](size_t slot, MDefinition* value) {
   6750 #ifdef DEBUG
   6751    // Assert we can elide the post write barrier. See also the comment in
   6752    // WarpBuilder::buildNamedLambdaEnv.
   6753    add(MAssertCanElidePostWriteBarrier::New(alloc(), bound, value));
   6754 #endif
   6755    addUnchecked(MStoreFixedSlot::NewUnbarriered(alloc(), bound, slot, value));
   6756  };
   6757 
   6758  initSlot(BoundFunctionObject::targetSlot(), target);
   6759  if (argc > 0) {
   6760    initSlot(BoundFunctionObject::boundThisSlot(), callInfo_->getArg(0));
   6761  }
   6762  for (size_t i = 0; i < numBoundArgs; i++) {
   6763    size_t slot = BoundFunctionObject::firstInlineBoundArgSlot() + i;
   6764    initSlot(slot, callInfo_->getArg(1 + i));
   6765  }
   6766 
   6767  pushResult(bound);
   6768  return true;
   6769 }
   6770 
   6771 bool WarpCacheIRTranspiler::emitCallWasmFunction(
   6772    ObjOperandId calleeId, Int32OperandId argcId, CallFlags flags,
   6773    uint32_t argcFixed, uint32_t funcExportOffset, uint32_t instanceOffset) {
   6774  MDefinition* callee = getOperand(calleeId);
   6775 #ifdef DEBUG
   6776  MDefinition* argc = getOperand(argcId);
   6777  MOZ_ASSERT(argc->toConstant()->toInt32() ==
   6778             static_cast<int32_t>(callInfo_->argc()));
   6779 #endif
   6780  JSObject* instanceObject = tenuredObjectStubField(instanceOffset);
   6781  auto* wasmInstanceObj = &instanceObject->as<WasmInstanceObject>();
   6782  const wasm::FuncExport* funcExport = wasmFuncExportField(funcExportOffset);
   6783  const wasm::FuncType& sig =
   6784      wasmInstanceObj->instance().code().codeMeta().getFuncType(
   6785          funcExport->funcIndex());
   6786 
   6787  if (!updateCallInfo(callee, flags)) {
   6788    return false;
   6789  }
   6790 
   6791  static_assert(wasm::MaxArgsForJitInlineCall <= MaxNumLInstructionOperands,
   6792                "arguments must fit in LIR operands");
   6793  MOZ_ASSERT(sig.args().length() <= wasm::MaxArgsForJitInlineCall);
   6794 
   6795  MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);
   6796 
   6797  auto* call = MIonToWasmCall::New(alloc(), wasmInstanceObj, *funcExport);
   6798  if (!call) {
   6799    return false;
   6800  }
   6801 
   6802  mozilla::Maybe<MDefinition*> undefined;
   6803  for (size_t i = 0; i < sig.args().length(); i++) {
   6804    if (!alloc().ensureBallast()) {
   6805      return false;
   6806    }
   6807 
   6808    MDefinition* arg;
   6809    if (i < callInfo_->argc()) {
   6810      arg = callInfo_->getArg(i);
   6811    } else {
   6812      if (!undefined) {
   6813        undefined.emplace(constant(UndefinedValue()));
   6814      }
   6815      arg = convertWasmArg(*undefined, sig.args()[i].kind());
   6816    }
   6817    call->initArg(i, arg);
   6818  }
   6819 
   6820  addEffectful(call);
   6821 
   6822  // Add any post-function call conversions that are necessary.
   6823  MInstruction* postConversion = call;
   6824  const wasm::ValTypeVector& results = sig.results();
   6825  MOZ_ASSERT(results.length() <= 1, "Multi-value returns not supported.");
   6826  if (results.length() == 0) {
   6827    // No results to convert.
   6828  } else {
   6829    switch (results[0].kind()) {
   6830      case wasm::ValType::I64:
   6831        // JS expects a BigInt from I64 types.
   6832        postConversion =
   6833            MInt64ToBigInt::New(alloc(), call, /* isSigned = */ true);
   6834 
   6835        // Make non-movable so we can attach a resume point.
   6836        postConversion->setNotMovable();
   6837 
   6838        add(postConversion);
   6839        break;
   6840      default:
   6841        // No spectre.index_masking of i32 results required, as the generated
   6842        // stub takes care of that.
   6843        break;
   6844    }
   6845  }
   6846 
   6847  // The resume point has to be attached to the post-conversion instruction
   6848  // (if present) instead of to the call. This way, if the call triggers an
   6849  // invalidation bailout, we will have the BigInt value on the Baseline stack.
   6850  // Potential alternative solution: attach the resume point to the call and
   6851  // have bailouts turn the Int64 value into a BigInt, maybe with a recover
   6852  // instruction.
   6853  pushResult(postConversion);
   6854  return resumeAfterUnchecked(postConversion);
   6855 }
   6856 
   6857 MDefinition* WarpCacheIRTranspiler::convertWasmArg(MDefinition* arg,
   6858                                                   wasm::ValType::Kind kind) {
   6859  // An invariant in this code is that any type conversion operation that has
   6860  // externally visible effects, such as invoking valueOf on an object argument,
   6861  // must bailout so that we don't have to worry about replaying effects during
   6862  // argument conversion.
   6863  MInstruction* conversion = nullptr;
   6864  switch (kind) {
   6865    case wasm::ValType::I32:
   6866      conversion = MTruncateToInt32::New(alloc(), arg);
   6867      break;
   6868    case wasm::ValType::I64:
   6869      conversion = MToInt64::New(alloc(), arg);
   6870      break;
   6871    case wasm::ValType::F32:
   6872      conversion = MToFloat32::New(alloc(), arg);
   6873      break;
   6874    case wasm::ValType::F64:
   6875      conversion = MToDouble::New(alloc(), arg);
   6876      break;
   6877    case wasm::ValType::V128:
   6878      MOZ_CRASH("Unexpected type for Wasm JitEntry");
   6879    case wasm::ValType::Ref:
   6880      // Transform the JS representation into an AnyRef representation.
   6881      // The resulting type is MIRType::WasmAnyRef.  These cases are all
   6882      // effect-free.
   6883      switch (arg->type()) {
   6884        case MIRType::Object:
   6885          conversion = MWasmAnyRefFromJSObject::New(alloc(), arg);
   6886          break;
   6887        case MIRType::String:
   6888          conversion = MWasmAnyRefFromJSString::New(alloc(), arg);
   6889          break;
   6890        case MIRType::Null:
   6891          arg->setImplicitlyUsedUnchecked();
   6892          conversion = MWasmNullConstant::New(alloc(), wasm::MaybeRefType());
   6893          break;
   6894        default:
   6895          conversion = MWasmAnyRefFromJSValue::New(alloc(), arg);
   6896          break;
   6897      }
   6898      break;
   6899  }
   6900 
   6901  add(conversion);
   6902  return conversion;
   6903 }
   6904 
   6905 bool WarpCacheIRTranspiler::emitGuardWasmArg(ValOperandId argId,
   6906                                             wasm::ValType::Kind kind) {
   6907  MDefinition* arg = getOperand(argId);
   6908  MDefinition* conversion = convertWasmArg(arg, kind);
   6909 
   6910  setOperand(argId, conversion);
   6911  return true;
   6912 }
   6913 
   6914 bool WarpCacheIRTranspiler::emitCallGetterResult(CallKind kind,
   6915                                                 ValOperandId receiverId,
   6916                                                 MDefinition* getter,
   6917                                                 bool sameRealm,
   6918                                                 uint32_t nargsAndFlagsOffset) {
   6919  MDefinition* receiver = getOperand(receiverId);
   6920  if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) {
   6921    // We are transpiling to generate the correct guards. We also update the
   6922    // CallInfo to use the correct arguments. Code for the inlined getter
   6923    // itself will be generated in WarpBuilder::buildInlinedCall.
   6924    callInfo_->initForGetterCall(getter, receiver);
   6925    callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor);
   6926 
   6927    // Make sure there's enough room to push the arguments on the stack.
   6928    if (!current->ensureHasSlots(2)) {
   6929      return false;
   6930    }
   6931 
   6932    return true;
   6933  }
   6934 
   6935  uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset);
   6936  uint16_t nargs = nargsAndFlags >> 16;
   6937  FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
   6938  WrappedFunction* wrappedTarget =
   6939      maybeGetterSetterTarget(getter, kind, nargs, flags);
   6940 
   6941  bool ignoresRval = loc_.resultIsPopped();
   6942  CallInfo callInfo(alloc(), /* constructing = */ false, ignoresRval);
   6943  callInfo.initForGetterCall(getter, receiver);
   6944 
   6945  MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, wrappedTarget);
   6946  if (!call) {
   6947    return false;
   6948  }
   6949 
   6950  if (sameRealm) {
   6951    call->setNotCrossRealm();
   6952  }
   6953 
   6954  addEffectful(call);
   6955  pushResult(call);
   6956 
   6957  return resumeAfter(call);
   6958 }
   6959 
   6960 bool WarpCacheIRTranspiler::emitCallScriptedGetterResult(
   6961    ValOperandId receiverId, ObjOperandId calleeId, bool sameRealm,
   6962    uint32_t nargsAndFlagsOffset) {
   6963  MDefinition* getter = getOperand(calleeId);
   6964  return emitCallGetterResult(CallKind::Scripted, receiverId, getter, sameRealm,
   6965                              nargsAndFlagsOffset);
   6966 }
   6967 
   6968 bool WarpCacheIRTranspiler::emitCallInlinedGetterResult(
   6969    ValOperandId receiverId, ObjOperandId calleeId, uint32_t icScriptOffset,
   6970    bool sameRealm, uint32_t nargsAndFlagsOffset) {
   6971  MDefinition* getter = getOperand(calleeId);
   6972  return emitCallGetterResult(CallKind::Scripted, receiverId, getter, sameRealm,
   6973                              nargsAndFlagsOffset);
   6974 }
   6975 
   6976 bool WarpCacheIRTranspiler::emitCallNativeGetterResult(
   6977    ValOperandId receiverId, uint32_t getterOffset, bool sameRealm,
   6978    uint32_t nargsAndFlagsOffset) {
   6979  MDefinition* getter = objectStubField(getterOffset);
   6980  return emitCallGetterResult(CallKind::Native, receiverId, getter, sameRealm,
   6981                              nargsAndFlagsOffset);
   6982 }
   6983 
   6984 bool WarpCacheIRTranspiler::emitCallSetter(CallKind kind,
   6985                                           ObjOperandId receiverId,
   6986                                           MDefinition* setter,
   6987                                           ValOperandId rhsId, bool sameRealm,
   6988                                           uint32_t nargsAndFlagsOffset) {
   6989  MDefinition* receiver = getOperand(receiverId);
   6990  MDefinition* rhs = getOperand(rhsId);
   6991  if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) {
   6992    // We are transpiling to generate the correct guards. We also update the
   6993    // CallInfo to use the correct arguments. Code for the inlined setter
   6994    // itself will be generated in WarpBuilder::buildInlinedCall.
   6995    callInfo_->initForSetterCall(setter, receiver, rhs);
   6996    callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor);
   6997 
   6998    // Make sure there's enough room to push the arguments on the stack.
   6999    if (!current->ensureHasSlots(3)) {
   7000      return false;
   7001    }
   7002 
   7003    return true;
   7004  }
   7005 
   7006  uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset);
   7007  uint16_t nargs = nargsAndFlags >> 16;
   7008  FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags));
   7009  WrappedFunction* wrappedTarget =
   7010      maybeGetterSetterTarget(setter, kind, nargs, flags);
   7011 
   7012  CallInfo callInfo(alloc(), /* constructing = */ false,
   7013                    /* ignoresReturnValue = */ true);
   7014  callInfo.initForSetterCall(setter, receiver, rhs);
   7015 
   7016  MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, wrappedTarget);
   7017  if (!call) {
   7018    return false;
   7019  }
   7020 
   7021  if (sameRealm) {
   7022    call->setNotCrossRealm();
   7023  }
   7024 
   7025  addEffectful(call);
   7026  return resumeAfter(call);
   7027 }
   7028 
   7029 bool WarpCacheIRTranspiler::emitCallScriptedSetter(
   7030    ObjOperandId receiverId, ObjOperandId calleeId, ValOperandId rhsId,
   7031    bool sameRealm, uint32_t nargsAndFlagsOffset) {
   7032  MDefinition* setter = getOperand(calleeId);
   7033  return emitCallSetter(CallKind::Scripted, receiverId, setter, rhsId,
   7034                        sameRealm, nargsAndFlagsOffset);
   7035 }
   7036 
   7037 bool WarpCacheIRTranspiler::emitCallInlinedSetter(
   7038    ObjOperandId receiverId, ObjOperandId calleeId, ValOperandId rhsId,
   7039    uint32_t icScriptOffset, bool sameRealm, uint32_t nargsAndFlagsOffset) {
   7040  MDefinition* setter = getOperand(calleeId);
   7041  return emitCallSetter(CallKind::Scripted, receiverId, setter, rhsId,
   7042                        sameRealm, nargsAndFlagsOffset);
   7043 }
   7044 
   7045 bool WarpCacheIRTranspiler::emitCallNativeSetter(ObjOperandId receiverId,
   7046                                                 uint32_t setterOffset,
   7047                                                 ValOperandId rhsId,
   7048                                                 bool sameRealm,
   7049                                                 uint32_t nargsAndFlagsOffset) {
   7050  MDefinition* setter = objectStubField(setterOffset);
   7051  return emitCallSetter(CallKind::Native, receiverId, setter, rhsId, sameRealm,
   7052                        nargsAndFlagsOffset);
   7053 }
   7054 
   7055 bool WarpCacheIRTranspiler::emitMetaScriptedThisShape(
   7056    uint32_t thisShapeOffset) {
   7057  SharedShape* shape = &shapeStubField(thisShapeOffset)->asShared();
   7058  MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_);
   7059 
   7060  MConstant* shapeConst = MConstant::NewShape(alloc(), shape);
   7061  add(shapeConst);
   7062 
   7063  // TODO: support pre-tenuring.
   7064  gc::Heap heap = gc::Heap::Default;
   7065 
   7066  uint32_t numFixedSlots = shape->numFixedSlots();
   7067  uint32_t numDynamicSlots = NativeObject::calculateDynamicSlots(shape);
   7068  gc::AllocKind kind = gc::GetGCObjectKind(numFixedSlots);
   7069  MOZ_ASSERT(gc::GetObjectFinalizeKind(&PlainObject::class_) ==
   7070             gc::FinalizeKind::None);
   7071  MOZ_ASSERT(!IsFinalizedKind(kind));
   7072 
   7073  auto* createThis = MNewPlainObject::New(alloc(), shapeConst, numFixedSlots,
   7074                                          numDynamicSlots, kind, heap);
   7075  add(createThis);
   7076 
   7077  callInfo_->thisArg()->setImplicitlyUsedUnchecked();
   7078  callInfo_->setThis(createThis);
   7079  return true;
   7080 }
   7081 
   7082 bool WarpCacheIRTranspiler::emitReturnFromIC() { return true; }
   7083 
   7084 bool WarpCacheIRTranspiler::emitBailout() {
   7085  auto* bail = MBail::New(alloc());
   7086  add(bail);
   7087 
   7088  return true;
   7089 }
   7090 
   7091 bool WarpCacheIRTranspiler::emitAssertPropertyLookup(ObjOperandId objId,
   7092                                                     uint32_t idOffset,
   7093                                                     uint32_t slotOffset) {
   7094  // We currently only emit checks in baseline.
   7095  return true;
   7096 }
   7097 
   7098 bool WarpCacheIRTranspiler::emitAssertFloat32Result(ValOperandId valId,
   7099                                                    bool mustBeFloat32) {
   7100  MDefinition* val = getOperand(valId);
   7101 
   7102  auto* assert = MAssertFloat32::New(alloc(), val, mustBeFloat32);
   7103  addEffectful(assert);
   7104 
   7105  pushResult(constant(UndefinedValue()));
   7106  return resumeAfter(assert);
   7107 }
   7108 
   7109 bool WarpCacheIRTranspiler::emitAssertRecoveredOnBailoutResult(
   7110    ValOperandId valId, bool mustBeRecovered) {
   7111  MDefinition* val = getOperand(valId);
   7112 
   7113  // Don't assert for recovered instructions when recovering is disabled.
   7114  if (JitOptions.disableRecoverIns) {
   7115    pushResult(constant(UndefinedValue()));
   7116    return true;
   7117  }
   7118 
   7119  if (JitOptions.checkRangeAnalysis) {
   7120    // If we are checking the range of all instructions, then the guards
   7121    // inserted by Range Analysis prevent the use of recover instruction. Thus,
   7122    // we just disable these checks.
   7123    pushResult(constant(UndefinedValue()));
   7124    return true;
   7125  }
   7126 
   7127  auto* assert = MAssertRecoveredOnBailout::New(alloc(), val, mustBeRecovered);
   7128  addEffectfulUnsafe(assert);
   7129  current->push(assert);
   7130 
   7131  // Create an instruction sequence which implies that the argument of the
   7132  // assertRecoveredOnBailout function would be encoded at least in one
   7133  // Snapshot.
   7134  auto* nop = MNop::New(alloc());
   7135  add(nop);
   7136 
   7137  auto* resumePoint = MResumePoint::New(
   7138      alloc(), nop->block(), loc_.toRawBytecode(), ResumeMode::ResumeAfter);
   7139  if (!resumePoint) {
   7140    return false;
   7141  }
   7142  nop->setResumePoint(resumePoint);
   7143 
   7144  auto* encode = MEncodeSnapshot::New(alloc());
   7145  addEffectfulUnsafe(encode);
   7146 
   7147  current->pop();
   7148 
   7149  pushResult(constant(UndefinedValue()));
   7150  return true;
   7151 }
   7152 
   7153 bool WarpCacheIRTranspiler::emitGuardNoAllocationMetadataBuilder(
   7154    uint32_t builderAddrOffset) {
   7155  // This is a no-op because we discard all JIT code when set an allocation
   7156  // metadata callback.
   7157  return true;
   7158 }
   7159 
   7160 bool WarpCacheIRTranspiler::emitNewPlainObjectResult(uint32_t numFixedSlots,
   7161                                                     uint32_t numDynamicSlots,
   7162                                                     gc::AllocKind allocKind,
   7163                                                     uint32_t shapeOffset,
   7164                                                     uint32_t siteOffset) {
   7165  Shape* shape = shapeStubField(shapeOffset);
   7166  gc::Heap heap = allocSiteInitialHeapField(siteOffset);
   7167 
   7168  auto* shapeConstant = MConstant::NewShape(alloc(), shape);
   7169  add(shapeConstant);
   7170 
   7171  auto* obj = MNewPlainObject::New(alloc(), shapeConstant, numFixedSlots,
   7172                                   numDynamicSlots, allocKind, heap);
   7173  add(obj);
   7174 
   7175  pushResult(obj);
   7176  return true;
   7177 }
   7178 
   7179 bool WarpCacheIRTranspiler::emitNewArrayObjectResult(uint32_t length,
   7180                                                     uint32_t shapeOffset,
   7181                                                     uint32_t siteOffset) {
   7182  Shape* shape = shapeStubField(shapeOffset);
   7183  gc::Heap heap = allocSiteInitialHeapField(siteOffset);
   7184 
   7185  auto* shapeConstant = MConstant::NewShape(alloc(), shape);
   7186  add(shapeConstant);
   7187 
   7188  auto* obj = MNewArrayObject::New(alloc(), shapeConstant, length, heap);
   7189  add(obj);
   7190 
   7191  pushResult(obj);
   7192  return true;
   7193 }
   7194 
   7195 bool WarpCacheIRTranspiler::emitNewFunctionCloneResult(uint32_t canonicalOffset,
   7196                                                       gc::AllocKind allocKind,
   7197                                                       uint32_t siteOffset) {
   7198  JSObject* fun = tenuredObjectStubField(canonicalOffset);
   7199  MOZ_ASSERT(fun->is<JSFunction>());
   7200 
   7201  gc::Heap heap = allocSiteInitialHeapField(siteOffset);
   7202 
   7203  MDefinition* env = currentBlock()->environmentChain();
   7204 
   7205  // The environment chain must be an object, but the MIR type can be Value when
   7206  // phis are involved.
   7207  if (env->type() != MIRType::Object) {
   7208    MOZ_ASSERT(env->type() == MIRType::Value);
   7209    auto* unbox =
   7210        MUnbox::New(alloc(), env, MIRType::Object, MUnbox::Infallible);
   7211    current->add(unbox);
   7212    env = unbox;
   7213  }
   7214 
   7215  MConstant* funConst = constant(ObjectValue(*fun));
   7216 
   7217  auto* ins = MLambda::New(alloc(), env, funConst, heap);
   7218  addEffectful(ins);
   7219  pushResult(ins);
   7220  return resumeAfter(ins);
   7221 }
   7222 
   7223 bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId,
   7224                                                        ObjOperandId calleeId,
   7225                                                        uint32_t calleeNargs) {
   7226  MDefinition* iter = getOperand(iterId);
   7227  MDefinition* callee = getOperand(calleeId);
   7228 
   7229  WrappedFunction* wrappedTarget = maybeCallTarget(callee, CallKind::Scripted);
   7230  MOZ_ASSERT(wrappedTarget);
   7231  MOZ_ASSERT(wrappedTarget->nargs() == calleeNargs);
   7232  MOZ_ASSERT(wrappedTarget->hasJitEntry());
   7233 
   7234  bool constructing = false;
   7235  bool ignoresRval = false;
   7236  bool needsThisCheck = false;
   7237  CallInfo callInfo(alloc(), constructing, ignoresRval);
   7238  callInfo.initForCloseIter(iter, callee);
   7239  MCall* call = makeCall(callInfo, needsThisCheck, wrappedTarget);
   7240  if (!call) {
   7241    return false;
   7242  }
   7243  addEffectful(call);
   7244 
   7245  // If we bail out here, after the call but before the CheckIsObj, we
   7246  // can't simply resume in the baseline interpreter. If we resume
   7247  // after the CloseIter, we won't check the return value. If we
   7248  // resume at the CloseIter, we will call the |return| method twice.
   7249  // Instead, we use a special resume mode that captures the
   7250  // intermediate value, and then checks that it's an object while
   7251  // bailing out.
   7252  current->push(call);
   7253  MResumePoint* resumePoint =
   7254      MResumePoint::New(alloc(), current, loc_.toRawBytecode(),
   7255                        ResumeMode::ResumeAfterCheckIsObject);
   7256  if (!resumePoint) {
   7257    return false;
   7258  }
   7259  call->setResumePoint(resumePoint);
   7260  current->pop();
   7261 
   7262  MCheckIsObj* check = MCheckIsObj::New(
   7263      alloc(), call, uint8_t(CheckIsObjectKind::IteratorReturn));
   7264  addEffectfulUnsafe(check);
   7265 
   7266  return resumeAfterUnchecked(check);
   7267 }
   7268 
   7269 bool WarpCacheIRTranspiler::emitGuardGlobalGeneration(
   7270    uint32_t expectedOffset, uint32_t generationAddrOffset) {
   7271  uint32_t expected = uint32StubField(expectedOffset);
   7272  const void* generationAddr = rawPointerField(generationAddrOffset);
   7273 
   7274  auto guard = MGuardGlobalGeneration::New(alloc(), expected, generationAddr);
   7275  add(guard);
   7276 
   7277  return true;
   7278 }
   7279 
   7280 #ifdef FUZZING_JS_FUZZILLI
   7281 bool WarpCacheIRTranspiler::emitFuzzilliHashResult(ValOperandId valId) {
   7282  MDefinition* input = getOperand(valId);
   7283 
   7284  auto* hash = MFuzzilliHash::New(alloc(), input);
   7285  add(hash);
   7286 
   7287  auto* store = MFuzzilliHashStore::New(alloc(), hash);
   7288  addEffectful(store);
   7289  pushResult(constant(UndefinedValue()));
   7290 
   7291  return resumeAfter(store);
   7292 }
   7293 #endif
   7294 
   7295 static void MaybeSetImplicitlyUsed(uint32_t numInstructionIdsBefore,
   7296                                   MDefinition* input) {
   7297  // When building MIR from bytecode, for each MDefinition that's an operand to
   7298  // a bytecode instruction, we must either add an SSA use or set the
   7299  // ImplicitlyUsed flag on that definition. The ImplicitlyUsed flag prevents
   7300  // the backend from optimizing-out values that will be used by Baseline after
   7301  // a bailout.
   7302  //
   7303  // WarpBuilder uses WarpPoppedValueUseChecker to assert this invariant in
   7304  // debug builds.
   7305  //
   7306  // This function is responsible for setting the ImplicitlyUsed flag for an
   7307  // input when using the transpiler. It looks at the input's most recent use
   7308  // and if that's an instruction that was added while transpiling this JSOp
   7309  // (based on the MIR instruction id) we don't set the ImplicitlyUsed flag.
   7310 
   7311  if (input->isImplicitlyUsed()) {
   7312    // Nothing to do.
   7313    return;
   7314  }
   7315 
   7316  // If the most recent use of 'input' is an instruction we just added, there is
   7317  // nothing to do.
   7318  MDefinition* inputUse = input->maybeMostRecentlyAddedDefUse();
   7319  if (inputUse && inputUse->id() >= numInstructionIdsBefore) {
   7320    return;
   7321  }
   7322 
   7323  // The transpiler didn't add a use for 'input'.
   7324  input->setImplicitlyUsed();
   7325 }
   7326 
   7327 bool jit::TranspileCacheIRToMIR(WarpBuilder* builder, BytecodeLocation loc,
   7328                                const WarpCacheIRBase* cacheIRSnapshot,
   7329                                std::initializer_list<MDefinition*> inputs,
   7330                                CallInfo* maybeCallInfo) {
   7331  uint32_t numInstructionIdsBefore =
   7332      builder->mirGen().graph().getNumInstructionIds();
   7333 
   7334  WarpCacheIRTranspiler transpiler(builder, loc, maybeCallInfo,
   7335                                   cacheIRSnapshot);
   7336  if (!transpiler.transpile(inputs)) {
   7337    return false;
   7338  }
   7339 
   7340  for (MDefinition* input : inputs) {
   7341    MaybeSetImplicitlyUsed(numInstructionIdsBefore, input);
   7342  }
   7343 
   7344  if (maybeCallInfo) {
   7345    auto maybeSetFlag = [numInstructionIdsBefore](MDefinition* def) {
   7346      MaybeSetImplicitlyUsed(numInstructionIdsBefore, def);
   7347    };
   7348    maybeCallInfo->forEachCallOperand(maybeSetFlag);
   7349  }
   7350 
   7351  return true;
   7352 }