tor-browser

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

WasmBaselineCompile.cpp (411152B)


      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 *
      4 * Copyright 2016 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 /*
     20 * [SMDOC] WebAssembly baseline compiler (RabaldrMonkey)
     21 *
     22 * For now, see WasmBCClass.h for general comments about the compiler's
     23 * structure.
     24 *
     25 * ----------------
     26 *
     27 * General assumptions for 32-bit vs 64-bit code:
     28 *
     29 * - A 32-bit register can be extended in-place to a 64-bit register on 64-bit
     30 *   systems.
     31 *
     32 * - Code that knows that Register64 has a '.reg' member on 64-bit systems and
     33 *   '.high' and '.low' members on 32-bit systems, or knows the implications
     34 *   thereof, is #ifdef JS_PUNBOX64.  All other code is #if(n)?def JS_64BIT.
     35 *
     36 * Coding standards are a little fluid:
     37 *
     38 * - In "small" code generating functions (eg emitMultiplyF64, emitQuotientI32,
     39 *   and surrounding functions; most functions fall into this class) where the
     40 *   meaning is obvious:
     41 *
     42 *   Old school:
     43 *   - if there is a single source + destination register, it is called 'r'
     44 *   - if there is one source and a different destination, they are called 'rs'
     45 *     and 'rd'
     46 *   - if there is one source + destination register and another source register
     47 *     they are called 'r' and 'rs'
     48 *   - if there are two source registers and a destination register they are
     49 *     called 'rs0', 'rs1', and 'rd'.
     50 *
     51 *   The new thing:
     52 *   - what is called 'r' in the old-school naming scheme is increasingly called
     53 *     'rsd' in source+dest cases.
     54 *
     55 * - Generic temp registers are named /temp[0-9]?/ not /tmp[0-9]?/.
     56 *
     57 * - Registers can be named non-generically for their function ('rp' for the
     58 *   'pointer' register and 'rv' for the 'value' register are typical) and those
     59 *   names may or may not have an 'r' prefix.
     60 *
     61 * - "Larger" code generating functions make their own rules.
     62 */
     63 
     64 /*
     65 * [SMDOC] WebAssembly baseline compiler -- Lazy Tier-Up mechanism
     66 *
     67 * For baseline functions, we compile in code to monitor the function's
     68 * "hotness" and request tier-up once that hotness crosses a threshold.
     69 *
     70 * (1) Each function has an associated int32_t counter,
     71 *     FuncDefInstanceData::hotnessCounter.  These are stored in an array in
     72 *     the Instance.  Hence access to them is fast and thread-local.
     73 *
     74 * (2) On instantiation, the counters are set to some positive number
     75 *     (Instance::init, Instance::computeInitialHotnessCounter), which is a
     76 *     very crude estimate of the cost of Ion compilation of the function.
     77 *
     78 * (3) In baseline compilation, a function decrements its counter at every
     79 *     entry (BaseCompiler::beginFunction) and at the start of every loop
     80 *     iteration (BaseCompiler::emitLoop).  The decrement code is created by
     81 *     BaseCompiler::addHotnessCheck.
     82 *
     83 * (4) The decrement is by some value in the range 1 .. 127, as computed from
     84 *     the function or loop-body size, by BlockSizeToDownwardsStep.
     85 *
     86 * (5) For loops, the body size is known only at the end of the loop, but the
     87 *     check is required at the start of the body.  Hence the value is patched
     88 *     in at the end (BaseCompiler::emitEnd, case LabelKind::Loop).
     89 *
     90 * (6) BaseCompiler::addHotnessCheck creates the shortest possible
     91 *     decrement/check code, to minimise both time and code-space overhead.  On
     92 *     Intel it is only two instructions.  The counter has the value from (4)
     93 *     subtracted from it.  If the result is negative, we jump to OOL code
     94 *     (class OutOfLineRequestTierUp) which requests tier up; control then
     95 *     continues immediately after the check.
     96 *
     97 * (7) The OOL tier-up request code calls the stub pointed to by
     98 *     Instance::requestTierUpStub_.  This always points to the stub created by
     99 *     GenerateRequestTierUpStub.  This saves all registers and calls onwards
    100 *     to WasmHandleRequestTierUp in C++-land.
    101 *
    102 * (8) WasmHandleRequestTierUp figures out which function in which Instance is
    103 *     requesting tier-up.  It sets the function's counter (1) to the largest
    104 *     possible value, which is 2^31-1.  It then calls onwards to
    105 *     Code::requestTierUp, which requests off-thread Ion compilation of the
    106 *     function, then immediately returns.
    107 *
    108 * (9) It is important that (8) sets the counter to 2^31-1 (as close to
    109 *     infinity as possible).  This is because it may be arbitrarily long
    110 *     before the optimised code becomes available.  In the meantime the
    111 *     baseline version of the function will continue to run.  We do not want
    112 *     it to make frequent duplicate requests for tier-up.  Although a request
    113 *     for tier-up is relatively cheap (a few hundred instructions), it is
    114 *     still way more expensive than the fast-case for a hotness check (2 insns
    115 *     on Intel), and performance of the baseline code will be badly affected
    116 *     if it makes many duplicate requests.
    117 *
    118 * (10) Of course it is impossible to *guarantee* that a baseline function will
    119 *      not make a duplicate request, because the Ion compilation of the
    120 *      function could take arbitrarily long, or even fail completely (eg OOM).
    121 *      Hence it is necessary for WasmCode::requestTierUp (8) to detect and
    122 *      ignore duplicate requests.
    123 *
    124 * (11) Each Instance of a Module runs in its own thread and has its own array
    125 *      of counters.  This makes the counter updating thread-local and cheap.
    126 *      But it means that, if a Module has multiple threads (Instances), it
    127 *      could be that a function never gets hot enough to request tier up,
    128 *      because it is not hot enough in any single thread, even though the
    129 *      total hotness summed across all threads is enough to request tier up.
    130 *      Whether this inaccuracy is a problem in practice remains to be seen.
    131 *
    132 * (12) Code::requestTierUp (8) creates a PartialTier2CompileTask and queues it
    133 *      for execution.  It does not do the compilation itself.
    134 *
    135 * (13) A PartialTier2CompileTask's runHelperThreadTask (running on a helper
    136 *      thread) calls CompilePartialTier2.  This compiles the function with Ion
    137 *      and racily updates the tiering table entry for the function, which
    138 *      lives in Code::jumpTables_::tiering_.
    139 *
    140 * (14) Subsequent calls to the function's baseline entry points will then jump
    141 *      to the Ion version of the function.  Hence lazy tier-up is achieved.
    142 */
    143 
    144 #include "wasm/WasmBaselineCompile.h"
    145 
    146 #include "wasm/WasmAnyRef.h"
    147 #include "wasm/WasmBCClass.h"
    148 #include "wasm/WasmBCDefs.h"
    149 #include "wasm/WasmBCFrame.h"
    150 #include "wasm/WasmBCRegDefs.h"
    151 #include "wasm/WasmBCStk.h"
    152 #include "wasm/WasmValType.h"
    153 
    154 #include "jit/MacroAssembler-inl.h"
    155 #include "wasm/WasmBCClass-inl.h"
    156 #include "wasm/WasmBCCodegen-inl.h"
    157 #include "wasm/WasmBCRegDefs-inl.h"
    158 #include "wasm/WasmBCRegMgmt-inl.h"
    159 #include "wasm/WasmBCStkMgmt-inl.h"
    160 
    161 namespace js {
    162 namespace wasm {
    163 
    164 using namespace js::jit;
    165 
    166 using mozilla::Maybe;
    167 using mozilla::Nothing;
    168 using mozilla::Some;
    169 
    170 ////////////////////////////////////////////////////////////
    171 //
    172 // Out of line code management.
    173 
    174 // The baseline compiler will use OOL code more sparingly than Ion since our
    175 // code is not high performance and frills like code density and branch
    176 // prediction friendliness will be less important.
    177 class OutOfLineCode : public TempObject {
    178 private:
    179  NonAssertingLabel entry_;
    180  NonAssertingLabel rejoin_;
    181  StackHeight stackHeight_;
    182 
    183 public:
    184  OutOfLineCode() : stackHeight_(StackHeight::Invalid()) {}
    185 
    186  Label* entry() { return &entry_; }
    187  Label* rejoin() { return &rejoin_; }
    188 
    189  void setStackHeight(StackHeight stackHeight) {
    190    MOZ_ASSERT(!stackHeight_.isValid());
    191    stackHeight_ = stackHeight;
    192  }
    193 
    194  void bind(BaseStackFrame* fr, MacroAssembler* masm) {
    195    MOZ_ASSERT(stackHeight_.isValid());
    196    masm->bind(&entry_);
    197    fr->setStackHeight(stackHeight_);
    198  }
    199 
    200  // The generate() method must be careful about register use because it will be
    201  // invoked when there is a register assignment in the BaseCompiler that does
    202  // not correspond to the available registers when the generated OOL code is
    203  // executed.  The register allocator *must not* be called.
    204  //
    205  // The best strategy is for the creator of the OOL object to allocate all
    206  // temps that the OOL code will need.
    207  //
    208  // Input, output, and temp registers are embedded in the OOL object and are
    209  // known to the code generator.
    210  //
    211  // Scratch registers are available to use in OOL code.
    212  //
    213  // All other registers must be explicitly saved and restored by the OOL code
    214  // before being used.
    215 
    216  virtual void generate(MacroAssembler* masm) = 0;
    217 };
    218 
    219 class OutOfLineAbortingTrap : public OutOfLineCode {
    220  Trap trap_;
    221  TrapSiteDesc desc_;
    222 
    223 public:
    224  OutOfLineAbortingTrap(Trap trap, const TrapSiteDesc& desc)
    225      : trap_(trap), desc_(desc) {}
    226 
    227  virtual void generate(MacroAssembler* masm) override {
    228    masm->wasmTrap(trap_, desc_);
    229    MOZ_ASSERT(!rejoin()->bound());
    230  }
    231 };
    232 
    233 class OutOfLineResumableTrap : public OutOfLineCode {
    234  Trap trap_;
    235  TrapSiteDesc desc_;
    236  wasm::StackMap* stackMap_;
    237  wasm::StackMaps* stackMaps_;
    238 
    239 public:
    240  OutOfLineResumableTrap(Trap trap, const TrapSiteDesc& desc,
    241                         wasm::StackMap* stackMap, wasm::StackMaps* stackMaps)
    242      : trap_(trap), desc_(desc), stackMap_(stackMap), stackMaps_(stackMaps) {}
    243 
    244  virtual void generate(MacroAssembler* masm) override {
    245    masm->wasmTrap(trap_, desc_);
    246    if (stackMap_ && !stackMaps_->add(masm->currentOffset(), stackMap_)) {
    247      masm->setOOM();
    248    }
    249    masm->jump(rejoin());
    250  }
    251 };
    252 
    253 OutOfLineCode* BaseCompiler::addOutOfLineCode(OutOfLineCode* ool) {
    254  if (!ool || !outOfLine_.append(ool)) {
    255    return nullptr;
    256  }
    257  ool->setStackHeight(fr.stackHeight());
    258  return ool;
    259 }
    260 
    261 bool BaseCompiler::generateOutOfLineCode() {
    262  for (auto* ool : outOfLine_) {
    263    if (!ool->entry()->used()) {
    264      continue;
    265    }
    266    ool->bind(&fr, &masm);
    267    ool->generate(&masm);
    268  }
    269 
    270  return !masm.oom();
    271 }
    272 
    273 //////////////////////////////////////////////////////////////////////////////
    274 //
    275 // Sundry code generation.
    276 
    277 bool BaseCompiler::addInterruptCheck() {
    278 #ifdef RABALDR_PIN_INSTANCE
    279  Register tmp(InstanceReg);
    280 #else
    281  ScratchI32 tmp(*this);
    282  fr.loadInstancePtr(tmp);
    283 #endif
    284  Label ok;
    285  masm.branch32(Assembler::Equal,
    286                Address(tmp, wasm::Instance::offsetOfInterrupt()), Imm32(0),
    287                &ok);
    288  trap(wasm::Trap::CheckInterrupt);
    289  masm.bind(&ok);
    290  return createStackMap("addInterruptCheck");
    291 }
    292 
    293 void BaseCompiler::checkDivideByZero(RegI32 rhs) {
    294  Label nonZero;
    295  masm.branchTest32(Assembler::NonZero, rhs, rhs, &nonZero);
    296  trap(Trap::IntegerDivideByZero);
    297  masm.bind(&nonZero);
    298 }
    299 
    300 void BaseCompiler::checkDivideByZero(RegI64 r) {
    301  Label nonZero;
    302  ScratchI32 scratch(*this);
    303  masm.branchTest64(Assembler::NonZero, r, r, scratch, &nonZero);
    304  trap(Trap::IntegerDivideByZero);
    305  masm.bind(&nonZero);
    306 }
    307 
    308 void BaseCompiler::checkDivideSignedOverflow(RegI32 rhs, RegI32 srcDest,
    309                                             Label* done, bool zeroOnOverflow) {
    310  Label notMin;
    311  masm.branch32(Assembler::NotEqual, srcDest, Imm32(INT32_MIN), &notMin);
    312  if (zeroOnOverflow) {
    313    masm.branch32(Assembler::NotEqual, rhs, Imm32(-1), &notMin);
    314    moveImm32(0, srcDest);
    315    masm.jump(done);
    316  } else {
    317    masm.branch32(Assembler::NotEqual, rhs, Imm32(-1), &notMin);
    318    trap(Trap::IntegerOverflow);
    319  }
    320  masm.bind(&notMin);
    321 }
    322 
    323 void BaseCompiler::checkDivideSignedOverflow(RegI64 rhs, RegI64 srcDest,
    324                                             Label* done, bool zeroOnOverflow) {
    325  Label notmin;
    326  masm.branch64(Assembler::NotEqual, srcDest, Imm64(INT64_MIN), &notmin);
    327  masm.branch64(Assembler::NotEqual, rhs, Imm64(-1), &notmin);
    328  if (zeroOnOverflow) {
    329    masm.xor64(srcDest, srcDest);
    330    masm.jump(done);
    331  } else {
    332    trap(Trap::IntegerOverflow);
    333  }
    334  masm.bind(&notmin);
    335 }
    336 
    337 void BaseCompiler::jumpTable(const LabelVector& labels, Label* theTable) {
    338  // Flush constant pools to ensure that the table is never interrupted by
    339  // constant pool entries.
    340  masm.flush();
    341 
    342 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
    343  // Prevent nop sequences to appear in the jump table.
    344  AutoForbidNops afn(&masm);
    345 #endif
    346  masm.bind(theTable);
    347 
    348  for (const auto& label : labels) {
    349    CodeLabel cl;
    350    masm.writeCodePointer(&cl);
    351    cl.target()->bind(label.offset());
    352    masm.addCodeLabel(cl);
    353  }
    354 }
    355 
    356 void BaseCompiler::tableSwitch(Label* theTable, RegI32 switchValue,
    357                               Label* dispatchCode) {
    358  masm.bind(dispatchCode);
    359 
    360 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    361  ScratchI32 scratch(*this);
    362  CodeLabel tableCl;
    363 
    364  masm.mov(&tableCl, scratch);
    365 
    366  tableCl.target()->bind(theTable->offset());
    367  masm.addCodeLabel(tableCl);
    368 
    369  masm.jmp(Operand(scratch, switchValue, ScalePointer));
    370 #elif defined(JS_CODEGEN_ARM)
    371  // Flush constant pools: offset must reflect the distance from the MOV
    372  // to the start of the table; as the address of the MOV is given by the
    373  // label, nothing must come between the bind() and the ma_mov().
    374  AutoForbidPoolsAndNops afp(&masm,
    375                             /* number of instructions in scope = */ 5);
    376 
    377  ScratchI32 scratch(*this);
    378 
    379  // Compute the offset from the ma_mov instruction to the jump table.
    380  Label here;
    381  masm.bind(&here);
    382  uint32_t offset = here.offset() - theTable->offset();
    383 
    384  // Read PC+8
    385  masm.ma_mov(pc, scratch);
    386 
    387  // ARM scratch register is required by ma_sub.
    388  ScratchRegisterScope arm_scratch(*this);
    389 
    390  // Compute the absolute table base pointer into `scratch`, offset by 8
    391  // to account for the fact that ma_mov read PC+8.
    392  masm.ma_sub(Imm32(offset + 8), scratch, arm_scratch);
    393 
    394  // Jump indirect via table element.
    395  masm.ma_ldr(DTRAddr(scratch, DtrRegImmShift(switchValue, LSL, 2)), pc, Offset,
    396              Assembler::Always);
    397 #elif defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \
    398    defined(JS_CODEGEN_RISCV64)
    399  ScratchI32 scratch(*this);
    400  CodeLabel tableCl;
    401 
    402  masm.ma_li(scratch, &tableCl);
    403 
    404  tableCl.target()->bind(theTable->offset());
    405  masm.addCodeLabel(tableCl);
    406 
    407  masm.branchToComputedAddress(BaseIndex(scratch, switchValue, ScalePointer));
    408 #elif defined(JS_CODEGEN_ARM64)
    409  AutoForbidPoolsAndNops afp(&masm,
    410                             /* number of instructions in scope = */ 4);
    411 
    412  ScratchI32 scratch(*this);
    413 
    414  ARMRegister s(scratch, 64);
    415  ARMRegister v(switchValue, 64);
    416  masm.Adr(s, theTable);
    417  masm.Add(s, s, Operand(v, vixl::LSL, 3));
    418  masm.Ldr(s, MemOperand(s, 0));
    419  masm.Br(s);
    420 #else
    421  MOZ_CRASH("BaseCompiler platform hook: tableSwitch");
    422 #endif
    423 }
    424 
    425 // Helpers for accessing the "baseline scratch" areas: all targets
    426 void BaseCompiler::stashWord(RegPtr instancePtr, size_t index, RegPtr r) {
    427  MOZ_ASSERT(r != instancePtr);
    428  MOZ_ASSERT(index < Instance::N_BASELINE_SCRATCH_WORDS);
    429  masm.storePtr(r,
    430                Address(instancePtr, Instance::offsetOfBaselineScratchWords() +
    431                                         index * sizeof(uintptr_t)));
    432 }
    433 
    434 void BaseCompiler::unstashWord(RegPtr instancePtr, size_t index, RegPtr r) {
    435  MOZ_ASSERT(index < Instance::N_BASELINE_SCRATCH_WORDS);
    436  masm.loadPtr(Address(instancePtr, Instance::offsetOfBaselineScratchWords() +
    437                                        index * sizeof(uintptr_t)),
    438               r);
    439 }
    440 
    441 // Helpers for accessing the "baseline scratch" areas: X86 only
    442 #ifdef JS_CODEGEN_X86
    443 void BaseCompiler::stashI64(RegPtr regForInstance, RegI64 r) {
    444  static_assert(sizeof(uintptr_t) == 4);
    445  MOZ_ASSERT(Instance::sizeOfBaselineScratchWords() >= 8);
    446  MOZ_ASSERT(regForInstance != r.low && regForInstance != r.high);
    447 #  ifdef RABALDR_PIN_INSTANCE
    448 #    error "Pinned instance not expected"
    449 #  endif
    450  fr.loadInstancePtr(regForInstance);
    451  masm.store32(
    452      r.low, Address(regForInstance, Instance::offsetOfBaselineScratchWords()));
    453  masm.store32(r.high, Address(regForInstance,
    454                               Instance::offsetOfBaselineScratchWords() + 4));
    455 }
    456 
    457 void BaseCompiler::unstashI64(RegPtr regForInstance, RegI64 r) {
    458  static_assert(sizeof(uintptr_t) == 4);
    459  MOZ_ASSERT(Instance::sizeOfBaselineScratchWords() >= 8);
    460 #  ifdef RABALDR_PIN_INSTANCE
    461 #    error "Pinned instance not expected"
    462 #  endif
    463  fr.loadInstancePtr(regForInstance);
    464  if (regForInstance == r.low) {
    465    masm.load32(
    466        Address(regForInstance, Instance::offsetOfBaselineScratchWords() + 4),
    467        r.high);
    468    masm.load32(
    469        Address(regForInstance, Instance::offsetOfBaselineScratchWords()),
    470        r.low);
    471  } else {
    472    masm.load32(
    473        Address(regForInstance, Instance::offsetOfBaselineScratchWords()),
    474        r.low);
    475    masm.load32(
    476        Address(regForInstance, Instance::offsetOfBaselineScratchWords() + 4),
    477        r.high);
    478  }
    479 }
    480 #endif
    481 
    482 // Given the bytecode size of a block (a complete function body, or a loop
    483 // body), return the required downwards step for the associated hotness
    484 // counter.  Returned value will be in 1 .. 127 inclusive.
    485 static uint32_t BlockSizeToDownwardsStep(size_t blockBytecodeSize) {
    486  MOZ_RELEASE_ASSERT(blockBytecodeSize <= size_t(MaxFunctionBytes));
    487  const uint32_t BYTECODES_PER_STEP = 20;  // tunable parameter
    488  size_t step = blockBytecodeSize / BYTECODES_PER_STEP;
    489  step = std::max<uint32_t>(step, 1);
    490  step = std::min<uint32_t>(step, 127);
    491  return uint32_t(step);
    492 }
    493 
    494 //////////////////////////////////////////////////////////////////////////////
    495 //
    496 // Function entry and exit
    497 
    498 bool BaseCompiler::beginFunction() {
    499  AutoCreatedBy acb(masm, "(wasm)BaseCompiler::beginFunction");
    500 
    501  JitSpew(JitSpew_Codegen, "# ========================================");
    502  JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
    503  JitSpew(JitSpew_Codegen,
    504          "# beginFunction: start of function prologue for index %d",
    505          (int)func_.index);
    506 
    507  // Make a start on the stackmap for this function.  Inspect the args so
    508  // as to determine which of them are both in-memory and pointer-typed, and
    509  // add entries to machineStackTracker as appropriate.
    510 
    511  ArgTypeVector args(funcType());
    512  size_t inboundStackArgBytes = StackArgAreaSizeUnaligned(args, ABIKind::Wasm);
    513  MOZ_ASSERT(inboundStackArgBytes % sizeof(void*) == 0);
    514  stackMapGenerator_.numStackArgBytes = inboundStackArgBytes;
    515 
    516  MOZ_ASSERT(stackMapGenerator_.machineStackTracker.length() == 0);
    517  if (!stackMapGenerator_.machineStackTracker.pushNonGCPointers(
    518          stackMapGenerator_.numStackArgBytes / sizeof(void*))) {
    519    return false;
    520  }
    521 
    522  // Identify GC-managed pointers passed on the stack.
    523  for (ABIArgIter i(args, ABIKind::Wasm); !i.done(); i++) {
    524    ABIArg argLoc = *i;
    525    if (argLoc.kind() == ABIArg::Stack &&
    526        args[i.index()] == MIRType::WasmAnyRef) {
    527      uint32_t offset = argLoc.offsetFromArgBase();
    528      MOZ_ASSERT(offset < inboundStackArgBytes);
    529      MOZ_ASSERT(offset % sizeof(void*) == 0);
    530      stackMapGenerator_.machineStackTracker.setGCPointer(offset /
    531                                                          sizeof(void*));
    532    }
    533  }
    534 
    535  perfSpewer_.startRecording();
    536  perfSpewer_.markStartOffset(masm.currentOffset());
    537  perfSpewer_.recordOffset(masm, "Prologue");
    538  GenerateFunctionPrologue(
    539      masm, CallIndirectId::forFunc(codeMeta_, func_.index),
    540      compilerEnv_.mode() != CompileMode::Once ? Some(func_.index) : Nothing(),
    541      &offsets_);
    542 
    543  // GenerateFunctionPrologue pushes exactly one wasm::Frame's worth of
    544  // stuff, and none of the values are GC pointers.  Hence:
    545  if (!stackMapGenerator_.machineStackTracker.pushNonGCPointers(
    546          sizeof(Frame) / sizeof(void*))) {
    547    return false;
    548  }
    549 
    550  // Initialize DebugFrame fields before the stack overflow trap so that
    551  // we have the invariant that all observable Frames in a debugEnabled
    552  // Module have valid DebugFrames.
    553  if (compilerEnv_.debugEnabled()) {
    554 #ifdef JS_CODEGEN_ARM64
    555    static_assert(DebugFrame::offsetOfFrame() % WasmStackAlignment == 0,
    556                  "aligned");
    557 #endif
    558    masm.reserveStack(DebugFrame::offsetOfFrame());
    559    if (!stackMapGenerator_.machineStackTracker.pushNonGCPointers(
    560            DebugFrame::offsetOfFrame() / sizeof(void*))) {
    561      return false;
    562    }
    563 
    564    masm.store32(Imm32(func_.index), Address(masm.getStackPointer(),
    565                                             DebugFrame::offsetOfFuncIndex()));
    566    masm.store32(Imm32(0),
    567                 Address(masm.getStackPointer(), DebugFrame::offsetOfFlags()));
    568 
    569    // No need to initialize cachedReturnJSValue_ or any ref-typed spilled
    570    // register results, as they are traced if and only if a corresponding
    571    // flag (hasCachedReturnJSValue or hasSpilledRefRegisterResult) is set.
    572  }
    573 
    574  // Generate a stack-overflow check and its associated stackmap.
    575 
    576  ExitStubMapVector extras;
    577  StackMap* functionEntryStackMap;
    578  if (!stackMapGenerator_.generateStackmapEntriesForTrapExit(args, &extras) ||
    579      !stackMapGenerator_.createStackMap("stack check", extras,
    580                                         HasDebugFrameWithLiveRefs::No, stk_,
    581                                         &functionEntryStackMap)) {
    582    return false;
    583  }
    584 
    585  OutOfLineCode* oolStackOverflowTrap =
    586      addOutOfLineCode(new (alloc_) OutOfLineAbortingTrap(
    587          Trap::StackOverflow,
    588          TrapSiteDesc(BytecodeOffset(func_.lineOrBytecode))));
    589  if (!oolStackOverflowTrap) {
    590    return false;
    591  }
    592  fr.checkStack(ABINonArgReg0, ABINonArgReg1, oolStackOverflowTrap->entry());
    593 
    594  OutOfLineCode* oolInterruptTrap = addOutOfLineCode(
    595      new (alloc_) OutOfLineResumableTrap(Trap::CheckInterrupt, trapSiteDesc(),
    596                                          functionEntryStackMap, stackMaps_));
    597  if (!oolInterruptTrap) {
    598    return false;
    599  }
    600  masm.branch32(Assembler::NotEqual,
    601                Address(InstanceReg, wasm::Instance::offsetOfInterrupt()),
    602                Imm32(0), oolInterruptTrap->entry());
    603  masm.bind(oolInterruptTrap->rejoin());
    604 
    605  size_t reservedBytes = fr.fixedAllocSize() - masm.framePushed();
    606  MOZ_ASSERT(0 == (reservedBytes % sizeof(void*)));
    607 
    608  masm.reserveStack(reservedBytes);
    609  fr.onFixedStackAllocated();
    610  if (!stackMapGenerator_.machineStackTracker.pushNonGCPointers(
    611          reservedBytes / sizeof(void*))) {
    612    return false;
    613  }
    614 
    615  // Locals are stack allocated.  Mark ref-typed ones in the stackmap
    616  // accordingly.
    617  for (const Local& l : localInfo_) {
    618    // Locals that are stack arguments were already added to the stackmap
    619    // before pushing the frame.
    620    if (l.type == MIRType::WasmAnyRef && !l.isStackArgument()) {
    621      uint32_t offs = fr.localOffsetFromSp(l);
    622      MOZ_ASSERT(0 == (offs % sizeof(void*)));
    623      stackMapGenerator_.machineStackTracker.setGCPointer(offs / sizeof(void*));
    624    }
    625  }
    626 
    627  // Copy arguments from registers to stack.
    628  for (ABIArgIter i(args, ABIKind::Wasm); !i.done(); i++) {
    629    if (args.isSyntheticStackResultPointerArg(i.index())) {
    630      // If there are stack results and the pointer to stack results
    631      // was passed in a register, store it to the stack.
    632      if (i->argInRegister()) {
    633        fr.storeIncomingStackResultAreaPtr(RegPtr(i->gpr()));
    634      }
    635      // If we're in a debug frame, copy the stack result pointer arg
    636      // to a well-known place.
    637      if (compilerEnv_.debugEnabled()) {
    638        Register target = ABINonArgReturnReg0;
    639        fr.loadIncomingStackResultAreaPtr(RegPtr(target));
    640        size_t debugFrameOffset =
    641            masm.framePushed() - DebugFrame::offsetOfFrame();
    642        size_t debugStackResultsPointerOffset =
    643            debugFrameOffset + DebugFrame::offsetOfStackResultsPointer();
    644        masm.storePtr(target, Address(masm.getStackPointer(),
    645                                      debugStackResultsPointerOffset));
    646      }
    647      continue;
    648    }
    649    if (!i->argInRegister()) {
    650      continue;
    651    }
    652    Local& l = localInfo_[args.naturalIndex(i.index())];
    653    switch (i.mirType()) {
    654      case MIRType::Int32:
    655        fr.storeLocalI32(RegI32(i->gpr()), l);
    656        break;
    657      case MIRType::Int64:
    658        fr.storeLocalI64(RegI64(i->gpr64()), l);
    659        break;
    660      case MIRType::WasmAnyRef: {
    661        mozilla::DebugOnly<uint32_t> offs = fr.localOffsetFromSp(l);
    662        MOZ_ASSERT(0 == (offs % sizeof(void*)));
    663        fr.storeLocalRef(RegRef(i->gpr()), l);
    664        // We should have just visited this local in the preceding loop.
    665        MOZ_ASSERT(stackMapGenerator_.machineStackTracker.isGCPointer(
    666            offs / sizeof(void*)));
    667        break;
    668      }
    669      case MIRType::Double:
    670        fr.storeLocalF64(RegF64(i->fpu()), l);
    671        break;
    672      case MIRType::Float32:
    673        fr.storeLocalF32(RegF32(i->fpu()), l);
    674        break;
    675 #ifdef ENABLE_WASM_SIMD
    676      case MIRType::Simd128:
    677        fr.storeLocalV128(RegV128(i->fpu()), l);
    678        break;
    679 #endif
    680      default:
    681        MOZ_CRASH("Function argument type");
    682    }
    683  }
    684 
    685  fr.zeroLocals(&ra);
    686  fr.storeInstancePtr(InstanceReg);
    687 
    688  if (compilerEnv_.debugEnabled()) {
    689    insertBreakablePoint(CallSiteKind::EnterFrame);
    690    if (!createStackMap("debug: enter-frame breakpoint")) {
    691      return false;
    692    }
    693  }
    694 
    695  JitSpew(JitSpew_Codegen,
    696          "# beginFunction: enter body with masm.framePushed = %u",
    697          masm.framePushed());
    698  MOZ_ASSERT(stackMapGenerator_.framePushedAtEntryToBody.isNothing());
    699  stackMapGenerator_.framePushedAtEntryToBody.emplace(masm.framePushed());
    700 
    701  if (compilerEnv_.mode() == CompileMode::LazyTiering) {
    702    size_t funcBytecodeSize = func_.end - func_.begin;
    703    uint32_t step = BlockSizeToDownwardsStep(funcBytecodeSize);
    704 
    705    // Create a patchable hotness check and patch it immediately (only because
    706    // there's no way to directly create a non-patchable check directly).
    707    Maybe<CodeOffset> ctrDecOffset = addHotnessCheck();
    708    if (ctrDecOffset.isNothing()) {
    709      return false;
    710    }
    711    patchHotnessCheck(ctrDecOffset.value(), step);
    712  }
    713 
    714  return true;
    715 }
    716 
    717 bool BaseCompiler::endFunction() {
    718  AutoCreatedBy acb(masm, "(wasm)BaseCompiler::endFunction");
    719 
    720  JitSpew(JitSpew_Codegen, "# endFunction: start of function epilogue");
    721 
    722  // Always branch to returnLabel_.
    723  masm.breakpoint();
    724 
    725  // Patch the add in the prologue so that it checks against the correct
    726  // frame size. Flush the constant pool in case it needs to be patched.
    727  masm.flush();
    728 
    729  // Precondition for patching.
    730  if (masm.oom()) {
    731    return false;
    732  }
    733 
    734  fr.patchCheckStack();
    735 
    736  // We could skip generating the epilogue for functions which never return,
    737  // but that would mess up invariants that all functions have a return address
    738  // offset in CodeRange. It's also a rare thing, so not worth optimizing for.
    739  deadCode_ = !returnLabel_.used();
    740  masm.bind(&returnLabel_);
    741 
    742  ResultType resultType(ResultType::Vector(funcType().results()));
    743 
    744  popStackReturnValues(resultType);
    745 
    746  if (compilerEnv_.debugEnabled() && !deadCode_) {
    747    // Store and reload the return value from DebugFrame::return so that
    748    // it can be clobbered, and/or modified by the debug trap.
    749    saveRegisterReturnValues(resultType);
    750    insertBreakablePoint(CallSiteKind::Breakpoint);
    751    if (!createStackMap("debug: return-point breakpoint",
    752                        HasDebugFrameWithLiveRefs::Maybe)) {
    753      return false;
    754    }
    755    insertBreakablePoint(CallSiteKind::LeaveFrame);
    756    if (!createStackMap("debug: leave-frame breakpoint",
    757                        HasDebugFrameWithLiveRefs::Maybe)) {
    758      return false;
    759    }
    760    restoreRegisterReturnValues(resultType);
    761  }
    762 
    763 #ifndef RABALDR_PIN_INSTANCE
    764  // To satisy instance extent invariant we need to reload InstanceReg because
    765  // baseline can clobber it.
    766  fr.loadInstancePtr(InstanceReg);
    767 #endif
    768  perfSpewer_.recordOffset(masm, "Epilogue");
    769  GenerateFunctionEpilogue(masm, fr.fixedAllocSize(), &offsets_);
    770 
    771 #if defined(JS_ION_PERF)
    772  // FIXME - profiling code missing.  No bug for this.
    773 
    774  // Note the end of the inline code and start of the OOL code.
    775  // gen->perfSpewer().noteEndInlineCode(masm);
    776 #endif
    777  JitSpew(JitSpew_Codegen, "# endFunction: end of function epilogue");
    778 
    779  JitSpew(JitSpew_Codegen, "# endFunction: start of OOL code");
    780  perfSpewer_.recordOffset(masm, "OOLCode");
    781  if (!generateOutOfLineCode()) {
    782    return false;
    783  }
    784  JitSpew(JitSpew_Codegen, "# endFunction: end of OOL code");
    785 
    786  if (compilerEnv_.debugEnabled()) {
    787    JitSpew(JitSpew_Codegen, "# endFunction: start of per-function debug stub");
    788    insertPerFunctionDebugStub();
    789    JitSpew(JitSpew_Codegen, "# endFunction: end of per-function debug stub");
    790  }
    791 
    792  offsets_.end = masm.currentOffset();
    793 
    794  if (!fr.checkStackHeight()) {
    795    return decoder_.fail(decoder_.beginOffset(), "stack frame is too large");
    796  }
    797 
    798  perfSpewer_.endRecording();
    799 
    800  JitSpew(JitSpew_Codegen, "# endFunction: end of OOL code for index %d",
    801          (int)func_.index);
    802  return !masm.oom();
    803 }
    804 
    805 //////////////////////////////////////////////////////////////////////////////
    806 //
    807 // Debugger API.
    808 
    809 // [SMDOC] Wasm debug traps -- code details
    810 //
    811 // There are four pieces of code involved.
    812 //
    813 // (1) The "breakable point".  This is placed at every location where we might
    814 //     want to transfer control to the debugger, most commonly before every
    815 //     bytecode.  It must be as short and fast as possible.  It checks
    816 //     Instance::debugStub_, which is either null or a pointer to (3).  If
    817 //     non-null, a call to (2) is performed; when null, nothing happens.
    818 //
    819 // (2) The "per function debug stub".  There is one per function.  It consults
    820 //     a bit-vector attached to the Instance, to see whether breakpoints for
    821 //     the current function are enabled.  If not, it returns (to (1), hence
    822 //     having no effect).  Otherwise, it jumps (not calls) onwards to (3).
    823 //
    824 // (3) The "debug stub" -- not to be confused with the "per function debug
    825 //     stub".  There is one per module.  This saves all the registers and
    826 //     calls onwards to (4), which is in C++ land.  When that call returns,
    827 //     (3) itself returns, which transfers control directly back to (after)
    828 //     (1).
    829 //
    830 // (4) In C++ land -- WasmHandleDebugTrap, corresponding to
    831 //     SymbolicAddress::HandleDebugTrap.  This contains the detailed logic
    832 //     needed to handle the breakpoint.
    833 
    834 void BaseCompiler::insertBreakablePoint(CallSiteKind kind) {
    835  MOZ_ASSERT(!deadCode_);
    836 
    837  // A sync() must happen before this. The debug stub does not save all live
    838  // registers.
    839  MOZ_ASSERT(!hasLiveRegsOnStk());
    840 
    841 #ifndef RABALDR_PIN_INSTANCE
    842  fr.loadInstancePtr(InstanceReg);
    843 #endif
    844 
    845  // The breakpoint code must call the breakpoint handler installed on the
    846  // instance if it is not null.  There is one breakable point before
    847  // every bytecode, and one at the beginning and at the end of the function.
    848  //
    849  // There are many constraints:
    850  //
    851  //  - Code should be read-only; we do not want to patch
    852  //  - The breakpoint code should be as dense as possible, given the volume of
    853  //    breakable points
    854  //  - The handler-is-null case should be as fast as we can make it
    855  //
    856  // The scratch register is available here.
    857  //
    858  // An unconditional callout would be densest but is too slow.  The best
    859  // balance results from an inline test for null with a conditional call.  The
    860  // best code sequence is platform-dependent.
    861  //
    862  // The conditional call goes to a stub attached to the function that performs
    863  // further filtering before calling the breakpoint handler.
    864 #if defined(JS_CODEGEN_X64)
    865  // REX 83 MODRM OFFS IB
    866  static_assert(Instance::offsetOfDebugStub() < 128);
    867  masm.cmpq(Imm32(0),
    868            Operand(Address(InstanceReg, Instance::offsetOfDebugStub())));
    869 
    870  // 74 OFFS
    871  Label L;
    872  L.bind(masm.currentOffset() + 7);
    873  masm.j(Assembler::Zero, &L);
    874 
    875  // E8 OFFS OFFS OFFS OFFS
    876  masm.call(&perFunctionDebugStub_);
    877  masm.append(CallSiteDesc(iter_.lastOpcodeOffset(), kind),
    878              CodeOffset(masm.currentOffset()));
    879 
    880  // Branch destination
    881  MOZ_ASSERT_IF(!masm.oom(), masm.currentOffset() == uint32_t(L.offset()));
    882 #elif defined(JS_CODEGEN_X86)
    883  // 83 MODRM OFFS IB
    884  static_assert(Instance::offsetOfDebugStub() < 128);
    885  masm.cmpl(Imm32(0),
    886            Operand(Address(InstanceReg, Instance::offsetOfDebugStub())));
    887 
    888  // 74 OFFS
    889  Label L;
    890  L.bind(masm.currentOffset() + 7);
    891  masm.j(Assembler::Zero, &L);
    892 
    893  // E8 OFFS OFFS OFFS OFFS
    894  masm.call(&perFunctionDebugStub_);
    895  masm.append(CallSiteDesc(iter_.lastOpcodeOffset(), kind),
    896              CodeOffset(masm.currentOffset()));
    897 
    898  // Branch destination
    899  MOZ_ASSERT_IF(!masm.oom(), masm.currentOffset() == uint32_t(L.offset()));
    900 #elif defined(JS_CODEGEN_ARM64)
    901  ScratchPtr scratch(*this);
    902  ARMRegister tmp(scratch, 64);
    903  Label L;
    904  masm.Ldr(tmp,
    905           MemOperand(Address(InstanceReg, Instance::offsetOfDebugStub())));
    906  masm.Cbz(tmp, &L);
    907  masm.Bl(&perFunctionDebugStub_);
    908  masm.append(CallSiteDesc(iter_.lastOpcodeOffset(), kind),
    909              CodeOffset(masm.currentOffset()));
    910  masm.bind(&L);
    911 #elif defined(JS_CODEGEN_ARM)
    912  ScratchPtr scratch(*this);
    913  masm.loadPtr(Address(InstanceReg, Instance::offsetOfDebugStub()), scratch);
    914  masm.ma_orr(scratch, scratch, SetCC);
    915  masm.ma_bl(&perFunctionDebugStub_, Assembler::NonZero);
    916  masm.append(CallSiteDesc(iter_.lastOpcodeOffset(), kind),
    917              CodeOffset(masm.currentOffset()));
    918 #elif defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_MIPS64) || \
    919    defined(JS_CODEGEN_RISCV64)
    920  ScratchPtr scratch(*this);
    921  Label L;
    922  masm.loadPtr(Address(InstanceReg, Instance::offsetOfDebugStub()), scratch);
    923  masm.branchPtr(Assembler::Equal, scratch, ImmWord(0), &L);
    924  const CodeOffset retAddr = masm.call(&perFunctionDebugStub_);
    925  masm.append(CallSiteDesc(iter_.lastOpcodeOffset(), kind), retAddr);
    926  masm.bind(&L);
    927 #else
    928  MOZ_CRASH("BaseCompiler platform hook: insertBreakablePoint");
    929 #endif
    930 }
    931 
    932 void BaseCompiler::insertPerFunctionDebugStub() {
    933  // The per-function debug stub performs out-of-line filtering before jumping
    934  // to the per-module debug stub if necessary.  The per-module debug stub
    935  // returns directly to the breakable point.
    936  //
    937  // NOTE, the link register is live here on platforms that have LR.
    938  //
    939  // The scratch register is available here (as it was at the call site).
    940  //
    941  // It's useful for the per-function debug stub to be compact, as every
    942  // function gets one.
    943 
    944  Label L;
    945  masm.bind(&perFunctionDebugStub_);
    946 
    947 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    948  {
    949    ScratchPtr scratch(*this);
    950 
    951    // Get the per-instance table of filtering bits.
    952    masm.loadPtr(Address(InstanceReg, Instance::offsetOfDebugFilter()),
    953                 scratch);
    954 
    955    // Check the filter bit.  There is one bit per function in the module.
    956    // Table elements are 32-bit because the masm makes that convenient.
    957    masm.branchTest32(Assembler::NonZero, Address(scratch, func_.index / 32),
    958                      Imm32(1 << (func_.index % 32)), &L);
    959 
    960    // Fast path: return to the execution.
    961    masm.ret();
    962  }
    963 #elif defined(JS_CODEGEN_ARM64)
    964  {
    965    ScratchPtr scratch(*this);
    966 
    967    // Logic as above, except abiret to jump to the LR directly
    968    masm.loadPtr(Address(InstanceReg, Instance::offsetOfDebugFilter()),
    969                 scratch);
    970    masm.branchTest32(Assembler::NonZero, Address(scratch, func_.index / 32),
    971                      Imm32(1 << (func_.index % 32)), &L);
    972    masm.abiret();
    973  }
    974 #elif defined(JS_CODEGEN_ARM)
    975  {
    976    // We must be careful not to use the SecondScratchRegister, which usually
    977    // is LR, as LR is live here.  This means avoiding masm abstractions such
    978    // as branchTest32.
    979 
    980    static_assert(ScratchRegister != lr);
    981    static_assert(Instance::offsetOfDebugFilter() < 0x1000);
    982 
    983    ScratchRegisterScope tmp1(masm);
    984    ScratchI32 tmp2(*this);
    985    masm.ma_ldr(
    986        DTRAddr(InstanceReg, DtrOffImm(Instance::offsetOfDebugFilter())), tmp1);
    987    masm.ma_mov(Imm32(func_.index / 32), tmp2);
    988    masm.ma_ldr(DTRAddr(tmp1, DtrRegImmShift(tmp2, LSL, 0)), tmp2);
    989    masm.ma_tst(tmp2, Imm32(1 << func_.index % 32), tmp1, Assembler::Always);
    990    masm.ma_bx(lr, Assembler::Zero);
    991  }
    992 #elif defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_MIPS64) || \
    993    defined(JS_CODEGEN_RISCV64)
    994  {
    995    ScratchPtr scratch(*this);
    996 
    997    // Logic same as ARM64.
    998    masm.loadPtr(Address(InstanceReg, Instance::offsetOfDebugFilter()),
    999                 scratch);
   1000    masm.branchTest32(Assembler::NonZero, Address(scratch, func_.index / 32),
   1001                      Imm32(1 << (func_.index % 32)), &L);
   1002    masm.abiret();
   1003  }
   1004 #else
   1005  MOZ_CRASH("BaseCompiler platform hook: endFunction");
   1006 #endif
   1007 
   1008  // Jump to the per-module debug stub, which calls onwards to C++ land.
   1009  masm.bind(&L);
   1010  masm.jump(Address(InstanceReg, Instance::offsetOfDebugStub()));
   1011 }
   1012 
   1013 void BaseCompiler::saveRegisterReturnValues(const ResultType& resultType) {
   1014  MOZ_ASSERT(compilerEnv_.debugEnabled());
   1015  size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
   1016  size_t registerResultIdx = 0;
   1017  for (ABIResultIter i(resultType); !i.done(); i.next()) {
   1018    const ABIResult result = i.cur();
   1019    if (!result.inRegister()) {
   1020 #ifdef DEBUG
   1021      for (i.next(); !i.done(); i.next()) {
   1022        MOZ_ASSERT(!i.cur().inRegister());
   1023      }
   1024 #endif
   1025      break;
   1026    }
   1027 
   1028    size_t resultOffset = DebugFrame::offsetOfRegisterResult(registerResultIdx);
   1029    Address dest(masm.getStackPointer(), debugFrameOffset + resultOffset);
   1030    switch (result.type().kind()) {
   1031      case ValType::I32:
   1032        masm.store32(RegI32(result.gpr()), dest);
   1033        break;
   1034      case ValType::I64:
   1035        masm.store64(RegI64(result.gpr64()), dest);
   1036        break;
   1037      case ValType::F64:
   1038        masm.storeDouble(RegF64(result.fpr()), dest);
   1039        break;
   1040      case ValType::F32:
   1041        masm.storeFloat32(RegF32(result.fpr()), dest);
   1042        break;
   1043      case ValType::Ref: {
   1044        uint32_t flag =
   1045            DebugFrame::hasSpilledRegisterRefResultBitMask(registerResultIdx);
   1046        // Tell Instance::traceFrame that we have a pointer to trace.
   1047        masm.or32(Imm32(flag),
   1048                  Address(masm.getStackPointer(),
   1049                          debugFrameOffset + DebugFrame::offsetOfFlags()));
   1050        masm.storePtr(RegRef(result.gpr()), dest);
   1051        break;
   1052      }
   1053      case ValType::V128:
   1054 #ifdef ENABLE_WASM_SIMD
   1055        masm.storeUnalignedSimd128(RegV128(result.fpr()), dest);
   1056        break;
   1057 #else
   1058        MOZ_CRASH("No SIMD support");
   1059 #endif
   1060    }
   1061    registerResultIdx++;
   1062  }
   1063 }
   1064 
   1065 void BaseCompiler::restoreRegisterReturnValues(const ResultType& resultType) {
   1066  MOZ_ASSERT(compilerEnv_.debugEnabled());
   1067  size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
   1068  size_t registerResultIdx = 0;
   1069  for (ABIResultIter i(resultType); !i.done(); i.next()) {
   1070    const ABIResult result = i.cur();
   1071    if (!result.inRegister()) {
   1072 #ifdef DEBUG
   1073      for (i.next(); !i.done(); i.next()) {
   1074        MOZ_ASSERT(!i.cur().inRegister());
   1075      }
   1076 #endif
   1077      break;
   1078    }
   1079    size_t resultOffset =
   1080        DebugFrame::offsetOfRegisterResult(registerResultIdx++);
   1081    Address src(masm.getStackPointer(), debugFrameOffset + resultOffset);
   1082    switch (result.type().kind()) {
   1083      case ValType::I32:
   1084        masm.load32(src, RegI32(result.gpr()));
   1085        break;
   1086      case ValType::I64:
   1087        masm.load64(src, RegI64(result.gpr64()));
   1088        break;
   1089      case ValType::F64:
   1090        masm.loadDouble(src, RegF64(result.fpr()));
   1091        break;
   1092      case ValType::F32:
   1093        masm.loadFloat32(src, RegF32(result.fpr()));
   1094        break;
   1095      case ValType::Ref:
   1096        masm.loadPtr(src, RegRef(result.gpr()));
   1097        break;
   1098      case ValType::V128:
   1099 #ifdef ENABLE_WASM_SIMD
   1100        masm.loadUnalignedSimd128(src, RegV128(result.fpr()));
   1101        break;
   1102 #else
   1103        MOZ_CRASH("No SIMD support");
   1104 #endif
   1105    }
   1106  }
   1107 }
   1108 
   1109 //////////////////////////////////////////////////////////////////////////////
   1110 //
   1111 // Support for lazy tiering
   1112 
   1113 // The key thing here is, we generate a short piece of code which, most of the
   1114 // time, has no effect, but just occasionally wants to call out to C++ land.
   1115 // That's a similar requirement to the Debugger API support (see above) and so
   1116 // we have a similar, but simpler, solution.  Specifically, we use a single
   1117 // stub routine for the whole module, whereas for debugging, there are
   1118 // per-function stub routines as well as a whole-module stub routine involved.
   1119 
   1120 class OutOfLineRequestTierUp : public OutOfLineCode {
   1121  Register instance_;  // points at the instance at entry; must remain unchanged
   1122  Maybe<RegI32> scratch_;    // only provided on arm32
   1123  size_t lastOpcodeOffset_;  // a bytecode offset
   1124 
   1125 public:
   1126  OutOfLineRequestTierUp(Register instance, Maybe<RegI32> scratch,
   1127                         size_t lastOpcodeOffset)
   1128      : instance_(instance),
   1129        scratch_(scratch),
   1130        lastOpcodeOffset_(lastOpcodeOffset) {}
   1131  virtual void generate(MacroAssembler* masm) override {
   1132    // Generate:
   1133    //
   1134    // [optionally, if `instance_` != InstanceReg: swap(instance_, InstanceReg)]
   1135    // call * $offsetOfRequestTierUpStub(InstanceReg)
   1136    // [optionally, if `instance_` != InstanceReg: swap(instance_, InstanceReg)]
   1137    // goto rejoin
   1138    //
   1139    // This is the unlikely path, where we call the (per-module)
   1140    // request-tier-up stub.  The stub wants the instance pointer to be in the
   1141    // official InstanceReg at this point, but InstanceReg itself might hold
   1142    // arbitrary other live data.  Hence, if necessary, swap `instance_` and
   1143    // InstanceReg before the call and swap them back after it.
   1144 #ifndef RABALDR_PIN_INSTANCE
   1145    if (Register(instance_) != InstanceReg) {
   1146 #  ifdef JS_CODEGEN_X86
   1147      // On x86_32 this is easy.
   1148      masm->xchgl(instance_, InstanceReg);
   1149 #  elif JS_CODEGEN_ARM
   1150      masm->mov(instance_,
   1151                scratch_.value());  // note, destination is second arg
   1152      masm->mov(InstanceReg, instance_);
   1153      masm->mov(scratch_.value(), InstanceReg);
   1154 #  else
   1155      MOZ_CRASH("BaseCompiler::OutOfLineRequestTierUp #1");
   1156 #  endif
   1157    }
   1158 #endif
   1159    // Call the stub
   1160    const CodeOffset retAddr =
   1161        masm->call(Address(InstanceReg, Instance::offsetOfRequestTierUpStub()));
   1162    masm->append(CallSiteDesc(lastOpcodeOffset_, CallSiteKind::RequestTierUp),
   1163                 retAddr);
   1164    // And swap again, if we swapped above.
   1165 #ifndef RABALDR_PIN_INSTANCE
   1166    if (Register(instance_) != InstanceReg) {
   1167 #  ifdef JS_CODEGEN_X86
   1168      masm->xchgl(instance_, InstanceReg);
   1169 #  elif JS_CODEGEN_ARM
   1170      masm->mov(instance_, scratch_.value());
   1171      masm->mov(InstanceReg, instance_);
   1172      masm->mov(scratch_.value(), InstanceReg);
   1173 #  else
   1174      MOZ_CRASH("BaseCompiler::OutOfLineRequestTierUp #2");
   1175 #  endif
   1176    }
   1177 #endif
   1178 
   1179    masm->jump(rejoin());
   1180  }
   1181 };
   1182 
   1183 Maybe<CodeOffset> BaseCompiler::addHotnessCheck() {
   1184  // Here's an example of what we'll create.  The path that almost always
   1185  // happens, where the counter doesn't go negative, has just one branch.
   1186  //
   1187  //   subl       $to_be_filled_in_later, 0x170(%r14)
   1188  //   js         oolCode // almost never taken
   1189  // rejoin:
   1190  // ----------------
   1191  // oolCode: // we get here when the counter is negative, viz, almost never
   1192  //   call       *0x160(%r14) // RequestTierUpStub
   1193  //   jmp        rejoin
   1194  //
   1195  // Note that the counter is updated regardless of whether or not it has gone
   1196  // negative.  That means that, at entry to RequestTierUpStub, we know the
   1197  // counter must be negative, and not merely zero.
   1198  //
   1199  // Non-Intel targets will have to generate a load / subtract-and-set-flags /
   1200  // store / jcond sequence.
   1201  //
   1202  // To ensure the shortest possible encoding, `to_be_filled_in_later` must be
   1203  // a value in the range 1 .. 127 inclusive.  This is good enough for
   1204  // hotness-counting purposes.
   1205 
   1206  AutoCreatedBy acb(masm, "BC::addHotnessCheck");
   1207 
   1208  // A sync() must happen before this. The request tier-up stub does not save
   1209  // all live registers.
   1210  MOZ_ASSERT(!hasLiveRegsOnStk());
   1211 
   1212 #ifdef RABALDR_PIN_INSTANCE
   1213  Register instance(InstanceReg);
   1214 #else
   1215  // This seems to assume that any non-RABALDR_PIN_INSTANCE target is 32-bit
   1216  ScratchI32 instance(*this);
   1217  fr.loadInstancePtr(instance);
   1218 #endif
   1219 
   1220  Address addressOfCounter = Address(
   1221      instance, wasm::Instance::offsetInData(
   1222                    codeMeta_.offsetOfFuncDefInstanceData(func_.index)));
   1223 
   1224 #if JS_CODEGEN_ARM
   1225  Maybe<RegI32> scratch = Some(needI32());
   1226 #else
   1227  Maybe<RegI32> scratch = Nothing();
   1228 #endif
   1229 
   1230  OutOfLineCode* ool = addOutOfLineCode(new (alloc_) OutOfLineRequestTierUp(
   1231      instance, scratch, iter_.lastOpcodeOffset()));
   1232  if (!ool) {
   1233    return Nothing();
   1234  }
   1235 
   1236  // Because of the Intel arch instruction formats, `patchPoint` points to the
   1237  // byte immediately following the last byte of the instruction to patch.
   1238  CodeOffset patchPoint = masm.sub32FromMemAndBranchIfNegativeWithPatch(
   1239      addressOfCounter, ool->entry());
   1240 
   1241  masm.bind(ool->rejoin());
   1242 
   1243  if (scratch.isSome()) {
   1244    freeI32(scratch.value());
   1245  }
   1246 
   1247  // `patchPoint` might be invalid if the assembler OOMd at some point.
   1248  return masm.oom() ? Nothing() : Some(patchPoint);
   1249 }
   1250 
   1251 void BaseCompiler::patchHotnessCheck(CodeOffset offset, uint32_t step) {
   1252  // Zero makes the hotness check pointless.  Above 127 is not representable in
   1253  // the short-form Intel encoding.
   1254  MOZ_RELEASE_ASSERT(step > 0 && step <= 127);
   1255  MOZ_ASSERT(!masm.oom());
   1256  masm.patchSub32FromMemAndBranchIfNegative(offset, Imm32(step));
   1257 }
   1258 
   1259 //////////////////////////////////////////////////////////////////////////////
   1260 //
   1261 // Results and block parameters
   1262 
   1263 void BaseCompiler::popStackReturnValues(const ResultType& resultType) {
   1264  uint32_t bytes = ABIResultIter::MeasureStackBytes(resultType);
   1265  if (bytes == 0) {
   1266    return;
   1267  }
   1268  Register target = ABINonArgReturnReg0;
   1269  Register temp = ABINonArgReturnReg1;
   1270  fr.loadIncomingStackResultAreaPtr(RegPtr(target));
   1271  fr.popStackResultsToMemory(target, bytes, temp);
   1272 }
   1273 
   1274 // TODO / OPTIMIZE (Bug 1316818): At the moment we use the Wasm
   1275 // inter-procedure ABI for block returns, which allocates ReturnReg as the
   1276 // single block result register.  It is possible other choices would lead to
   1277 // better register allocation, as ReturnReg is often first in the register set
   1278 // and will be heavily wanted by the register allocator that uses takeFirst().
   1279 //
   1280 // Obvious options:
   1281 //  - pick a register at the back of the register set
   1282 //  - pick a random register per block (different blocks have
   1283 //    different join regs)
   1284 
   1285 void BaseCompiler::popRegisterResults(ABIResultIter& iter) {
   1286  // Pop register results.  Note that in the single-value case, popping to a
   1287  // register may cause a sync(); for multi-value we sync'd already.
   1288  for (; !iter.done(); iter.next()) {
   1289    const ABIResult& result = iter.cur();
   1290    if (!result.inRegister()) {
   1291      // TODO / OPTIMIZE: We sync here to avoid solving the general parallel
   1292      // move problem in popStackResults.  However we could avoid syncing the
   1293      // values that are going to registers anyway, if they are already in
   1294      // registers.
   1295      sync();
   1296      break;
   1297    }
   1298    switch (result.type().kind()) {
   1299      case ValType::I32:
   1300        popI32(RegI32(result.gpr()));
   1301        break;
   1302      case ValType::I64:
   1303        popI64(RegI64(result.gpr64()));
   1304        break;
   1305      case ValType::F32:
   1306        popF32(RegF32(result.fpr()));
   1307        break;
   1308      case ValType::F64:
   1309        popF64(RegF64(result.fpr()));
   1310        break;
   1311      case ValType::Ref:
   1312        popRef(RegRef(result.gpr()));
   1313        break;
   1314      case ValType::V128:
   1315 #ifdef ENABLE_WASM_SIMD
   1316        popV128(RegV128(result.fpr()));
   1317 #else
   1318        MOZ_CRASH("No SIMD support");
   1319 #endif
   1320    }
   1321  }
   1322 }
   1323 
   1324 void BaseCompiler::popStackResults(ABIResultIter& iter, StackHeight stackBase) {
   1325  MOZ_ASSERT(!iter.done());
   1326 
   1327  // The iterator should be advanced beyond register results, and register
   1328  // results should be popped already from the value stack.
   1329  uint32_t alreadyPopped = iter.index();
   1330 
   1331  // At this point, only stack arguments are remaining.  Iterate through them
   1332  // to measure how much stack space they will take up.
   1333  for (; !iter.done(); iter.next()) {
   1334    MOZ_ASSERT(iter.cur().onStack());
   1335  }
   1336 
   1337  // Calculate the space needed to store stack results, in bytes.
   1338  uint32_t stackResultBytes = iter.stackBytesConsumedSoFar();
   1339  MOZ_ASSERT(stackResultBytes);
   1340 
   1341  // Compute the stack height including the stack results.  Note that it's
   1342  // possible that this call expands the stack, for example if some of the
   1343  // results are supplied by constants and so are not already on the machine
   1344  // stack.
   1345  uint32_t endHeight = fr.prepareStackResultArea(stackBase, stackResultBytes);
   1346 
   1347  // Find a free GPR to use when shuffling stack values.  If none is
   1348  // available, push ReturnReg and restore it after we're done.
   1349  bool saved = false;
   1350  RegPtr temp = ra.needTempPtr(RegPtr(ReturnReg), &saved);
   1351 
   1352  // The sequence of Stk values is in the same order on the machine stack as
   1353  // the result locations, but there is a complication: constant values are
   1354  // not actually pushed on the machine stack.  (At this point registers and
   1355  // locals have been spilled already.)  So, moving the Stk values into place
   1356  // isn't simply a shuffle-down or shuffle-up operation.  There is a part of
   1357  // the Stk sequence that shuffles toward the FP, a part that's already in
   1358  // place, and a part that shuffles toward the SP.  After shuffling, we have
   1359  // to materialize the constants.
   1360 
   1361  // Shuffle mem values toward the frame pointer, copying deepest values
   1362  // first.  Stop when we run out of results, get to a register result, or
   1363  // find a Stk value that is closer to the FP than the result.
   1364  for (iter.switchToPrev(); !iter.done(); iter.prev()) {
   1365    const ABIResult& result = iter.cur();
   1366    if (!result.onStack()) {
   1367      break;
   1368    }
   1369    MOZ_ASSERT(result.stackOffset() < stackResultBytes);
   1370    uint32_t destHeight = endHeight - result.stackOffset();
   1371    uint32_t stkBase = stk_.length() - (iter.count() - alreadyPopped);
   1372    Stk& v = stk_[stkBase + iter.index()];
   1373    if (v.isMem()) {
   1374      uint32_t srcHeight = v.offs();
   1375      if (srcHeight <= destHeight) {
   1376        break;
   1377      }
   1378      fr.shuffleStackResultsTowardFP(srcHeight, destHeight, result.size(),
   1379                                     temp);
   1380    }
   1381  }
   1382 
   1383  // Reset iterator and skip register results.
   1384  for (iter.reset(); !iter.done(); iter.next()) {
   1385    if (iter.cur().onStack()) {
   1386      break;
   1387    }
   1388  }
   1389 
   1390  // Revisit top stack values, shuffling mem values toward the stack pointer,
   1391  // copying shallowest values first.
   1392  for (; !iter.done(); iter.next()) {
   1393    const ABIResult& result = iter.cur();
   1394    MOZ_ASSERT(result.onStack());
   1395    MOZ_ASSERT(result.stackOffset() < stackResultBytes);
   1396    uint32_t destHeight = endHeight - result.stackOffset();
   1397    Stk& v = stk_[stk_.length() - (iter.index() - alreadyPopped) - 1];
   1398    if (v.isMem()) {
   1399      uint32_t srcHeight = v.offs();
   1400      if (srcHeight >= destHeight) {
   1401        break;
   1402      }
   1403      fr.shuffleStackResultsTowardSP(srcHeight, destHeight, result.size(),
   1404                                     temp);
   1405    }
   1406  }
   1407 
   1408  // Reset iterator and skip register results, which are already popped off
   1409  // the value stack.
   1410  for (iter.reset(); !iter.done(); iter.next()) {
   1411    if (iter.cur().onStack()) {
   1412      break;
   1413    }
   1414  }
   1415 
   1416  // Materialize constants and pop the remaining items from the value stack.
   1417  for (; !iter.done(); iter.next()) {
   1418    const ABIResult& result = iter.cur();
   1419    uint32_t resultHeight = endHeight - result.stackOffset();
   1420    Stk& v = stk_.back();
   1421    switch (v.kind()) {
   1422      case Stk::ConstI32:
   1423 #if defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \
   1424    defined(JS_CODEGEN_RISCV64)
   1425        fr.storeImmediatePtrToStack(v.i32val_, resultHeight, temp);
   1426 #else
   1427        fr.storeImmediatePtrToStack(uint32_t(v.i32val_), resultHeight, temp);
   1428 #endif
   1429        break;
   1430      case Stk::ConstF32:
   1431        fr.storeImmediateF32ToStack(v.f32val_, resultHeight, temp);
   1432        break;
   1433      case Stk::ConstI64:
   1434        fr.storeImmediateI64ToStack(v.i64val_, resultHeight, temp);
   1435        break;
   1436      case Stk::ConstF64:
   1437        fr.storeImmediateF64ToStack(v.f64val_, resultHeight, temp);
   1438        break;
   1439 #ifdef ENABLE_WASM_SIMD
   1440      case Stk::ConstV128:
   1441        fr.storeImmediateV128ToStack(v.v128val_, resultHeight, temp);
   1442        break;
   1443 #endif
   1444      case Stk::ConstRef:
   1445        fr.storeImmediatePtrToStack(v.refval_, resultHeight, temp);
   1446        break;
   1447      case Stk::MemRef:
   1448        // Update bookkeeping as we pop the Stk entry.
   1449        stackMapGenerator_.memRefsOnStk--;
   1450        break;
   1451      default:
   1452        MOZ_ASSERT(v.isMem());
   1453        break;
   1454    }
   1455    stk_.popBack();
   1456  }
   1457 
   1458  ra.freeTempPtr(temp, saved);
   1459 
   1460  // This will pop the stack if needed.
   1461  fr.finishStackResultArea(stackBase, stackResultBytes);
   1462 }
   1463 
   1464 void BaseCompiler::popBlockResults(ResultType type, StackHeight stackBase,
   1465                                   ContinuationKind kind) {
   1466  if (!type.empty()) {
   1467    ABIResultIter iter(type);
   1468    popRegisterResults(iter);
   1469    if (!iter.done()) {
   1470      popStackResults(iter, stackBase);
   1471      // Because popStackResults might clobber the stack, it leaves the stack
   1472      // pointer already in the right place for the continuation, whether the
   1473      // continuation is a jump or fallthrough.
   1474      return;
   1475    }
   1476  }
   1477  // We get here if there are no stack results.  For a fallthrough, the stack
   1478  // is already at the right height.  For a jump, we may need to pop the stack
   1479  // pointer if the continuation's stack height is lower than the current
   1480  // stack height.
   1481  if (kind == ContinuationKind::Jump) {
   1482    fr.popStackBeforeBranch(stackBase, type);
   1483  }
   1484 }
   1485 
   1486 // This function is similar to popBlockResults, but additionally handles the
   1487 // implicit exception pointer that is pushed to the value stack on entry to
   1488 // a catch handler by dropping it appropriately.
   1489 void BaseCompiler::popCatchResults(ResultType type, StackHeight stackBase) {
   1490  if (!type.empty()) {
   1491    ABIResultIter iter(type);
   1492    popRegisterResults(iter);
   1493    if (!iter.done()) {
   1494      popStackResults(iter, stackBase);
   1495      // Since popStackResults clobbers the stack, we only need to free the
   1496      // exception off of the value stack.
   1497      popValueStackBy(1);
   1498    } else {
   1499      // If there are no stack results, we have to adjust the stack by
   1500      // dropping the exception reference that's now on the stack.
   1501      dropValue();
   1502    }
   1503  } else {
   1504    dropValue();
   1505  }
   1506  fr.popStackBeforeBranch(stackBase, type);
   1507 }
   1508 
   1509 Stk BaseCompiler::captureStackResult(const ABIResult& result,
   1510                                     StackHeight resultsBase,
   1511                                     uint32_t stackResultBytes) {
   1512  MOZ_ASSERT(result.onStack());
   1513  uint32_t offs = fr.locateStackResult(result, resultsBase, stackResultBytes);
   1514  return Stk::StackResult(result.type(), offs);
   1515 }
   1516 
   1517 // TODO: It may be fruitful to inline the fast path here, as it will be common.
   1518 
   1519 bool BaseCompiler::pushResults(ResultType type, StackHeight resultsBase) {
   1520  if (type.empty()) {
   1521    return true;
   1522  }
   1523 
   1524  if (type.length() > 1) {
   1525    // Reserve extra space on the stack for all the values we'll push.
   1526    // Multi-value push is not accounted for by the pre-sizing of the stack in
   1527    // the decoding loop.
   1528    //
   1529    // Also make sure we leave headroom for other pushes that will occur after
   1530    // pushing results, just to be safe.
   1531    if (!stk_.reserve(stk_.length() + type.length() + MaxPushesPerOpcode)) {
   1532      return false;
   1533    }
   1534  }
   1535 
   1536  // We need to push the results in reverse order, so first iterate through
   1537  // all results to determine the locations of stack result types.
   1538  ABIResultIter iter(type);
   1539  while (!iter.done()) {
   1540    iter.next();
   1541  }
   1542  uint32_t stackResultBytes = iter.stackBytesConsumedSoFar();
   1543  for (iter.switchToPrev(); !iter.done(); iter.prev()) {
   1544    const ABIResult& result = iter.cur();
   1545    if (!result.onStack()) {
   1546      break;
   1547    }
   1548    Stk v = captureStackResult(result, resultsBase, stackResultBytes);
   1549    push(v);
   1550    if (v.kind() == Stk::MemRef) {
   1551      stackMapGenerator_.memRefsOnStk++;
   1552    }
   1553  }
   1554 
   1555  for (; !iter.done(); iter.prev()) {
   1556    const ABIResult& result = iter.cur();
   1557    MOZ_ASSERT(result.inRegister());
   1558    switch (result.type().kind()) {
   1559      case ValType::I32:
   1560        pushI32(RegI32(result.gpr()));
   1561        break;
   1562      case ValType::I64:
   1563        pushI64(RegI64(result.gpr64()));
   1564        break;
   1565      case ValType::V128:
   1566 #ifdef ENABLE_WASM_SIMD
   1567        pushV128(RegV128(result.fpr()));
   1568        break;
   1569 #else
   1570        MOZ_CRASH("No SIMD support");
   1571 #endif
   1572      case ValType::F32:
   1573        pushF32(RegF32(result.fpr()));
   1574        break;
   1575      case ValType::F64:
   1576        pushF64(RegF64(result.fpr()));
   1577        break;
   1578      case ValType::Ref:
   1579        pushRef(RegRef(result.gpr()));
   1580        break;
   1581    }
   1582  }
   1583 
   1584  return true;
   1585 }
   1586 
   1587 bool BaseCompiler::pushBlockResults(ResultType type) {
   1588  return pushResults(type, controlItem().stackHeight);
   1589 }
   1590 
   1591 // A combination of popBlockResults + pushBlockResults, used when entering a
   1592 // block with a control-flow join (loops) or split (if) to shuffle the
   1593 // fallthrough block parameters into the locations expected by the
   1594 // continuation.
   1595 bool BaseCompiler::topBlockParams(ResultType type) {
   1596  // This function should only be called when entering a block with a
   1597  // control-flow join at the entry, where there are no live temporaries in
   1598  // the current block.
   1599  StackHeight base = controlItem().stackHeight;
   1600  MOZ_ASSERT(fr.stackResultsBase(stackConsumed(type.length())) == base);
   1601  popBlockResults(type, base, ContinuationKind::Fallthrough);
   1602  return pushBlockResults(type);
   1603 }
   1604 
   1605 // A combination of popBlockResults + pushBlockResults, used before branches
   1606 // where we don't know the target (br_if / br_table).  If and when the branch
   1607 // is taken, the stack results will be shuffled down into place.  For br_if
   1608 // that has fallthrough, the parameters for the untaken branch flow through to
   1609 // the continuation.
   1610 bool BaseCompiler::topBranchParams(ResultType type, StackHeight* height) {
   1611  if (type.empty()) {
   1612    *height = fr.stackHeight();
   1613    return true;
   1614  }
   1615  // There may be temporary values that need spilling; delay computation of
   1616  // the stack results base until after the popRegisterResults(), which spills
   1617  // if needed.
   1618  ABIResultIter iter(type);
   1619  popRegisterResults(iter);
   1620  StackHeight base = fr.stackResultsBase(stackConsumed(iter.remaining()));
   1621  if (!iter.done()) {
   1622    popStackResults(iter, base);
   1623  }
   1624  if (!pushResults(type, base)) {
   1625    return false;
   1626  }
   1627  *height = base;
   1628  return true;
   1629 }
   1630 
   1631 // Conditional branches with fallthrough are preceded by a topBranchParams, so
   1632 // we know that there are no stack results that need to be materialized.  In
   1633 // that case, we can just shuffle the whole block down before popping the
   1634 // stack.
   1635 void BaseCompiler::shuffleStackResultsBeforeBranch(StackHeight srcHeight,
   1636                                                   StackHeight destHeight,
   1637                                                   ResultType type) {
   1638  uint32_t stackResultBytes = 0;
   1639 
   1640  if (ABIResultIter::HasStackResults(type)) {
   1641    MOZ_ASSERT(stk_.length() >= type.length());
   1642    ABIResultIter iter(type);
   1643    for (; !iter.done(); iter.next()) {
   1644 #ifdef DEBUG
   1645      const ABIResult& result = iter.cur();
   1646      const Stk& v = stk_[stk_.length() - iter.index() - 1];
   1647      MOZ_ASSERT(v.isMem() == result.onStack());
   1648 #endif
   1649    }
   1650 
   1651    stackResultBytes = iter.stackBytesConsumedSoFar();
   1652    MOZ_ASSERT(stackResultBytes > 0);
   1653 
   1654    if (srcHeight != destHeight) {
   1655      // Find a free GPR to use when shuffling stack values.  If none
   1656      // is available, push ReturnReg and restore it after we're done.
   1657      bool saved = false;
   1658      RegPtr temp = ra.needTempPtr(RegPtr(ReturnReg), &saved);
   1659      fr.shuffleStackResultsTowardFP(srcHeight, destHeight, stackResultBytes,
   1660                                     temp);
   1661      ra.freeTempPtr(temp, saved);
   1662    }
   1663  }
   1664 
   1665  fr.popStackBeforeBranch(destHeight, stackResultBytes);
   1666 }
   1667 
   1668 bool BaseCompiler::insertDebugCollapseFrame() {
   1669  if (!compilerEnv_.debugEnabled() || deadCode_) {
   1670    return true;
   1671  }
   1672  insertBreakablePoint(CallSiteKind::CollapseFrame);
   1673  return createStackMap("debug: collapse-frame breakpoint",
   1674                        HasDebugFrameWithLiveRefs::Maybe);
   1675 }
   1676 
   1677 //////////////////////////////////////////////////////////////////////////////
   1678 //
   1679 // Function calls.
   1680 
   1681 void BaseCompiler::beginCall(FunctionCall& call) {
   1682  // Use masm.framePushed() because the value we want here does not depend
   1683  // on the height of the frame's stack area, but the actual size of the
   1684  // allocated frame.
   1685  call.frameAlignAdjustment = ComputeByteAlignment(
   1686      masm.framePushed() + sizeof(Frame), JitStackAlignment);
   1687 }
   1688 
   1689 void BaseCompiler::endCall(FunctionCall& call, size_t stackSpace) {
   1690  size_t adjustment = call.stackArgAreaSize + call.frameAlignAdjustment;
   1691  fr.freeArgAreaAndPopBytes(adjustment, stackSpace);
   1692 
   1693  MOZ_ASSERT(stackMapGenerator_.framePushedExcludingOutboundCallArgs.isSome());
   1694  stackMapGenerator_.framePushedExcludingOutboundCallArgs.reset();
   1695 
   1696  if (call.restoreState == RestoreState::All) {
   1697    fr.loadInstancePtr(InstanceReg);
   1698    masm.loadWasmPinnedRegsFromInstance(mozilla::Nothing());
   1699    masm.switchToWasmInstanceRealm(ABINonArgReturnReg0, ABINonArgReturnReg1);
   1700  } else if (call.restoreState == RestoreState::PinnedRegs) {
   1701    masm.loadWasmPinnedRegsFromInstance(mozilla::Nothing());
   1702  }
   1703 }
   1704 
   1705 void BaseCompiler::startCallArgs(size_t stackArgAreaSizeUnaligned,
   1706                                 FunctionCall* call) {
   1707  size_t stackArgAreaSizeAligned =
   1708      AlignStackArgAreaSize(stackArgAreaSizeUnaligned);
   1709  MOZ_ASSERT(stackArgAreaSizeUnaligned <= stackArgAreaSizeAligned);
   1710 
   1711  // Record the masm.framePushed() value at this point, before we push args
   1712  // for the call and any required alignment space. This defines the lower limit
   1713  // of the stackmap that will be created for this call.
   1714  MOZ_ASSERT(
   1715      stackMapGenerator_.framePushedExcludingOutboundCallArgs.isNothing());
   1716  stackMapGenerator_.framePushedExcludingOutboundCallArgs.emplace(
   1717      // However much we've pushed so far
   1718      masm.framePushed() +
   1719      // Extra space we'll push to get the frame aligned
   1720      call->frameAlignAdjustment);
   1721 
   1722  call->stackArgAreaSize = stackArgAreaSizeAligned;
   1723 
   1724  size_t adjustment = call->stackArgAreaSize + call->frameAlignAdjustment;
   1725  fr.allocArgArea(adjustment);
   1726 }
   1727 
   1728 ABIArg BaseCompiler::reservePointerArgument(FunctionCall* call) {
   1729  return call->abi.next(MIRType::Pointer);
   1730 }
   1731 
   1732 // TODO / OPTIMIZE (Bug 1316821): Note passArg is used only in one place.
   1733 // (Or it was, until Luke wandered through, but that can be fixed again.)
   1734 // I'm not saying we should manually inline it, but we could hoist the
   1735 // dispatch into the caller and have type-specific implementations of
   1736 // passArg: passArgI32(), etc.  Then those might be inlined, at least in PGO
   1737 // builds.
   1738 //
   1739 // The bulk of the work here (60%) is in the next() call, though.
   1740 //
   1741 // Notably, since next() is so expensive, StackArgAreaSizeUnaligned()
   1742 // becomes expensive too.
   1743 //
   1744 // Somehow there could be a trick here where the sequence of argument types
   1745 // (read from the input stream) leads to a cached entry for
   1746 // StackArgAreaSizeUnaligned() and for how to pass arguments...
   1747 //
   1748 // But at least we could reduce the cost of StackArgAreaSizeUnaligned() by
   1749 // first reading the argument types into a (reusable) vector, then we have
   1750 // the outgoing size at low cost, and then we can pass args based on the
   1751 // info we read.
   1752 
   1753 void BaseCompiler::passArg(ValType type, const Stk& arg, FunctionCall* call) {
   1754  switch (type.kind()) {
   1755    case ValType::I32: {
   1756      ABIArg argLoc = call->abi.next(MIRType::Int32);
   1757      if (argLoc.kind() == ABIArg::Stack) {
   1758        ScratchI32 scratch(*this);
   1759        loadI32(arg, scratch);
   1760        masm.store32(scratch, Address(masm.getStackPointer(),
   1761                                      argLoc.offsetFromArgBase()));
   1762      } else {
   1763        loadI32(arg, RegI32(argLoc.gpr()));
   1764      }
   1765      break;
   1766    }
   1767    case ValType::I64: {
   1768      ABIArg argLoc = call->abi.next(MIRType::Int64);
   1769      if (argLoc.kind() == ABIArg::Stack) {
   1770        ScratchI32 scratch(*this);
   1771 #ifdef JS_PUNBOX64
   1772        loadI64(arg, fromI32(scratch));
   1773        masm.storePtr(scratch, Address(masm.getStackPointer(),
   1774                                       argLoc.offsetFromArgBase()));
   1775 #else
   1776        loadI64Low(arg, scratch);
   1777        masm.store32(scratch, LowWord(Address(masm.getStackPointer(),
   1778                                              argLoc.offsetFromArgBase())));
   1779        loadI64High(arg, scratch);
   1780        masm.store32(scratch, HighWord(Address(masm.getStackPointer(),
   1781                                               argLoc.offsetFromArgBase())));
   1782 #endif
   1783      } else {
   1784        loadI64(arg, RegI64(argLoc.gpr64()));
   1785      }
   1786      break;
   1787    }
   1788    case ValType::V128: {
   1789 #ifdef ENABLE_WASM_SIMD
   1790      ABIArg argLoc = call->abi.next(MIRType::Simd128);
   1791      switch (argLoc.kind()) {
   1792        case ABIArg::Stack: {
   1793          ScratchV128 scratch(*this);
   1794          loadV128(arg, scratch);
   1795          masm.storeUnalignedSimd128(
   1796              (RegV128)scratch,
   1797              Address(masm.getStackPointer(), argLoc.offsetFromArgBase()));
   1798          break;
   1799        }
   1800        case ABIArg::GPR: {
   1801          MOZ_CRASH("Unexpected parameter passing discipline");
   1802        }
   1803        case ABIArg::FPU: {
   1804          loadV128(arg, RegV128(argLoc.fpu()));
   1805          break;
   1806        }
   1807 #  if defined(JS_CODEGEN_REGISTER_PAIR)
   1808        case ABIArg::GPR_PAIR: {
   1809          MOZ_CRASH("Unexpected parameter passing discipline");
   1810        }
   1811 #  endif
   1812        case ABIArg::Uninitialized:
   1813          MOZ_CRASH("Uninitialized ABIArg kind");
   1814      }
   1815      break;
   1816 #else
   1817      MOZ_CRASH("No SIMD support");
   1818 #endif
   1819    }
   1820    case ValType::F64: {
   1821      ABIArg argLoc = call->abi.next(MIRType::Double);
   1822      switch (argLoc.kind()) {
   1823        case ABIArg::Stack: {
   1824          ScratchF64 scratch(*this);
   1825          loadF64(arg, scratch);
   1826          masm.storeDouble(scratch, Address(masm.getStackPointer(),
   1827                                            argLoc.offsetFromArgBase()));
   1828          break;
   1829        }
   1830 #if defined(JS_CODEGEN_REGISTER_PAIR)
   1831        case ABIArg::GPR_PAIR: {
   1832 #  if defined(JS_CODEGEN_ARM)
   1833          ScratchF64 scratch(*this);
   1834          loadF64(arg, scratch);
   1835          masm.ma_vxfer(scratch, argLoc.evenGpr(), argLoc.oddGpr());
   1836          break;
   1837 #  else
   1838          MOZ_CRASH("BaseCompiler platform hook: passArg F64 pair");
   1839 #  endif
   1840        }
   1841 #endif
   1842        case ABIArg::FPU: {
   1843          loadF64(arg, RegF64(argLoc.fpu()));
   1844          break;
   1845        }
   1846        case ABIArg::GPR: {
   1847          MOZ_CRASH("Unexpected parameter passing discipline");
   1848        }
   1849        case ABIArg::Uninitialized:
   1850          MOZ_CRASH("Uninitialized ABIArg kind");
   1851      }
   1852      break;
   1853    }
   1854    case ValType::F32: {
   1855      ABIArg argLoc = call->abi.next(MIRType::Float32);
   1856      switch (argLoc.kind()) {
   1857        case ABIArg::Stack: {
   1858          ScratchF32 scratch(*this);
   1859          loadF32(arg, scratch);
   1860          masm.storeFloat32(scratch, Address(masm.getStackPointer(),
   1861                                             argLoc.offsetFromArgBase()));
   1862          break;
   1863        }
   1864        case ABIArg::GPR: {
   1865          ScratchF32 scratch(*this);
   1866          loadF32(arg, scratch);
   1867          masm.moveFloat32ToGPR(scratch, argLoc.gpr());
   1868          break;
   1869        }
   1870        case ABIArg::FPU: {
   1871          loadF32(arg, RegF32(argLoc.fpu()));
   1872          break;
   1873        }
   1874 #if defined(JS_CODEGEN_REGISTER_PAIR)
   1875        case ABIArg::GPR_PAIR: {
   1876          MOZ_CRASH("Unexpected parameter passing discipline");
   1877        }
   1878 #endif
   1879        case ABIArg::Uninitialized:
   1880          MOZ_CRASH("Uninitialized ABIArg kind");
   1881      }
   1882      break;
   1883    }
   1884    case ValType::Ref: {
   1885      ABIArg argLoc = call->abi.next(MIRType::WasmAnyRef);
   1886      if (argLoc.kind() == ABIArg::Stack) {
   1887        ScratchRef scratch(*this);
   1888        loadRef(arg, scratch);
   1889        masm.storePtr(scratch, Address(masm.getStackPointer(),
   1890                                       argLoc.offsetFromArgBase()));
   1891      } else {
   1892        loadRef(arg, RegRef(argLoc.gpr()));
   1893      }
   1894      break;
   1895    }
   1896  }
   1897 }
   1898 
   1899 template <typename T>
   1900 bool BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, T results,
   1901                                FunctionCall* baselineCall,
   1902                                CalleeOnStack calleeOnStack) {
   1903  MOZ_ASSERT(!deadCode_);
   1904 
   1905  ArgTypeVector args(argTypes, results.stackResults());
   1906  uint32_t naturalArgCount = argTypes.length();
   1907  uint32_t abiArgCount = args.lengthWithStackResults();
   1908  startCallArgs(StackArgAreaSizeUnaligned(args, baselineCall->abiKind),
   1909                baselineCall);
   1910 
   1911  // Args are deeper on the stack than the stack result area, if any.
   1912  size_t argsDepth = results.onStackCount();
   1913  // They're deeper than the callee too, for callIndirect.
   1914  if (calleeOnStack == CalleeOnStack::True) {
   1915    argsDepth++;
   1916  }
   1917 
   1918  for (size_t i = 0; i < abiArgCount; ++i) {
   1919    if (args.isNaturalArg(i)) {
   1920      size_t naturalIndex = args.naturalIndex(i);
   1921      size_t stackIndex = naturalArgCount - 1 - naturalIndex + argsDepth;
   1922      passArg(argTypes[naturalIndex], peek(stackIndex), baselineCall);
   1923    } else {
   1924      // The synthetic stack result area pointer.
   1925      ABIArg argLoc = baselineCall->abi.next(MIRType::Pointer);
   1926      if (argLoc.kind() == ABIArg::Stack) {
   1927        ScratchPtr scratch(*this);
   1928        results.getStackResultArea(fr, scratch);
   1929        masm.storePtr(scratch, Address(masm.getStackPointer(),
   1930                                       argLoc.offsetFromArgBase()));
   1931      } else {
   1932        results.getStackResultArea(fr, RegPtr(argLoc.gpr()));
   1933      }
   1934    }
   1935  }
   1936 
   1937 #ifndef RABALDR_PIN_INSTANCE
   1938  fr.loadInstancePtr(InstanceReg);
   1939 #endif
   1940  return true;
   1941 }
   1942 
   1943 bool BaseCompiler::pushStackResultsForWasmCall(const ResultType& type,
   1944                                               RegPtr temp,
   1945                                               StackResultsLoc* loc) {
   1946  if (!ABIResultIter::HasStackResults(type)) {
   1947    return true;
   1948  }
   1949 
   1950  // This method can increase stk_.length() by an unbounded amount, so we need
   1951  // to perform an allocation here to accomodate the variable number of values.
   1952  // There is enough headroom for any fixed number of values.  The general case
   1953  // is handled in emitBody.
   1954  if (!stk_.reserve(stk_.length() + type.length())) {
   1955    return false;
   1956  }
   1957 
   1958  // Measure stack results.
   1959  ABIResultIter i(type);
   1960  size_t count = 0;
   1961  for (; !i.done(); i.next()) {
   1962    if (i.cur().onStack()) {
   1963      count++;
   1964    }
   1965  }
   1966  uint32_t bytes = i.stackBytesConsumedSoFar();
   1967 
   1968  // Reserve space for the stack results.
   1969  StackHeight resultsBase = fr.stackHeight();
   1970  uint32_t height = fr.prepareStackResultArea(resultsBase, bytes);
   1971 
   1972  // Push Stk values onto the value stack, and zero out Ref values.
   1973  for (i.switchToPrev(); !i.done(); i.prev()) {
   1974    const ABIResult& result = i.cur();
   1975    if (result.onStack()) {
   1976      Stk v = captureStackResult(result, resultsBase, bytes);
   1977      push(v);
   1978      if (v.kind() == Stk::MemRef) {
   1979        stackMapGenerator_.memRefsOnStk++;
   1980        fr.storeImmediatePtrToStack(intptr_t(0), v.offs(), temp);
   1981      }
   1982    }
   1983  }
   1984 
   1985  *loc = StackResultsLoc(bytes, count, height);
   1986 
   1987  return true;
   1988 }
   1989 
   1990 // After a call, some results may be written to the stack result locations that
   1991 // are pushed on the machine stack after any stack args.  If there are stack
   1992 // args and stack results, these results need to be shuffled down, as the args
   1993 // are "consumed" by the call.
   1994 void BaseCompiler::popStackResultsAfterWasmCall(const StackResultsLoc& results,
   1995                                                uint32_t stackArgBytes) {
   1996  if (results.bytes() != 0) {
   1997    popValueStackBy(results.count());
   1998    if (stackArgBytes != 0) {
   1999      uint32_t srcHeight = results.height();
   2000      MOZ_ASSERT(srcHeight >= stackArgBytes + results.bytes());
   2001      uint32_t destHeight = srcHeight - stackArgBytes;
   2002 
   2003      fr.shuffleStackResultsTowardFP(srcHeight, destHeight, results.bytes(),
   2004                                     ABINonArgReturnVolatileReg);
   2005    }
   2006  }
   2007 }
   2008 
   2009 void BaseCompiler::pushBuiltinCallResult(const FunctionCall& call,
   2010                                         MIRType type) {
   2011  switch (type) {
   2012    case MIRType::Int32: {
   2013      RegI32 rv = captureReturnedI32();
   2014      pushI32(rv);
   2015      break;
   2016    }
   2017    case MIRType::Int64: {
   2018      RegI64 rv = captureReturnedI64();
   2019      pushI64(rv);
   2020      break;
   2021    }
   2022    case MIRType::Float32: {
   2023      RegF32 rv = captureReturnedF32(call);
   2024      pushF32(rv);
   2025      break;
   2026    }
   2027    case MIRType::Double: {
   2028      RegF64 rv = captureReturnedF64(call);
   2029      pushF64(rv);
   2030      break;
   2031    }
   2032 #ifdef ENABLE_WASM_SIMD
   2033    case MIRType::Simd128: {
   2034      RegV128 rv = captureReturnedV128(call);
   2035      pushV128(rv);
   2036      break;
   2037    }
   2038 #endif
   2039    case MIRType::WasmAnyRef: {
   2040      RegRef rv = captureReturnedRef();
   2041      pushRef(rv);
   2042      break;
   2043    }
   2044    default:
   2045      // In particular, passing |type| as MIRType::Void or MIRType::Pointer to
   2046      // this function is an error.
   2047      MOZ_CRASH("Function return type");
   2048  }
   2049 }
   2050 
   2051 bool BaseCompiler::pushWasmCallResults(const FunctionCall& call,
   2052                                       ResultType type,
   2053                                       const StackResultsLoc& loc) {
   2054  // pushResults currently bypasses special case code in captureReturnedFxx()
   2055  // that converts GPR results to FPR results for the system ABI when using
   2056  // softFP.  If we ever start using that combination for calls we need more
   2057  // code.
   2058  MOZ_ASSERT(call.abiKind == ABIKind::Wasm);
   2059  return pushResults(type, fr.stackResultsBase(loc.bytes()));
   2060 }
   2061 
   2062 CodeOffset BaseCompiler::callDefinition(uint32_t funcIndex,
   2063                                        const FunctionCall& call) {
   2064  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Func);
   2065  return masm.call(desc, funcIndex);
   2066 }
   2067 
   2068 CodeOffset BaseCompiler::callSymbolic(SymbolicAddress callee,
   2069                                      const FunctionCall& call) {
   2070  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Symbolic);
   2071  return masm.call(desc, callee);
   2072 }
   2073 
   2074 // Precondition: sync()
   2075 
   2076 static ReturnCallAdjustmentInfo BuildReturnCallAdjustmentInfo(
   2077    const FuncType& callerType, const FuncType& calleeType) {
   2078  return ReturnCallAdjustmentInfo(
   2079      StackArgAreaSizeUnaligned(ArgTypeVector(calleeType), ABIKind::Wasm),
   2080      StackArgAreaSizeUnaligned(ArgTypeVector(callerType), ABIKind::Wasm));
   2081 }
   2082 
   2083 bool BaseCompiler::callIndirect(uint32_t funcTypeIndex, uint32_t tableIndex,
   2084                                const Stk& indexVal, const FunctionCall& call,
   2085                                bool tailCall, CodeOffset* fastCallOffset,
   2086                                CodeOffset* slowCallOffset) {
   2087  CallIndirectId callIndirectId =
   2088      CallIndirectId::forFuncType(codeMeta_, funcTypeIndex);
   2089  MOZ_ASSERT(callIndirectId.kind() != CallIndirectIdKind::AsmJS);
   2090 
   2091  const TableDesc& table = codeMeta_.tables[tableIndex];
   2092  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Indirect);
   2093  CalleeDesc callee =
   2094      CalleeDesc::wasmTable(codeMeta_, table, tableIndex, callIndirectId);
   2095  OutOfLineCode* oob = addOutOfLineCode(
   2096      new (alloc_) OutOfLineAbortingTrap(Trap::OutOfBounds, trapSiteDesc()));
   2097  if (!oob) {
   2098    return false;
   2099  }
   2100 
   2101  if (table.addressType() == AddressType::I64) {
   2102 #ifdef JS_PUNBOX64
   2103    RegI64 indexReg = RegI64(Register64(WasmTableCallIndexReg));
   2104 #else
   2105    RegI64 indexReg =
   2106        RegI64(Register64(WasmTableCallScratchReg0, WasmTableCallIndexReg));
   2107 #endif
   2108    loadI64(indexVal, indexReg);
   2109    masm.branch64(
   2110        Assembler::Condition::BelowOrEqual,
   2111        Address(InstanceReg, wasm::Instance::offsetInData(
   2112                                 callee.tableLengthInstanceDataOffset())),
   2113        indexReg, oob->entry());
   2114    // From this point forward, the callee index is known to fit in 32 bits and
   2115    // therefore we only need WasmTableCallIndexReg.
   2116  } else {
   2117    loadI32(indexVal, RegI32(WasmTableCallIndexReg));
   2118    masm.branch32(
   2119        Assembler::Condition::BelowOrEqual,
   2120        Address(InstanceReg, wasm::Instance::offsetInData(
   2121                                 callee.tableLengthInstanceDataOffset())),
   2122        WasmTableCallIndexReg, oob->entry());
   2123  }
   2124 
   2125  Label* nullCheckFailed = nullptr;
   2126 #ifndef WASM_HAS_HEAPREG
   2127  OutOfLineCode* nullref = addOutOfLineCode(new (alloc_) OutOfLineAbortingTrap(
   2128      Trap::IndirectCallToNull, trapSiteDesc()));
   2129  if (!nullref) {
   2130    return false;
   2131  }
   2132  nullCheckFailed = nullref->entry();
   2133 #endif
   2134  if (!tailCall) {
   2135    masm.wasmCallIndirect(desc, callee, nullCheckFailed, fastCallOffset,
   2136                          slowCallOffset);
   2137  } else {
   2138    ReturnCallAdjustmentInfo retCallInfo = BuildReturnCallAdjustmentInfo(
   2139        this->funcType(), (*codeMeta_.types)[funcTypeIndex].funcType());
   2140    masm.wasmReturnCallIndirect(desc, callee, nullCheckFailed, retCallInfo);
   2141  }
   2142  return true;
   2143 }
   2144 
   2145 class OutOfLineUpdateCallRefMetrics : public OutOfLineCode {
   2146 public:
   2147  virtual void generate(MacroAssembler* masm) override {
   2148    // Call the stub pointed to by Instance::updateCallRefMetricsStub, then
   2149    // rejoin.  See "Register management" in BaseCompiler::updateCallRefMetrics
   2150    // for details of register management.
   2151    //
   2152    // The monitored call may or may not be cross-instance.  The stub will only
   2153    // modify `regMetrics`, `regFuncRef`, `regScratch` and `regMetrics*` (that
   2154    // is, the pointed-at CallRefMetrics) and cannot fail or trap.
   2155    masm->call(
   2156        Address(InstanceReg, Instance::offsetOfUpdateCallRefMetricsStub()));
   2157    masm->jump(rejoin());
   2158  }
   2159 };
   2160 
   2161 // Generate code that updates the `callRefIndex`th CallRefMetrics attached to
   2162 // the current Instance, to reflect the fact that this call site is just about
   2163 // to make a call to the funcref to which WasmCallRefReg currently points.
   2164 bool BaseCompiler::updateCallRefMetrics(size_t callRefIndex) {
   2165  AutoCreatedBy acb(masm, "BC::updateCallRefMetrics");
   2166 
   2167  // See declaration of CallRefMetrics for comments about assignments of
   2168  // funcrefs to `CallRefMetrics::targets[]` fields.
   2169 
   2170  // Register management: we will use three regs, `regMetrics`, `regFuncRef`,
   2171  // `regScratch` as detailed below.  All of them may be trashed.  But
   2172  // WasmCallRefReg needs to be unchanged across the update, so copy it into
   2173  // `regFuncRef` and use that instead of the original.
   2174  //
   2175  // At entry here, at entry to the OOL code, and at entry to the stub it
   2176  // calls, InstanceReg must be pointing at a valid Instance.
   2177  const Register regMetrics = WasmCallRefCallScratchReg0;  // CallRefMetrics*
   2178  const Register regFuncRef = WasmCallRefCallScratchReg1;  // FuncExtended*
   2179  const Register regScratch = WasmCallRefCallScratchReg2;  // scratch
   2180 
   2181  OutOfLineCode* ool =
   2182      addOutOfLineCode(new (alloc_) OutOfLineUpdateCallRefMetrics());
   2183  if (!ool) {
   2184    return false;
   2185  }
   2186 
   2187  // We only need one Rejoin label, so use ool->rejoin() for that.
   2188 
   2189  // if (target == nullptr) goto Rejoin
   2190  masm.branchWasmAnyRefIsNull(/*isNull=*/true, WasmCallRefReg, ool->rejoin());
   2191 
   2192  // regFuncRef = target (make a copy of WasmCallRefReg)
   2193  masm.mov(WasmCallRefReg, regFuncRef);
   2194 
   2195  // regMetrics = thisInstance::callRefMetrics_ + <imm>
   2196  //
   2197  // Emit a patchable mov32 which will load the offset of the `CallRefMetrics`
   2198  // stored inside the `Instance::callRefMetrics_` array
   2199  const CodeOffset offsetOfCallRefOffset = masm.move32WithPatch(regScratch);
   2200  masm.callRefMetricsPatches()[callRefIndex].setOffset(
   2201      offsetOfCallRefOffset.offset());
   2202  // Get a pointer to the `CallRefMetrics` for this call_ref
   2203  masm.loadPtr(Address(InstanceReg, wasm::Instance::offsetOfCallRefMetrics()),
   2204               regMetrics);
   2205  masm.addPtr(regScratch, regMetrics);
   2206 
   2207  // At this point, regFuncRef = the FuncExtended*, regMetrics = the
   2208  // CallRefMetrics* and we know regFuncRef is not null.
   2209  //
   2210  // if (target->instance != thisInstance) goto Out-Of-Line
   2211  const size_t instanceSlotOffset = FunctionExtended::offsetOfExtendedSlot(
   2212      FunctionExtended::WASM_INSTANCE_SLOT);
   2213  masm.loadPtr(Address(regFuncRef, instanceSlotOffset), regScratch);
   2214  masm.branchPtr(Assembler::NotEqual, InstanceReg, regScratch, ool->entry());
   2215 
   2216  // At this point, regFuncRef = the FuncExtended*, regMetrics = the
   2217  // CallRefMetrics*, we know regFuncRef is not null and it's a same-instance
   2218  // call.
   2219  //
   2220  // if (target != metrics->targets[0]) goto Out-Of-Line
   2221  const size_t offsetOfTarget0 = CallRefMetrics::offsetOfTarget(0);
   2222  masm.loadPtr(Address(regMetrics, offsetOfTarget0), regScratch);
   2223  masm.branchPtr(Assembler::NotEqual, regScratch, regFuncRef, ool->entry());
   2224 
   2225  // At this point, regFuncRef = the FuncExtended*, regMetrics = the
   2226  // CallRefMetrics*, we know regFuncRef is not null, it's a same-instance
   2227  // call, and it is to the destination `regMetrics->targets[0]`.
   2228  //
   2229  // metrics->count0++
   2230  const size_t offsetOfCount0 = CallRefMetrics::offsetOfCount(0);
   2231  masm.load32(Address(regMetrics, offsetOfCount0), regScratch);
   2232  masm.add32(Imm32(1), regScratch);
   2233  masm.store32(regScratch, Address(regMetrics, offsetOfCount0));
   2234 
   2235  masm.bind(ool->rejoin());
   2236  return true;
   2237 }
   2238 
   2239 bool BaseCompiler::callRef(const Stk& calleeRef, const FunctionCall& call,
   2240                           mozilla::Maybe<size_t> callRefIndex,
   2241                           CodeOffset* fastCallOffset,
   2242                           CodeOffset* slowCallOffset) {
   2243  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::FuncRef);
   2244  CalleeDesc callee = CalleeDesc::wasmFuncRef();
   2245 
   2246  loadRef(calleeRef, RegRef(WasmCallRefReg));
   2247  if (compilerEnv_.mode() == CompileMode::LazyTiering) {
   2248    if (!updateCallRefMetrics(*callRefIndex)) {
   2249      return false;
   2250    }
   2251  } else {
   2252    MOZ_ASSERT(callRefIndex.isNothing());
   2253  }
   2254 
   2255  masm.wasmCallRef(desc, callee, fastCallOffset, slowCallOffset);
   2256  return true;
   2257 }
   2258 
   2259 void BaseCompiler::returnCallRef(const Stk& calleeRef, const FunctionCall& call,
   2260                                 const FuncType& funcType) {
   2261  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::FuncRef);
   2262  CalleeDesc callee = CalleeDesc::wasmFuncRef();
   2263 
   2264  loadRef(calleeRef, RegRef(WasmCallRefReg));
   2265  ReturnCallAdjustmentInfo retCallInfo =
   2266      BuildReturnCallAdjustmentInfo(this->funcType(), funcType);
   2267  masm.wasmReturnCallRef(desc, callee, retCallInfo);
   2268 }
   2269 
   2270 // Precondition: sync()
   2271 
   2272 CodeOffset BaseCompiler::callImport(unsigned instanceDataOffset,
   2273                                    const FunctionCall& call) {
   2274  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Import);
   2275  CalleeDesc callee = CalleeDesc::import(instanceDataOffset);
   2276  return masm.wasmCallImport(desc, callee);
   2277 }
   2278 
   2279 CodeOffset BaseCompiler::builtinCall(SymbolicAddress builtin,
   2280                                     const FunctionCall& call) {
   2281  return callSymbolic(builtin, call);
   2282 }
   2283 
   2284 CodeOffset BaseCompiler::builtinInstanceMethodCall(
   2285    const SymbolicAddressSignature& builtin, const ABIArg& instanceArg,
   2286    const FunctionCall& call) {
   2287 #ifndef RABALDR_PIN_INSTANCE
   2288  // Builtin method calls assume the instance register has been set.
   2289  fr.loadInstancePtr(InstanceReg);
   2290 #endif
   2291  CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Symbolic);
   2292  return masm.wasmCallBuiltinInstanceMethod(desc, instanceArg, builtin.identity,
   2293                                            builtin.failureMode,
   2294                                            builtin.failureTrap);
   2295 }
   2296 
   2297 //////////////////////////////////////////////////////////////////////////////
   2298 //
   2299 // Exception handling
   2300 
   2301 // Abstracted helper for throwing, used for throw, rethrow, and rethrowing
   2302 // at the end of a series of catch blocks (if none matched the exception).
   2303 bool BaseCompiler::throwFrom(RegRef exn) {
   2304  pushRef(exn);
   2305 
   2306  // ThrowException invokes a trap, and the rest is dead code.
   2307  return emitInstanceCall(SASigThrowException);
   2308 }
   2309 
   2310 void BaseCompiler::loadTag(RegPtr instance, uint32_t tagIndex, RegRef tagDst) {
   2311  size_t offset =
   2312      Instance::offsetInData(codeMeta_.offsetOfTagInstanceData(tagIndex));
   2313  masm.loadPtr(Address(instance, offset), tagDst);
   2314 }
   2315 
   2316 void BaseCompiler::consumePendingException(RegPtr instance, RegRef* exnDst,
   2317                                           RegRef* tagDst) {
   2318  RegPtr pendingAddr = RegPtr(PreBarrierReg);
   2319  needPtr(pendingAddr);
   2320  masm.computeEffectiveAddress(
   2321      Address(instance, Instance::offsetOfPendingException()), pendingAddr);
   2322  *exnDst = needRef();
   2323  masm.loadPtr(Address(pendingAddr, 0), *exnDst);
   2324  emitBarrieredClear(pendingAddr);
   2325 
   2326  *tagDst = needRef();
   2327  masm.computeEffectiveAddress(
   2328      Address(instance, Instance::offsetOfPendingExceptionTag()), pendingAddr);
   2329  masm.loadPtr(Address(pendingAddr, 0), *tagDst);
   2330  emitBarrieredClear(pendingAddr);
   2331  freePtr(pendingAddr);
   2332 }
   2333 
   2334 bool BaseCompiler::startTryNote(size_t* tryNoteIndex) {
   2335  // Check the previous try note to ensure that we don't share an edge with
   2336  // it that could lead to ambiguity. Insert a nop, if required.
   2337  TryNoteVector& tryNotes = masm.tryNotes();
   2338  if (tryNotes.length() > 0) {
   2339    const TryNote& previous = tryNotes.back();
   2340    uint32_t currentOffset = masm.currentOffset();
   2341    if (previous.tryBodyBegin() == currentOffset ||
   2342        previous.tryBodyEnd() == currentOffset) {
   2343      masm.nop();
   2344    }
   2345  }
   2346 
   2347  // Mark the beginning of the try note
   2348  wasm::TryNote tryNote = wasm::TryNote();
   2349  tryNote.setTryBodyBegin(masm.currentOffset());
   2350  return masm.append(tryNote, tryNoteIndex);
   2351 }
   2352 
   2353 void BaseCompiler::finishTryNote(size_t tryNoteIndex) {
   2354  TryNoteVector& tryNotes = masm.tryNotes();
   2355  TryNote& tryNote = tryNotes[tryNoteIndex];
   2356 
   2357  // Disallow zero-length try notes by inserting a no-op
   2358  if (tryNote.tryBodyBegin() == masm.currentOffset()) {
   2359    masm.nop();
   2360  }
   2361 
   2362  // Check the most recent finished try note to ensure that we don't share an
   2363  // edge with it that could lead to ambiguity. Insert a nop, if required.
   2364  //
   2365  // Notice that finishTryNote is called in LIFO order -- using depth-first
   2366  // search numbering to see if we are traversing back from a nested try to a
   2367  // parent try, where we may need to ensure that the end offsets do not
   2368  // coincide.
   2369  //
   2370  // In the case the tryNodeIndex >= mostRecentFinishedTryNoteIndex_, we have
   2371  // finished a try that began after the most recent finished try, and so
   2372  // startTryNote will take care of any nops.
   2373  if (tryNoteIndex < mostRecentFinishedTryNoteIndex_) {
   2374    const TryNote& previous = tryNotes[mostRecentFinishedTryNoteIndex_];
   2375    uint32_t currentOffset = masm.currentOffset();
   2376    if (previous.tryBodyEnd() == currentOffset) {
   2377      masm.nop();
   2378    }
   2379  }
   2380  mostRecentFinishedTryNoteIndex_ = tryNoteIndex;
   2381 
   2382  // Don't set the end of the try note if we've OOM'ed, as the above nop's may
   2383  // not have been placed. This is okay as this compilation will be thrown
   2384  // away.
   2385  if (masm.oom()) {
   2386    return;
   2387  }
   2388 
   2389  // Mark the end of the try note
   2390  tryNote.setTryBodyEnd(masm.currentOffset());
   2391 }
   2392 
   2393 ////////////////////////////////////////////////////////////
   2394 //
   2395 // Platform-specific popping and register targeting.
   2396 
   2397 // The simple popping methods pop values into targeted registers; the caller
   2398 // can free registers using standard functions.  These are always called
   2399 // popXForY where X says something about types and Y something about the
   2400 // operation being targeted.
   2401 
   2402 RegI32 BaseCompiler::needRotate64Temp() {
   2403 #if defined(JS_CODEGEN_X86)
   2404  return needI32();
   2405 #elif defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) ||    \
   2406    defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS64) || \
   2407    defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64)
   2408  return RegI32::Invalid();
   2409 #else
   2410  MOZ_CRASH("BaseCompiler platform hook: needRotate64Temp");
   2411 #endif
   2412 }
   2413 
   2414 void BaseCompiler::popAndAllocateForDivAndRemI32(RegI32* r0, RegI32* r1,
   2415                                                 RegI32* reserved) {
   2416 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2417  // r0 must be eax, and edx will be clobbered.
   2418  need2xI32(specific_.eax, specific_.edx);
   2419  *r1 = popI32();
   2420  *r0 = popI32ToSpecific(specific_.eax);
   2421  *reserved = specific_.edx;
   2422 #else
   2423  pop2xI32(r0, r1);
   2424 #endif
   2425 }
   2426 
   2427 static void QuotientI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd,
   2428                        RegI32 reserved, IsUnsigned isUnsigned) {
   2429 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2430  masm.quotient32(rsd, rs, rsd, reserved, isUnsigned);
   2431 #else
   2432  masm.quotient32(rsd, rs, rsd, isUnsigned);
   2433 #endif
   2434 }
   2435 
   2436 static void RemainderI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd,
   2437                         RegI32 reserved, IsUnsigned isUnsigned) {
   2438 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2439  masm.remainder32(rsd, rs, rsd, reserved, isUnsigned);
   2440 #else
   2441  masm.remainder32(rsd, rs, rsd, isUnsigned);
   2442 #endif
   2443 }
   2444 
   2445 void BaseCompiler::popAndAllocateForMulI64(RegI64* r0, RegI64* r1,
   2446                                           RegI32* temp) {
   2447 #if defined(JS_CODEGEN_X64)
   2448  pop2xI64(r0, r1);
   2449 #elif defined(JS_CODEGEN_X86)
   2450  // lhsDest must be edx:eax and rhs must not be that.
   2451  needI64(specific_.edx_eax);
   2452  *r1 = popI64();
   2453  *r0 = popI64ToSpecific(specific_.edx_eax);
   2454  *temp = needI32();
   2455 #elif defined(JS_CODEGEN_MIPS64)
   2456  pop2xI64(r0, r1);
   2457 #elif defined(JS_CODEGEN_ARM)
   2458  pop2xI64(r0, r1);
   2459  *temp = needI32();
   2460 #elif defined(JS_CODEGEN_ARM64)
   2461  pop2xI64(r0, r1);
   2462 #elif defined(JS_CODEGEN_LOONG64)
   2463  pop2xI64(r0, r1);
   2464 #elif defined(JS_CODEGEN_RISCV64)
   2465  pop2xI64(r0, r1);
   2466 #else
   2467  MOZ_CRASH("BaseCompiler porting interface: popAndAllocateForMulI64");
   2468 #endif
   2469 }
   2470 
   2471 #ifndef RABALDR_INT_DIV_I64_CALLOUT
   2472 
   2473 void BaseCompiler::popAndAllocateForDivAndRemI64(RegI64* r0, RegI64* r1,
   2474                                                 RegI64* reserved,
   2475                                                 IsRemainder isRemainder) {
   2476 #  if defined(JS_CODEGEN_X64)
   2477  // r0 must be rax, and rdx will be clobbered.
   2478  need2xI64(specific_.rax, specific_.rdx);
   2479  *r1 = popI64();
   2480  *r0 = popI64ToSpecific(specific_.rax);
   2481  *reserved = specific_.rdx;
   2482 #  elif defined(JS_CODEGEN_ARM64)
   2483  pop2xI64(r0, r1);
   2484  if (isRemainder) {
   2485    *reserved = needI64();
   2486  }
   2487 #  else
   2488  pop2xI64(r0, r1);
   2489 #  endif
   2490 }
   2491 
   2492 static void QuotientI64(MacroAssembler& masm, RegI64 rhs, RegI64 srcDest,
   2493                        RegI64 reserved, IsUnsigned isUnsigned) {
   2494 #  if defined(JS_CODEGEN_X64)
   2495  // The caller must set up the following situation.
   2496  MOZ_ASSERT(srcDest.reg == rax);
   2497  MOZ_ASSERT(reserved.reg == rdx);
   2498  if (isUnsigned) {
   2499    masm.xorq(rdx, rdx);
   2500    masm.udivq(rhs.reg);
   2501  } else {
   2502    masm.cqo();
   2503    masm.idivq(rhs.reg);
   2504  }
   2505 #  elif !defined(JS_CODEGEN_NONE) && !defined(JS_CODEGEN_WASM32)
   2506  masm.quotient64(srcDest.reg, rhs.reg, srcDest.reg, isUnsigned);
   2507 #  else
   2508  MOZ_CRASH("BaseCompiler platform hook: quotientI64");
   2509 #  endif
   2510 }
   2511 
   2512 static void RemainderI64(MacroAssembler& masm, RegI64 rhs, RegI64 srcDest,
   2513                         RegI64 reserved, IsUnsigned isUnsigned) {
   2514 #  if defined(JS_CODEGEN_X64)
   2515  // The caller must set up the following situation.
   2516  MOZ_ASSERT(srcDest.reg == rax);
   2517  MOZ_ASSERT(reserved.reg == rdx);
   2518 
   2519  if (isUnsigned) {
   2520    masm.xorq(rdx, rdx);
   2521    masm.udivq(rhs.reg);
   2522  } else {
   2523    masm.cqo();
   2524    masm.idivq(rhs.reg);
   2525  }
   2526  masm.movq(rdx, rax);
   2527 #  elif !defined(JS_CODEGEN_NONE) && !defined(JS_CODEGEN_WASM32)
   2528  masm.remainder64(srcDest.reg, rhs.reg, srcDest.reg, isUnsigned);
   2529 #  else
   2530  MOZ_CRASH("BaseCompiler platform hook: remainderI64");
   2531 #  endif
   2532 }
   2533 
   2534 #endif  // RABALDR_INT_DIV_I64_CALLOUT
   2535 
   2536 RegI32 BaseCompiler::popI32RhsForShift() {
   2537 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2538  // r1 must be ecx for a variable shift, unless BMI2 is available.
   2539  if (!Assembler::HasBMI2()) {
   2540    return popI32(specific_.ecx);
   2541  }
   2542 #endif
   2543  RegI32 r = popI32();
   2544 #if defined(JS_CODEGEN_ARM)
   2545  masm.and32(Imm32(31), r);
   2546 #endif
   2547  return r;
   2548 }
   2549 
   2550 RegI32 BaseCompiler::popI32RhsForShiftI64() {
   2551 #if defined(JS_CODEGEN_X86)
   2552  // A limitation in the x86 masm requires ecx here
   2553  return popI32(specific_.ecx);
   2554 #elif defined(JS_CODEGEN_X64)
   2555  if (!Assembler::HasBMI2()) {
   2556    return popI32(specific_.ecx);
   2557  }
   2558  return popI32();
   2559 #else
   2560  return popI32();
   2561 #endif
   2562 }
   2563 
   2564 RegI64 BaseCompiler::popI64RhsForShift() {
   2565 #if defined(JS_CODEGEN_X86)
   2566  // r1 must be ecx for a variable shift.
   2567  needI32(specific_.ecx);
   2568  return popI64ToSpecific(widenI32(specific_.ecx));
   2569 #else
   2570 #  if defined(JS_CODEGEN_X64)
   2571  // r1 must be rcx for a variable shift, unless BMI2 is available.
   2572  if (!Assembler::HasBMI2()) {
   2573    needI64(specific_.rcx);
   2574    return popI64ToSpecific(specific_.rcx);
   2575  }
   2576 #  endif
   2577  // No masking is necessary on 64-bit platforms, and on arm32 the masm
   2578  // implementation masks.
   2579  return popI64();
   2580 #endif
   2581 }
   2582 
   2583 RegI32 BaseCompiler::popI32RhsForRotate() {
   2584 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2585  // r1 must be ecx for a variable rotate.
   2586  return popI32(specific_.ecx);
   2587 #else
   2588  return popI32();
   2589 #endif
   2590 }
   2591 
   2592 RegI64 BaseCompiler::popI64RhsForRotate() {
   2593 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2594  // r1 must be ecx for a variable rotate.
   2595  needI32(specific_.ecx);
   2596  return popI64ToSpecific(widenI32(specific_.ecx));
   2597 #else
   2598  return popI64();
   2599 #endif
   2600 }
   2601 
   2602 void BaseCompiler::popI32ForSignExtendI64(RegI64* r0) {
   2603 #if defined(JS_CODEGEN_X86)
   2604  // r0 must be edx:eax for cdq
   2605  need2xI32(specific_.edx, specific_.eax);
   2606  *r0 = specific_.edx_eax;
   2607  popI32ToSpecific(specific_.eax);
   2608 #else
   2609  *r0 = widenI32(popI32());
   2610 #endif
   2611 }
   2612 
   2613 void BaseCompiler::popI64ForSignExtendI64(RegI64* r0) {
   2614 #if defined(JS_CODEGEN_X86)
   2615  // r0 must be edx:eax for cdq
   2616  need2xI32(specific_.edx, specific_.eax);
   2617  // Low on top, high underneath
   2618  *r0 = popI64ToSpecific(specific_.edx_eax);
   2619 #else
   2620  *r0 = popI64();
   2621 #endif
   2622 }
   2623 
   2624 class OutOfLineTruncateCheckF32OrF64ToI32 : public OutOfLineCode {
   2625  AnyReg src;
   2626  RegI32 dest;
   2627  TruncFlags flags;
   2628  TrapSiteDesc trapSiteDesc;
   2629 
   2630 public:
   2631  OutOfLineTruncateCheckF32OrF64ToI32(AnyReg src, RegI32 dest, TruncFlags flags,
   2632                                      TrapSiteDesc trapSiteDesc)
   2633      : src(src), dest(dest), flags(flags), trapSiteDesc(trapSiteDesc) {}
   2634 
   2635  virtual void generate(MacroAssembler* masm) override {
   2636    if (src.tag == AnyReg::F32) {
   2637      masm->oolWasmTruncateCheckF32ToI32(src.f32(), dest, flags, trapSiteDesc,
   2638                                         rejoin());
   2639    } else if (src.tag == AnyReg::F64) {
   2640      masm->oolWasmTruncateCheckF64ToI32(src.f64(), dest, flags, trapSiteDesc,
   2641                                         rejoin());
   2642    } else {
   2643      MOZ_CRASH("unexpected type");
   2644    }
   2645  }
   2646 };
   2647 
   2648 bool BaseCompiler::truncateF32ToI32(RegF32 src, RegI32 dest, TruncFlags flags) {
   2649  OutOfLineCode* ool =
   2650      addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI32(
   2651          AnyReg(src), dest, flags, trapSiteDesc()));
   2652  if (!ool) {
   2653    return false;
   2654  }
   2655  bool isSaturating = flags & TRUNC_SATURATING;
   2656  if (flags & TRUNC_UNSIGNED) {
   2657    masm.wasmTruncateFloat32ToUInt32(src, dest, isSaturating, ool->entry());
   2658  } else {
   2659    masm.wasmTruncateFloat32ToInt32(src, dest, isSaturating, ool->entry());
   2660  }
   2661  masm.bind(ool->rejoin());
   2662  return true;
   2663 }
   2664 
   2665 bool BaseCompiler::truncateF64ToI32(RegF64 src, RegI32 dest, TruncFlags flags) {
   2666  OutOfLineCode* ool =
   2667      addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI32(
   2668          AnyReg(src), dest, flags, trapSiteDesc()));
   2669  if (!ool) {
   2670    return false;
   2671  }
   2672  bool isSaturating = flags & TRUNC_SATURATING;
   2673  if (flags & TRUNC_UNSIGNED) {
   2674    masm.wasmTruncateDoubleToUInt32(src, dest, isSaturating, ool->entry());
   2675  } else {
   2676    masm.wasmTruncateDoubleToInt32(src, dest, isSaturating, ool->entry());
   2677  }
   2678  masm.bind(ool->rejoin());
   2679  return true;
   2680 }
   2681 
   2682 class OutOfLineTruncateCheckF32OrF64ToI64 : public OutOfLineCode {
   2683  AnyReg src;
   2684  RegI64 dest;
   2685  TruncFlags flags;
   2686  TrapSiteDesc trapSiteDesc;
   2687 
   2688 public:
   2689  OutOfLineTruncateCheckF32OrF64ToI64(AnyReg src, RegI64 dest, TruncFlags flags,
   2690                                      TrapSiteDesc trapSiteDesc)
   2691      : src(src), dest(dest), flags(flags), trapSiteDesc(trapSiteDesc) {}
   2692 
   2693  virtual void generate(MacroAssembler* masm) override {
   2694    if (src.tag == AnyReg::F32) {
   2695      masm->oolWasmTruncateCheckF32ToI64(src.f32(), dest, flags, trapSiteDesc,
   2696                                         rejoin());
   2697    } else if (src.tag == AnyReg::F64) {
   2698      masm->oolWasmTruncateCheckF64ToI64(src.f64(), dest, flags, trapSiteDesc,
   2699                                         rejoin());
   2700    } else {
   2701      MOZ_CRASH("unexpected type");
   2702    }
   2703  }
   2704 };
   2705 
   2706 #ifndef RABALDR_FLOAT_TO_I64_CALLOUT
   2707 
   2708 RegF64 BaseCompiler::needTempForFloatingToI64(TruncFlags flags) {
   2709 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2710  if (flags & TRUNC_UNSIGNED) {
   2711    return needF64();
   2712  }
   2713 #  endif
   2714  return RegF64::Invalid();
   2715 }
   2716 
   2717 bool BaseCompiler::truncateF32ToI64(RegF32 src, RegI64 dest, TruncFlags flags,
   2718                                    RegF64 temp) {
   2719  OutOfLineCode* ool =
   2720      addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(
   2721          AnyReg(src), dest, flags, trapSiteDesc()));
   2722  if (!ool) {
   2723    return false;
   2724  }
   2725  bool isSaturating = flags & TRUNC_SATURATING;
   2726  if (flags & TRUNC_UNSIGNED) {
   2727    masm.wasmTruncateFloat32ToUInt64(src, dest, isSaturating, ool->entry(),
   2728                                     ool->rejoin(), temp);
   2729  } else {
   2730    masm.wasmTruncateFloat32ToInt64(src, dest, isSaturating, ool->entry(),
   2731                                    ool->rejoin(), temp);
   2732  }
   2733  return true;
   2734 }
   2735 
   2736 bool BaseCompiler::truncateF64ToI64(RegF64 src, RegI64 dest, TruncFlags flags,
   2737                                    RegF64 temp) {
   2738  OutOfLineCode* ool =
   2739      addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(
   2740          AnyReg(src), dest, flags, trapSiteDesc()));
   2741  if (!ool) {
   2742    return false;
   2743  }
   2744  bool isSaturating = flags & TRUNC_SATURATING;
   2745  if (flags & TRUNC_UNSIGNED) {
   2746    masm.wasmTruncateDoubleToUInt64(src, dest, isSaturating, ool->entry(),
   2747                                    ool->rejoin(), temp);
   2748  } else {
   2749    masm.wasmTruncateDoubleToInt64(src, dest, isSaturating, ool->entry(),
   2750                                   ool->rejoin(), temp);
   2751  }
   2752  return true;
   2753 }
   2754 
   2755 #endif  // RABALDR_FLOAT_TO_I64_CALLOUT
   2756 
   2757 #ifndef RABALDR_I64_TO_FLOAT_CALLOUT
   2758 
   2759 RegI32 BaseCompiler::needConvertI64ToFloatTemp(ValType to, bool isUnsigned) {
   2760  bool needs = false;
   2761  if (to == ValType::F64) {
   2762    needs = isUnsigned && masm.convertUInt64ToDoubleNeedsTemp();
   2763  } else {
   2764 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2765    needs = true;
   2766 #  endif
   2767  }
   2768  return needs ? needI32() : RegI32::Invalid();
   2769 }
   2770 
   2771 void BaseCompiler::convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest,
   2772                                   RegI32 temp) {
   2773  if (isUnsigned) {
   2774    masm.convertUInt64ToFloat32(src, dest, temp);
   2775  } else {
   2776    masm.convertInt64ToFloat32(src, dest);
   2777  }
   2778 }
   2779 
   2780 void BaseCompiler::convertI64ToF64(RegI64 src, bool isUnsigned, RegF64 dest,
   2781                                   RegI32 temp) {
   2782  if (isUnsigned) {
   2783    masm.convertUInt64ToDouble(src, dest, temp);
   2784  } else {
   2785    masm.convertInt64ToDouble(src, dest);
   2786  }
   2787 }
   2788 
   2789 #endif  // RABALDR_I64_TO_FLOAT_CALLOUT
   2790 
   2791 //////////////////////////////////////////////////////////////////////
   2792 //
   2793 // Global variable access.
   2794 
   2795 Address BaseCompiler::addressOfGlobalVar(const GlobalDesc& global, RegPtr tmp) {
   2796  uint32_t globalToInstanceOffset = Instance::offsetInData(global.offset());
   2797 #ifdef RABALDR_PIN_INSTANCE
   2798  movePtr(RegPtr(InstanceReg), tmp);
   2799 #else
   2800  fr.loadInstancePtr(tmp);
   2801 #endif
   2802  if (global.isIndirect()) {
   2803    masm.loadPtr(Address(tmp, globalToInstanceOffset), tmp);
   2804    return Address(tmp, 0);
   2805  }
   2806  return Address(tmp, globalToInstanceOffset);
   2807 }
   2808 
   2809 //////////////////////////////////////////////////////////////////////
   2810 //
   2811 // Table access.
   2812 
   2813 Address BaseCompiler::addressOfTableField(uint32_t tableIndex,
   2814                                          uint32_t fieldOffset,
   2815                                          RegPtr instance) {
   2816  uint32_t tableToInstanceOffset = wasm::Instance::offsetInData(
   2817      codeMeta_.offsetOfTableInstanceData(tableIndex) + fieldOffset);
   2818  return Address(instance, tableToInstanceOffset);
   2819 }
   2820 
   2821 void BaseCompiler::loadTableLength(uint32_t tableIndex, RegPtr instance,
   2822                                   RegI32 length) {
   2823  masm.load32(addressOfTableField(
   2824                  tableIndex, offsetof(TableInstanceData, length), instance),
   2825              length);
   2826 }
   2827 
   2828 void BaseCompiler::loadTableElements(uint32_t tableIndex, RegPtr instance,
   2829                                     RegPtr elements) {
   2830  masm.loadPtr(addressOfTableField(
   2831                   tableIndex, offsetof(TableInstanceData, elements), instance),
   2832               elements);
   2833 }
   2834 
   2835 //////////////////////////////////////////////////////////////////////////////
   2836 //
   2837 // Basic emitters for simple operators.
   2838 
   2839 static void AddI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2840  masm.add32(rs, rsd);
   2841 }
   2842 
   2843 static void AddImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2844  masm.add32(Imm32(c), rsd);
   2845 }
   2846 
   2847 static void SubI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2848  masm.sub32(rs, rsd);
   2849 }
   2850 
   2851 static void SubImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2852  masm.sub32(Imm32(c), rsd);
   2853 }
   2854 
   2855 static void MulI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2856  masm.mul32(rs, rsd);
   2857 }
   2858 
   2859 static void OrI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2860  masm.or32(rs, rsd);
   2861 }
   2862 
   2863 static void OrImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2864  masm.or32(Imm32(c), rsd);
   2865 }
   2866 
   2867 static void AndI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2868  masm.and32(rs, rsd);
   2869 }
   2870 
   2871 static void AndImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2872  masm.and32(Imm32(c), rsd);
   2873 }
   2874 
   2875 static void XorI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2876  masm.xor32(rs, rsd);
   2877 }
   2878 
   2879 static void XorImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2880  masm.xor32(Imm32(c), rsd);
   2881 }
   2882 
   2883 static void ClzI32(MacroAssembler& masm, RegI32 rsd) {
   2884  masm.clz32(rsd, rsd, IsKnownNotZero(false));
   2885 }
   2886 
   2887 static void CtzI32(MacroAssembler& masm, RegI32 rsd) {
   2888  masm.ctz32(rsd, rsd, IsKnownNotZero(false));
   2889 }
   2890 
   2891 // Currently common to PopcntI32 and PopcntI64
   2892 static RegI32 PopcntTemp(BaseCompiler& bc) {
   2893 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   2894  return AssemblerX86Shared::HasPOPCNT() ? RegI32::Invalid() : bc.needI32();
   2895 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) ||    \
   2896    defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \
   2897    defined(JS_CODEGEN_RISCV64)
   2898  return bc.needI32();
   2899 #else
   2900  MOZ_CRASH("BaseCompiler platform hook: PopcntTemp");
   2901 #endif
   2902 }
   2903 
   2904 static void PopcntI32(BaseCompiler& bc, RegI32 rsd, RegI32 temp) {
   2905  bc.masm.popcnt32(rsd, rsd, temp);
   2906 }
   2907 
   2908 static void ShlI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2909  masm.lshift32(rs, rsd);
   2910 }
   2911 
   2912 static void ShlImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2913  masm.lshift32(Imm32(c & 31), rsd);
   2914 }
   2915 
   2916 static void ShrI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2917  masm.rshift32Arithmetic(rs, rsd);
   2918 }
   2919 
   2920 static void ShrImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2921  masm.rshift32Arithmetic(Imm32(c & 31), rsd);
   2922 }
   2923 
   2924 static void ShrUI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2925  masm.rshift32(rs, rsd);
   2926 }
   2927 
   2928 static void ShrUImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2929  masm.rshift32(Imm32(c & 31), rsd);
   2930 }
   2931 
   2932 static void RotlI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2933  masm.rotateLeft(rs, rsd, rsd);
   2934 }
   2935 
   2936 static void RotlImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2937  masm.rotateLeft(Imm32(c & 31), rsd, rsd);
   2938 }
   2939 
   2940 static void RotrI32(MacroAssembler& masm, RegI32 rs, RegI32 rsd) {
   2941  masm.rotateRight(rs, rsd, rsd);
   2942 }
   2943 
   2944 static void RotrImmI32(MacroAssembler& masm, int32_t c, RegI32 rsd) {
   2945  masm.rotateRight(Imm32(c & 31), rsd, rsd);
   2946 }
   2947 
   2948 static void EqzI32(MacroAssembler& masm, RegI32 rsd) {
   2949  masm.cmp32Set(Assembler::Equal, rsd, Imm32(0), rsd);
   2950 }
   2951 
   2952 static void WrapI64ToI32(MacroAssembler& masm, RegI64 rs, RegI32 rd) {
   2953  masm.move64To32(rs, rd);
   2954 }
   2955 
   2956 static void AddI64(MacroAssembler& masm, RegI64 rs, RegI64 rsd) {
   2957  masm.add64(rs, rsd);
   2958 }
   2959 
   2960 static void AddImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   2961  masm.add64(Imm64(c), rsd);
   2962 }
   2963 
   2964 static void SubI64(MacroAssembler& masm, RegI64 rs, RegI64 rsd) {
   2965  masm.sub64(rs, rsd);
   2966 }
   2967 
   2968 static void SubImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   2969  masm.sub64(Imm64(c), rsd);
   2970 }
   2971 
   2972 static void OrI64(MacroAssembler& masm, RegI64 rs, RegI64 rsd) {
   2973  masm.or64(rs, rsd);
   2974 }
   2975 
   2976 static void OrImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   2977  masm.or64(Imm64(c), rsd);
   2978 }
   2979 
   2980 static void AndI64(MacroAssembler& masm, RegI64 rs, RegI64 rsd) {
   2981  masm.and64(rs, rsd);
   2982 }
   2983 
   2984 static void AndImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   2985  masm.and64(Imm64(c), rsd);
   2986 }
   2987 
   2988 static void XorI64(MacroAssembler& masm, RegI64 rs, RegI64 rsd) {
   2989  masm.xor64(rs, rsd);
   2990 }
   2991 
   2992 static void XorImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   2993  masm.xor64(Imm64(c), rsd);
   2994 }
   2995 
   2996 static void ClzI64(BaseCompiler& bc, RegI64 rsd) { bc.masm.clz64(rsd, rsd); }
   2997 
   2998 static void CtzI64(BaseCompiler& bc, RegI64 rsd) { bc.masm.ctz64(rsd, rsd); }
   2999 
   3000 static void PopcntI64(BaseCompiler& bc, RegI64 rsd, RegI32 temp) {
   3001  bc.masm.popcnt64(rsd, rsd, temp);
   3002 }
   3003 
   3004 static void ShlI64(BaseCompiler& bc, RegI64 rs, RegI64 rsd) {
   3005  bc.masm.lshift64(bc.lowPart(rs), rsd);
   3006 }
   3007 
   3008 static void ShlImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   3009  masm.lshift64(Imm32(c & 63), rsd);
   3010 }
   3011 
   3012 static void ShrI64(BaseCompiler& bc, RegI64 rs, RegI64 rsd) {
   3013  bc.masm.rshift64Arithmetic(bc.lowPart(rs), rsd);
   3014 }
   3015 
   3016 static void ShrImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   3017  masm.rshift64Arithmetic(Imm32(c & 63), rsd);
   3018 }
   3019 
   3020 static void ShrUI64(BaseCompiler& bc, RegI64 rs, RegI64 rsd) {
   3021  bc.masm.rshift64(bc.lowPart(rs), rsd);
   3022 }
   3023 
   3024 static void ShrUImmI64(MacroAssembler& masm, int64_t c, RegI64 rsd) {
   3025  masm.rshift64(Imm32(c & 63), rsd);
   3026 }
   3027 
   3028 static void EqzI64(MacroAssembler& masm, RegI64 rs, RegI32 rd) {
   3029 #ifdef JS_PUNBOX64
   3030  masm.cmpPtrSet(Assembler::Equal, rs.reg, ImmWord(0), rd);
   3031 #else
   3032  MOZ_ASSERT(rs.low == rd);
   3033  masm.or32(rs.high, rs.low);
   3034  masm.cmp32Set(Assembler::Equal, rs.low, Imm32(0), rd);
   3035 #endif
   3036 }
   3037 
   3038 static void AddF64(MacroAssembler& masm, RegF64 rs, RegF64 rsd) {
   3039  masm.addDouble(rs, rsd);
   3040 }
   3041 
   3042 static void SubF64(MacroAssembler& masm, RegF64 rs, RegF64 rsd) {
   3043  masm.subDouble(rs, rsd);
   3044 }
   3045 
   3046 static void MulF64(MacroAssembler& masm, RegF64 rs, RegF64 rsd) {
   3047  masm.mulDouble(rs, rsd);
   3048 }
   3049 
   3050 static void DivF64(MacroAssembler& masm, RegF64 rs, RegF64 rsd) {
   3051  masm.divDouble(rs, rsd);
   3052 }
   3053 
   3054 static void MinF64(BaseCompiler& bc, RegF64 rs, RegF64 rsd) {
   3055  // Convert signaling NaN to quiet NaNs.
   3056  //
   3057  // TODO / OPTIMIZE (bug 1316824): see comment in MinF32.
   3058 #ifdef RABALDR_SCRATCH_F64
   3059  ScratchF64 zero(bc.ra);
   3060 #else
   3061  ScratchF64 zero(bc.masm);
   3062 #endif
   3063  bc.masm.loadConstantDouble(0, zero);
   3064  bc.masm.subDouble(zero, rsd);
   3065  bc.masm.subDouble(zero, rs);
   3066  bc.masm.minDouble(rs, rsd, HandleNaNSpecially(true));
   3067 }
   3068 
   3069 static void MaxF64(BaseCompiler& bc, RegF64 rs, RegF64 rsd) {
   3070  // Convert signaling NaN to quiet NaNs.
   3071  //
   3072  // TODO / OPTIMIZE (bug 1316824): see comment in MinF32.
   3073 #ifdef RABALDR_SCRATCH_F64
   3074  ScratchF64 zero(bc.ra);
   3075 #else
   3076  ScratchF64 zero(bc.masm);
   3077 #endif
   3078  bc.masm.loadConstantDouble(0, zero);
   3079  bc.masm.subDouble(zero, rsd);
   3080  bc.masm.subDouble(zero, rs);
   3081  bc.masm.maxDouble(rs, rsd, HandleNaNSpecially(true));
   3082 }
   3083 
   3084 static void CopysignF64(MacroAssembler& masm, RegF64 rs, RegF64 rsd) {
   3085  // No code generated for the no-op case.
   3086  if (rs == rsd) {
   3087    return;
   3088  }
   3089  masm.copySignDouble(rsd, rs, rsd);
   3090 }
   3091 
   3092 static void AbsF64(MacroAssembler& masm, RegF64 rsd) {
   3093  masm.absDouble(rsd, rsd);
   3094 }
   3095 
   3096 static void NegateF64(MacroAssembler& masm, RegF64 rsd) {
   3097  masm.negateDouble(rsd);
   3098 }
   3099 
   3100 static void SqrtF64(MacroAssembler& masm, RegF64 rsd) {
   3101  masm.sqrtDouble(rsd, rsd);
   3102 }
   3103 
   3104 static void AddF32(MacroAssembler& masm, RegF32 rs, RegF32 rsd) {
   3105  masm.addFloat32(rs, rsd);
   3106 }
   3107 
   3108 static void SubF32(MacroAssembler& masm, RegF32 rs, RegF32 rsd) {
   3109  masm.subFloat32(rs, rsd);
   3110 }
   3111 
   3112 static void MulF32(MacroAssembler& masm, RegF32 rs, RegF32 rsd) {
   3113  masm.mulFloat32(rs, rsd);
   3114 }
   3115 
   3116 static void DivF32(MacroAssembler& masm, RegF32 rs, RegF32 rsd) {
   3117  masm.divFloat32(rs, rsd);
   3118 }
   3119 
   3120 static void MinF32(BaseCompiler& bc, RegF32 rs, RegF32 rsd) {
   3121  // Convert signaling NaN to quiet NaNs.
   3122  //
   3123  // TODO / OPTIMIZE (bug 1316824): Don't do this if one of the operands
   3124  // is known to be a constant.
   3125 #ifdef RABALDR_SCRATCH_F32
   3126  ScratchF32 zero(bc.ra);
   3127 #else
   3128  ScratchF32 zero(bc.masm);
   3129 #endif
   3130  bc.masm.loadConstantFloat32(0.f, zero);
   3131  bc.masm.subFloat32(zero, rsd);
   3132  bc.masm.subFloat32(zero, rs);
   3133  bc.masm.minFloat32(rs, rsd, HandleNaNSpecially(true));
   3134 }
   3135 
   3136 static void MaxF32(BaseCompiler& bc, RegF32 rs, RegF32 rsd) {
   3137  // Convert signaling NaN to quiet NaNs.
   3138  //
   3139  // TODO / OPTIMIZE (bug 1316824): see comment in MinF32.
   3140 #ifdef RABALDR_SCRATCH_F32
   3141  ScratchF32 zero(bc.ra);
   3142 #else
   3143  ScratchF32 zero(bc.masm);
   3144 #endif
   3145  bc.masm.loadConstantFloat32(0.f, zero);
   3146  bc.masm.subFloat32(zero, rsd);
   3147  bc.masm.subFloat32(zero, rs);
   3148  bc.masm.maxFloat32(rs, rsd, HandleNaNSpecially(true));
   3149 }
   3150 
   3151 static void CopysignF32(MacroAssembler& masm, RegF32 rs, RegF32 rsd) {
   3152  // No code generated for the no-op case.
   3153  if (rs == rsd) {
   3154    return;
   3155  }
   3156  masm.copySignFloat32(rsd, rs, rsd);
   3157 }
   3158 
   3159 static void AbsF32(MacroAssembler& masm, RegF32 rsd) {
   3160  masm.absFloat32(rsd, rsd);
   3161 }
   3162 
   3163 static void NegateF32(MacroAssembler& masm, RegF32 rsd) {
   3164  masm.negateFloat(rsd);
   3165 }
   3166 
   3167 static void SqrtF32(MacroAssembler& masm, RegF32 rsd) {
   3168  masm.sqrtFloat32(rsd, rsd);
   3169 }
   3170 
   3171 #ifndef RABALDR_I64_TO_FLOAT_CALLOUT
   3172 static void ConvertI64ToF32(MacroAssembler& masm, RegI64 rs, RegF32 rd) {
   3173  masm.convertInt64ToFloat32(rs, rd);
   3174 }
   3175 
   3176 static void ConvertI64ToF64(MacroAssembler& masm, RegI64 rs, RegF64 rd) {
   3177  masm.convertInt64ToDouble(rs, rd);
   3178 }
   3179 #endif
   3180 
   3181 static void ReinterpretF32AsI32(MacroAssembler& masm, RegF32 rs, RegI32 rd) {
   3182  masm.moveFloat32ToGPR(rs, rd);
   3183 }
   3184 
   3185 static void ReinterpretF64AsI64(MacroAssembler& masm, RegF64 rs, RegI64 rd) {
   3186  masm.moveDoubleToGPR64(rs, rd);
   3187 }
   3188 
   3189 static void ConvertF64ToF32(MacroAssembler& masm, RegF64 rs, RegF32 rd) {
   3190  masm.convertDoubleToFloat32(rs, rd);
   3191 }
   3192 
   3193 static void ConvertI32ToF32(MacroAssembler& masm, RegI32 rs, RegF32 rd) {
   3194  masm.convertInt32ToFloat32(rs, rd);
   3195 }
   3196 
   3197 static void ConvertU32ToF32(MacroAssembler& masm, RegI32 rs, RegF32 rd) {
   3198  masm.convertUInt32ToFloat32(rs, rd);
   3199 }
   3200 
   3201 static void ConvertF32ToF64(MacroAssembler& masm, RegF32 rs, RegF64 rd) {
   3202  masm.convertFloat32ToDouble(rs, rd);
   3203 }
   3204 
   3205 static void ConvertI32ToF64(MacroAssembler& masm, RegI32 rs, RegF64 rd) {
   3206  masm.convertInt32ToDouble(rs, rd);
   3207 }
   3208 
   3209 static void ConvertU32ToF64(MacroAssembler& masm, RegI32 rs, RegF64 rd) {
   3210  masm.convertUInt32ToDouble(rs, rd);
   3211 }
   3212 
   3213 static void ReinterpretI32AsF32(MacroAssembler& masm, RegI32 rs, RegF32 rd) {
   3214  masm.moveGPRToFloat32(rs, rd);
   3215 }
   3216 
   3217 static void ReinterpretI64AsF64(MacroAssembler& masm, RegI64 rs, RegF64 rd) {
   3218  masm.moveGPR64ToDouble(rs, rd);
   3219 }
   3220 
   3221 static void ExtendI32_8(BaseCompiler& bc, RegI32 rsd) {
   3222 #ifdef JS_CODEGEN_X86
   3223  if (!bc.ra.isSingleByteI32(rsd)) {
   3224    ScratchI8 scratch(bc.ra);
   3225    bc.masm.move32(rsd, scratch);
   3226    bc.masm.move8SignExtend(scratch, rsd);
   3227    return;
   3228  }
   3229 #endif
   3230  bc.masm.move8SignExtend(rsd, rsd);
   3231 }
   3232 
   3233 static void ExtendI32_16(MacroAssembler& masm, RegI32 rsd) {
   3234  masm.move16SignExtend(rsd, rsd);
   3235 }
   3236 
   3237 void BaseCompiler::emitMultiplyI64() {
   3238  RegI64 r, rs;
   3239  RegI32 temp;
   3240  popAndAllocateForMulI64(&r, &rs, &temp);
   3241  masm.mul64(rs, r, temp);
   3242  maybeFree(temp);
   3243  freeI64(rs);
   3244  pushI64(r);
   3245 }
   3246 
   3247 template <typename RegType, typename IntType>
   3248 void BaseCompiler::quotientOrRemainder(
   3249    RegType rs, RegType rsd, RegType reserved, IsUnsigned isUnsigned,
   3250    ZeroOnOverflow zeroOnOverflow, bool isConst, IntType c,
   3251    void (*operate)(MacroAssembler& masm, RegType rs, RegType rsd,
   3252                    RegType reserved, IsUnsigned isUnsigned)) {
   3253  Label done;
   3254  if (!isConst || c == 0) {
   3255    checkDivideByZero(rs);
   3256  }
   3257  if (!isUnsigned && (!isConst || c == -1)) {
   3258    checkDivideSignedOverflow(rs, rsd, &done, zeroOnOverflow);
   3259  }
   3260  operate(masm, rs, rsd, reserved, isUnsigned);
   3261  masm.bind(&done);
   3262 }
   3263 
   3264 void BaseCompiler::emitQuotientI32() {
   3265  int32_t c;
   3266  uint_fast8_t power;
   3267  if (popConstPositivePowerOfTwo(&c, &power, 0)) {
   3268    if (power != 0) {
   3269      RegI32 r = popI32();
   3270      Label positive;
   3271      masm.branchTest32(Assembler::NotSigned, r, r, &positive);
   3272      masm.add32(Imm32(c - 1), r);
   3273      masm.bind(&positive);
   3274 
   3275      masm.rshift32Arithmetic(Imm32(power & 31), r);
   3276      pushI32(r);
   3277    }
   3278  } else {
   3279    bool isConst = peekConst(&c);
   3280    RegI32 r, rs, reserved;
   3281    popAndAllocateForDivAndRemI32(&r, &rs, &reserved);
   3282    quotientOrRemainder(rs, r, reserved, IsUnsigned(false),
   3283                        ZeroOnOverflow(false), isConst, c, QuotientI32);
   3284    maybeFree(reserved);
   3285    freeI32(rs);
   3286    pushI32(r);
   3287  }
   3288 }
   3289 
   3290 void BaseCompiler::emitQuotientU32() {
   3291  int32_t c;
   3292  uint_fast8_t power;
   3293  if (popConstPositivePowerOfTwo(&c, &power, 0)) {
   3294    if (power != 0) {
   3295      RegI32 r = popI32();
   3296      masm.rshift32(Imm32(power & 31), r);
   3297      pushI32(r);
   3298    }
   3299  } else {
   3300    bool isConst = peekConst(&c);
   3301    RegI32 r, rs, reserved;
   3302    popAndAllocateForDivAndRemI32(&r, &rs, &reserved);
   3303    quotientOrRemainder(rs, r, reserved, IsUnsigned(true),
   3304                        ZeroOnOverflow(false), isConst, c, QuotientI32);
   3305    maybeFree(reserved);
   3306    freeI32(rs);
   3307    pushI32(r);
   3308  }
   3309 }
   3310 
   3311 void BaseCompiler::emitRemainderI32() {
   3312  int32_t c;
   3313  uint_fast8_t power;
   3314  if (popConstPositivePowerOfTwo(&c, &power, 1)) {
   3315    RegI32 r = popI32();
   3316    RegI32 temp = needI32();
   3317    moveI32(r, temp);
   3318 
   3319    Label positive;
   3320    masm.branchTest32(Assembler::NotSigned, temp, temp, &positive);
   3321    masm.add32(Imm32(c - 1), temp);
   3322    masm.bind(&positive);
   3323 
   3324    masm.rshift32Arithmetic(Imm32(power & 31), temp);
   3325    masm.lshift32(Imm32(power & 31), temp);
   3326    masm.sub32(temp, r);
   3327    freeI32(temp);
   3328 
   3329    pushI32(r);
   3330  } else {
   3331    bool isConst = peekConst(&c);
   3332    RegI32 r, rs, reserved;
   3333    popAndAllocateForDivAndRemI32(&r, &rs, &reserved);
   3334    quotientOrRemainder(rs, r, reserved, IsUnsigned(false),
   3335                        ZeroOnOverflow(true), isConst, c, RemainderI32);
   3336    maybeFree(reserved);
   3337    freeI32(rs);
   3338    pushI32(r);
   3339  }
   3340 }
   3341 
   3342 void BaseCompiler::emitRemainderU32() {
   3343  int32_t c;
   3344  uint_fast8_t power;
   3345  if (popConstPositivePowerOfTwo(&c, &power, 1)) {
   3346    RegI32 r = popI32();
   3347    masm.and32(Imm32(c - 1), r);
   3348    pushI32(r);
   3349  } else {
   3350    bool isConst = peekConst(&c);
   3351    RegI32 r, rs, reserved;
   3352    popAndAllocateForDivAndRemI32(&r, &rs, &reserved);
   3353    quotientOrRemainder(rs, r, reserved, IsUnsigned(true), ZeroOnOverflow(true),
   3354                        isConst, c, RemainderI32);
   3355    maybeFree(reserved);
   3356    freeI32(rs);
   3357    pushI32(r);
   3358  }
   3359 }
   3360 
   3361 #ifndef RABALDR_INT_DIV_I64_CALLOUT
   3362 void BaseCompiler::emitQuotientI64() {
   3363  int64_t c;
   3364  uint_fast8_t power;
   3365  if (popConstPositivePowerOfTwo(&c, &power, 0)) {
   3366    if (power != 0) {
   3367      RegI64 r = popI64();
   3368      Label positive;
   3369      masm.branchTest64(Assembler::NotSigned, r, r, &positive);
   3370      masm.add64(Imm64(c - 1), r);
   3371      masm.bind(&positive);
   3372 
   3373      masm.rshift64Arithmetic(Imm32(power & 63), r);
   3374      pushI64(r);
   3375    }
   3376  } else {
   3377    bool isConst = peekConst(&c);
   3378    RegI64 r, rs, reserved;
   3379    popAndAllocateForDivAndRemI64(&r, &rs, &reserved, IsRemainder(false));
   3380    quotientOrRemainder(rs, r, reserved, IsUnsigned(false),
   3381                        ZeroOnOverflow(false), isConst, c, QuotientI64);
   3382    maybeFree(reserved);
   3383    freeI64(rs);
   3384    pushI64(r);
   3385  }
   3386 }
   3387 
   3388 void BaseCompiler::emitQuotientU64() {
   3389  int64_t c;
   3390  uint_fast8_t power;
   3391  if (popConstPositivePowerOfTwo(&c, &power, 0)) {
   3392    if (power != 0) {
   3393      RegI64 r = popI64();
   3394      masm.rshift64(Imm32(power & 63), r);
   3395      pushI64(r);
   3396    }
   3397  } else {
   3398    bool isConst = peekConst(&c);
   3399    RegI64 r, rs, reserved;
   3400    popAndAllocateForDivAndRemI64(&r, &rs, &reserved, IsRemainder(false));
   3401    quotientOrRemainder(rs, r, reserved, IsUnsigned(true),
   3402                        ZeroOnOverflow(false), isConst, c, QuotientI64);
   3403    maybeFree(reserved);
   3404    freeI64(rs);
   3405    pushI64(r);
   3406  }
   3407 }
   3408 
   3409 void BaseCompiler::emitRemainderI64() {
   3410  int64_t c;
   3411  uint_fast8_t power;
   3412  if (popConstPositivePowerOfTwo(&c, &power, 1)) {
   3413    RegI64 r = popI64();
   3414    RegI64 temp = needI64();
   3415    moveI64(r, temp);
   3416 
   3417    Label positive;
   3418    masm.branchTest64(Assembler::NotSigned, temp, temp, &positive);
   3419    masm.add64(Imm64(c - 1), temp);
   3420    masm.bind(&positive);
   3421 
   3422    masm.rshift64Arithmetic(Imm32(power & 63), temp);
   3423    masm.lshift64(Imm32(power & 63), temp);
   3424    masm.sub64(temp, r);
   3425    freeI64(temp);
   3426 
   3427    pushI64(r);
   3428  } else {
   3429    bool isConst = peekConst(&c);
   3430    RegI64 r, rs, reserved;
   3431    popAndAllocateForDivAndRemI64(&r, &rs, &reserved, IsRemainder(true));
   3432    quotientOrRemainder(rs, r, reserved, IsUnsigned(false),
   3433                        ZeroOnOverflow(true), isConst, c, RemainderI64);
   3434    maybeFree(reserved);
   3435    freeI64(rs);
   3436    pushI64(r);
   3437  }
   3438 }
   3439 
   3440 void BaseCompiler::emitRemainderU64() {
   3441  int64_t c;
   3442  uint_fast8_t power;
   3443  if (popConstPositivePowerOfTwo(&c, &power, 1)) {
   3444    RegI64 r = popI64();
   3445    masm.and64(Imm64(c - 1), r);
   3446    pushI64(r);
   3447  } else {
   3448    bool isConst = peekConst(&c);
   3449    RegI64 r, rs, reserved;
   3450    popAndAllocateForDivAndRemI64(&r, &rs, &reserved, IsRemainder(true));
   3451    quotientOrRemainder(rs, r, reserved, IsUnsigned(true), ZeroOnOverflow(true),
   3452                        isConst, c, RemainderI64);
   3453    maybeFree(reserved);
   3454    freeI64(rs);
   3455    pushI64(r);
   3456  }
   3457 }
   3458 #endif  // RABALDR_INT_DIV_I64_CALLOUT
   3459 
   3460 void BaseCompiler::emitRotrI64() {
   3461  int64_t c;
   3462  if (popConst(&c)) {
   3463    RegI64 r = popI64();
   3464    RegI32 temp = needRotate64Temp();
   3465    masm.rotateRight64(Imm32(c & 63), r, r, temp);
   3466    maybeFree(temp);
   3467    pushI64(r);
   3468  } else {
   3469    RegI64 rs = popI64RhsForRotate();
   3470    RegI64 r = popI64();
   3471    masm.rotateRight64(lowPart(rs), r, r, maybeHighPart(rs));
   3472    freeI64(rs);
   3473    pushI64(r);
   3474  }
   3475 }
   3476 
   3477 void BaseCompiler::emitRotlI64() {
   3478  int64_t c;
   3479  if (popConst(&c)) {
   3480    RegI64 r = popI64();
   3481    RegI32 temp = needRotate64Temp();
   3482    masm.rotateLeft64(Imm32(c & 63), r, r, temp);
   3483    maybeFree(temp);
   3484    pushI64(r);
   3485  } else {
   3486    RegI64 rs = popI64RhsForRotate();
   3487    RegI64 r = popI64();
   3488    masm.rotateLeft64(lowPart(rs), r, r, maybeHighPart(rs));
   3489    freeI64(rs);
   3490    pushI64(r);
   3491  }
   3492 }
   3493 
   3494 void BaseCompiler::emitEqzI32() {
   3495  if (sniffConditionalControlEqz(ValType::I32)) {
   3496    return;
   3497  }
   3498  emitUnop(EqzI32);
   3499 }
   3500 
   3501 void BaseCompiler::emitEqzI64() {
   3502  if (sniffConditionalControlEqz(ValType::I64)) {
   3503    return;
   3504  }
   3505  emitUnop(EqzI64);
   3506 }
   3507 
   3508 template <TruncFlags flags>
   3509 bool BaseCompiler::emitTruncateF32ToI32() {
   3510  RegF32 rs = popF32();
   3511  RegI32 rd = needI32();
   3512  if (!truncateF32ToI32(rs, rd, flags)) {
   3513    return false;
   3514  }
   3515  freeF32(rs);
   3516  pushI32(rd);
   3517  return true;
   3518 }
   3519 
   3520 template <TruncFlags flags>
   3521 bool BaseCompiler::emitTruncateF64ToI32() {
   3522  RegF64 rs = popF64();
   3523  RegI32 rd = needI32();
   3524  if (!truncateF64ToI32(rs, rd, flags)) {
   3525    return false;
   3526  }
   3527  freeF64(rs);
   3528  pushI32(rd);
   3529  return true;
   3530 }
   3531 
   3532 #ifndef RABALDR_FLOAT_TO_I64_CALLOUT
   3533 template <TruncFlags flags>
   3534 bool BaseCompiler::emitTruncateF32ToI64() {
   3535  RegF32 rs = popF32();
   3536  RegI64 rd = needI64();
   3537  RegF64 temp = needTempForFloatingToI64(flags);
   3538  if (!truncateF32ToI64(rs, rd, flags, temp)) {
   3539    return false;
   3540  }
   3541  maybeFree(temp);
   3542  freeF32(rs);
   3543  pushI64(rd);
   3544  return true;
   3545 }
   3546 
   3547 template <TruncFlags flags>
   3548 bool BaseCompiler::emitTruncateF64ToI64() {
   3549  RegF64 rs = popF64();
   3550  RegI64 rd = needI64();
   3551  RegF64 temp = needTempForFloatingToI64(flags);
   3552  if (!truncateF64ToI64(rs, rd, flags, temp)) {
   3553    return false;
   3554  }
   3555  maybeFree(temp);
   3556  freeF64(rs);
   3557  pushI64(rd);
   3558  return true;
   3559 }
   3560 #endif  // RABALDR_FLOAT_TO_I64_CALLOUT
   3561 
   3562 void BaseCompiler::emitExtendI64_8() {
   3563  RegI64 r;
   3564  popI64ForSignExtendI64(&r);
   3565  masm.move8To64SignExtend(lowPart(r), r);
   3566  pushI64(r);
   3567 }
   3568 
   3569 void BaseCompiler::emitExtendI64_16() {
   3570  RegI64 r;
   3571  popI64ForSignExtendI64(&r);
   3572  masm.move16To64SignExtend(lowPart(r), r);
   3573  pushI64(r);
   3574 }
   3575 
   3576 void BaseCompiler::emitExtendI64_32() {
   3577  RegI64 r;
   3578  popI64ForSignExtendI64(&r);
   3579  masm.move32To64SignExtend(lowPart(r), r);
   3580  pushI64(r);
   3581 }
   3582 
   3583 void BaseCompiler::emitExtendI32ToI64() {
   3584  RegI64 r;
   3585  popI32ForSignExtendI64(&r);
   3586  masm.move32To64SignExtend(lowPart(r), r);
   3587  pushI64(r);
   3588 }
   3589 
   3590 void BaseCompiler::emitExtendU32ToI64() {
   3591  RegI32 rs = popI32();
   3592  RegI64 rd = widenI32(rs);
   3593  masm.move32To64ZeroExtend(rs, rd);
   3594  pushI64(rd);
   3595 }
   3596 
   3597 #ifndef RABALDR_I64_TO_FLOAT_CALLOUT
   3598 void BaseCompiler::emitConvertU64ToF32() {
   3599  RegI64 rs = popI64();
   3600  RegF32 rd = needF32();
   3601  RegI32 temp = needConvertI64ToFloatTemp(ValType::F32, IsUnsigned(true));
   3602  convertI64ToF32(rs, IsUnsigned(true), rd, temp);
   3603  maybeFree(temp);
   3604  freeI64(rs);
   3605  pushF32(rd);
   3606 }
   3607 
   3608 void BaseCompiler::emitConvertU64ToF64() {
   3609  RegI64 rs = popI64();
   3610  RegF64 rd = needF64();
   3611  RegI32 temp = needConvertI64ToFloatTemp(ValType::F64, IsUnsigned(true));
   3612  convertI64ToF64(rs, IsUnsigned(true), rd, temp);
   3613  maybeFree(temp);
   3614  freeI64(rs);
   3615  pushF64(rd);
   3616 }
   3617 #endif  // RABALDR_I64_TO_FLOAT_CALLOUT
   3618 
   3619 ////////////////////////////////////////////////////////////
   3620 //
   3621 // Machinery for optimized conditional branches.
   3622 //
   3623 // To disable this optimization it is enough always to return false from
   3624 // sniffConditionalControl{Cmp,Eqz}.
   3625 
   3626 struct BranchState {
   3627  union {
   3628    struct {
   3629      RegI32 lhs;
   3630      RegI32 rhs;
   3631      int32_t imm;
   3632      bool rhsImm;
   3633    } i32;
   3634    struct {
   3635      RegI64 lhs;
   3636      RegI64 rhs;
   3637      int64_t imm;
   3638      bool rhsImm;
   3639    } i64;
   3640    struct {
   3641      RegF32 lhs;
   3642      RegF32 rhs;
   3643    } f32;
   3644    struct {
   3645      RegF64 lhs;
   3646      RegF64 rhs;
   3647    } f64;
   3648  };
   3649 
   3650  Label* const label;             // The target of the branch, never NULL
   3651  const StackHeight stackHeight;  // The stack base above which to place
   3652  // stack-spilled block results, if
   3653  // hasBlockResults().
   3654  const bool invertBranch;      // If true, invert the sense of the branch
   3655  const ResultType resultType;  // The result propagated along the edges
   3656 
   3657  explicit BranchState(Label* label)
   3658      : label(label),
   3659        stackHeight(StackHeight::Invalid()),
   3660        invertBranch(false),
   3661        resultType(ResultType::Empty()) {}
   3662 
   3663  BranchState(Label* label, bool invertBranch)
   3664      : label(label),
   3665        stackHeight(StackHeight::Invalid()),
   3666        invertBranch(invertBranch),
   3667        resultType(ResultType::Empty()) {}
   3668 
   3669  BranchState(Label* label, StackHeight stackHeight, bool invertBranch,
   3670              ResultType resultType)
   3671      : label(label),
   3672        stackHeight(stackHeight),
   3673        invertBranch(invertBranch),
   3674        resultType(resultType) {}
   3675 
   3676  bool hasBlockResults() const { return stackHeight.isValid(); }
   3677 };
   3678 
   3679 void BaseCompiler::setLatentCompare(Assembler::Condition compareOp,
   3680                                    ValType operandType) {
   3681  latentOp_ = LatentOp::Compare;
   3682  latentType_ = operandType;
   3683  latentIntCmp_ = compareOp;
   3684 }
   3685 
   3686 void BaseCompiler::setLatentCompare(Assembler::DoubleCondition compareOp,
   3687                                    ValType operandType) {
   3688  latentOp_ = LatentOp::Compare;
   3689  latentType_ = operandType;
   3690  latentDoubleCmp_ = compareOp;
   3691 }
   3692 
   3693 void BaseCompiler::setLatentEqz(ValType operandType) {
   3694  latentOp_ = LatentOp::Eqz;
   3695  latentType_ = operandType;
   3696 }
   3697 
   3698 bool BaseCompiler::hasLatentOp() const { return latentOp_ != LatentOp::None; }
   3699 
   3700 void BaseCompiler::resetLatentOp() { latentOp_ = LatentOp::None; }
   3701 
   3702 // Emit a conditional branch that optionally and optimally cleans up the CPU
   3703 // stack before we branch.
   3704 //
   3705 // Cond is either Assembler::Condition or Assembler::DoubleCondition.
   3706 //
   3707 // Lhs is RegI32, RegI64, or RegF32, RegF64, or RegRef.
   3708 //
   3709 // Rhs is either the same as Lhs, or an immediate expression compatible with
   3710 // Lhs "when applicable".
   3711 
   3712 template <typename Cond, typename Lhs, typename Rhs>
   3713 bool BaseCompiler::jumpConditionalWithResults(BranchState* b, Cond cond,
   3714                                              Lhs lhs, Rhs rhs) {
   3715  if (b->hasBlockResults()) {
   3716    StackHeight resultsBase(0);
   3717    if (!topBranchParams(b->resultType, &resultsBase)) {
   3718      return false;
   3719    }
   3720    if (b->stackHeight != resultsBase) {
   3721      Label notTaken;
   3722      branchTo(b->invertBranch ? cond : Assembler::InvertCondition(cond), lhs,
   3723               rhs, &notTaken);
   3724 
   3725      // Shuffle stack args.
   3726      shuffleStackResultsBeforeBranch(resultsBase, b->stackHeight,
   3727                                      b->resultType);
   3728      masm.jump(b->label);
   3729      masm.bind(&notTaken);
   3730      return true;
   3731    }
   3732  }
   3733 
   3734  branchTo(b->invertBranch ? Assembler::InvertCondition(cond) : cond, lhs, rhs,
   3735           b->label);
   3736  return true;
   3737 }
   3738 
   3739 bool BaseCompiler::jumpConditionalWithResults(BranchState* b, RegRef object,
   3740                                              MaybeRefType sourceType,
   3741                                              RefType destType,
   3742                                              bool onSuccess) {
   3743  // Temporarily take the result registers so that branchIfRefSubtype
   3744  // doesn't use them.
   3745  needIntegerResultRegisters(b->resultType);
   3746  BranchIfRefSubtypeRegisters regs =
   3747      allocRegistersForBranchIfRefSubtype(destType);
   3748  freeIntegerResultRegisters(b->resultType);
   3749 
   3750  if (b->hasBlockResults()) {
   3751    StackHeight resultsBase(0);
   3752    if (!topBranchParams(b->resultType, &resultsBase)) {
   3753      return false;
   3754    }
   3755    if (b->stackHeight != resultsBase) {
   3756      Label notTaken;
   3757 
   3758      masm.branchWasmRefIsSubtype(
   3759          object, sourceType, destType, &notTaken,
   3760          /*onSuccess=*/b->invertBranch ? onSuccess : !onSuccess,
   3761          /*signalNullChecks=*/false, regs.superSTV, regs.scratch1,
   3762          regs.scratch2);
   3763      freeRegistersForBranchIfRefSubtype(regs);
   3764 
   3765      // Shuffle stack args.
   3766      shuffleStackResultsBeforeBranch(resultsBase, b->stackHeight,
   3767                                      b->resultType);
   3768      masm.jump(b->label);
   3769      masm.bind(&notTaken);
   3770      return true;
   3771    }
   3772  }
   3773 
   3774  masm.branchWasmRefIsSubtype(
   3775      object, sourceType, destType, b->label,
   3776      /*onSuccess=*/b->invertBranch ? !onSuccess : onSuccess,
   3777      /*signalNullChecks=*/false, regs.superSTV, regs.scratch1, regs.scratch2);
   3778  freeRegistersForBranchIfRefSubtype(regs);
   3779  return true;
   3780 }
   3781 
   3782 // sniffConditionalControl{Cmp,Eqz} may modify the latentWhatever_ state in
   3783 // the BaseCompiler so that a subsequent conditional branch can be compiled
   3784 // optimally.  emitBranchSetup() and emitBranchPerform() will consume that
   3785 // state.  If the latter methods are not called because deadCode_ is true
   3786 // then the compiler MUST instead call resetLatentOp() to reset the state.
   3787 
   3788 template <typename Cond>
   3789 bool BaseCompiler::sniffConditionalControlCmp(Cond compareOp,
   3790                                              ValType operandType) {
   3791  MOZ_ASSERT(latentOp_ == LatentOp::None,
   3792             "Latent comparison state not properly reset");
   3793 
   3794 #ifdef JS_CODEGEN_X86
   3795  // On x86, latent i64 binary comparisons use too many registers: the
   3796  // reserved join register and the lhs and rhs operands require six, but we
   3797  // only have five.
   3798  if (operandType == ValType::I64) {
   3799    return false;
   3800  }
   3801 #endif
   3802 
   3803  // No optimization for pointer compares yet.
   3804  if (operandType.isRefRepr()) {
   3805    return false;
   3806  }
   3807 
   3808  OpBytes op{};
   3809  iter_.peekOp(&op);
   3810  switch (op.b0) {
   3811    case uint16_t(Op::BrIf):
   3812    case uint16_t(Op::If):
   3813    case uint16_t(Op::SelectNumeric):
   3814    case uint16_t(Op::SelectTyped):
   3815      setLatentCompare(compareOp, operandType);
   3816      return true;
   3817    default:
   3818      return false;
   3819  }
   3820 }
   3821 
   3822 bool BaseCompiler::sniffConditionalControlEqz(ValType operandType) {
   3823  MOZ_ASSERT(latentOp_ == LatentOp::None,
   3824             "Latent comparison state not properly reset");
   3825 
   3826  OpBytes op{};
   3827  iter_.peekOp(&op);
   3828  switch (op.b0) {
   3829    case uint16_t(Op::BrIf):
   3830    case uint16_t(Op::SelectNumeric):
   3831    case uint16_t(Op::SelectTyped):
   3832    case uint16_t(Op::If):
   3833      setLatentEqz(operandType);
   3834      return true;
   3835    default:
   3836      return false;
   3837  }
   3838 }
   3839 
   3840 void BaseCompiler::emitBranchSetup(BranchState* b) {
   3841  // Avoid allocating operands to latentOp_ to result registers.
   3842  if (b->hasBlockResults()) {
   3843    needResultRegisters(b->resultType);
   3844  }
   3845 
   3846  // Set up fields so that emitBranchPerform() need not switch on latentOp_.
   3847  switch (latentOp_) {
   3848    case LatentOp::None: {
   3849      latentIntCmp_ = Assembler::NotEqual;
   3850      latentType_ = ValType::I32;
   3851      b->i32.lhs = popI32();
   3852      b->i32.rhsImm = true;
   3853      b->i32.imm = 0;
   3854      break;
   3855    }
   3856    case LatentOp::Compare: {
   3857      switch (latentType_.kind()) {
   3858        case ValType::I32: {
   3859          if (popConst(&b->i32.imm)) {
   3860            b->i32.lhs = popI32();
   3861            b->i32.rhsImm = true;
   3862          } else {
   3863            pop2xI32(&b->i32.lhs, &b->i32.rhs);
   3864            b->i32.rhsImm = false;
   3865          }
   3866          break;
   3867        }
   3868        case ValType::I64: {
   3869          pop2xI64(&b->i64.lhs, &b->i64.rhs);
   3870          b->i64.rhsImm = false;
   3871          break;
   3872        }
   3873        case ValType::F32: {
   3874          pop2xF32(&b->f32.lhs, &b->f32.rhs);
   3875          break;
   3876        }
   3877        case ValType::F64: {
   3878          pop2xF64(&b->f64.lhs, &b->f64.rhs);
   3879          break;
   3880        }
   3881        default: {
   3882          MOZ_CRASH("Unexpected type for LatentOp::Compare");
   3883        }
   3884      }
   3885      break;
   3886    }
   3887    case LatentOp::Eqz: {
   3888      switch (latentType_.kind()) {
   3889        case ValType::I32: {
   3890          latentIntCmp_ = Assembler::Equal;
   3891          b->i32.lhs = popI32();
   3892          b->i32.rhsImm = true;
   3893          b->i32.imm = 0;
   3894          break;
   3895        }
   3896        case ValType::I64: {
   3897          latentIntCmp_ = Assembler::Equal;
   3898          b->i64.lhs = popI64();
   3899          b->i64.rhsImm = true;
   3900          b->i64.imm = 0;
   3901          break;
   3902        }
   3903        default: {
   3904          MOZ_CRASH("Unexpected type for LatentOp::Eqz");
   3905        }
   3906      }
   3907      break;
   3908    }
   3909  }
   3910 
   3911  if (b->hasBlockResults()) {
   3912    freeResultRegisters(b->resultType);
   3913  }
   3914 }
   3915 
   3916 bool BaseCompiler::emitBranchPerform(BranchState* b) {
   3917  switch (latentType_.kind()) {
   3918    case ValType::I32: {
   3919      if (b->i32.rhsImm) {
   3920        if (!jumpConditionalWithResults(b, latentIntCmp_, b->i32.lhs,
   3921                                        Imm32(b->i32.imm))) {
   3922          return false;
   3923        }
   3924      } else {
   3925        if (!jumpConditionalWithResults(b, latentIntCmp_, b->i32.lhs,
   3926                                        b->i32.rhs)) {
   3927          return false;
   3928        }
   3929        freeI32(b->i32.rhs);
   3930      }
   3931      freeI32(b->i32.lhs);
   3932      break;
   3933    }
   3934    case ValType::I64: {
   3935      if (b->i64.rhsImm) {
   3936        if (!jumpConditionalWithResults(b, latentIntCmp_, b->i64.lhs,
   3937                                        Imm64(b->i64.imm))) {
   3938          return false;
   3939        }
   3940      } else {
   3941        if (!jumpConditionalWithResults(b, latentIntCmp_, b->i64.lhs,
   3942                                        b->i64.rhs)) {
   3943          return false;
   3944        }
   3945        freeI64(b->i64.rhs);
   3946      }
   3947      freeI64(b->i64.lhs);
   3948      break;
   3949    }
   3950    case ValType::F32: {
   3951      if (!jumpConditionalWithResults(b, latentDoubleCmp_, b->f32.lhs,
   3952                                      b->f32.rhs)) {
   3953        return false;
   3954      }
   3955      freeF32(b->f32.lhs);
   3956      freeF32(b->f32.rhs);
   3957      break;
   3958    }
   3959    case ValType::F64: {
   3960      if (!jumpConditionalWithResults(b, latentDoubleCmp_, b->f64.lhs,
   3961                                      b->f64.rhs)) {
   3962        return false;
   3963      }
   3964      freeF64(b->f64.lhs);
   3965      freeF64(b->f64.rhs);
   3966      break;
   3967    }
   3968    default: {
   3969      MOZ_CRASH("Unexpected type for LatentOp::Compare");
   3970    }
   3971  }
   3972  resetLatentOp();
   3973  return true;
   3974 }
   3975 
   3976 // For blocks and loops and ifs:
   3977 //
   3978 //  - Sync the value stack before going into the block in order to simplify exit
   3979 //    from the block: all exits from the block can assume that there are no
   3980 //    live registers except the one carrying the exit value.
   3981 //  - The block can accumulate a number of dead values on the stacks, so when
   3982 //    branching out of the block or falling out at the end be sure to
   3983 //    pop the appropriate stacks back to where they were on entry, while
   3984 //    preserving the exit value.
   3985 //  - A continue branch in a loop is much like an exit branch, but the branch
   3986 //    value must not be preserved.
   3987 //  - The exit value is always in a designated join register (type dependent).
   3988 
   3989 bool BaseCompiler::emitBlock() {
   3990  BlockType type;
   3991  if (!iter_.readBlock(&type)) {
   3992    return false;
   3993  }
   3994 
   3995  if (!deadCode_) {
   3996    sync();  // Simplifies branching out from block
   3997  }
   3998 
   3999  initControl(controlItem(), type.params());
   4000 
   4001  return true;
   4002 }
   4003 
   4004 bool BaseCompiler::endBlock(ResultType type) {
   4005  Control& block = controlItem();
   4006 
   4007  if (deadCode_) {
   4008    // Block does not fall through; reset stack.
   4009    fr.resetStackHeight(block.stackHeight, type);
   4010    popValueStackTo(block.stackSize);
   4011  } else {
   4012    // If the block label is used, we have a control join, so we need to shuffle
   4013    // fallthrough values into place.  Otherwise if it's not a control join, we
   4014    // can leave the value stack alone.
   4015    MOZ_ASSERT(stk_.length() == block.stackSize + type.length());
   4016    if (block.label.used()) {
   4017      popBlockResults(type, block.stackHeight, ContinuationKind::Fallthrough);
   4018    }
   4019    block.bceSafeOnExit &= bceSafe_;
   4020  }
   4021 
   4022  // Bind after cleanup: branches out will have popped the stack.
   4023  if (block.label.used()) {
   4024    masm.bind(&block.label);
   4025    if (deadCode_) {
   4026      captureResultRegisters(type);
   4027      deadCode_ = false;
   4028    }
   4029    if (!pushBlockResults(type)) {
   4030      return false;
   4031    }
   4032  }
   4033 
   4034  bceSafe_ = block.bceSafeOnExit;
   4035 
   4036  return true;
   4037 }
   4038 
   4039 bool BaseCompiler::emitLoop() {
   4040  BlockType type;
   4041  if (!iter_.readLoop(&type)) {
   4042    return false;
   4043  }
   4044 
   4045  if (!deadCode_) {
   4046    sync();  // Simplifies branching out from block
   4047  }
   4048 
   4049  initControl(controlItem(), type.params());
   4050  bceSafe_ = 0;
   4051 
   4052  if (!deadCode_) {
   4053    // Loop entry is a control join, so shuffle the entry parameters into the
   4054    // well-known locations.
   4055    if (!topBlockParams(type.params())) {
   4056      return false;
   4057    }
   4058    masm.nopAlign(CodeAlignment);
   4059    masm.bind(&controlItem(0).label);
   4060 
   4061    // The interrupt check barfs if there are live registers. The hotness check
   4062    // also can call the request tier-up stub, which assumes that no registers
   4063    // are live.
   4064    sync();
   4065 
   4066    if (!addInterruptCheck()) {
   4067      return false;
   4068    }
   4069 
   4070    if (compilerEnv_.mode() == CompileMode::LazyTiering) {
   4071      // Create an unpatched hotness check and stash enough information that we
   4072      // can patch it with a value related to the loop's size when we get to
   4073      // the corresponding `end` opcode.
   4074      Maybe<CodeOffset> ctrDecOffset = addHotnessCheck();
   4075      if (ctrDecOffset.isNothing()) {
   4076        return false;
   4077      }
   4078      controlItem().loopBytecodeStart = iter_.lastOpcodeOffset();
   4079      controlItem().offsetOfCtrDec = ctrDecOffset.value();
   4080    }
   4081  }
   4082 
   4083  return true;
   4084 }
   4085 
   4086 // The bodies of the "then" and "else" arms can be arbitrary sequences
   4087 // of expressions, they push control and increment the nesting and can
   4088 // even be targeted by jumps.  A branch to the "if" block branches to
   4089 // the exit of the if, ie, it's like "break".  Consider:
   4090 //
   4091 //      (func (result i32)
   4092 //       (if (i32.const 1)
   4093 //           (begin (br 1) (unreachable))
   4094 //           (begin (unreachable)))
   4095 //       (i32.const 1))
   4096 //
   4097 // The branch causes neither of the unreachable expressions to be
   4098 // evaluated.
   4099 
   4100 bool BaseCompiler::emitIf() {
   4101  BlockType type;
   4102  Nothing unused_cond;
   4103  if (!iter_.readIf(&type, &unused_cond)) {
   4104    return false;
   4105  }
   4106 
   4107  BranchState b(&controlItem().otherLabel, InvertBranch(true));
   4108  if (!deadCode_) {
   4109    needResultRegisters(type.params());
   4110    emitBranchSetup(&b);
   4111    freeResultRegisters(type.params());
   4112    sync();
   4113  } else {
   4114    resetLatentOp();
   4115  }
   4116 
   4117  initControl(controlItem(), type.params());
   4118 
   4119  if (!deadCode_) {
   4120    // Because params can flow immediately to results in the case of an empty
   4121    // "then" or "else" block, and the result of an if/then is a join in
   4122    // general, we shuffle params eagerly to the result allocations.
   4123    if (!topBlockParams(type.params())) {
   4124      return false;
   4125    }
   4126    if (!emitBranchPerform(&b)) {
   4127      return false;
   4128    }
   4129  }
   4130 
   4131  return true;
   4132 }
   4133 
   4134 bool BaseCompiler::endIfThen(ResultType type) {
   4135  Control& ifThen = controlItem();
   4136 
   4137  // The parameters to the "if" logically flow to both the "then" and "else"
   4138  // blocks, but the "else" block is empty.  Since we know that the "if"
   4139  // type-checks, that means that the "else" parameters are the "else" results,
   4140  // and that the "if"'s result type is the same as its parameter type.
   4141 
   4142  if (deadCode_) {
   4143    // "then" arm does not fall through; reset stack.
   4144    fr.resetStackHeight(ifThen.stackHeight, type);
   4145    popValueStackTo(ifThen.stackSize);
   4146    if (!ifThen.deadOnArrival) {
   4147      captureResultRegisters(type);
   4148    }
   4149  } else {
   4150    MOZ_ASSERT(stk_.length() == ifThen.stackSize + type.length());
   4151    // Assume we have a control join, so place results in block result
   4152    // allocations.
   4153    popBlockResults(type, ifThen.stackHeight, ContinuationKind::Fallthrough);
   4154    MOZ_ASSERT(!ifThen.deadOnArrival);
   4155  }
   4156 
   4157  if (ifThen.otherLabel.used()) {
   4158    masm.bind(&ifThen.otherLabel);
   4159  }
   4160 
   4161  if (ifThen.label.used()) {
   4162    masm.bind(&ifThen.label);
   4163  }
   4164 
   4165  if (!deadCode_) {
   4166    ifThen.bceSafeOnExit &= bceSafe_;
   4167  }
   4168 
   4169  deadCode_ = ifThen.deadOnArrival;
   4170  if (!deadCode_) {
   4171    if (!pushBlockResults(type)) {
   4172      return false;
   4173    }
   4174  }
   4175 
   4176  bceSafe_ = ifThen.bceSafeOnExit & ifThen.bceSafeOnEntry;
   4177 
   4178  return true;
   4179 }
   4180 
   4181 bool BaseCompiler::emitElse() {
   4182  ResultType params, results;
   4183  BaseNothingVector unused_thenValues{};
   4184 
   4185  if (!iter_.readElse(&params, &results, &unused_thenValues)) {
   4186    return false;
   4187  }
   4188 
   4189  Control& ifThenElse = controlItem(0);
   4190 
   4191  // See comment in endIfThenElse, below.
   4192 
   4193  // Exit the "then" branch.
   4194 
   4195  ifThenElse.deadThenBranch = deadCode_;
   4196 
   4197  if (deadCode_) {
   4198    fr.resetStackHeight(ifThenElse.stackHeight, results);
   4199    popValueStackTo(ifThenElse.stackSize);
   4200  } else {
   4201    MOZ_ASSERT(stk_.length() == ifThenElse.stackSize + results.length());
   4202    popBlockResults(results, ifThenElse.stackHeight, ContinuationKind::Jump);
   4203    freeResultRegisters(results);
   4204    MOZ_ASSERT(!ifThenElse.deadOnArrival);
   4205  }
   4206 
   4207  if (!deadCode_) {
   4208    masm.jump(&ifThenElse.label);
   4209  }
   4210 
   4211  if (ifThenElse.otherLabel.used()) {
   4212    masm.bind(&ifThenElse.otherLabel);
   4213  }
   4214 
   4215  // Reset to the "else" branch.
   4216 
   4217  if (!deadCode_) {
   4218    ifThenElse.bceSafeOnExit &= bceSafe_;
   4219  }
   4220 
   4221  deadCode_ = ifThenElse.deadOnArrival;
   4222  bceSafe_ = ifThenElse.bceSafeOnEntry;
   4223 
   4224  fr.resetStackHeight(ifThenElse.stackHeight, params);
   4225 
   4226  if (!deadCode_) {
   4227    captureResultRegisters(params);
   4228    if (!pushBlockResults(params)) {
   4229      return false;
   4230    }
   4231  }
   4232 
   4233  return true;
   4234 }
   4235 
   4236 bool BaseCompiler::endIfThenElse(ResultType type) {
   4237  Control& ifThenElse = controlItem();
   4238 
   4239  // The expression type is not a reliable guide to what we'll find
   4240  // on the stack, we could have (if E (i32.const 1) (unreachable))
   4241  // in which case the "else" arm is AnyType but the type of the
   4242  // full expression is I32.  So restore whatever's there, not what
   4243  // we want to find there.  The "then" arm has the same constraint.
   4244 
   4245  if (deadCode_) {
   4246    // "then" arm does not fall through; reset stack.
   4247    fr.resetStackHeight(ifThenElse.stackHeight, type);
   4248    popValueStackTo(ifThenElse.stackSize);
   4249  } else {
   4250    MOZ_ASSERT(stk_.length() == ifThenElse.stackSize + type.length());
   4251    // Assume we have a control join, so place results in block result
   4252    // allocations.
   4253    popBlockResults(type, ifThenElse.stackHeight,
   4254                    ContinuationKind::Fallthrough);
   4255    ifThenElse.bceSafeOnExit &= bceSafe_;
   4256    MOZ_ASSERT(!ifThenElse.deadOnArrival);
   4257  }
   4258 
   4259  if (ifThenElse.label.used()) {
   4260    masm.bind(&ifThenElse.label);
   4261  }
   4262 
   4263  bool joinLive =
   4264      !ifThenElse.deadOnArrival &&
   4265      (!ifThenElse.deadThenBranch || !deadCode_ || ifThenElse.label.bound());
   4266 
   4267  if (joinLive) {
   4268    // No values were provided by the "then" path, but capture the values
   4269    // provided by the "else" path.
   4270    if (deadCode_) {
   4271      captureResultRegisters(type);
   4272    }
   4273    deadCode_ = false;
   4274  }
   4275 
   4276  bceSafe_ = ifThenElse.bceSafeOnExit;
   4277 
   4278  if (!deadCode_) {
   4279    if (!pushBlockResults(type)) {
   4280      return false;
   4281    }
   4282  }
   4283 
   4284  return true;
   4285 }
   4286 
   4287 bool BaseCompiler::emitEnd() {
   4288  LabelKind kind;
   4289  ResultType type;
   4290  BaseNothingVector unused_values{};
   4291  if (!iter_.readEnd(&kind, &type, &unused_values, &unused_values)) {
   4292    return false;
   4293  }
   4294 
   4295  // Every label case is responsible to pop the control item at the appropriate
   4296  // time for the label case
   4297  switch (kind) {
   4298    case LabelKind::Body: {
   4299      if (!endBlock(type)) {
   4300        return false;
   4301      }
   4302      doReturn(ContinuationKind::Fallthrough);
   4303      iter_.popEnd();
   4304      MOZ_ASSERT(iter_.controlStackEmpty());
   4305      return iter_.endFunction(iter_.end());
   4306    }
   4307    case LabelKind::Block:
   4308      if (!endBlock(type)) {
   4309        return false;
   4310      }
   4311      iter_.popEnd();
   4312      break;
   4313    case LabelKind::Loop: {
   4314      if (compilerEnv_.mode() == CompileMode::LazyTiering) {
   4315        // These are set (or not set) together.
   4316        MOZ_ASSERT((controlItem().loopBytecodeStart != UINTPTR_MAX) ==
   4317                   (controlItem().offsetOfCtrDec.bound()));
   4318        if (controlItem().loopBytecodeStart != UINTPTR_MAX) {
   4319          // If the above condition is false, the loop was in dead code and so
   4320          // there is no loop-head hotness check that needs to be patched.  See
   4321          // ::emitLoop.
   4322          MOZ_ASSERT(controlItem().loopBytecodeStart <=
   4323                     iter_.lastOpcodeOffset());
   4324          size_t loopBytecodeSize =
   4325              iter_.lastOpcodeOffset() - controlItem().loopBytecodeStart;
   4326          uint32_t step = BlockSizeToDownwardsStep(loopBytecodeSize);
   4327          // Don't try to patch the check if we've OOM'd, since the check might
   4328          // not actually exist.
   4329          if (masm.oom()) {
   4330            return false;
   4331          }
   4332          patchHotnessCheck(controlItem().offsetOfCtrDec, step);
   4333        }
   4334      }
   4335      // The end of a loop isn't a branch target, so we can just leave its
   4336      // results on the expression stack to be consumed by the outer block.
   4337      iter_.popEnd();
   4338      break;
   4339    }
   4340    case LabelKind::Then:
   4341      if (!endIfThen(type)) {
   4342        return false;
   4343      }
   4344      iter_.popEnd();
   4345      break;
   4346    case LabelKind::Else:
   4347      if (!endIfThenElse(type)) {
   4348        return false;
   4349      }
   4350      iter_.popEnd();
   4351      break;
   4352    case LabelKind::Try:
   4353    case LabelKind::Catch:
   4354    case LabelKind::CatchAll:
   4355      if (!endTryCatch(type)) {
   4356        return false;
   4357      }
   4358      iter_.popEnd();
   4359      break;
   4360    case LabelKind::TryTable:
   4361      if (!endTryTable(type)) {
   4362        return false;
   4363      }
   4364      iter_.popEnd();
   4365      break;
   4366  }
   4367 
   4368  return true;
   4369 }
   4370 
   4371 bool BaseCompiler::emitBr() {
   4372  uint32_t relativeDepth;
   4373  ResultType type;
   4374  BaseNothingVector unused_values{};
   4375  if (!iter_.readBr(&relativeDepth, &type, &unused_values)) {
   4376    return false;
   4377  }
   4378 
   4379  if (deadCode_) {
   4380    return true;
   4381  }
   4382 
   4383  Control& target = controlItem(relativeDepth);
   4384  target.bceSafeOnExit &= bceSafe_;
   4385 
   4386  // Save any values in the designated join registers, as if the target block
   4387  // returned normally.
   4388 
   4389  popBlockResults(type, target.stackHeight, ContinuationKind::Jump);
   4390  masm.jump(&target.label);
   4391 
   4392  // The registers holding the join values are free for the remainder of this
   4393  // block.
   4394 
   4395  freeResultRegisters(type);
   4396 
   4397  deadCode_ = true;
   4398 
   4399  return true;
   4400 }
   4401 
   4402 bool BaseCompiler::emitBrIf() {
   4403  uint32_t relativeDepth;
   4404  ResultType type;
   4405  BaseNothingVector unused_values{};
   4406  Nothing unused_condition;
   4407  if (!iter_.readBrIf(&relativeDepth, &type, &unused_values,
   4408                      &unused_condition)) {
   4409    return false;
   4410  }
   4411 
   4412  if (deadCode_) {
   4413    resetLatentOp();
   4414    return true;
   4415  }
   4416 
   4417  Control& target = controlItem(relativeDepth);
   4418  target.bceSafeOnExit &= bceSafe_;
   4419 
   4420  BranchState b(&target.label, target.stackHeight, InvertBranch(false), type);
   4421  emitBranchSetup(&b);
   4422  return emitBranchPerform(&b);
   4423 }
   4424 
   4425 bool BaseCompiler::emitBrOnNull() {
   4426  MOZ_ASSERT(!hasLatentOp());
   4427 
   4428  uint32_t relativeDepth;
   4429  ResultType type;
   4430  BaseNothingVector unused_values{};
   4431  Nothing unused_condition;
   4432  if (!iter_.readBrOnNull(&relativeDepth, &type, &unused_values,
   4433                          &unused_condition)) {
   4434    return false;
   4435  }
   4436 
   4437  if (deadCode_) {
   4438    return true;
   4439  }
   4440 
   4441  Control& target = controlItem(relativeDepth);
   4442  target.bceSafeOnExit &= bceSafe_;
   4443 
   4444  BranchState b(&target.label, target.stackHeight, InvertBranch(false), type);
   4445  if (b.hasBlockResults()) {
   4446    needResultRegisters(b.resultType);
   4447  }
   4448  RegRef ref = popRef();
   4449  if (b.hasBlockResults()) {
   4450    freeResultRegisters(b.resultType);
   4451  }
   4452  if (!jumpConditionalWithResults(&b, Assembler::Equal, ref,
   4453                                  ImmWord(AnyRef::NullRefValue))) {
   4454    return false;
   4455  }
   4456  pushRef(ref);
   4457 
   4458  return true;
   4459 }
   4460 
   4461 bool BaseCompiler::emitBrOnNonNull() {
   4462  MOZ_ASSERT(!hasLatentOp());
   4463 
   4464  uint32_t relativeDepth;
   4465  ResultType type;
   4466  BaseNothingVector unused_values{};
   4467  Nothing unused_condition;
   4468  if (!iter_.readBrOnNonNull(&relativeDepth, &type, &unused_values,
   4469                             &unused_condition)) {
   4470    return false;
   4471  }
   4472 
   4473  if (deadCode_) {
   4474    return true;
   4475  }
   4476 
   4477  Control& target = controlItem(relativeDepth);
   4478  target.bceSafeOnExit &= bceSafe_;
   4479 
   4480  BranchState b(&target.label, target.stackHeight, InvertBranch(false), type);
   4481  MOZ_ASSERT(b.hasBlockResults(), "br_on_non_null has block results");
   4482 
   4483  // Don't allocate the result register used in the branch
   4484  needIntegerResultRegisters(b.resultType);
   4485 
   4486  // Get the ref from the top of the stack
   4487  RegRef refCondition = popRef();
   4488 
   4489  // Create a copy of the ref for passing to the on_non_null label,
   4490  // the original ref is used in the condition.
   4491  RegRef ref = needRef();
   4492  moveRef(refCondition, ref);
   4493  pushRef(ref);
   4494 
   4495  freeIntegerResultRegisters(b.resultType);
   4496 
   4497  if (!jumpConditionalWithResults(&b, Assembler::NotEqual, refCondition,
   4498                                  ImmWord(AnyRef::NullRefValue))) {
   4499    return false;
   4500  }
   4501 
   4502  freeRef(refCondition);
   4503 
   4504  // Dropping null reference.
   4505  dropValue();
   4506 
   4507  return true;
   4508 }
   4509 
   4510 bool BaseCompiler::emitBrTable() {
   4511  Uint32Vector depths;
   4512  uint32_t defaultDepth;
   4513  ResultType branchParams;
   4514  BaseNothingVector unused_values{};
   4515  Nothing unused_index;
   4516  // N.B., `branchParams' gets set to the type of the default branch target.  In
   4517  // the presence of subtyping, it could be that the different branch targets
   4518  // have different types.  Here we rely on the assumption that the value
   4519  // representations (e.g. Stk value types) of all branch target types are the
   4520  // same, in the baseline compiler.  Notably, this means that all Ref types
   4521  // should be represented the same.
   4522  if (!iter_.readBrTable(&depths, &defaultDepth, &branchParams, &unused_values,
   4523                         &unused_index)) {
   4524    return false;
   4525  }
   4526 
   4527  if (deadCode_) {
   4528    return true;
   4529  }
   4530 
   4531  // Don't use param registers for rc
   4532  needIntegerResultRegisters(branchParams);
   4533 
   4534  // Table switch value always on top.
   4535  RegI32 rc = popI32();
   4536 
   4537  freeIntegerResultRegisters(branchParams);
   4538 
   4539  StackHeight resultsBase(0);
   4540  if (!topBranchParams(branchParams, &resultsBase)) {
   4541    return false;
   4542  }
   4543 
   4544  Label dispatchCode;
   4545  masm.branch32(Assembler::Below, rc, Imm32(depths.length()), &dispatchCode);
   4546 
   4547  // This is the out-of-range stub.  rc is dead here but we don't need it.
   4548 
   4549  shuffleStackResultsBeforeBranch(
   4550      resultsBase, controlItem(defaultDepth).stackHeight, branchParams);
   4551  controlItem(defaultDepth).bceSafeOnExit &= bceSafe_;
   4552  masm.jump(&controlItem(defaultDepth).label);
   4553 
   4554  // Emit stubs.  rc is dead in all of these but we don't need it.
   4555  //
   4556  // The labels in the vector are in the TempAllocator and will
   4557  // be freed by and by.
   4558  //
   4559  // TODO / OPTIMIZE (Bug 1316804): Branch directly to the case code if we
   4560  // can, don't emit an intermediate stub.
   4561 
   4562  LabelVector stubs;
   4563  if (!stubs.reserve(depths.length())) {
   4564    return false;
   4565  }
   4566 
   4567  for (uint32_t depth : depths) {
   4568    stubs.infallibleEmplaceBack(NonAssertingLabel());
   4569    masm.bind(&stubs.back());
   4570    shuffleStackResultsBeforeBranch(resultsBase, controlItem(depth).stackHeight,
   4571                                    branchParams);
   4572    controlItem(depth).bceSafeOnExit &= bceSafe_;
   4573    masm.jump(&controlItem(depth).label);
   4574  }
   4575 
   4576  // Emit table.
   4577 
   4578  Label theTable;
   4579  jumpTable(stubs, &theTable);
   4580 
   4581  // Emit indirect jump.  rc is live here.
   4582 
   4583  tableSwitch(&theTable, rc, &dispatchCode);
   4584 
   4585  deadCode_ = true;
   4586 
   4587  // Clean up.
   4588 
   4589  freeI32(rc);
   4590  popValueStackBy(branchParams.length());
   4591 
   4592  return true;
   4593 }
   4594 
   4595 bool BaseCompiler::emitTry() {
   4596  BlockType type;
   4597  if (!iter_.readTry(&type)) {
   4598    return false;
   4599  }
   4600 
   4601  if (!deadCode_) {
   4602    // Simplifies jumping out, but it is also necessary so that control
   4603    // can re-enter the catch handler without restoring registers.
   4604    sync();
   4605  }
   4606 
   4607  initControl(controlItem(), type.params());
   4608 
   4609  if (!deadCode_) {
   4610    // Be conservative for BCE due to complex control flow in try blocks.
   4611    controlItem().bceSafeOnExit = 0;
   4612    if (!startTryNote(&controlItem().tryNoteIndex)) {
   4613      return false;
   4614    }
   4615  }
   4616 
   4617  return true;
   4618 }
   4619 
   4620 bool BaseCompiler::emitTryTable() {
   4621  BlockType type;
   4622  TryTableCatchVector catches;
   4623  if (!iter_.readTryTable(&type, &catches)) {
   4624    return false;
   4625  }
   4626 
   4627  if (!deadCode_) {
   4628    // Simplifies jumping out, but it is also necessary so that control
   4629    // can re-enter the catch handler without restoring registers.
   4630    sync();
   4631  }
   4632 
   4633  initControl(controlItem(), type.params());
   4634  // Be conservative for BCE due to complex control flow in try blocks.
   4635  controlItem().bceSafeOnExit = 0;
   4636 
   4637  // Don't emit a landing pad if this whole try is dead code
   4638  if (deadCode_) {
   4639    return true;
   4640  }
   4641 
   4642  // Emit a landing pad that exceptions will jump into. Jump over it for now.
   4643  Label skipLandingPad;
   4644  masm.jump(&skipLandingPad);
   4645 
   4646  StackHeight prePadHeight = fr.stackHeight();
   4647  uint32_t padOffset = masm.currentOffset();
   4648  uint32_t padStackHeight = masm.framePushed();
   4649 
   4650  // InstanceReg is live and contains this function's instance by the exception
   4651  // handling resume method. We keep it alive for use in loading the tag for
   4652  // each catch handler.
   4653  RegPtr instance = RegPtr(InstanceReg);
   4654 #ifndef RABALDR_PIN_INSTANCE
   4655  needPtr(instance);
   4656 #endif
   4657 
   4658  // Load exception and tag from instance, clearing it in the process.
   4659  RegRef exn;
   4660  RegRef exnTag;
   4661  consumePendingException(instance, &exn, &exnTag);
   4662 
   4663  // Get a register to hold the tags for each catch
   4664  RegRef catchTag = needRef();
   4665 
   4666  bool hadCatchAll = false;
   4667  for (const TryTableCatch& tryTableCatch : catches) {
   4668    ResultType labelParams = ResultType::Vector(tryTableCatch.labelType);
   4669 
   4670    Control& target = controlItem(tryTableCatch.labelRelativeDepth);
   4671    target.bceSafeOnExit = 0;
   4672 
   4673    // Handle a catch_all by jumping to the target block
   4674    if (tryTableCatch.tagIndex == CatchAllIndex) {
   4675      // Capture the exnref if it has been requested, or else free it.
   4676      if (tryTableCatch.captureExnRef) {
   4677        pushRef(exn);
   4678      } else {
   4679        freeRef(exn);
   4680      }
   4681      // Free all of the other registers
   4682      freeRef(exnTag);
   4683      freeRef(catchTag);
   4684 #ifndef RABALDR_PIN_INSTANCE
   4685      freePtr(instance);
   4686 #endif
   4687 
   4688      // Pop the results needed for the target branch and perform the jump
   4689      popBlockResults(labelParams, target.stackHeight, ContinuationKind::Jump);
   4690      masm.jump(&target.label);
   4691      freeResultRegisters(labelParams);
   4692 
   4693      // Break from the loop and skip the implicit rethrow that's needed
   4694      // if we didn't have a catch_all
   4695      hadCatchAll = true;
   4696      break;
   4697    }
   4698 
   4699    // This is a `catch $t`, load the tag type we're trying to match
   4700    const TagType& tagType = *codeMeta_.tags[tryTableCatch.tagIndex].type;
   4701    const TagOffsetVector& tagOffsets = tagType.argOffsets();
   4702    ResultType tagParams = tagType.resultType();
   4703 
   4704    // Load the tag for this catch and compare it against the exception's tag.
   4705    // If they don't match, skip to the next catch handler.
   4706    Label skipCatch;
   4707    loadTag(instance, tryTableCatch.tagIndex, catchTag);
   4708    masm.branchPtr(Assembler::NotEqual, exnTag, catchTag, &skipCatch);
   4709 
   4710    // The tags and instance are dead after we've had a match, free them
   4711    freeRef(exnTag);
   4712    freeRef(catchTag);
   4713 #ifndef RABALDR_PIN_INSTANCE
   4714    freePtr(instance);
   4715 #endif
   4716 
   4717    // Allocate a register to hold the exception data pointer
   4718    RegPtr data = needPtr();
   4719 
   4720    // Unpack the tag and jump to the block
   4721    masm.loadPtr(Address(exn, (int32_t)WasmExceptionObject::offsetOfData()),
   4722                 data);
   4723    // This method can increase stk_.length() by an unbounded amount, so we need
   4724    // to perform an allocation here to accomodate the variable number of
   4725    // values. There is enough headroom for the fixed number of values.  The
   4726    // general case is handled in emitBody.
   4727    if (!stk_.reserve(stk_.length() + labelParams.length())) {
   4728      return false;
   4729    }
   4730 
   4731    for (uint32_t i = 0; i < tagParams.length(); i++) {
   4732      int32_t offset = tagOffsets[i];
   4733      switch (tagParams[i].kind()) {
   4734        case ValType::I32: {
   4735          RegI32 reg = needI32();
   4736          masm.load32(Address(data, offset), reg);
   4737          pushI32(reg);
   4738          break;
   4739        }
   4740        case ValType::I64: {
   4741          RegI64 reg = needI64();
   4742          masm.load64(Address(data, offset), reg);
   4743          pushI64(reg);
   4744          break;
   4745        }
   4746        case ValType::F32: {
   4747          RegF32 reg = needF32();
   4748          masm.loadFloat32(Address(data, offset), reg);
   4749          pushF32(reg);
   4750          break;
   4751        }
   4752        case ValType::F64: {
   4753          RegF64 reg = needF64();
   4754          masm.loadDouble(Address(data, offset), reg);
   4755          pushF64(reg);
   4756          break;
   4757        }
   4758        case ValType::V128: {
   4759 #ifdef ENABLE_WASM_SIMD
   4760          RegV128 reg = needV128();
   4761          masm.loadUnalignedSimd128(Address(data, offset), reg);
   4762          pushV128(reg);
   4763          break;
   4764 #else
   4765          MOZ_CRASH("No SIMD support");
   4766 #endif
   4767        }
   4768        case ValType::Ref: {
   4769          RegRef reg = needRef();
   4770          masm.loadPtr(Address(data, offset), reg);
   4771          pushRef(reg);
   4772          break;
   4773        }
   4774      }
   4775    }
   4776 
   4777    // The exception data pointer is no longer live after unpacking the
   4778    // exception
   4779    freePtr(data);
   4780 
   4781    // Capture the exnref if it has been requested, or else free it.
   4782    if (tryTableCatch.captureExnRef) {
   4783      pushRef(exn);
   4784    } else {
   4785      freeRef(exn);
   4786    }
   4787 
   4788    // Pop the results needed for the target branch and perform the jump
   4789    popBlockResults(labelParams, target.stackHeight, ContinuationKind::Jump);
   4790    masm.jump(&target.label);
   4791    freeResultRegisters(labelParams);
   4792 
   4793    // Reset the stack height for the skip to the next catch handler
   4794    fr.setStackHeight(prePadHeight);
   4795    masm.bind(&skipCatch);
   4796 
   4797    // Reset ownership of the registers for the next catch handler we emit
   4798    needRef(exn);
   4799    needRef(exnTag);
   4800    needRef(catchTag);
   4801 #ifndef RABALDR_PIN_INSTANCE
   4802    needPtr(instance);
   4803 #endif
   4804  }
   4805 
   4806  if (!hadCatchAll) {
   4807    // Free all registers, except for the exception
   4808    freeRef(exnTag);
   4809    freeRef(catchTag);
   4810 #ifndef RABALDR_PIN_INSTANCE
   4811    freePtr(instance);
   4812 #endif
   4813 
   4814    // If none of the tag checks succeed and there is no catch_all,
   4815    // then we rethrow the exception
   4816    if (!throwFrom(exn)) {
   4817      return false;
   4818    }
   4819  } else {
   4820    // All registers should have been freed by the catch_all
   4821    MOZ_ASSERT(isAvailableRef(exn));
   4822    MOZ_ASSERT(isAvailableRef(exnTag));
   4823    MOZ_ASSERT(isAvailableRef(catchTag));
   4824 #ifndef RABALDR_PIN_INSTANCE
   4825    MOZ_ASSERT(isAvailablePtr(instance));
   4826 #endif
   4827  }
   4828 
   4829  // Reset stack height for skipLandingPad, and bind it
   4830  fr.setStackHeight(prePadHeight);
   4831  masm.bind(&skipLandingPad);
   4832 
   4833  // Start the try note for this try block, after the landing pad
   4834  if (!startTryNote(&controlItem().tryNoteIndex)) {
   4835    return false;
   4836  }
   4837 
   4838  // Mark the try note to start at the landing pad we created above
   4839  TryNoteVector& tryNotes = masm.tryNotes();
   4840  TryNote& tryNote = tryNotes[controlItem().tryNoteIndex];
   4841  tryNote.setLandingPad(padOffset, padStackHeight);
   4842 
   4843  return true;
   4844 }
   4845 
   4846 void BaseCompiler::emitCatchSetup(LabelKind kind, Control& tryCatch,
   4847                                  const ResultType& resultType) {
   4848  // Catch ends the try or last catch, so we finish this like endIfThen.
   4849  if (deadCode_) {
   4850    fr.resetStackHeight(tryCatch.stackHeight, resultType);
   4851    popValueStackTo(tryCatch.stackSize);
   4852  } else {
   4853    // If the previous block is a catch, we need to handle the extra exception
   4854    // reference on the stack (for rethrow) and thus the stack size is 1 more.
   4855    MOZ_ASSERT(stk_.length() == tryCatch.stackSize + resultType.length() +
   4856                                    (kind == LabelKind::Try ? 0 : 1));
   4857    // Try jumps to the end of the try-catch block unless a throw is done.
   4858    if (kind == LabelKind::Try) {
   4859      popBlockResults(resultType, tryCatch.stackHeight, ContinuationKind::Jump);
   4860    } else {
   4861      popCatchResults(resultType, tryCatch.stackHeight);
   4862    }
   4863    MOZ_ASSERT(stk_.length() == tryCatch.stackSize);
   4864    freeResultRegisters(resultType);
   4865    MOZ_ASSERT(!tryCatch.deadOnArrival);
   4866  }
   4867 
   4868  // Reset to this "catch" branch.
   4869  deadCode_ = tryCatch.deadOnArrival;
   4870 
   4871  // We use the empty result type here because catch does *not* take the
   4872  // try-catch block parameters.
   4873  fr.resetStackHeight(tryCatch.stackHeight, ResultType::Empty());
   4874 
   4875  if (deadCode_) {
   4876    return;
   4877  }
   4878 
   4879  bceSafe_ = 0;
   4880 
   4881  // The end of the previous try/catch jumps to the join point.
   4882  masm.jump(&tryCatch.label);
   4883 
   4884  // Note end of try block for finding the catch block target. This needs
   4885  // to happen after the stack is reset to the correct height.
   4886  if (kind == LabelKind::Try) {
   4887    finishTryNote(controlItem().tryNoteIndex);
   4888  }
   4889 }
   4890 
   4891 bool BaseCompiler::emitCatch() {
   4892  LabelKind kind;
   4893  uint32_t tagIndex;
   4894  ResultType paramType, resultType;
   4895  BaseNothingVector unused_tryValues{};
   4896 
   4897  if (!iter_.readCatch(&kind, &tagIndex, &paramType, &resultType,
   4898                       &unused_tryValues)) {
   4899    return false;
   4900  }
   4901 
   4902  Control& tryCatch = controlItem();
   4903 
   4904  emitCatchSetup(kind, tryCatch, resultType);
   4905 
   4906  if (deadCode_) {
   4907    return true;
   4908  }
   4909 
   4910  // Construct info used for the exception landing pad.
   4911  CatchInfo catchInfo(tagIndex);
   4912  if (!tryCatch.catchInfos.emplaceBack(catchInfo)) {
   4913    return false;
   4914  }
   4915 
   4916  masm.bind(&tryCatch.catchInfos.back().label);
   4917 
   4918  // Extract the arguments in the exception package and push them.
   4919  const SharedTagType& tagType = codeMeta_.tags[tagIndex].type;
   4920  const ValTypeVector& params = tagType->argTypes();
   4921  const TagOffsetVector& offsets = tagType->argOffsets();
   4922 
   4923  // The landing pad uses the block return protocol to communicate the
   4924  // exception object pointer to the catch block.
   4925  ResultType exnResult = ResultType::Single(RefType::extern_());
   4926  captureResultRegisters(exnResult);
   4927  if (!pushBlockResults(exnResult)) {
   4928    return false;
   4929  }
   4930  RegRef exn = popRef();
   4931  RegPtr data = needPtr();
   4932 
   4933  masm.loadPtr(Address(exn, (int32_t)WasmExceptionObject::offsetOfData()),
   4934               data);
   4935 
   4936  // This method can increase stk_.length() by an unbounded amount, so we need
   4937  // to perform an allocation here to accomodate the variable number of values.
   4938  // There is enough headroom for the fixed number of values.  The general case
   4939  // is handled in emitBody.
   4940  if (!stk_.reserve(stk_.length() + params.length() + 1)) {
   4941    return false;
   4942  }
   4943 
   4944  // This reference is pushed onto the stack because a potential rethrow
   4945  // may need to access it. It is always popped at the end of the block.
   4946  pushRef(exn);
   4947 
   4948  for (uint32_t i = 0; i < params.length(); i++) {
   4949    int32_t offset = offsets[i];
   4950    switch (params[i].kind()) {
   4951      case ValType::I32: {
   4952        RegI32 reg = needI32();
   4953        masm.load32(Address(data, offset), reg);
   4954        pushI32(reg);
   4955        break;
   4956      }
   4957      case ValType::I64: {
   4958        RegI64 reg = needI64();
   4959        masm.load64(Address(data, offset), reg);
   4960        pushI64(reg);
   4961        break;
   4962      }
   4963      case ValType::F32: {
   4964        RegF32 reg = needF32();
   4965        masm.loadFloat32(Address(data, offset), reg);
   4966        pushF32(reg);
   4967        break;
   4968      }
   4969      case ValType::F64: {
   4970        RegF64 reg = needF64();
   4971        masm.loadDouble(Address(data, offset), reg);
   4972        pushF64(reg);
   4973        break;
   4974      }
   4975      case ValType::V128: {
   4976 #ifdef ENABLE_WASM_SIMD
   4977        RegV128 reg = needV128();
   4978        masm.loadUnalignedSimd128(Address(data, offset), reg);
   4979        pushV128(reg);
   4980        break;
   4981 #else
   4982        MOZ_CRASH("No SIMD support");
   4983 #endif
   4984      }
   4985      case ValType::Ref: {
   4986        RegRef reg = needRef();
   4987        masm.loadPtr(Address(data, offset), reg);
   4988        pushRef(reg);
   4989        break;
   4990      }
   4991    }
   4992  }
   4993  freePtr(data);
   4994 
   4995  return true;
   4996 }
   4997 
   4998 bool BaseCompiler::emitCatchAll() {
   4999  LabelKind kind;
   5000  ResultType paramType, resultType;
   5001  BaseNothingVector unused_tryValues{};
   5002 
   5003  if (!iter_.readCatchAll(&kind, &paramType, &resultType, &unused_tryValues)) {
   5004    return false;
   5005  }
   5006 
   5007  Control& tryCatch = controlItem();
   5008 
   5009  emitCatchSetup(kind, tryCatch, resultType);
   5010 
   5011  if (deadCode_) {
   5012    return true;
   5013  }
   5014 
   5015  CatchInfo catchInfo(CatchAllIndex);
   5016  if (!tryCatch.catchInfos.emplaceBack(catchInfo)) {
   5017    return false;
   5018  }
   5019 
   5020  masm.bind(&tryCatch.catchInfos.back().label);
   5021 
   5022  // The landing pad uses the block return protocol to communicate the
   5023  // exception object pointer to the catch block.
   5024  ResultType exnResult = ResultType::Single(RefType::extern_());
   5025  captureResultRegisters(exnResult);
   5026  // This reference is pushed onto the stack because a potential rethrow
   5027  // may need to access it. It is always popped at the end of the block.
   5028  return pushBlockResults(exnResult);
   5029 }
   5030 
   5031 bool BaseCompiler::emitDelegate() {
   5032  uint32_t relativeDepth;
   5033  ResultType resultType;
   5034  BaseNothingVector unused_tryValues{};
   5035 
   5036  if (!iter_.readDelegate(&relativeDepth, &resultType, &unused_tryValues)) {
   5037    return false;
   5038  }
   5039 
   5040  if (!endBlock(resultType)) {
   5041    return false;
   5042  }
   5043 
   5044  if (controlItem().deadOnArrival) {
   5045    return true;
   5046  }
   5047 
   5048  // Mark the end of the try body. This may insert a nop.
   5049  finishTryNote(controlItem().tryNoteIndex);
   5050 
   5051  // If the target block is a non-try block, skip over it and find the next
   5052  // try block or the very last block (to re-throw out of the function).
   5053  Control& lastBlock = controlOutermost();
   5054  while (controlKind(relativeDepth) != LabelKind::Try &&
   5055         controlKind(relativeDepth) != LabelKind::TryTable &&
   5056         &controlItem(relativeDepth) != &lastBlock) {
   5057    relativeDepth++;
   5058  }
   5059  Control& target = controlItem(relativeDepth);
   5060  TryNoteVector& tryNotes = masm.tryNotes();
   5061  TryNote& delegateTryNote = tryNotes[controlItem().tryNoteIndex];
   5062 
   5063  if (&target == &lastBlock) {
   5064    // A delegate targeting the function body block means that any exception
   5065    // in this try needs to be propagated to the caller function. We use the
   5066    // delegate code offset of `0` as that will be in the prologue and cannot
   5067    // have a try note.
   5068    delegateTryNote.setDelegate(0);
   5069  } else {
   5070    // Delegate to one byte inside the beginning of the target try note, as
   5071    // that's when matches hit. Try notes are guaranteed to not be empty either
   5072    // and so this will not miss either.
   5073    const TryNote& targetTryNote = tryNotes[target.tryNoteIndex];
   5074    delegateTryNote.setDelegate(targetTryNote.tryBodyBegin() + 1);
   5075  }
   5076 
   5077  return true;
   5078 }
   5079 
   5080 bool BaseCompiler::endTryCatch(ResultType type) {
   5081  Control& tryCatch = controlItem();
   5082  LabelKind tryKind = controlKind(0);
   5083 
   5084  if (deadCode_) {
   5085    fr.resetStackHeight(tryCatch.stackHeight, type);
   5086    popValueStackTo(tryCatch.stackSize);
   5087  } else {
   5088    // If the previous block is a catch, we must handle the extra exception
   5089    // reference on the stack (for rethrow) and thus the stack size is 1 more.
   5090    MOZ_ASSERT(stk_.length() == tryCatch.stackSize + type.length() +
   5091                                    (tryKind == LabelKind::Try ? 0 : 1));
   5092    // Assume we have a control join, so place results in block result
   5093    // allocations and also handle the implicit exception reference if needed.
   5094    if (tryKind == LabelKind::Try) {
   5095      popBlockResults(type, tryCatch.stackHeight, ContinuationKind::Jump);
   5096    } else {
   5097      popCatchResults(type, tryCatch.stackHeight);
   5098    }
   5099    MOZ_ASSERT(stk_.length() == tryCatch.stackSize);
   5100    // Since we will emit a landing pad after this and jump over it to get to
   5101    // the control join, we free these here and re-capture at the join.
   5102    freeResultRegisters(type);
   5103    masm.jump(&tryCatch.label);
   5104    MOZ_ASSERT(!tryCatch.bceSafeOnExit);
   5105    MOZ_ASSERT(!tryCatch.deadOnArrival);
   5106  }
   5107 
   5108  deadCode_ = tryCatch.deadOnArrival;
   5109 
   5110  if (deadCode_) {
   5111    return true;
   5112  }
   5113 
   5114  // Create landing pad for all catch handlers in this block.
   5115  // When used for a catchless try block, this will generate a landing pad
   5116  // with no handlers and only the fall-back rethrow.
   5117 
   5118  // The stack height also needs to be set not for a block result, but for the
   5119  // entry to the exception handlers. This is reset again below for the join.
   5120  StackHeight prePadHeight = fr.stackHeight();
   5121  fr.setStackHeight(tryCatch.stackHeight);
   5122 
   5123  // If we are in a catchless try block, then there were no catch blocks to
   5124  // mark the end of the try note, so we need to end it here.
   5125  if (tryKind == LabelKind::Try) {
   5126    // Mark the end of the try body. This may insert a nop.
   5127    finishTryNote(controlItem().tryNoteIndex);
   5128  }
   5129 
   5130  // The landing pad begins at this point
   5131  TryNoteVector& tryNotes = masm.tryNotes();
   5132  TryNote& tryNote = tryNotes[controlItem().tryNoteIndex];
   5133  tryNote.setLandingPad(masm.currentOffset(), masm.framePushed());
   5134 
   5135  // Store the Instance that was left in InstanceReg by the exception
   5136  // handling mechanism, that is this frame's Instance but with the exception
   5137  // filled in Instance::pendingException.
   5138  fr.storeInstancePtr(InstanceReg);
   5139 
   5140  // Load exception pointer from Instance and make sure that it is
   5141  // saved before the following call will clear it.
   5142  RegRef exn;
   5143  RegRef tag;
   5144  consumePendingException(RegPtr(InstanceReg), &exn, &tag);
   5145 
   5146  // Get a register to hold the tags for each catch
   5147  RegRef catchTag = needRef();
   5148 
   5149  // Ensure that the exception is assigned to the block return register
   5150  // before branching to a handler.
   5151  pushRef(exn);
   5152  ResultType exnResult = ResultType::Single(RefType::extern_());
   5153  popBlockResults(exnResult, tryCatch.stackHeight, ContinuationKind::Jump);
   5154  freeResultRegisters(exnResult);
   5155 
   5156  bool hasCatchAll = false;
   5157  for (CatchInfo& info : tryCatch.catchInfos) {
   5158    if (info.tagIndex != CatchAllIndex) {
   5159      MOZ_ASSERT(!hasCatchAll);
   5160      loadTag(RegPtr(InstanceReg), info.tagIndex, catchTag);
   5161      masm.branchPtr(Assembler::Equal, tag, catchTag, &info.label);
   5162    } else {
   5163      masm.jump(&info.label);
   5164      hasCatchAll = true;
   5165    }
   5166  }
   5167  freeRef(catchTag);
   5168  freeRef(tag);
   5169 
   5170  // If none of the tag checks succeed and there is no catch_all,
   5171  // then we rethrow the exception.
   5172  if (!hasCatchAll) {
   5173    captureResultRegisters(exnResult);
   5174    if (!pushBlockResults(exnResult) || !throwFrom(popRef())) {
   5175      return false;
   5176    }
   5177  }
   5178 
   5179  // Reset stack height for join.
   5180  fr.setStackHeight(prePadHeight);
   5181 
   5182  // Create join point.
   5183  if (tryCatch.label.used()) {
   5184    masm.bind(&tryCatch.label);
   5185  }
   5186 
   5187  captureResultRegisters(type);
   5188  deadCode_ = tryCatch.deadOnArrival;
   5189  bceSafe_ = tryCatch.bceSafeOnExit;
   5190 
   5191  return pushBlockResults(type);
   5192 }
   5193 
   5194 bool BaseCompiler::endTryTable(ResultType type) {
   5195  if (!controlItem().deadOnArrival) {
   5196    // Mark the end of the try body. This may insert a nop.
   5197    finishTryNote(controlItem().tryNoteIndex);
   5198  }
   5199  return endBlock(type);
   5200 }
   5201 
   5202 bool BaseCompiler::emitThrow() {
   5203  uint32_t tagIndex;
   5204  BaseNothingVector unused_argValues{};
   5205 
   5206  if (!iter_.readThrow(&tagIndex, &unused_argValues)) {
   5207    return false;
   5208  }
   5209 
   5210  if (deadCode_) {
   5211    return true;
   5212  }
   5213 
   5214  const TagDesc& tagDesc = codeMeta_.tags[tagIndex];
   5215  const ResultType& params = tagDesc.type->resultType();
   5216  const TagOffsetVector& offsets = tagDesc.type->argOffsets();
   5217 
   5218  // Load the tag object
   5219 #ifdef RABALDR_PIN_INSTANCE
   5220  RegPtr instance(InstanceReg);
   5221 #else
   5222  RegPtr instance = needPtr();
   5223  fr.loadInstancePtr(instance);
   5224 #endif
   5225  RegRef tag = needRef();
   5226  loadTag(instance, tagIndex, tag);
   5227 #ifndef RABALDR_PIN_INSTANCE
   5228  freePtr(instance);
   5229 #endif
   5230 
   5231  // Create the new exception object that we will throw.
   5232  pushRef(tag);
   5233  if (!emitInstanceCall(SASigExceptionNew)) {
   5234    return false;
   5235  }
   5236 
   5237  // Get registers for exn and data, excluding the prebarrier register
   5238  needPtr(RegPtr(PreBarrierReg));
   5239  RegRef exn = popRef();
   5240  RegPtr data = needPtr();
   5241  freePtr(RegPtr(PreBarrierReg));
   5242 
   5243  masm.loadPtr(Address(exn, WasmExceptionObject::offsetOfData()), data);
   5244 
   5245  for (int32_t i = params.length() - 1; i >= 0; i--) {
   5246    uint32_t offset = offsets[i];
   5247    switch (params[i].kind()) {
   5248      case ValType::I32: {
   5249        RegI32 reg = popI32();
   5250        masm.store32(reg, Address(data, offset));
   5251        freeI32(reg);
   5252        break;
   5253      }
   5254      case ValType::I64: {
   5255        RegI64 reg = popI64();
   5256        masm.store64(reg, Address(data, offset));
   5257        freeI64(reg);
   5258        break;
   5259      }
   5260      case ValType::F32: {
   5261        RegF32 reg = popF32();
   5262        masm.storeFloat32(reg, Address(data, offset));
   5263        freeF32(reg);
   5264        break;
   5265      }
   5266      case ValType::F64: {
   5267        RegF64 reg = popF64();
   5268        masm.storeDouble(reg, Address(data, offset));
   5269        freeF64(reg);
   5270        break;
   5271      }
   5272      case ValType::V128: {
   5273 #ifdef ENABLE_WASM_SIMD
   5274        RegV128 reg = popV128();
   5275        masm.storeUnalignedSimd128(reg, Address(data, offset));
   5276        freeV128(reg);
   5277        break;
   5278 #else
   5279        MOZ_CRASH("No SIMD support");
   5280 #endif
   5281      }
   5282      case ValType::Ref: {
   5283        RegPtr valueAddr(PreBarrierReg);
   5284        needPtr(valueAddr);
   5285        masm.computeEffectiveAddress(Address(data, offset), valueAddr);
   5286        RegRef rv = popRef();
   5287        pushPtr(data);
   5288        // emitBarrieredStore preserves exn, rv
   5289        if (!emitBarrieredStore(Some(exn), valueAddr, rv,
   5290                                PreBarrierKind::Normal,
   5291                                PostBarrierKind::Imprecise)) {
   5292          return false;
   5293        }
   5294        popPtr(data);
   5295        freeRef(rv);
   5296        break;
   5297      }
   5298    }
   5299  }
   5300  freePtr(data);
   5301 
   5302  deadCode_ = true;
   5303 
   5304  return throwFrom(exn);
   5305 }
   5306 
   5307 bool BaseCompiler::emitThrowRef() {
   5308  Nothing unused{};
   5309 
   5310  if (!iter_.readThrowRef(&unused)) {
   5311    return false;
   5312  }
   5313 
   5314  if (deadCode_) {
   5315    return true;
   5316  }
   5317 
   5318  RegRef exn = popRef();
   5319  Label ok;
   5320  masm.branchWasmAnyRefIsNull(false, exn, &ok);
   5321  trap(Trap::NullPointerDereference);
   5322  masm.bind(&ok);
   5323  deadCode_ = true;
   5324  return throwFrom(exn);
   5325 }
   5326 
   5327 bool BaseCompiler::emitRethrow() {
   5328  uint32_t relativeDepth;
   5329  if (!iter_.readRethrow(&relativeDepth)) {
   5330    return false;
   5331  }
   5332 
   5333  if (deadCode_) {
   5334    return true;
   5335  }
   5336 
   5337  Control& tryCatch = controlItem(relativeDepth);
   5338  RegRef exn = needRef();
   5339  peekRefAt(tryCatch.stackSize, exn);
   5340 
   5341  deadCode_ = true;
   5342 
   5343  return throwFrom(exn);
   5344 }
   5345 
   5346 bool BaseCompiler::emitDrop() {
   5347  if (!iter_.readDrop()) {
   5348    return false;
   5349  }
   5350 
   5351  if (deadCode_) {
   5352    return true;
   5353  }
   5354 
   5355  dropValue();
   5356  return true;
   5357 }
   5358 
   5359 void BaseCompiler::doReturn(ContinuationKind kind) {
   5360  if (deadCode_) {
   5361    return;
   5362  }
   5363 
   5364  StackHeight height = controlOutermost().stackHeight;
   5365  ResultType type = ResultType::Vector(funcType().results());
   5366  popBlockResults(type, height, kind);
   5367  masm.jump(&returnLabel_);
   5368  freeResultRegisters(type);
   5369 }
   5370 
   5371 bool BaseCompiler::emitReturn() {
   5372  BaseNothingVector unused_values{};
   5373  if (!iter_.readReturn(&unused_values)) {
   5374    return false;
   5375  }
   5376 
   5377  if (deadCode_) {
   5378    return true;
   5379  }
   5380 
   5381  doReturn(ContinuationKind::Jump);
   5382  deadCode_ = true;
   5383 
   5384  return true;
   5385 }
   5386 
   5387 // For now, always sync() at the beginning of the call to easily save live
   5388 // values.
   5389 //
   5390 // TODO / OPTIMIZE (Bug 1316806): We may be able to avoid a full sync(), since
   5391 // all we want is to save live registers that won't be saved by the callee or
   5392 // that we need for outgoing args - we don't need to sync the locals.  We can
   5393 // just push the necessary registers, it'll be like a lightweight sync.
   5394 //
   5395 // Even some of the pushing may be unnecessary if the registers will be consumed
   5396 // by the call, because then what we want is parallel assignment to the argument
   5397 // registers or onto the stack for outgoing arguments.  A sync() is just
   5398 // simpler.
   5399 
   5400 bool BaseCompiler::emitCall() {
   5401  uint32_t funcIndex;
   5402  BaseNothingVector args_{};
   5403  if (!iter_.readCall(&funcIndex, &args_)) {
   5404    return false;
   5405  }
   5406 
   5407  if (deadCode_) {
   5408    return true;
   5409  }
   5410 
   5411  bool import = codeMeta_.funcIsImport(funcIndex);
   5412 
   5413  if (import) {
   5414    BuiltinModuleFuncId knownFuncImport = codeMeta_.knownFuncImport(funcIndex);
   5415    if (knownFuncImport != BuiltinModuleFuncId::None) {
   5416      const BuiltinModuleFunc& builtinModuleFunc =
   5417          BuiltinModuleFuncs::getFromId(knownFuncImport);
   5418      if (builtinModuleFunc.usesMemory()) {
   5419        // The final parameter of an builtinModuleFunc is implicitly the heap
   5420        // base
   5421        pushHeapBase(0);
   5422      }
   5423 
   5424      // Call the builtinModuleFunc
   5425      return emitInstanceCall(*builtinModuleFunc.sig());
   5426    }
   5427  }
   5428 
   5429  sync();
   5430 
   5431  const FuncType& funcType = codeMeta_.getFuncType(funcIndex);
   5432 
   5433  uint32_t numArgs = funcType.args().length();
   5434  size_t stackArgBytes = stackConsumed(numArgs);
   5435 
   5436  ResultType resultType(ResultType::Vector(funcType.results()));
   5437  StackResultsLoc results;
   5438  if (!pushStackResultsForWasmCall(resultType, RegPtr(ABINonArgReg0),
   5439                                   &results)) {
   5440    return false;
   5441  }
   5442 
   5443  FunctionCall baselineCall(ABIKind::Wasm,
   5444                            import ? RestoreState::All : RestoreState::None);
   5445  beginCall(baselineCall);
   5446 
   5447  if (!emitCallArgs(funcType.args(), NormalCallResults(results), &baselineCall,
   5448                    CalleeOnStack::False)) {
   5449    return false;
   5450  }
   5451 
   5452  CodeOffset raOffset;
   5453  if (import) {
   5454    raOffset = callImport(codeMeta_.offsetOfFuncImportInstanceData(funcIndex),
   5455                          baselineCall);
   5456  } else {
   5457    raOffset = callDefinition(funcIndex, baselineCall);
   5458  }
   5459 
   5460  if (!createStackMap("emitCall", raOffset)) {
   5461    return false;
   5462  }
   5463 
   5464  popStackResultsAfterWasmCall(results, stackArgBytes);
   5465 
   5466  endCall(baselineCall, stackArgBytes);
   5467 
   5468  popValueStackBy(numArgs);
   5469 
   5470  captureCallResultRegisters(resultType);
   5471  return pushWasmCallResults(baselineCall, resultType, results);
   5472 }
   5473 
   5474 bool BaseCompiler::emitReturnCall() {
   5475  uint32_t funcIndex;
   5476  BaseNothingVector args_{};
   5477  if (!iter_.readReturnCall(&funcIndex, &args_)) {
   5478    return false;
   5479  }
   5480 
   5481  if (deadCode_) {
   5482    return true;
   5483  }
   5484 
   5485  sync();
   5486  if (!insertDebugCollapseFrame()) {
   5487    return false;
   5488  }
   5489 
   5490  const FuncType& funcType = codeMeta_.getFuncType(funcIndex);
   5491  bool import = codeMeta_.funcIsImport(funcIndex);
   5492 
   5493  uint32_t numArgs = funcType.args().length();
   5494 
   5495  FunctionCall baselineCall(ABIKind::Wasm,
   5496                            import ? RestoreState::All : RestoreState::None);
   5497  beginCall(baselineCall);
   5498 
   5499  if (!emitCallArgs(funcType.args(), TailCallResults(funcType), &baselineCall,
   5500                    CalleeOnStack::False)) {
   5501    return false;
   5502  }
   5503 
   5504  ReturnCallAdjustmentInfo retCallInfo =
   5505      BuildReturnCallAdjustmentInfo(this->funcType(), funcType);
   5506 
   5507  if (import) {
   5508    CallSiteDesc desc(bytecodeOffset(), CallSiteKind::Import);
   5509    CalleeDesc callee =
   5510        CalleeDesc::import(codeMeta_.offsetOfFuncImportInstanceData(funcIndex));
   5511    masm.wasmReturnCallImport(desc, callee, retCallInfo);
   5512  } else {
   5513    CallSiteDesc desc(bytecodeOffset(), CallSiteKind::ReturnFunc);
   5514    masm.wasmReturnCall(desc, funcIndex, retCallInfo);
   5515  }
   5516 
   5517  MOZ_ASSERT(stackMapGenerator_.framePushedExcludingOutboundCallArgs.isSome());
   5518  stackMapGenerator_.framePushedExcludingOutboundCallArgs.reset();
   5519 
   5520  popValueStackBy(numArgs);
   5521 
   5522  deadCode_ = true;
   5523  return true;
   5524 }
   5525 
   5526 bool BaseCompiler::emitCallIndirect() {
   5527  uint32_t funcTypeIndex;
   5528  uint32_t tableIndex;
   5529  Nothing callee_;
   5530  BaseNothingVector args_{};
   5531  if (!iter_.readCallIndirect(&funcTypeIndex, &tableIndex, &callee_, &args_)) {
   5532    return false;
   5533  }
   5534 
   5535  if (deadCode_) {
   5536    return true;
   5537  }
   5538 
   5539  // Stack: ... arg1 .. argn callee
   5540  sync();
   5541 
   5542  const FuncType& funcType = (*codeMeta_.types)[funcTypeIndex].funcType();
   5543 
   5544  uint32_t numArgs = funcType.args().length() + 1;
   5545  size_t stackArgBytes = stackConsumed(numArgs);
   5546 
   5547  ResultType resultType(ResultType::Vector(funcType.results()));
   5548  StackResultsLoc results;
   5549  if (!pushStackResultsForWasmCall(resultType, RegPtr(ABINonArgReg0),
   5550                                   &results)) {
   5551    return false;
   5552  }
   5553 
   5554  // State and realm are restored as needed by by callIndirect (really by
   5555  // MacroAssembler::wasmCallIndirect).
   5556  FunctionCall baselineCall(ABIKind::Wasm, RestoreState::None);
   5557  beginCall(baselineCall);
   5558 
   5559  if (!emitCallArgs(funcType.args(), NormalCallResults(results), &baselineCall,
   5560                    CalleeOnStack::True)) {
   5561    return false;
   5562  }
   5563 
   5564  const Stk& callee = peek(results.count());
   5565  CodeOffset fastCallOffset;
   5566  CodeOffset slowCallOffset;
   5567  if (!callIndirect(funcTypeIndex, tableIndex, callee, baselineCall,
   5568                    /*tailCall*/ false, &fastCallOffset, &slowCallOffset)) {
   5569    return false;
   5570  }
   5571  if (!createStackMap("emitCallIndirect", fastCallOffset)) {
   5572    return false;
   5573  }
   5574  if (!createStackMap("emitCallIndirect", slowCallOffset)) {
   5575    return false;
   5576  }
   5577 
   5578  popStackResultsAfterWasmCall(results, stackArgBytes);
   5579 
   5580  endCall(baselineCall, stackArgBytes);
   5581 
   5582  popValueStackBy(numArgs);
   5583 
   5584  captureCallResultRegisters(resultType);
   5585  return pushWasmCallResults(baselineCall, resultType, results);
   5586 }
   5587 
   5588 bool BaseCompiler::emitReturnCallIndirect() {
   5589  uint32_t funcTypeIndex;
   5590  uint32_t tableIndex;
   5591  Nothing callee_;
   5592  BaseNothingVector args_{};
   5593  if (!iter_.readReturnCallIndirect(&funcTypeIndex, &tableIndex, &callee_,
   5594                                    &args_)) {
   5595    return false;
   5596  }
   5597 
   5598  if (deadCode_) {
   5599    return true;
   5600  }
   5601 
   5602  // Stack: ... arg1 .. argn callee
   5603 
   5604  sync();
   5605  if (!insertDebugCollapseFrame()) {
   5606    return false;
   5607  }
   5608 
   5609  const FuncType& funcType = (*codeMeta_.types)[funcTypeIndex].funcType();
   5610 
   5611  uint32_t numArgs = funcType.args().length() + 1;
   5612 
   5613  // State and realm are restored as needed by by callIndirect (really by
   5614  // MacroAssembler::wasmCallIndirect).
   5615  FunctionCall baselineCall(ABIKind::Wasm, RestoreState::None);
   5616  beginCall(baselineCall);
   5617 
   5618  if (!emitCallArgs(funcType.args(), TailCallResults(funcType), &baselineCall,
   5619                    CalleeOnStack::True)) {
   5620    return false;
   5621  }
   5622 
   5623  const Stk& callee = peek(0);
   5624  CodeOffset fastCallOffset;
   5625  CodeOffset slowCallOffset;
   5626  if (!callIndirect(funcTypeIndex, tableIndex, callee, baselineCall,
   5627                    /*tailCall*/ true, &fastCallOffset, &slowCallOffset)) {
   5628    return false;
   5629  }
   5630 
   5631  MOZ_ASSERT(stackMapGenerator_.framePushedExcludingOutboundCallArgs.isSome());
   5632  stackMapGenerator_.framePushedExcludingOutboundCallArgs.reset();
   5633 
   5634  popValueStackBy(numArgs);
   5635 
   5636  deadCode_ = true;
   5637  return true;
   5638 }
   5639 
   5640 bool BaseCompiler::emitCallRef() {
   5641  uint32_t funcTypeIndex;
   5642  Nothing unused_callee;
   5643  BaseNothingVector unused_args{};
   5644  if (!iter_.readCallRef(&funcTypeIndex, &unused_callee, &unused_args)) {
   5645    return false;
   5646  }
   5647 
   5648  // Add a metrics entry to track this call_ref site. Do this even if we're in
   5649  // 'dead code' to have easy consistency with ion, which consumes these.
   5650  Maybe<size_t> callRefIndex;
   5651  if (compilerEnv_.mode() == CompileMode::LazyTiering) {
   5652    masm.append(wasm::CallRefMetricsPatch());
   5653    if (masm.oom()) {
   5654      return false;
   5655    }
   5656    callRefIndex = Some(masm.callRefMetricsPatches().length() - 1);
   5657  }
   5658 
   5659  if (deadCode_) {
   5660    return true;
   5661  }
   5662 
   5663  const FuncType& funcType = codeMeta_.types->type(funcTypeIndex).funcType();
   5664 
   5665  sync();
   5666 
   5667  // Stack: ... arg1 .. argn callee
   5668 
   5669  uint32_t numArgs = funcType.args().length() + 1;
   5670  size_t stackArgBytes = stackConsumed(numArgs);
   5671 
   5672  ResultType resultType(ResultType::Vector(funcType.results()));
   5673  StackResultsLoc results;
   5674  if (!pushStackResultsForWasmCall(resultType, RegPtr(ABINonArgReg0),
   5675                                   &results)) {
   5676    return false;
   5677  }
   5678 
   5679  // State and realm are restored as needed by by callRef (really by
   5680  // MacroAssembler::wasmCallRef).
   5681  FunctionCall baselineCall(ABIKind::Wasm, RestoreState::None);
   5682  beginCall(baselineCall);
   5683 
   5684  if (!emitCallArgs(funcType.args(), NormalCallResults(results), &baselineCall,
   5685                    CalleeOnStack::True)) {
   5686    return false;
   5687  }
   5688 
   5689  const Stk& callee = peek(results.count());
   5690  CodeOffset fastCallOffset;
   5691  CodeOffset slowCallOffset;
   5692  if (!callRef(callee, baselineCall, callRefIndex, &fastCallOffset,
   5693               &slowCallOffset)) {
   5694    return false;
   5695  }
   5696  if (!createStackMap("emitCallRef", fastCallOffset)) {
   5697    return false;
   5698  }
   5699  if (!createStackMap("emitCallRef", slowCallOffset)) {
   5700    return false;
   5701  }
   5702 
   5703  popStackResultsAfterWasmCall(results, stackArgBytes);
   5704 
   5705  endCall(baselineCall, stackArgBytes);
   5706 
   5707  popValueStackBy(numArgs);
   5708 
   5709  captureCallResultRegisters(resultType);
   5710  return pushWasmCallResults(baselineCall, resultType, results);
   5711 }
   5712 
   5713 bool BaseCompiler::emitReturnCallRef() {
   5714  uint32_t funcTypeIndex;
   5715  Nothing unused_callee;
   5716  BaseNothingVector unused_args{};
   5717  if (!iter_.readReturnCallRef(&funcTypeIndex, &unused_callee, &unused_args)) {
   5718    return false;
   5719  }
   5720 
   5721  if (deadCode_) {
   5722    return true;
   5723  }
   5724 
   5725  const FuncType& funcType = codeMeta_.types->type(funcTypeIndex).funcType();
   5726 
   5727  sync();
   5728 
   5729  if (!insertDebugCollapseFrame()) {
   5730    return false;
   5731  }
   5732 
   5733  // Stack: ... arg1 .. argn callee
   5734 
   5735  uint32_t numArgs = funcType.args().length() + 1;
   5736 
   5737  // State and realm are restored as needed by by callRef (really by
   5738  // MacroAssembler::wasmCallRef).
   5739  FunctionCall baselineCall(ABIKind::Wasm, RestoreState::None);
   5740  beginCall(baselineCall);
   5741 
   5742  if (!emitCallArgs(funcType.args(), TailCallResults(funcType), &baselineCall,
   5743                    CalleeOnStack::True)) {
   5744    return false;
   5745  }
   5746 
   5747  const Stk& callee = peek(0);
   5748  returnCallRef(callee, baselineCall, funcType);
   5749 
   5750  MOZ_ASSERT(stackMapGenerator_.framePushedExcludingOutboundCallArgs.isSome());
   5751  stackMapGenerator_.framePushedExcludingOutboundCallArgs.reset();
   5752 
   5753  popValueStackBy(numArgs);
   5754 
   5755  deadCode_ = true;
   5756  return true;
   5757 }
   5758 
   5759 void BaseCompiler::emitRound(RoundingMode roundingMode, ValType operandType) {
   5760  if (operandType == ValType::F32) {
   5761    RegF32 f0 = popF32();
   5762    roundF32(roundingMode, f0);
   5763    pushF32(f0);
   5764  } else if (operandType == ValType::F64) {
   5765    RegF64 f0 = popF64();
   5766    roundF64(roundingMode, f0);
   5767    pushF64(f0);
   5768  } else {
   5769    MOZ_CRASH("unexpected type");
   5770  }
   5771 }
   5772 
   5773 bool BaseCompiler::emitUnaryMathBuiltinCall(SymbolicAddress callee,
   5774                                            ValType operandType) {
   5775  Nothing operand_;
   5776  if (!iter_.readUnary(operandType, &operand_)) {
   5777    return false;
   5778  }
   5779 
   5780  if (deadCode_) {
   5781    return true;
   5782  }
   5783 
   5784  RoundingMode roundingMode;
   5785  if (IsRoundingFunction(callee, &roundingMode) &&
   5786      supportsRoundInstruction(roundingMode)) {
   5787    emitRound(roundingMode, operandType);
   5788    return true;
   5789  }
   5790 
   5791  sync();
   5792 
   5793  ValTypeVector& signature = operandType == ValType::F32 ? SigF_ : SigD_;
   5794  ValType retType = operandType;
   5795  uint32_t numArgs = signature.length();
   5796  size_t stackSpace = stackConsumed(numArgs);
   5797 
   5798  FunctionCall baselineCall(ABIForBuiltin(callee), RestoreState::None);
   5799  beginCall(baselineCall);
   5800 
   5801  if (!emitCallArgs(signature, NoCallResults(), &baselineCall,
   5802                    CalleeOnStack::False)) {
   5803    return false;
   5804  }
   5805 
   5806  CodeOffset raOffset = builtinCall(callee, baselineCall);
   5807  if (!createStackMap("emitUnaryMathBuiltin[..]", raOffset)) {
   5808    return false;
   5809  }
   5810 
   5811  endCall(baselineCall, stackSpace);
   5812 
   5813  popValueStackBy(numArgs);
   5814 
   5815  pushBuiltinCallResult(baselineCall, retType.toMIRType());
   5816 
   5817  return true;
   5818 }
   5819 
   5820 #ifdef RABALDR_INT_DIV_I64_CALLOUT
   5821 bool BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee,
   5822                                              ValType operandType) {
   5823  MOZ_ASSERT(operandType == ValType::I64);
   5824  MOZ_ASSERT(!deadCode_);
   5825 
   5826  sync();
   5827 
   5828  needI64(specific_.abiReturnRegI64);
   5829 
   5830  RegI64 rhs = popI64();
   5831  RegI64 srcDest = popI64ToSpecific(specific_.abiReturnRegI64);
   5832 
   5833  Label done;
   5834 
   5835  checkDivideByZero(rhs);
   5836 
   5837  if (callee == SymbolicAddress::DivI64) {
   5838    checkDivideSignedOverflow(rhs, srcDest, &done, ZeroOnOverflow(false));
   5839  } else if (callee == SymbolicAddress::ModI64) {
   5840    checkDivideSignedOverflow(rhs, srcDest, &done, ZeroOnOverflow(true));
   5841  }
   5842 
   5843  masm.setupWasmABICall(callee);
   5844  masm.passABIArg(srcDest.high);
   5845  masm.passABIArg(srcDest.low);
   5846  masm.passABIArg(rhs.high);
   5847  masm.passABIArg(rhs.low);
   5848  CodeOffset raOffset = masm.callWithABI(
   5849      bytecodeOffset(), callee, mozilla::Some(fr.getInstancePtrOffset()));
   5850  if (!createStackMap("emitDivOrModI64Bui[..]", raOffset)) {
   5851    return false;
   5852  }
   5853 
   5854  masm.bind(&done);
   5855 
   5856  freeI64(rhs);
   5857  pushI64(srcDest);
   5858  return true;
   5859 }
   5860 #endif  // RABALDR_INT_DIV_I64_CALLOUT
   5861 
   5862 #ifdef RABALDR_I64_TO_FLOAT_CALLOUT
   5863 bool BaseCompiler::emitConvertInt64ToFloatingCallout(SymbolicAddress callee,
   5864                                                     ValType operandType,
   5865                                                     ValType resultType) {
   5866  sync();
   5867 
   5868  RegI64 input = popI64();
   5869 
   5870  FunctionCall call(ABIKind::Wasm, RestoreState::None);
   5871 
   5872  masm.setupWasmABICall(callee);
   5873 #  ifdef JS_PUNBOX64
   5874  MOZ_CRASH("BaseCompiler platform hook: emitConvertInt64ToFloatingCallout");
   5875 #  else
   5876  masm.passABIArg(input.high);
   5877  masm.passABIArg(input.low);
   5878 #  endif
   5879  CodeOffset raOffset = masm.callWithABI(
   5880      bytecodeOffset(), callee, mozilla::Some(fr.getInstancePtrOffset()),
   5881      resultType == ValType::F32 ? ABIType::Float32 : ABIType::Float64);
   5882  if (!createStackMap("emitConvertInt64To[..]", raOffset)) {
   5883    return false;
   5884  }
   5885 
   5886  freeI64(input);
   5887 
   5888  if (resultType == ValType::F32) {
   5889    pushF32(captureReturnedF32(call));
   5890  } else {
   5891    pushF64(captureReturnedF64(call));
   5892  }
   5893 
   5894  return true;
   5895 }
   5896 #endif  // RABALDR_I64_TO_FLOAT_CALLOUT
   5897 
   5898 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
   5899 // `Callee` always takes a double, so a float32 input must be converted.
   5900 bool BaseCompiler::emitConvertFloatingToInt64Callout(SymbolicAddress callee,
   5901                                                     ValType operandType,
   5902                                                     ValType resultType) {
   5903  RegF64 doubleInput;
   5904  if (operandType == ValType::F32) {
   5905    doubleInput = needF64();
   5906    RegF32 input = popF32();
   5907    masm.convertFloat32ToDouble(input, doubleInput);
   5908    freeF32(input);
   5909  } else {
   5910    doubleInput = popF64();
   5911  }
   5912 
   5913  // We may need the value after the call for the ool check.
   5914  RegF64 otherReg = needF64();
   5915  moveF64(doubleInput, otherReg);
   5916  pushF64(otherReg);
   5917 
   5918  sync();
   5919 
   5920  FunctionCall call(ABIKind::Wasm, RestoreState::None);
   5921 
   5922  masm.setupWasmABICall(callee);
   5923  masm.passABIArg(doubleInput, ABIType::Float64);
   5924  CodeOffset raOffset = masm.callWithABI(
   5925      bytecodeOffset(), callee, mozilla::Some(fr.getInstancePtrOffset()));
   5926  if (!createStackMap("emitConvertFloatin[..]", raOffset)) {
   5927    return false;
   5928  }
   5929 
   5930  freeF64(doubleInput);
   5931 
   5932  RegI64 rv = captureReturnedI64();
   5933 
   5934  RegF64 inputVal = popF64();
   5935 
   5936  TruncFlags flags = 0;
   5937  if (callee == SymbolicAddress::TruncateDoubleToUint64) {
   5938    flags |= TRUNC_UNSIGNED;
   5939  }
   5940  if (callee == SymbolicAddress::SaturatingTruncateDoubleToInt64 ||
   5941      callee == SymbolicAddress::SaturatingTruncateDoubleToUint64) {
   5942    flags |= TRUNC_SATURATING;
   5943  }
   5944 
   5945  // If we're saturating, the callout will always produce the final result
   5946  // value. Otherwise, the callout value will return 0x8000000000000000
   5947  // and we need to produce traps.
   5948  OutOfLineCode* ool = nullptr;
   5949  if (!(flags & TRUNC_SATURATING)) {
   5950    // The OOL check just succeeds or fails, it does not generate a value.
   5951    ool = addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(
   5952        AnyReg(inputVal), rv, flags, trapSiteDesc()));
   5953    if (!ool) {
   5954      return false;
   5955    }
   5956 
   5957    masm.branch64(Assembler::Equal, rv, Imm64(0x8000000000000000),
   5958                  ool->entry());
   5959    masm.bind(ool->rejoin());
   5960  }
   5961 
   5962  pushI64(rv);
   5963  freeF64(inputVal);
   5964 
   5965  return true;
   5966 }
   5967 #endif  // RABALDR_FLOAT_TO_I64_CALLOUT
   5968 
   5969 bool BaseCompiler::emitGetLocal() {
   5970  uint32_t slot;
   5971  if (!iter_.readGetLocal(&slot)) {
   5972    return false;
   5973  }
   5974 
   5975  if (deadCode_) {
   5976    return true;
   5977  }
   5978 
   5979  // Local loads are pushed unresolved, ie, they may be deferred
   5980  // until needed, until they may be affected by a store, or until a
   5981  // sync.  This is intended to reduce register pressure.
   5982 
   5983  switch (locals_[slot].kind()) {
   5984    case ValType::I32:
   5985      pushLocalI32(slot);
   5986      break;
   5987    case ValType::I64:
   5988      pushLocalI64(slot);
   5989      break;
   5990    case ValType::V128:
   5991 #ifdef ENABLE_WASM_SIMD
   5992      pushLocalV128(slot);
   5993      break;
   5994 #else
   5995      MOZ_CRASH("No SIMD support");
   5996 #endif
   5997    case ValType::F64:
   5998      pushLocalF64(slot);
   5999      break;
   6000    case ValType::F32:
   6001      pushLocalF32(slot);
   6002      break;
   6003    case ValType::Ref:
   6004      pushLocalRef(slot);
   6005      break;
   6006  }
   6007 
   6008  return true;
   6009 }
   6010 
   6011 template <bool isSetLocal>
   6012 bool BaseCompiler::emitSetOrTeeLocal(uint32_t slot) {
   6013  if (deadCode_) {
   6014    return true;
   6015  }
   6016 
   6017  bceLocalIsUpdated(slot);
   6018  switch (locals_[slot].kind()) {
   6019    case ValType::I32: {
   6020      RegI32 rv = popI32();
   6021      syncLocal(slot);
   6022      fr.storeLocalI32(rv, localFromSlot(slot, MIRType::Int32));
   6023      if (isSetLocal) {
   6024        freeI32(rv);
   6025      } else {
   6026        pushI32(rv);
   6027      }
   6028      break;
   6029    }
   6030    case ValType::I64: {
   6031      RegI64 rv = popI64();
   6032      syncLocal(slot);
   6033      fr.storeLocalI64(rv, localFromSlot(slot, MIRType::Int64));
   6034      if (isSetLocal) {
   6035        freeI64(rv);
   6036      } else {
   6037        pushI64(rv);
   6038      }
   6039      break;
   6040    }
   6041    case ValType::F64: {
   6042      RegF64 rv = popF64();
   6043      syncLocal(slot);
   6044      fr.storeLocalF64(rv, localFromSlot(slot, MIRType::Double));
   6045      if (isSetLocal) {
   6046        freeF64(rv);
   6047      } else {
   6048        pushF64(rv);
   6049      }
   6050      break;
   6051    }
   6052    case ValType::F32: {
   6053      RegF32 rv = popF32();
   6054      syncLocal(slot);
   6055      fr.storeLocalF32(rv, localFromSlot(slot, MIRType::Float32));
   6056      if (isSetLocal) {
   6057        freeF32(rv);
   6058      } else {
   6059        pushF32(rv);
   6060      }
   6061      break;
   6062    }
   6063    case ValType::V128: {
   6064 #ifdef ENABLE_WASM_SIMD
   6065      RegV128 rv = popV128();
   6066      syncLocal(slot);
   6067      fr.storeLocalV128(rv, localFromSlot(slot, MIRType::Simd128));
   6068      if (isSetLocal) {
   6069        freeV128(rv);
   6070      } else {
   6071        pushV128(rv);
   6072      }
   6073      break;
   6074 #else
   6075      MOZ_CRASH("No SIMD support");
   6076 #endif
   6077    }
   6078    case ValType::Ref: {
   6079      RegRef rv = popRef();
   6080      syncLocal(slot);
   6081      fr.storeLocalRef(rv, localFromSlot(slot, MIRType::WasmAnyRef));
   6082      if (isSetLocal) {
   6083        freeRef(rv);
   6084      } else {
   6085        pushRef(rv);
   6086      }
   6087      break;
   6088    }
   6089  }
   6090 
   6091  return true;
   6092 }
   6093 
   6094 bool BaseCompiler::emitSetLocal() {
   6095  uint32_t slot;
   6096  Nothing unused_value;
   6097  if (!iter_.readSetLocal(&slot, &unused_value)) {
   6098    return false;
   6099  }
   6100  return emitSetOrTeeLocal<true>(slot);
   6101 }
   6102 
   6103 bool BaseCompiler::emitTeeLocal() {
   6104  uint32_t slot;
   6105  Nothing unused_value;
   6106  if (!iter_.readTeeLocal(&slot, &unused_value)) {
   6107    return false;
   6108  }
   6109  return emitSetOrTeeLocal<false>(slot);
   6110 }
   6111 
   6112 bool BaseCompiler::emitGetGlobal() {
   6113  uint32_t id;
   6114  if (!iter_.readGetGlobal(&id)) {
   6115    return false;
   6116  }
   6117 
   6118  if (deadCode_) {
   6119    return true;
   6120  }
   6121 
   6122  const GlobalDesc& global = codeMeta_.globals[id];
   6123 
   6124  if (global.isConstant()) {
   6125    LitVal value = global.constantValue();
   6126    switch (value.type().kind()) {
   6127      case ValType::I32:
   6128        pushI32(value.i32());
   6129        break;
   6130      case ValType::I64:
   6131        pushI64(value.i64());
   6132        break;
   6133      case ValType::F32:
   6134        pushF32(value.f32());
   6135        break;
   6136      case ValType::F64:
   6137        pushF64(value.f64());
   6138        break;
   6139      case ValType::Ref:
   6140        pushRef(intptr_t(value.ref().forCompiledCode()));
   6141        break;
   6142 #ifdef ENABLE_WASM_SIMD
   6143      case ValType::V128:
   6144        pushV128(value.v128());
   6145        break;
   6146 #endif
   6147      default:
   6148        MOZ_CRASH("Global constant type");
   6149    }
   6150    return true;
   6151  }
   6152 
   6153  switch (global.type().kind()) {
   6154    case ValType::I32: {
   6155      RegI32 rv = needI32();
   6156      ScratchPtr tmp(*this);
   6157      masm.load32(addressOfGlobalVar(global, tmp), rv);
   6158      pushI32(rv);
   6159      break;
   6160    }
   6161    case ValType::I64: {
   6162      RegI64 rv = needI64();
   6163      ScratchPtr tmp(*this);
   6164      masm.load64(addressOfGlobalVar(global, tmp), rv);
   6165      pushI64(rv);
   6166      break;
   6167    }
   6168    case ValType::F32: {
   6169      RegF32 rv = needF32();
   6170      ScratchPtr tmp(*this);
   6171      masm.loadFloat32(addressOfGlobalVar(global, tmp), rv);
   6172      pushF32(rv);
   6173      break;
   6174    }
   6175    case ValType::F64: {
   6176      RegF64 rv = needF64();
   6177      ScratchPtr tmp(*this);
   6178      masm.loadDouble(addressOfGlobalVar(global, tmp), rv);
   6179      pushF64(rv);
   6180      break;
   6181    }
   6182    case ValType::Ref: {
   6183      RegRef rv = needRef();
   6184      ScratchPtr tmp(*this);
   6185      masm.loadPtr(addressOfGlobalVar(global, tmp), rv);
   6186      pushRef(rv);
   6187      break;
   6188    }
   6189 #ifdef ENABLE_WASM_SIMD
   6190    case ValType::V128: {
   6191      RegV128 rv = needV128();
   6192      ScratchPtr tmp(*this);
   6193      masm.loadUnalignedSimd128(addressOfGlobalVar(global, tmp), rv);
   6194      pushV128(rv);
   6195      break;
   6196    }
   6197 #endif
   6198    default:
   6199      MOZ_CRASH("Global variable type");
   6200      break;
   6201  }
   6202  return true;
   6203 }
   6204 
   6205 bool BaseCompiler::emitSetGlobal() {
   6206  uint32_t id;
   6207  Nothing unused_value;
   6208  if (!iter_.readSetGlobal(&id, &unused_value)) {
   6209    return false;
   6210  }
   6211 
   6212  if (deadCode_) {
   6213    return true;
   6214  }
   6215 
   6216  const GlobalDesc& global = codeMeta_.globals[id];
   6217 
   6218  switch (global.type().kind()) {
   6219    case ValType::I32: {
   6220      RegI32 rv = popI32();
   6221      ScratchPtr tmp(*this);
   6222      masm.store32(rv, addressOfGlobalVar(global, tmp));
   6223      freeI32(rv);
   6224      break;
   6225    }
   6226    case ValType::I64: {
   6227      RegI64 rv = popI64();
   6228      ScratchPtr tmp(*this);
   6229      masm.store64(rv, addressOfGlobalVar(global, tmp));
   6230      freeI64(rv);
   6231      break;
   6232    }
   6233    case ValType::F32: {
   6234      RegF32 rv = popF32();
   6235      ScratchPtr tmp(*this);
   6236      masm.storeFloat32(rv, addressOfGlobalVar(global, tmp));
   6237      freeF32(rv);
   6238      break;
   6239    }
   6240    case ValType::F64: {
   6241      RegF64 rv = popF64();
   6242      ScratchPtr tmp(*this);
   6243      masm.storeDouble(rv, addressOfGlobalVar(global, tmp));
   6244      freeF64(rv);
   6245      break;
   6246    }
   6247    case ValType::Ref: {
   6248      RegPtr valueAddr(PreBarrierReg);
   6249      needPtr(valueAddr);
   6250      {
   6251        ScratchPtr tmp(*this);
   6252        masm.computeEffectiveAddress(addressOfGlobalVar(global, tmp),
   6253                                     valueAddr);
   6254      }
   6255      RegRef rv = popRef();
   6256      // emitBarrieredStore preserves rv
   6257      if (!emitBarrieredStore(Nothing(), valueAddr, rv, PreBarrierKind::Normal,
   6258                              PostBarrierKind::Imprecise)) {
   6259        return false;
   6260      }
   6261      freeRef(rv);
   6262      break;
   6263    }
   6264 #ifdef ENABLE_WASM_SIMD
   6265    case ValType::V128: {
   6266      RegV128 rv = popV128();
   6267      ScratchPtr tmp(*this);
   6268      masm.storeUnalignedSimd128(rv, addressOfGlobalVar(global, tmp));
   6269      freeV128(rv);
   6270      break;
   6271    }
   6272 #endif
   6273    default:
   6274      MOZ_CRASH("Global variable type");
   6275      break;
   6276  }
   6277  return true;
   6278 }
   6279 
   6280 bool BaseCompiler::emitLoad(ValType type, Scalar::Type viewType) {
   6281  LinearMemoryAddress<Nothing> addr;
   6282  if (!iter_.readLoad(type, Scalar::byteSize(viewType), &addr)) {
   6283    return false;
   6284  }
   6285  if (deadCode_) {
   6286    return true;
   6287  }
   6288  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6289                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
   6290  loadCommon(&access, AccessCheck(), type);
   6291  return true;
   6292 }
   6293 
   6294 bool BaseCompiler::emitStore(ValType resultType, Scalar::Type viewType) {
   6295  LinearMemoryAddress<Nothing> addr;
   6296  Nothing unused_value;
   6297  if (!iter_.readStore(resultType, Scalar::byteSize(viewType), &addr,
   6298                       &unused_value)) {
   6299    return false;
   6300  }
   6301  if (deadCode_) {
   6302    return true;
   6303  }
   6304  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6305                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
   6306  storeCommon(&access, AccessCheck(), resultType);
   6307  return true;
   6308 }
   6309 
   6310 bool BaseCompiler::emitSelect(bool typed) {
   6311  StackType type;
   6312  Nothing unused_trueValue;
   6313  Nothing unused_falseValue;
   6314  Nothing unused_condition;
   6315  if (!iter_.readSelect(typed, &type, &unused_trueValue, &unused_falseValue,
   6316                        &unused_condition)) {
   6317    return false;
   6318  }
   6319 
   6320  if (deadCode_) {
   6321    resetLatentOp();
   6322    return true;
   6323  }
   6324 
   6325  // I32 condition on top, then false, then true.
   6326 
   6327  Label done;
   6328  BranchState b(&done);
   6329  emitBranchSetup(&b);
   6330 
   6331  switch (type.valType().kind()) {
   6332    case ValType::I32: {
   6333      RegI32 r, rs;
   6334      pop2xI32(&r, &rs);
   6335      if (!emitBranchPerform(&b)) {
   6336        return false;
   6337      }
   6338      moveI32(rs, r);
   6339      masm.bind(&done);
   6340      freeI32(rs);
   6341      pushI32(r);
   6342      break;
   6343    }
   6344    case ValType::I64: {
   6345 #ifdef JS_CODEGEN_X86
   6346      // There may be as many as four Int64 values in registers at a time: two
   6347      // for the latent branch operands, and two for the true/false values we
   6348      // normally pop before executing the branch.  On x86 this is one value
   6349      // too many, so we need to generate more complicated code here, and for
   6350      // simplicity's sake we do so even if the branch operands are not Int64.
   6351      // However, the resulting control flow diamond is complicated since the
   6352      // arms of the diamond will have to stay synchronized with respect to
   6353      // their evaluation stack and regalloc state.  To simplify further, we
   6354      // use a double branch and a temporary boolean value for now.
   6355      RegI32 temp = needI32();
   6356      moveImm32(0, temp);
   6357      if (!emitBranchPerform(&b)) {
   6358        return false;
   6359      }
   6360      moveImm32(1, temp);
   6361      masm.bind(&done);
   6362 
   6363      Label trueValue;
   6364      RegI64 r, rs;
   6365      pop2xI64(&r, &rs);
   6366      masm.branch32(Assembler::Equal, temp, Imm32(0), &trueValue);
   6367      moveI64(rs, r);
   6368      masm.bind(&trueValue);
   6369      freeI32(temp);
   6370      freeI64(rs);
   6371      pushI64(r);
   6372 #else
   6373      RegI64 r, rs;
   6374      pop2xI64(&r, &rs);
   6375      if (!emitBranchPerform(&b)) {
   6376        return false;
   6377      }
   6378      moveI64(rs, r);
   6379      masm.bind(&done);
   6380      freeI64(rs);
   6381      pushI64(r);
   6382 #endif
   6383      break;
   6384    }
   6385    case ValType::F32: {
   6386      RegF32 r, rs;
   6387      pop2xF32(&r, &rs);
   6388      if (!emitBranchPerform(&b)) {
   6389        return false;
   6390      }
   6391      moveF32(rs, r);
   6392      masm.bind(&done);
   6393      freeF32(rs);
   6394      pushF32(r);
   6395      break;
   6396    }
   6397    case ValType::F64: {
   6398      RegF64 r, rs;
   6399      pop2xF64(&r, &rs);
   6400      if (!emitBranchPerform(&b)) {
   6401        return false;
   6402      }
   6403      moveF64(rs, r);
   6404      masm.bind(&done);
   6405      freeF64(rs);
   6406      pushF64(r);
   6407      break;
   6408    }
   6409 #ifdef ENABLE_WASM_SIMD
   6410    case ValType::V128: {
   6411      RegV128 r, rs;
   6412      pop2xV128(&r, &rs);
   6413      if (!emitBranchPerform(&b)) {
   6414        return false;
   6415      }
   6416      moveV128(rs, r);
   6417      masm.bind(&done);
   6418      freeV128(rs);
   6419      pushV128(r);
   6420      break;
   6421    }
   6422 #endif
   6423    case ValType::Ref: {
   6424      RegRef r, rs;
   6425      pop2xRef(&r, &rs);
   6426      if (!emitBranchPerform(&b)) {
   6427        return false;
   6428      }
   6429      moveRef(rs, r);
   6430      masm.bind(&done);
   6431      freeRef(rs);
   6432      pushRef(r);
   6433      break;
   6434    }
   6435    default: {
   6436      MOZ_CRASH("select type");
   6437    }
   6438  }
   6439 
   6440  return true;
   6441 }
   6442 
   6443 void BaseCompiler::emitCompareI32(Assembler::Condition compareOp,
   6444                                  ValType compareType) {
   6445  MOZ_ASSERT(compareType == ValType::I32);
   6446 
   6447  if (sniffConditionalControlCmp(compareOp, compareType)) {
   6448    return;
   6449  }
   6450 
   6451  int32_t c;
   6452  if (popConst(&c)) {
   6453    RegI32 r = popI32();
   6454    masm.cmp32Set(compareOp, r, Imm32(c), r);
   6455    pushI32(r);
   6456  } else {
   6457    RegI32 r, rs;
   6458    pop2xI32(&r, &rs);
   6459    masm.cmp32Set(compareOp, r, rs, r);
   6460    freeI32(rs);
   6461    pushI32(r);
   6462  }
   6463 }
   6464 
   6465 void BaseCompiler::emitCompareI64(Assembler::Condition compareOp,
   6466                                  ValType compareType) {
   6467  MOZ_ASSERT(compareType == ValType::I64);
   6468 
   6469  if (sniffConditionalControlCmp(compareOp, compareType)) {
   6470    return;
   6471  }
   6472 
   6473  RegI64 rs0, rs1;
   6474  pop2xI64(&rs0, &rs1);
   6475  RegI32 rd(fromI64(rs0));
   6476  cmp64Set(compareOp, rs0, rs1, rd);
   6477  freeI64(rs1);
   6478  freeI64Except(rs0, rd);
   6479  pushI32(rd);
   6480 }
   6481 
   6482 void BaseCompiler::emitCompareF32(Assembler::DoubleCondition compareOp,
   6483                                  ValType compareType) {
   6484  MOZ_ASSERT(compareType == ValType::F32);
   6485 
   6486  if (sniffConditionalControlCmp(compareOp, compareType)) {
   6487    return;
   6488  }
   6489 
   6490  Label across;
   6491  RegF32 rs0, rs1;
   6492  pop2xF32(&rs0, &rs1);
   6493  RegI32 rd = needI32();
   6494  moveImm32(1, rd);
   6495  masm.branchFloat(compareOp, rs0, rs1, &across);
   6496  moveImm32(0, rd);
   6497  masm.bind(&across);
   6498  freeF32(rs0);
   6499  freeF32(rs1);
   6500  pushI32(rd);
   6501 }
   6502 
   6503 void BaseCompiler::emitCompareF64(Assembler::DoubleCondition compareOp,
   6504                                  ValType compareType) {
   6505  MOZ_ASSERT(compareType == ValType::F64);
   6506 
   6507  if (sniffConditionalControlCmp(compareOp, compareType)) {
   6508    return;
   6509  }
   6510 
   6511  Label across;
   6512  RegF64 rs0, rs1;
   6513  pop2xF64(&rs0, &rs1);
   6514  RegI32 rd = needI32();
   6515  moveImm32(1, rd);
   6516  masm.branchDouble(compareOp, rs0, rs1, &across);
   6517  moveImm32(0, rd);
   6518  masm.bind(&across);
   6519  freeF64(rs0);
   6520  freeF64(rs1);
   6521  pushI32(rd);
   6522 }
   6523 
   6524 void BaseCompiler::emitCompareRef(Assembler::Condition compareOp,
   6525                                  ValType compareType) {
   6526  MOZ_ASSERT(!sniffConditionalControlCmp(compareOp, compareType));
   6527 
   6528  RegRef rs1, rs2;
   6529  pop2xRef(&rs1, &rs2);
   6530  RegI32 rd = needI32();
   6531  masm.cmpPtrSet(compareOp, rs1, rs2, rd);
   6532  freeRef(rs1);
   6533  freeRef(rs2);
   6534  pushI32(rd);
   6535 }
   6536 
   6537 bool BaseCompiler::emitInstanceCall(const SymbolicAddressSignature& builtin) {
   6538  // See declaration (WasmBCClass.h) for info on the relationship between the
   6539  // compiler's value stack and the argument order for the to-be-called
   6540  // function.
   6541  const MIRType* argTypes = builtin.argTypes;
   6542  MOZ_ASSERT(argTypes[0] == MIRType::Pointer);
   6543 
   6544  sync();
   6545 
   6546  uint32_t numNonInstanceArgs = builtin.numArgs - 1 /* instance */;
   6547  size_t stackSpace = stackConsumed(numNonInstanceArgs);
   6548 
   6549  FunctionCall baselineCall(ABIForBuiltin(builtin.identity),
   6550                            RestoreState::PinnedRegs);
   6551  beginCall(baselineCall);
   6552 
   6553  ABIArg instanceArg = reservePointerArgument(&baselineCall);
   6554 
   6555  startCallArgs(StackArgAreaSizeUnaligned(builtin, baselineCall.abiKind),
   6556                &baselineCall);
   6557  for (uint32_t i = 1; i < builtin.numArgs; i++) {
   6558    ValType t;
   6559    switch (argTypes[i]) {
   6560      case MIRType::Int32:
   6561        t = ValType::I32;
   6562        break;
   6563      case MIRType::Int64:
   6564        t = ValType::I64;
   6565        break;
   6566      case MIRType::Float32:
   6567        t = ValType::F32;
   6568        break;
   6569      case MIRType::WasmAnyRef:
   6570        t = RefType::extern_();
   6571        break;
   6572      case MIRType::Pointer:
   6573        // Instance function args can now be uninterpreted pointers (eg, for
   6574        // the cases PostBarrier and PostBarrierFilter) so we simply treat
   6575        // them like the equivalently sized integer.
   6576        t = ValType::fromMIRType(TargetWordMIRType());
   6577        break;
   6578      default:
   6579        MOZ_CRASH("Unexpected type");
   6580    }
   6581    passArg(t, peek(numNonInstanceArgs - i), &baselineCall);
   6582  }
   6583  CodeOffset raOffset =
   6584      builtinInstanceMethodCall(builtin, instanceArg, baselineCall);
   6585  if (!createStackMap("emitInstanceCall", raOffset)) {
   6586    return false;
   6587  }
   6588 
   6589  endCall(baselineCall, stackSpace);
   6590 
   6591  popValueStackBy(numNonInstanceArgs);
   6592 
   6593  // Note, many clients of emitInstanceCall currently assume that pushing the
   6594  // result here does not destroy ReturnReg.
   6595  //
   6596  // Furthermore, clients assume that if builtin.retType != MIRType::None, the
   6597  // callee will have returned a result and left it in ReturnReg for us to
   6598  // find, and that that register will not be destroyed here (or above).
   6599 
   6600  // For the return type only, MIRType::None is used to indicate that the
   6601  // call doesn't return a result, that is, returns a C/C++ "void".
   6602 
   6603  if (builtin.retType != MIRType::None) {
   6604    pushBuiltinCallResult(baselineCall, builtin.retType);
   6605  }
   6606  return true;
   6607 }
   6608 
   6609 //////////////////////////////////////////////////////////////////////////////
   6610 //
   6611 // Reference types.
   6612 
   6613 bool BaseCompiler::emitRefFunc() {
   6614  return emitInstanceCallOp<uint32_t>(SASigRefFunc,
   6615                                      [this](uint32_t* funcIndex) -> bool {
   6616                                        return iter_.readRefFunc(funcIndex);
   6617                                      });
   6618 }
   6619 
   6620 bool BaseCompiler::emitRefNull() {
   6621  RefType type;
   6622  if (!iter_.readRefNull(&type)) {
   6623    return false;
   6624  }
   6625 
   6626  if (deadCode_) {
   6627    return true;
   6628  }
   6629 
   6630  pushRef(AnyRef::NullRefValue);
   6631  return true;
   6632 }
   6633 
   6634 bool BaseCompiler::emitRefIsNull() {
   6635  Nothing nothing;
   6636  if (!iter_.readRefIsNull(&nothing)) {
   6637    return false;
   6638  }
   6639 
   6640  if (deadCode_) {
   6641    return true;
   6642  }
   6643 
   6644  RegRef r = popRef();
   6645  RegI32 rd = narrowRef(r);
   6646 
   6647  masm.cmpPtrSet(Assembler::Equal, r, ImmWord(AnyRef::NullRefValue), rd);
   6648  pushI32(rd);
   6649  return true;
   6650 }
   6651 
   6652 bool BaseCompiler::emitRefAsNonNull() {
   6653  Nothing nothing;
   6654  if (!iter_.readRefAsNonNull(&nothing)) {
   6655    return false;
   6656  }
   6657 
   6658  if (deadCode_) {
   6659    return true;
   6660  }
   6661 
   6662  RegRef rp = popRef();
   6663  Label ok;
   6664  masm.branchWasmAnyRefIsNull(false, rp, &ok);
   6665  trap(Trap::NullPointerDereference);
   6666  masm.bind(&ok);
   6667  pushRef(rp);
   6668 
   6669  return true;
   6670 }
   6671 
   6672 //////////////////////////////////////////////////////////////////////////////
   6673 //
   6674 // Atomic operations.
   6675 
   6676 bool BaseCompiler::emitAtomicCmpXchg(ValType type, Scalar::Type viewType) {
   6677  LinearMemoryAddress<Nothing> addr;
   6678  Nothing unused{};
   6679  if (!iter_.readAtomicCmpXchg(&addr, type, Scalar::byteSize(viewType), &unused,
   6680                               &unused)) {
   6681    return false;
   6682  }
   6683  if (deadCode_) {
   6684    return true;
   6685  }
   6686  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6687                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex),
   6688                          Synchronization::Full());
   6689  atomicCmpXchg(&access, type);
   6690  return true;
   6691 }
   6692 
   6693 bool BaseCompiler::emitAtomicLoad(ValType type, Scalar::Type viewType) {
   6694  LinearMemoryAddress<Nothing> addr;
   6695  if (!iter_.readAtomicLoad(&addr, type, Scalar::byteSize(viewType))) {
   6696    return false;
   6697  }
   6698  if (deadCode_) {
   6699    return true;
   6700  }
   6701  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6702                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex),
   6703                          Synchronization::Load());
   6704  atomicLoad(&access, type);
   6705  return true;
   6706 }
   6707 
   6708 bool BaseCompiler::emitAtomicRMW(ValType type, Scalar::Type viewType,
   6709                                 AtomicOp op) {
   6710  LinearMemoryAddress<Nothing> addr;
   6711  Nothing unused_value;
   6712  if (!iter_.readAtomicRMW(&addr, type, Scalar::byteSize(viewType),
   6713                           &unused_value)) {
   6714    return false;
   6715  }
   6716  if (deadCode_) {
   6717    return true;
   6718  }
   6719  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6720                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex),
   6721                          Synchronization::Full());
   6722  atomicRMW(&access, type, op);
   6723  return true;
   6724 }
   6725 
   6726 bool BaseCompiler::emitAtomicStore(ValType type, Scalar::Type viewType) {
   6727  LinearMemoryAddress<Nothing> addr;
   6728  Nothing unused_value;
   6729  if (!iter_.readAtomicStore(&addr, type, Scalar::byteSize(viewType),
   6730                             &unused_value)) {
   6731    return false;
   6732  }
   6733  if (deadCode_) {
   6734    return true;
   6735  }
   6736  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6737                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex),
   6738                          Synchronization::Store());
   6739  atomicStore(&access, type);
   6740  return true;
   6741 }
   6742 
   6743 bool BaseCompiler::emitAtomicXchg(ValType type, Scalar::Type viewType) {
   6744  LinearMemoryAddress<Nothing> addr;
   6745  Nothing unused_value;
   6746  if (!iter_.readAtomicRMW(&addr, type, Scalar::byteSize(viewType),
   6747                           &unused_value)) {
   6748    return false;
   6749  }
   6750  if (deadCode_) {
   6751    return true;
   6752  }
   6753  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
   6754                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex),
   6755                          Synchronization::Full());
   6756  atomicXchg(&access, type);
   6757  return true;
   6758 }
   6759 
   6760 bool BaseCompiler::emitWait(ValType type, uint32_t byteSize) {
   6761  Nothing nothing;
   6762  LinearMemoryAddress<Nothing> addr;
   6763  if (!iter_.readWait(&addr, type, byteSize, &nothing, &nothing)) {
   6764    return false;
   6765  }
   6766  if (deadCode_) {
   6767    return true;
   6768  }
   6769  MemoryAccessDesc access(
   6770      addr.memoryIndex,
   6771      type.kind() == ValType::I32 ? Scalar::Int32 : Scalar::Int64, addr.align,
   6772      addr.offset, trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
   6773  return atomicWait(type, &access);
   6774 }
   6775 
   6776 bool BaseCompiler::emitNotify() {
   6777  Nothing nothing;
   6778  LinearMemoryAddress<Nothing> addr;
   6779  if (!iter_.readNotify(&addr, &nothing)) {
   6780    return false;
   6781  }
   6782  if (deadCode_) {
   6783    return true;
   6784  }
   6785  MemoryAccessDesc access(addr.memoryIndex, Scalar::Int32, addr.align,
   6786                          addr.offset, trapSiteDesc(),
   6787                          hugeMemoryEnabled(addr.memoryIndex));
   6788  return atomicNotify(&access);
   6789 }
   6790 
   6791 bool BaseCompiler::emitFence() {
   6792  if (!iter_.readFence()) {
   6793    return false;
   6794  }
   6795  if (deadCode_) {
   6796    return true;
   6797  }
   6798  masm.memoryBarrier(MemoryBarrier::Full());
   6799  return true;
   6800 }
   6801 
   6802 //////////////////////////////////////////////////////////////////////////////
   6803 //
   6804 // Bulk memory operations.
   6805 
   6806 bool BaseCompiler::emitMemoryGrow() {
   6807  uint32_t memoryIndex;
   6808  Nothing nothing;
   6809  if (!iter_.readMemoryGrow(&memoryIndex, &nothing)) {
   6810    return false;
   6811  }
   6812  if (deadCode_) {
   6813    return true;
   6814  }
   6815 
   6816  pushI32(memoryIndex);
   6817  return emitInstanceCall(isMem32(memoryIndex) ? SASigMemoryGrowM32
   6818                                               : SASigMemoryGrowM64);
   6819 }
   6820 
   6821 bool BaseCompiler::emitMemorySize() {
   6822  uint32_t memoryIndex;
   6823  if (!iter_.readMemorySize(&memoryIndex)) {
   6824    return false;
   6825  }
   6826  if (deadCode_) {
   6827    return true;
   6828  }
   6829 
   6830  pushI32(memoryIndex);
   6831  return emitInstanceCall(isMem32(memoryIndex) ? SASigMemorySizeM32
   6832                                               : SASigMemorySizeM64);
   6833 }
   6834 
   6835 bool BaseCompiler::emitMemCopy() {
   6836  uint32_t dstMemIndex = 0;
   6837  uint32_t srcMemIndex = 0;
   6838  Nothing nothing;
   6839  if (!iter_.readMemOrTableCopy(true, &dstMemIndex, &nothing, &srcMemIndex,
   6840                                &nothing, &nothing)) {
   6841    return false;
   6842  }
   6843  if (deadCode_) {
   6844    return true;
   6845  }
   6846 
   6847  if (dstMemIndex == 0 && srcMemIndex == 0 && isMem32(dstMemIndex)) {
   6848    int32_t signedLength;
   6849    if (peekConst(&signedLength) && signedLength != 0 &&
   6850        uint32_t(signedLength) <= MaxInlineMemoryCopyLength) {
   6851      memCopyInlineM32();
   6852      return true;
   6853    }
   6854  }
   6855 
   6856  return memCopyCall(dstMemIndex, srcMemIndex);
   6857 }
   6858 
   6859 bool BaseCompiler::memCopyCall(uint32_t dstMemIndex, uint32_t srcMemIndex) {
   6860  // Common and optimized path for when the src/dest memories are the same
   6861  if (dstMemIndex == srcMemIndex) {
   6862    bool mem32 = isMem32(dstMemIndex);
   6863    pushHeapBase(dstMemIndex);
   6864    return emitInstanceCall(
   6865        usesSharedMemory(dstMemIndex)
   6866            ? (mem32 ? SASigMemCopySharedM32 : SASigMemCopySharedM64)
   6867            : (mem32 ? SASigMemCopyM32 : SASigMemCopyM64));
   6868  }
   6869 
   6870  // Do the general-purpose fallback for copying between any combination of
   6871  // memories. This works by moving everything to the lowest-common denominator.
   6872  // i32 addresses are promoted to i64, and non-shared memories are treated as
   6873  // shared.
   6874  AddressType dstAddressType = codeMeta_.memories[dstMemIndex].addressType();
   6875  AddressType srcAddressType = codeMeta_.memories[srcMemIndex].addressType();
   6876  AddressType lenAddressType = MinAddressType(dstAddressType, srcAddressType);
   6877 
   6878  // Pop the operands off of the stack and widen them
   6879  RegI64 len = popAddressToInt64(lenAddressType);
   6880 #ifdef JS_CODEGEN_X86
   6881  {
   6882    // Stash the length value to prevent running out of registers
   6883    ScratchPtr scratch(*this);
   6884    stashI64(scratch, len);
   6885    freeI64(len);
   6886  }
   6887 #endif
   6888  RegI64 srcIndex = popAddressToInt64(srcAddressType);
   6889  RegI64 dstIndex = popAddressToInt64(dstAddressType);
   6890 
   6891  pushI64(dstIndex);
   6892  pushI64(srcIndex);
   6893 #ifdef JS_CODEGEN_X86
   6894  {
   6895    // Unstash the length value and push it back on the stack
   6896    ScratchPtr scratch(*this);
   6897    len = needI64();
   6898    unstashI64(scratch, len);
   6899  }
   6900 #endif
   6901  pushI64(len);
   6902  pushI32(dstMemIndex);
   6903  pushI32(srcMemIndex);
   6904  return emitInstanceCall(SASigMemCopyAny);
   6905 }
   6906 
   6907 bool BaseCompiler::emitMemFill() {
   6908  uint32_t memoryIndex;
   6909  Nothing nothing;
   6910  if (!iter_.readMemFill(&memoryIndex, &nothing, &nothing, &nothing)) {
   6911    return false;
   6912  }
   6913  if (deadCode_) {
   6914    return true;
   6915  }
   6916 
   6917  if (memoryIndex == 0 && isMem32(memoryIndex)) {
   6918    int32_t signedLength;
   6919    int32_t signedValue;
   6920    if (peek2xConst(&signedLength, &signedValue) && signedLength != 0 &&
   6921        uint32_t(signedLength) <= MaxInlineMemoryFillLength) {
   6922      memFillInlineM32();
   6923      return true;
   6924    }
   6925  }
   6926  return memFillCall(memoryIndex);
   6927 }
   6928 
   6929 bool BaseCompiler::memFillCall(uint32_t memoryIndex) {
   6930  pushHeapBase(memoryIndex);
   6931  return emitInstanceCall(
   6932      usesSharedMemory(memoryIndex)
   6933          ? (isMem32(memoryIndex) ? SASigMemFillSharedM32
   6934                                  : SASigMemFillSharedM64)
   6935          : (isMem32(memoryIndex) ? SASigMemFillM32 : SASigMemFillM64));
   6936 }
   6937 
   6938 bool BaseCompiler::emitMemInit() {
   6939  uint32_t segIndex;
   6940  uint32_t memIndex;
   6941  Nothing nothing;
   6942  if (!iter_.readMemOrTableInit(/*isMem*/ true, &segIndex, &memIndex, &nothing,
   6943                                &nothing, &nothing)) {
   6944    return false;
   6945  }
   6946  if (deadCode_) {
   6947    return true;
   6948  }
   6949 
   6950  pushI32(segIndex);
   6951  pushI32(memIndex);
   6952  return emitInstanceCall(isMem32(memIndex) ? SASigMemInitM32
   6953                                            : SASigMemInitM64);
   6954 }
   6955 
   6956 //////////////////////////////////////////////////////////////////////////////
   6957 //
   6958 // Bulk table operations.
   6959 
   6960 bool BaseCompiler::emitTableCopy() {
   6961  uint32_t dstTable = 0;
   6962  uint32_t srcTable = 0;
   6963  Nothing nothing;
   6964  if (!iter_.readMemOrTableCopy(false, &dstTable, &nothing, &srcTable, &nothing,
   6965                                &nothing)) {
   6966    return false;
   6967  }
   6968 
   6969  if (deadCode_) {
   6970    return true;
   6971  }
   6972 
   6973  AddressType dstAddressType = codeMeta_.tables[dstTable].addressType();
   6974  AddressType srcAddressType = codeMeta_.tables[srcTable].addressType();
   6975  AddressType lenAddressType = MinAddressType(dstAddressType, srcAddressType);
   6976 
   6977  // Instance::tableCopy(dstOffset:u32, srcOffset:u32, len:u32, dstTable:u32,
   6978  // srcTable:u32)
   6979  RegI32 len = popTableAddressToClampedInt32(lenAddressType);
   6980  RegI32 src = popTableAddressToClampedInt32(srcAddressType);
   6981  replaceTableAddressWithClampedInt32(dstAddressType);
   6982  pushI32(src);
   6983  pushI32(len);
   6984  pushI32(dstTable);
   6985  pushI32(srcTable);
   6986  return emitInstanceCall(SASigTableCopy);
   6987 }
   6988 
   6989 bool BaseCompiler::emitTableInit() {
   6990  uint32_t segIndex = 0;
   6991  uint32_t dstTable = 0;
   6992  Nothing nothing;
   6993  if (!iter_.readMemOrTableInit(false, &segIndex, &dstTable, &nothing, &nothing,
   6994                                &nothing)) {
   6995    return false;
   6996  }
   6997 
   6998  if (deadCode_) {
   6999    return true;
   7000  }
   7001 
   7002  // Instance::tableInit(dst:u32, src:u32, len:u32, seg:u32, table:u32)
   7003  RegI32 len = popI32();
   7004  RegI32 src = popI32();
   7005  replaceTableAddressWithClampedInt32(codeMeta_.tables[dstTable].addressType());
   7006  pushI32(src);
   7007  pushI32(len);
   7008  pushI32(segIndex);
   7009  pushI32(dstTable);
   7010  return emitInstanceCall(SASigTableInit);
   7011 }
   7012 
   7013 bool BaseCompiler::emitTableFill() {
   7014  uint32_t tableIndex;
   7015  Nothing nothing;
   7016  if (!iter_.readTableFill(&tableIndex, &nothing, &nothing, &nothing)) {
   7017    return false;
   7018  }
   7019  if (deadCode_) {
   7020    return true;
   7021  }
   7022 
   7023  AddressType addressType = codeMeta_.tables[tableIndex].addressType();
   7024 
   7025  // Instance::tableFill(start:u32, val:ref, len:u32, table:u32) -> void
   7026  RegI32 len = popTableAddressToClampedInt32(addressType);
   7027  AnyReg val = popAny();
   7028  replaceTableAddressWithClampedInt32(addressType);
   7029  pushAny(val);
   7030  pushI32(len);
   7031  pushI32(tableIndex);
   7032  return emitInstanceCall(SASigTableFill);
   7033 }
   7034 
   7035 bool BaseCompiler::emitMemDiscard() {
   7036  uint32_t memoryIndex;
   7037  Nothing nothing;
   7038  if (!iter_.readMemDiscard(&memoryIndex, &nothing, &nothing)) {
   7039    return false;
   7040  }
   7041  if (deadCode_) {
   7042    return true;
   7043  }
   7044 
   7045  pushHeapBase(memoryIndex);
   7046  return emitInstanceCall(
   7047      usesSharedMemory(memoryIndex)
   7048          ? (isMem32(memoryIndex) ? SASigMemDiscardSharedM32
   7049                                  : SASigMemDiscardSharedM64)
   7050          : (isMem32(memoryIndex) ? SASigMemDiscardM32 : SASigMemDiscardM64));
   7051 }
   7052 
   7053 bool BaseCompiler::emitTableGet() {
   7054  uint32_t tableIndex;
   7055  Nothing nothing;
   7056  if (!iter_.readTableGet(&tableIndex, &nothing)) {
   7057    return false;
   7058  }
   7059  if (deadCode_) {
   7060    return true;
   7061  }
   7062 
   7063  replaceTableAddressWithClampedInt32(
   7064      codeMeta_.tables[tableIndex].addressType());
   7065  if (codeMeta_.tables[tableIndex].elemType.tableRepr() == TableRepr::Ref) {
   7066    return emitTableGetAnyRef(tableIndex);
   7067  }
   7068  pushI32(tableIndex);
   7069  // Instance::tableGet(index:u32, table:u32) -> AnyRef
   7070  return emitInstanceCall(SASigTableGet);
   7071 }
   7072 
   7073 bool BaseCompiler::emitTableGrow() {
   7074  uint32_t tableIndex;
   7075  Nothing nothing;
   7076  if (!iter_.readTableGrow(&tableIndex, &nothing, &nothing)) {
   7077    return false;
   7078  }
   7079  if (deadCode_) {
   7080    return true;
   7081  }
   7082 
   7083  AddressType addressType = codeMeta_.tables[tableIndex].addressType();
   7084 
   7085  // Instance::tableGrow(initValue:anyref, delta:u32, table:u32) -> u32
   7086  replaceTableAddressWithClampedInt32(addressType);
   7087  pushI32(tableIndex);
   7088  if (!emitInstanceCall(SASigTableGrow)) {
   7089    return false;
   7090  }
   7091 
   7092  if (addressType == AddressType::I64) {
   7093    RegI64 r;
   7094    popI32ForSignExtendI64(&r);
   7095    masm.move32To64SignExtend(lowPart(r), r);
   7096    pushI64(r);
   7097  }
   7098 
   7099  return true;
   7100 }
   7101 
   7102 bool BaseCompiler::emitTableSet() {
   7103  uint32_t tableIndex;
   7104  Nothing nothing;
   7105  if (!iter_.readTableSet(&tableIndex, &nothing, &nothing)) {
   7106    return false;
   7107  }
   7108  if (deadCode_) {
   7109    return true;
   7110  }
   7111  if (codeMeta_.tables[tableIndex].addressType() == AddressType::I64) {
   7112    AnyReg value = popAny();
   7113    replaceTableAddressWithClampedInt32(AddressType::I64);
   7114    pushAny(value);
   7115  }
   7116  if (codeMeta_.tables[tableIndex].elemType.tableRepr() == TableRepr::Ref) {
   7117    return emitTableSetAnyRef(tableIndex);
   7118  }
   7119  pushI32(tableIndex);
   7120  // Instance::tableSet(address:u32, value:ref, table:u32) -> void
   7121  return emitInstanceCall(SASigTableSet);
   7122 }
   7123 
   7124 bool BaseCompiler::emitTableSize() {
   7125  uint32_t tableIndex;
   7126  if (!iter_.readTableSize(&tableIndex)) {
   7127    return false;
   7128  }
   7129  if (deadCode_) {
   7130    return true;
   7131  }
   7132 
   7133  RegPtr instance = needPtr();
   7134  RegI32 length = needI32();
   7135 
   7136  fr.loadInstancePtr(instance);
   7137  loadTableLength(tableIndex, instance, length);
   7138 
   7139  if (codeMeta_.tables[tableIndex].addressType() == AddressType::I64) {
   7140    pushU32AsI64(length);
   7141  } else {
   7142    pushI32(length);
   7143  }
   7144  freePtr(instance);
   7145  return true;
   7146 }
   7147 
   7148 void BaseCompiler::emitTableBoundsCheck(uint32_t tableIndex, RegI32 address,
   7149                                        RegPtr instance) {
   7150  Label ok;
   7151  masm.wasmBoundsCheck32(
   7152      Assembler::Condition::Below, address,
   7153      addressOfTableField(tableIndex, offsetof(TableInstanceData, length),
   7154                          instance),
   7155      &ok);
   7156  trap(wasm::Trap::OutOfBounds);
   7157  masm.bind(&ok);
   7158 }
   7159 
   7160 bool BaseCompiler::emitTableGetAnyRef(uint32_t tableIndex) {
   7161  RegPtr instance = needPtr();
   7162  RegPtr elements = needPtr();
   7163  RegI32 address = popI32();
   7164 
   7165  fr.loadInstancePtr(instance);
   7166  emitTableBoundsCheck(tableIndex, address, instance);
   7167  loadTableElements(tableIndex, instance, elements);
   7168  masm.loadPtr(BaseIndex(elements, address, ScalePointer), elements);
   7169 
   7170  pushRef(RegRef(elements));
   7171  freeI32(address);
   7172  freePtr(instance);
   7173 
   7174  return true;
   7175 }
   7176 
   7177 bool BaseCompiler::emitTableSetAnyRef(uint32_t tableIndex) {
   7178  // Create temporaries for valueAddr that is not in the prebarrier register
   7179  // and can be consumed by the barrier operation
   7180  RegPtr valueAddr = RegPtr(PreBarrierReg);
   7181  needPtr(valueAddr);
   7182 
   7183  RegPtr instance = needPtr();
   7184  RegPtr elements = needPtr();
   7185  RegRef value = popRef();
   7186  RegI32 address = popI32();
   7187 
   7188  // x86 is one register too short for this operation, shuffle `value` back
   7189  // onto the stack until it is needed.
   7190 #ifdef JS_CODEGEN_X86
   7191  pushRef(value);
   7192 #endif
   7193 
   7194  fr.loadInstancePtr(instance);
   7195  emitTableBoundsCheck(tableIndex, address, instance);
   7196  loadTableElements(tableIndex, instance, elements);
   7197  masm.computeEffectiveAddress(BaseIndex(elements, address, ScalePointer),
   7198                               valueAddr);
   7199 
   7200  freeI32(address);
   7201  freePtr(elements);
   7202  freePtr(instance);
   7203 
   7204 #ifdef JS_CODEGEN_X86
   7205  value = popRef();
   7206 #endif
   7207 
   7208  if (!emitBarrieredStore(Nothing(), valueAddr, value, PreBarrierKind::Normal,
   7209                          PostBarrierKind::Precise)) {
   7210    return false;
   7211  }
   7212  freeRef(value);
   7213  return true;
   7214 }
   7215 
   7216 //////////////////////////////////////////////////////////////////////////////
   7217 //
   7218 // Data and element segment management.
   7219 
   7220 bool BaseCompiler::emitDataOrElemDrop(bool isData) {
   7221  return emitInstanceCallOp<uint32_t>(
   7222      isData ? SASigDataDrop : SASigElemDrop, [&](uint32_t* segIndex) -> bool {
   7223        return iter_.readDataOrElemDrop(isData, segIndex);
   7224      });
   7225 }
   7226 
   7227 //////////////////////////////////////////////////////////////////////////////
   7228 //
   7229 // General object support.
   7230 
   7231 void BaseCompiler::emitPreBarrier(RegPtr valueAddr) {
   7232  Label skipBarrier;
   7233  ScratchPtr scratch(*this);
   7234 
   7235 #ifdef RABALDR_PIN_INSTANCE
   7236  Register instance(InstanceReg);
   7237 #else
   7238  Register instance(scratch);
   7239  fr.loadInstancePtr(instance);
   7240 #endif
   7241 
   7242  EmitWasmPreBarrierGuard(masm, instance, scratch, Address(valueAddr, 0),
   7243                          &skipBarrier, mozilla::Nothing());
   7244 
   7245 #ifndef RABALDR_PIN_INSTANCE
   7246  fr.loadInstancePtr(instance);
   7247 #endif
   7248 #ifdef JS_CODEGEN_ARM64
   7249  // The prebarrier stub assumes the PseudoStackPointer is set up.  It is OK
   7250  // to just move the sp to x28 here because x28 is not being used by the
   7251  // baseline compiler and need not be saved or restored.
   7252  MOZ_ASSERT(!GeneralRegisterSet::All().hasRegisterIndex(x28.asUnsized()));
   7253  masm.Mov(x28, sp);
   7254 #endif
   7255  // The prebarrier call preserves all volatile registers
   7256  EmitWasmPreBarrierCallImmediate(masm, instance, scratch, valueAddr,
   7257                                  /*valueOffset=*/0);
   7258 
   7259  masm.bind(&skipBarrier);
   7260 }
   7261 
   7262 bool BaseCompiler::emitPostBarrierWholeCell(RegRef object, RegRef value,
   7263                                            RegPtr temp) {
   7264  // We must force a sync before the guard so that locals are in a consistent
   7265  // location for whether or not the post-barrier call is taken.
   7266  sync();
   7267 
   7268  // Emit guards to skip the post-barrier call if it is not needed.
   7269  Label skipBarrier;
   7270  EmitWasmPostBarrierGuard(masm, mozilla::Some(object), temp, value,
   7271                           &skipBarrier);
   7272 
   7273 #ifdef RABALDR_PIN_INSTANCE
   7274  Register instance(InstanceReg);
   7275 #else
   7276  Register instance(temp);
   7277  fr.loadInstancePtr(instance);
   7278 #endif
   7279  CheckWholeCellLastElementCache(masm, instance, object, temp, &skipBarrier);
   7280 
   7281  movePtr(RegPtr(object), temp);
   7282 
   7283  // Push `object` and `value` to preserve them across the call.
   7284  pushRef(object);
   7285  pushRef(value);
   7286 
   7287  pushPtr(temp);
   7288  if (!emitInstanceCall(SASigPostBarrierWholeCell)) {
   7289    return false;
   7290  }
   7291 
   7292  // Restore `object` and `value`.
   7293  popRef(value);
   7294  popRef(object);
   7295 
   7296  masm.bind(&skipBarrier);
   7297  return true;
   7298 }
   7299 
   7300 bool BaseCompiler::emitPostBarrierEdgeImprecise(const Maybe<RegRef>& object,
   7301                                                RegPtr valueAddr,
   7302                                                RegRef value) {
   7303  // We must force a sync before the guard so that locals are in a consistent
   7304  // location for whether or not the post-barrier call is taken.
   7305  sync();
   7306 
   7307  // Emit a guard to skip the post-barrier call if it is not needed.
   7308  Label skipBarrier;
   7309  RegPtr otherScratch = needPtr();
   7310  EmitWasmPostBarrierGuard(masm, object, otherScratch, value, &skipBarrier);
   7311  freePtr(otherScratch);
   7312 
   7313  // Push `object` and `value` to preserve them across the call.
   7314  if (object) {
   7315    pushRef(*object);
   7316  }
   7317  pushRef(value);
   7318 
   7319  // The `valueAddr` is a raw pointer to the cell within some GC object or
   7320  // instance area, and we are careful so that the GC will not run while the
   7321  // post-barrier call is active, so push a uintptr_t value.
   7322  pushPtr(valueAddr);
   7323  if (!emitInstanceCall(SASigPostBarrierEdge)) {
   7324    return false;
   7325  }
   7326 
   7327  // Restore `object` and `value`.
   7328  popRef(value);
   7329  if (object) {
   7330    popRef(*object);
   7331  }
   7332 
   7333  masm.bind(&skipBarrier);
   7334  return true;
   7335 }
   7336 
   7337 bool BaseCompiler::emitPostBarrierEdgePrecise(const Maybe<RegRef>& object,
   7338                                              RegPtr valueAddr,
   7339                                              RegRef prevValue, RegRef value) {
   7340  // Currently this is only called to write into wasm tables.
   7341  //
   7342  // If this changes and we use this method to write into objects which might be
   7343  // in the nursery then we need to check for that here and skip the barrier (we
   7344  // only need to record pointers from the tenured heap into the nursery).
   7345  MOZ_ASSERT(object.isNothing());
   7346 
   7347  // Push `object` and `value` to preserve them across the call.
   7348  if (object) {
   7349    pushRef(*object);
   7350  }
   7351  pushRef(value);
   7352 
   7353  // Push the arguments and call the precise post-barrier
   7354  pushPtr(valueAddr);
   7355  pushRef(prevValue);
   7356  if (!emitInstanceCall(SASigPostBarrierEdgePrecise)) {
   7357    return false;
   7358  }
   7359 
   7360  // Restore `object` and `value`.
   7361  popRef(value);
   7362  if (object) {
   7363    popRef(*object);
   7364  }
   7365 
   7366  return true;
   7367 }
   7368 
   7369 bool BaseCompiler::emitBarrieredStore(const Maybe<RegRef>& object,
   7370                                      RegPtr valueAddr, RegRef value,
   7371                                      PreBarrierKind preBarrierKind,
   7372                                      PostBarrierKind postBarrierKind) {
   7373  // The pre-barrier preserves all allocated registers.
   7374  if (preBarrierKind == PreBarrierKind::Normal) {
   7375    emitPreBarrier(valueAddr);
   7376  }
   7377 
   7378  // The precise post-barrier requires the previous value stored in the field,
   7379  // in order to know if the previous store buffer entry needs to be removed.
   7380  RegRef prevValue;
   7381  if (postBarrierKind == PostBarrierKind::Precise) {
   7382    prevValue = needRef();
   7383    masm.loadPtr(Address(valueAddr, 0), prevValue);
   7384  }
   7385 
   7386  // Store the value
   7387  masm.storePtr(value, Address(valueAddr, 0));
   7388 
   7389  // The post-barrier preserves object and value.
   7390  switch (postBarrierKind) {
   7391    case PostBarrierKind::None:
   7392      freePtr(valueAddr);
   7393      return true;
   7394    case PostBarrierKind::Imprecise:
   7395      return emitPostBarrierEdgeImprecise(object, valueAddr, value);
   7396    case PostBarrierKind::Precise:
   7397      return emitPostBarrierEdgePrecise(object, valueAddr, prevValue, value);
   7398    case PostBarrierKind::WholeCell:
   7399      // valueAddr is reused as a temp register.
   7400      return emitPostBarrierWholeCell(object.value(), value, valueAddr);
   7401    default:
   7402      MOZ_CRASH("unknown barrier kind");
   7403  }
   7404 }
   7405 
   7406 void BaseCompiler::emitBarrieredClear(RegPtr valueAddr) {
   7407  // The pre-barrier preserves all allocated registers.
   7408  emitPreBarrier(valueAddr);
   7409 
   7410  // Store null
   7411  masm.storePtr(ImmWord(AnyRef::NullRefValue), Address(valueAddr, 0));
   7412 
   7413  // No post-barrier is needed, as null does not require a store buffer entry
   7414 }
   7415 
   7416 //////////////////////////////////////////////////////////////////////////////
   7417 //
   7418 // GC proposal.
   7419 
   7420 RegPtr BaseCompiler::loadAllocSiteInstanceData(uint32_t allocSiteIndex) {
   7421  RegPtr rp = needPtr();
   7422  RegPtr instance;
   7423 #ifndef RABALDR_PIN_INSTANCE
   7424  instance = rp;
   7425  fr.loadInstancePtr(instance);
   7426 #else
   7427  // We can use the pinned instance register.
   7428  instance = RegPtr(InstanceReg);
   7429 #endif
   7430  masm.loadPtr(Address(instance, Instance::offsetOfAllocSites()), rp);
   7431 
   7432  ScratchI32 scratch(*this);
   7433  CodeOffset offset = masm.move32WithPatch(scratch);
   7434  masm.allocSitesPatches()[allocSiteIndex].setPatchOffset(offset.offset());
   7435  masm.addPtr(scratch, rp);
   7436  return rp;
   7437 }
   7438 
   7439 bool BaseCompiler::readAllocSiteIndex(uint32_t* index) {
   7440  *index = masm.allocSitesPatches().length();
   7441  masm.append(wasm::AllocSitePatch());
   7442  return !masm.oom();
   7443 }
   7444 
   7445 RegPtr BaseCompiler::loadSuperTypeVector(uint32_t typeIndex) {
   7446  RegPtr rp = needPtr();
   7447  RegPtr instance;
   7448 #ifndef RABALDR_PIN_INSTANCE
   7449  // We need to load the instance register, but can use the destination
   7450  // register as a temporary.
   7451  instance = rp;
   7452  fr.loadInstancePtr(rp);
   7453 #else
   7454  // We can use the pinned instance register.
   7455  instance = RegPtr(InstanceReg);
   7456 #endif
   7457  masm.loadPtr(
   7458      Address(instance, Instance::offsetInData(
   7459                            codeMeta_.offsetOfSuperTypeVector(typeIndex))),
   7460      rp);
   7461  return rp;
   7462 }
   7463 
   7464 /* static */
   7465 void BaseCompiler::SignalNullCheck::emitNullCheck(BaseCompiler* bc, RegRef rp) {
   7466  Label ok;
   7467  MacroAssembler& masm = bc->masm;
   7468  masm.branchTestPtr(Assembler::NonZero, rp, rp, &ok);
   7469  bc->trap(Trap::NullPointerDereference);
   7470  masm.bind(&ok);
   7471 }
   7472 
   7473 /* static */
   7474 void BaseCompiler::SignalNullCheck::emitTrapSite(BaseCompiler* bc,
   7475                                                 FaultingCodeOffset fco,
   7476                                                 TrapMachineInsn tmi) {
   7477  MacroAssembler& masm = bc->masm;
   7478  masm.append(wasm::Trap::NullPointerDereference, tmi, fco.get(),
   7479              bc->trapSiteDesc());
   7480 }
   7481 
   7482 template <typename NullCheckPolicy>
   7483 RegPtr BaseCompiler::emitGcArrayGetData(RegRef rp) {
   7484  // `rp` points at a WasmArrayObject.  Return a reg holding the value of its
   7485  // `data_` field.
   7486  RegPtr rdata = needPtr();
   7487  FaultingCodeOffset fco =
   7488      masm.loadPtr(Address(rp, WasmArrayObject::offsetOfData()), rdata);
   7489  NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsnForLoadWord());
   7490  return rdata;
   7491 }
   7492 
   7493 template <typename NullCheckPolicy>
   7494 RegI32 BaseCompiler::emitGcArrayGetNumElements(RegRef rp) {
   7495  // `rp` points at a WasmArrayObject.  Return a reg holding the value of its
   7496  // `numElements_` field.
   7497  STATIC_ASSERT_WASMARRAYELEMENTS_NUMELEMENTS_IS_U32;
   7498  RegI32 numElements = needI32();
   7499  FaultingCodeOffset fco = masm.load32(
   7500      Address(rp, WasmArrayObject::offsetOfNumElements()), numElements);
   7501  NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load32);
   7502  return numElements;
   7503 }
   7504 
   7505 void BaseCompiler::emitGcArrayBoundsCheck(RegI32 index, RegI32 numElements) {
   7506  Label inBounds;
   7507  masm.branch32(Assembler::Below, index, numElements, &inBounds);
   7508  trap(Trap::OutOfBounds);
   7509  masm.bind(&inBounds);
   7510 }
   7511 
   7512 template <typename T, typename NullCheckPolicy>
   7513 void BaseCompiler::emitGcGet(StorageType type, FieldWideningOp wideningOp,
   7514                             const T& src) {
   7515  switch (type.kind()) {
   7516    case StorageType::I8: {
   7517      MOZ_ASSERT(wideningOp != FieldWideningOp::None);
   7518      RegI32 r = needI32();
   7519      FaultingCodeOffset fco;
   7520      if (wideningOp == FieldWideningOp::Unsigned) {
   7521        fco = masm.load8ZeroExtend(src, r);
   7522      } else {
   7523        fco = masm.load8SignExtend(src, r);
   7524      }
   7525      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load8);
   7526      pushI32(r);
   7527      break;
   7528    }
   7529    case StorageType::I16: {
   7530      MOZ_ASSERT(wideningOp != FieldWideningOp::None);
   7531      RegI32 r = needI32();
   7532      FaultingCodeOffset fco;
   7533      if (wideningOp == FieldWideningOp::Unsigned) {
   7534        fco = masm.load16ZeroExtend(src, r);
   7535      } else {
   7536        fco = masm.load16SignExtend(src, r);
   7537      }
   7538      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load16);
   7539      pushI32(r);
   7540      break;
   7541    }
   7542    case StorageType::I32: {
   7543      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7544      RegI32 r = needI32();
   7545      FaultingCodeOffset fco = masm.load32(src, r);
   7546      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load32);
   7547      pushI32(r);
   7548      break;
   7549    }
   7550    case StorageType::I64: {
   7551      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7552      RegI64 r = needI64();
   7553 #ifdef JS_64BIT
   7554      FaultingCodeOffset fco = masm.load64(src, r);
   7555      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load64);
   7556 #else
   7557      FaultingCodeOffsetPair fcop = masm.load64(src, r);
   7558      NullCheckPolicy::emitTrapSite(this, fcop.first, TrapMachineInsn::Load32);
   7559      NullCheckPolicy::emitTrapSite(this, fcop.second, TrapMachineInsn::Load32);
   7560 #endif
   7561      pushI64(r);
   7562      break;
   7563    }
   7564    case StorageType::F32: {
   7565      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7566      RegF32 r = needF32();
   7567      FaultingCodeOffset fco = masm.loadFloat32(src, r);
   7568      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load32);
   7569      pushF32(r);
   7570      break;
   7571    }
   7572    case StorageType::F64: {
   7573      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7574      RegF64 r = needF64();
   7575      FaultingCodeOffset fco = masm.loadDouble(src, r);
   7576      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load64);
   7577      pushF64(r);
   7578      break;
   7579    }
   7580 #ifdef ENABLE_WASM_SIMD
   7581    case StorageType::V128: {
   7582      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7583      RegV128 r = needV128();
   7584      FaultingCodeOffset fco = masm.loadUnalignedSimd128(src, r);
   7585      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Load128);
   7586      pushV128(r);
   7587      break;
   7588    }
   7589 #endif
   7590    case StorageType::Ref: {
   7591      MOZ_ASSERT(wideningOp == FieldWideningOp::None);
   7592      RegRef r = needRef();
   7593      FaultingCodeOffset fco = masm.loadPtr(src, r);
   7594      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsnForLoadWord());
   7595      pushRef(r);
   7596      break;
   7597    }
   7598    default: {
   7599      MOZ_CRASH("Unexpected field type");
   7600    }
   7601  }
   7602 }
   7603 
   7604 template <typename T, typename NullCheckPolicy>
   7605 void BaseCompiler::emitGcSetScalar(const T& dst, StorageType type,
   7606                                   AnyReg value) {
   7607  switch (type.kind()) {
   7608    case StorageType::I8: {
   7609      FaultingCodeOffset fco = masm.store8(value.i32(), dst);
   7610      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store8);
   7611      break;
   7612    }
   7613    case StorageType::I16: {
   7614      FaultingCodeOffset fco = masm.store16(value.i32(), dst);
   7615      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store16);
   7616      break;
   7617    }
   7618    case StorageType::I32: {
   7619      FaultingCodeOffset fco = masm.store32(value.i32(), dst);
   7620      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store32);
   7621      break;
   7622    }
   7623    case StorageType::I64: {
   7624 #ifdef JS_64BIT
   7625      FaultingCodeOffset fco = masm.store64(value.i64(), dst);
   7626      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store64);
   7627 #else
   7628      FaultingCodeOffsetPair fcop = masm.store64(value.i64(), dst);
   7629      NullCheckPolicy::emitTrapSite(this, fcop.first, TrapMachineInsn::Store32);
   7630      NullCheckPolicy::emitTrapSite(this, fcop.second,
   7631                                    TrapMachineInsn::Store32);
   7632 #endif
   7633      break;
   7634    }
   7635    case StorageType::F32: {
   7636      FaultingCodeOffset fco = masm.storeFloat32(value.f32(), dst);
   7637      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store32);
   7638      break;
   7639    }
   7640    case StorageType::F64: {
   7641      FaultingCodeOffset fco = masm.storeDouble(value.f64(), dst);
   7642      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store64);
   7643      break;
   7644    }
   7645 #ifdef ENABLE_WASM_SIMD
   7646    case StorageType::V128: {
   7647      FaultingCodeOffset fco = masm.storeUnalignedSimd128(value.v128(), dst);
   7648      NullCheckPolicy::emitTrapSite(this, fco, TrapMachineInsn::Store128);
   7649      break;
   7650    }
   7651 #endif
   7652    default: {
   7653      MOZ_CRASH("Unexpected field type");
   7654    }
   7655  }
   7656 }
   7657 
   7658 template <typename NullCheckPolicy>
   7659 bool BaseCompiler::emitGcStructSet(RegRef object, RegPtr areaBase,
   7660                                   uint32_t areaOffset, StorageType type,
   7661                                   AnyReg value,
   7662                                   PreBarrierKind preBarrierKind) {
   7663  // Easy path if the field is a scalar
   7664  if (!type.isRefRepr()) {
   7665    emitGcSetScalar<Address, NullCheckPolicy>(Address(areaBase, areaOffset),
   7666                                              type, value);
   7667    freeAny(value);
   7668    return true;
   7669  }
   7670 
   7671  // Create temporary for the valueAddr that is not in the prebarrier register
   7672  // and can be consumed by the barrier operation
   7673  RegPtr valueAddr = RegPtr(PreBarrierReg);
   7674  needPtr(valueAddr);
   7675  masm.computeEffectiveAddress(Address(areaBase, areaOffset), valueAddr);
   7676 
   7677  NullCheckPolicy::emitNullCheck(this, object);
   7678 
   7679  // emitBarrieredStore preserves object and value
   7680  if (!emitBarrieredStore(Some(object), valueAddr, value.ref(), preBarrierKind,
   7681                          PostBarrierKind::WholeCell)) {
   7682    return false;
   7683  }
   7684  freeRef(value.ref());
   7685 
   7686  return true;
   7687 }
   7688 
   7689 bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
   7690                                  const ArrayType& arrayType, AnyReg value,
   7691                                  PreBarrierKind preBarrierKind,
   7692                                  PostBarrierKind postBarrierKind) {
   7693  // Try to use a base index store instruction if the field type fits in a
   7694  // shift immediate. If not we shift the index manually and then unshift
   7695  // it after the store. We don't use an extra register for this because we
   7696  // don't have any to spare on x86.
   7697  uint32_t shift = arrayType.elementType().indexingShift();
   7698  Scale scale;
   7699  bool shiftedIndex = false;
   7700  if (IsShiftInScaleRange(shift)) {
   7701    scale = ShiftToScale(shift);
   7702  } else {
   7703    masm.lshiftPtr(Imm32(shift), index);
   7704    scale = TimesOne;
   7705    shiftedIndex = true;
   7706  }
   7707  auto unshiftIndex = mozilla::MakeScopeExit([&] {
   7708    if (shiftedIndex) {
   7709      masm.rshiftPtr(Imm32(shift), index);
   7710    }
   7711  });
   7712 
   7713  // Easy path if the field is a scalar
   7714  if (!arrayType.elementType().isRefRepr()) {
   7715    emitGcSetScalar<BaseIndex, NoNullCheck>(BaseIndex(data, index, scale, 0),
   7716                                            arrayType.elementType(), value);
   7717    return true;
   7718  }
   7719 
   7720  // Create temporaries for valueAddr that is not in the prebarrier register
   7721  // and can be consumed by the barrier operation
   7722  RegPtr valueAddr = RegPtr(PreBarrierReg);
   7723  needPtr(valueAddr);
   7724  masm.computeEffectiveAddress(BaseIndex(data, index, scale, 0), valueAddr);
   7725 
   7726  // Save state for after barriered write
   7727  pushPtr(data);
   7728  pushI32(index);
   7729 
   7730  // emitBarrieredStore preserves object and value
   7731  if (!emitBarrieredStore(Some(object), valueAddr, value.ref(), preBarrierKind,
   7732                          postBarrierKind)) {
   7733    return false;
   7734  }
   7735 
   7736  // Restore state
   7737  popI32(index);
   7738  popPtr(data);
   7739 
   7740  return true;
   7741 }
   7742 
   7743 template <bool ZeroFields>
   7744 bool BaseCompiler::emitStructAlloc(uint32_t typeIndex, RegRef* object,
   7745                                   bool* isOutlineStruct, RegPtr* outlineBase,
   7746                                   uint32_t allocSiteIndex) {
   7747  const TypeDef& typeDef = (*codeMeta_.types)[typeIndex];
   7748  const StructType& structType = typeDef.structType();
   7749  gc::AllocKind allocKind = structType.allocKind_;
   7750 
   7751  *isOutlineStruct = structType.hasOOL();
   7752 
   7753  // Reserve this register early if we will need it so that it is not taken by
   7754  // any register used in this function.
   7755  needPtr(RegPtr(PreBarrierReg));
   7756 
   7757  *object = RegRef();
   7758 
   7759  // Allocate an uninitialized struct. This requires the type definition
   7760  // for the struct to be pushed on the stack. This will trap on OOM.
   7761  if (*isOutlineStruct) {
   7762    pushI32(int32_t(typeIndex));
   7763    pushPtr(loadAllocSiteInstanceData(allocSiteIndex));
   7764    if (!emitInstanceCall(ZeroFields ? SASigStructNewOOL_true
   7765                                     : SASigStructNewOOL_false)) {
   7766      return false;
   7767    }
   7768    *object = popRef();
   7769  } else {
   7770    // We eagerly sync the value stack to the machine stack here so as not to
   7771    // confuse things with the conditional instance call below.
   7772    sync();
   7773 
   7774    RegPtr instance;
   7775    *object = RegRef(ReturnReg);
   7776    needRef(*object);
   7777 #ifndef RABALDR_PIN_INSTANCE
   7778    // We reuse the result register for the instance.
   7779    instance = needPtr();
   7780    fr.loadInstancePtr(instance);
   7781 #else
   7782    // We can use the pinned instance register.
   7783    instance = RegPtr(InstanceReg);
   7784 #endif
   7785 
   7786    RegPtr allocSite = loadAllocSiteInstanceData(allocSiteIndex);
   7787 
   7788    size_t offsetOfTypeDefData = wasm::Instance::offsetInData(
   7789        codeMeta_.offsetOfTypeDefInstanceData(typeIndex));
   7790 
   7791    Label success;
   7792    Label fail;
   7793    {
   7794      ScratchPtr scratch(*this);
   7795 
   7796      masm.wasmNewStructObject(instance, *object, allocSite, scratch,
   7797                               offsetOfTypeDefData, &fail, allocKind,
   7798                               ZeroFields);
   7799    }
   7800    masm.jump(&success);
   7801 
   7802    masm.bind(&fail);
   7803 #ifndef RABALDR_PIN_INSTANCE
   7804    freePtr(instance);
   7805 #endif
   7806    freeRef(*object);
   7807    pushI32(int32_t(typeIndex));
   7808    pushPtr(allocSite);
   7809    if (!emitInstanceCall(ZeroFields ? SASigStructNewIL_true
   7810                                     : SASigStructNewIL_false)) {
   7811      return false;
   7812    }
   7813    *object = popRef();
   7814    MOZ_ASSERT(*object == RegRef(ReturnReg));
   7815 
   7816    masm.bind(&success);
   7817  }
   7818 
   7819  *outlineBase = *isOutlineStruct ? needPtr() : RegPtr();
   7820 
   7821  // Free the barrier reg for later use
   7822  freePtr(RegPtr(PreBarrierReg));
   7823 
   7824  return true;
   7825 }
   7826 
   7827 bool BaseCompiler::emitStructNew() {
   7828  uint32_t typeIndex;
   7829  BaseNothingVector args{};
   7830  if (!iter_.readStructNew(&typeIndex, &args)) {
   7831    return false;
   7832  }
   7833 
   7834  uint32_t allocSiteIndex;
   7835  if (!readAllocSiteIndex(&allocSiteIndex)) {
   7836    return false;
   7837  }
   7838 
   7839  if (deadCode_) {
   7840    return true;
   7841  }
   7842 
   7843  const TypeDef& typeDef = (*codeMeta_.types)[typeIndex];
   7844  const StructType& structType = typeDef.structType();
   7845 
   7846  RegRef object;
   7847  RegPtr outlineBase;
   7848  bool isOutlineStruct;
   7849  if (!emitStructAlloc<false>(typeIndex, &object, &isOutlineStruct,
   7850                              &outlineBase, allocSiteIndex)) {
   7851    return false;
   7852  }
   7853 
   7854  // Optimization opportunity: Iterate backward to pop arguments off the
   7855  // stack.  This will generate more instructions than we want, since we
   7856  // really only need to pop the stack once at the end, not for every element,
   7857  // but to do better we need a bit more machinery to load elements off the
   7858  // stack into registers.
   7859 
   7860  // Optimization opportunity: when the value being stored is a known
   7861  // zero/null we need store nothing.  This case may be somewhat common
   7862  // because struct.new forces a value to be specified for every field.
   7863 
   7864  // Optimization opportunity: this loop reestablishes the outline base pointer
   7865  // every iteration, which really isn't very clever.  It would be better to
   7866  // establish it once before we start, then re-set it if/when we transition
   7867  // from the out-of-line area back to the in-line area.  That would however
   7868  // require making ::emitGcStructSet preserve that register, which it
   7869  // currently doesn't.
   7870 
   7871  uint32_t fieldIndex = structType.fields_.length();
   7872  while (fieldIndex-- > 0) {
   7873    const FieldType& field = structType.fields_[fieldIndex];
   7874    StorageType type = field.type;
   7875    FieldAccessPath path = structType.fieldAccessPaths_[fieldIndex];
   7876 
   7877    // Reserve the barrier reg if we might need it for this store
   7878    if (type.isRefRepr()) {
   7879      needPtr(RegPtr(PreBarrierReg));
   7880    }
   7881    AnyReg value = popAny();
   7882    // Free the barrier reg now that we've loaded the value
   7883    if (type.isRefRepr()) {
   7884      freePtr(RegPtr(PreBarrierReg));
   7885    }
   7886 
   7887    if (path.hasOOL()) {
   7888      // Load the outline data pointer.
   7889      // The path has two components, of which the first (the IL component) is
   7890      // the offset where the OOL pointer is stored.  Hence `path.ilOffset()`.
   7891      masm.loadPtr(Address(object, path.ilOffset()), outlineBase);
   7892 
   7893      // Consumes value and outline data, object is preserved by this call.
   7894      if (!emitGcStructSet<NoNullCheck>(object, outlineBase, path.oolOffset(),
   7895                                        type, value, PreBarrierKind::None)) {
   7896        return false;
   7897      }
   7898    } else {
   7899      // Consumes value. object is unchanged by this call.
   7900      if (!emitGcStructSet<NoNullCheck>(object, RegPtr(object), path.ilOffset(),
   7901                                        type, value, PreBarrierKind::None)) {
   7902        return false;
   7903      }
   7904    }
   7905  }
   7906 
   7907  if (isOutlineStruct) {
   7908    freePtr(outlineBase);
   7909  }
   7910  pushRef(object);
   7911 
   7912  return true;
   7913 }
   7914 
   7915 bool BaseCompiler::emitStructNewDefault() {
   7916  uint32_t typeIndex;
   7917  if (!iter_.readStructNewDefault(&typeIndex)) {
   7918    return false;
   7919  }
   7920 
   7921  uint32_t allocSiteIndex;
   7922  if (!readAllocSiteIndex(&allocSiteIndex)) {
   7923    return false;
   7924  }
   7925 
   7926  if (deadCode_) {
   7927    return true;
   7928  }
   7929 
   7930  RegRef object;
   7931  bool isOutlineStruct;
   7932  RegPtr outlineBase;
   7933  if (!emitStructAlloc<true>(typeIndex, &object, &isOutlineStruct, &outlineBase,
   7934                             allocSiteIndex)) {
   7935    return false;
   7936  }
   7937 
   7938  if (isOutlineStruct) {
   7939    freePtr(outlineBase);
   7940  }
   7941  pushRef(object);
   7942 
   7943  return true;
   7944 }
   7945 
   7946 bool BaseCompiler::emitStructGet(FieldWideningOp wideningOp) {
   7947  uint32_t typeIndex;
   7948  uint32_t fieldIndex;
   7949  Nothing nothing;
   7950  if (!iter_.readStructGet(&typeIndex, &fieldIndex, wideningOp, &nothing)) {
   7951    return false;
   7952  }
   7953 
   7954  if (deadCode_) {
   7955    return true;
   7956  }
   7957 
   7958  const StructType& structType = (*codeMeta_.types)[typeIndex].structType();
   7959  const FieldType& structField = structType.fields_[fieldIndex];
   7960  StorageType fieldType = structField.type;
   7961  FieldAccessPath path = structType.fieldAccessPaths_[fieldIndex];
   7962 
   7963  RegRef object = popRef();
   7964  if (path.hasOOL()) {
   7965    // The path has two components, of which the first (the IL component) is
   7966    // the offset where the OOL pointer is stored.  Hence `path.ilOffset()`.
   7967    RegPtr outlineBase = needPtr();
   7968    FaultingCodeOffset fco =
   7969        masm.loadPtr(Address(object, path.ilOffset()), outlineBase);
   7970    SignalNullCheck::emitTrapSite(this, fco, TrapMachineInsnForLoadWord());
   7971    // Load the value
   7972    emitGcGet<Address, NoNullCheck>(fieldType, wideningOp,
   7973                                    Address(outlineBase, path.oolOffset()));
   7974    freePtr(outlineBase);
   7975  } else {
   7976    // Load the value
   7977    emitGcGet<Address, SignalNullCheck>(fieldType, wideningOp,
   7978                                        Address(object, path.ilOffset()));
   7979  }
   7980  freeRef(object);
   7981 
   7982  return true;
   7983 }
   7984 
   7985 bool BaseCompiler::emitStructSet() {
   7986  uint32_t typeIndex;
   7987  uint32_t fieldIndex;
   7988  Nothing nothing;
   7989  if (!iter_.readStructSet(&typeIndex, &fieldIndex, &nothing, &nothing)) {
   7990    return false;
   7991  }
   7992 
   7993  if (deadCode_) {
   7994    return true;
   7995  }
   7996 
   7997  const StructType& structType = (*codeMeta_.types)[typeIndex].structType();
   7998  const FieldType& structField = structType.fields_[fieldIndex];
   7999  StorageType fieldType = structField.type;
   8000  FieldAccessPath path = structType.fieldAccessPaths_[fieldIndex];
   8001 
   8002  // Reserve this register early if we will need it so that it is not taken by
   8003  // any register used in this function.
   8004  if (fieldType.isRefRepr()) {
   8005    needPtr(RegPtr(PreBarrierReg));
   8006  }
   8007 
   8008  // Set up other required registers
   8009  RegPtr outlineBase = path.hasOOL() ? needPtr() : RegPtr();
   8010  AnyReg value = popAny();
   8011  RegRef object = popRef();
   8012 
   8013  // Free the barrier reg after we've allocated all registers
   8014  if (fieldType.isRefRepr()) {
   8015    freePtr(RegPtr(PreBarrierReg));
   8016  }
   8017 
   8018  if (path.hasOOL()) {
   8019    // Make `outlineBase` point at the first byte of the relevant area.
   8020    // The path has two components, of which the first (the IL component) is
   8021    // the offset where the OOL pointer is stored.  Hence `path.ilOffset()`.
   8022    FaultingCodeOffset fco =
   8023        masm.loadPtr(Address(object, path.ilOffset()), outlineBase);
   8024    SignalNullCheck::emitTrapSite(this, fco, TrapMachineInsnForLoadWord());
   8025    // Consumes `value`. `object` is unchanged by this call.
   8026    if (!emitGcStructSet<NoNullCheck>(object, outlineBase, path.oolOffset(),
   8027                                      fieldType, value,
   8028                                      PreBarrierKind::Normal)) {
   8029      return false;
   8030    }
   8031  } else {
   8032    // Consumes `value`. `object` is unchanged by this call.
   8033    if (!emitGcStructSet<SignalNullCheck>(object, RegPtr(object),
   8034                                          path.ilOffset(), fieldType, value,
   8035                                          PreBarrierKind::Normal)) {
   8036      return false;
   8037    }
   8038  }
   8039 
   8040  if (path.hasOOL()) {
   8041    freePtr(outlineBase);
   8042  }
   8043  freeRef(object);
   8044 
   8045  return true;
   8046 }
   8047 
   8048 template <bool ZeroFields>
   8049 bool BaseCompiler::emitArrayAlloc(uint32_t typeIndex, RegRef object,
   8050                                  RegI32 numElements, uint32_t elemSize,
   8051                                  uint32_t allocSiteIndex) {
   8052  // We eagerly sync the value stack to the machine stack here so as not to
   8053  // confuse things with the conditional instance call below.
   8054  sync();
   8055 
   8056  RegPtr instance;
   8057 #ifndef RABALDR_PIN_INSTANCE
   8058  // We reuse the object register for the instance. This is ok because object is
   8059  // not live until instance is dead.
   8060  instance = needPtr();
   8061  fr.loadInstancePtr(instance);
   8062 #else
   8063  // We can use the pinned instance register.
   8064  instance = RegPtr(InstanceReg);
   8065 #endif
   8066 
   8067  RegPtr allocSite = loadAllocSiteInstanceData(allocSiteIndex);
   8068 
   8069  size_t offsetOfTypeDefData = wasm::Instance::offsetInData(
   8070      codeMeta_.offsetOfTypeDefInstanceData(typeIndex));
   8071 
   8072  Label success;
   8073  Label fail;
   8074  {
   8075    ScratchPtr scratch(*this);
   8076    masm.wasmNewArrayObject(instance, object, numElements, allocSite, scratch,
   8077                            offsetOfTypeDefData, &fail, elemSize, ZeroFields);
   8078  }
   8079  masm.jump(&success);
   8080 
   8081  masm.bind(&fail);
   8082 #ifndef RABALDR_PIN_INSTANCE
   8083  freePtr(instance);
   8084 #endif
   8085  freeRef(object);
   8086  pushI32(numElements);
   8087  pushI32(int32_t(typeIndex));
   8088  pushPtr(allocSite);
   8089  if (!emitInstanceCall(ZeroFields ? SASigArrayNew_true
   8090                                   : SASigArrayNew_false)) {
   8091    return false;
   8092  }
   8093  popRef(object);
   8094 
   8095  masm.bind(&success);
   8096  return true;
   8097 }
   8098 
   8099 template <bool ZeroFields>
   8100 bool BaseCompiler::emitArrayAllocFixed(uint32_t typeIndex, RegRef object,
   8101                                       uint32_t numElements, uint32_t elemSize,
   8102                                       uint32_t allocSiteIndex) {
   8103  SymbolicAddressSignature fun =
   8104      ZeroFields ? SASigArrayNew_true : SASigArrayNew_false;
   8105 
   8106  // The maximum number of elements for array.new_fixed enforced in validation
   8107  // should always prevent overflow here.
   8108  static_assert(MaxArrayNewFixedElements * sizeof(wasm::LitVal) <
   8109                MaxArrayPayloadBytes);
   8110  uint32_t storageBytes =
   8111      WasmArrayObject::calcStorageBytesUnchecked(elemSize, numElements);
   8112  if (storageBytes > WasmArrayObject_MaxInlineBytes) {
   8113    freeRef(object);
   8114    pushI32(numElements);
   8115    pushI32(int32_t(typeIndex));
   8116    pushPtr(loadAllocSiteInstanceData(allocSiteIndex));
   8117    if (!emitInstanceCall(fun)) {
   8118      return false;
   8119    }
   8120    popRef(object);
   8121 
   8122    return true;
   8123  }
   8124 
   8125  // We eagerly sync the value stack to the machine stack here so as not to
   8126  // confuse things with the conditional instance call below.
   8127  sync();
   8128 
   8129  RegPtr instance;
   8130 #ifndef RABALDR_PIN_INSTANCE
   8131  // We reuse the object register for the instance. This is ok because object is
   8132  // not live until instance is dead.
   8133  instance = needPtr();
   8134  fr.loadInstancePtr(instance);
   8135 #else
   8136  // We can use the pinned instance register.
   8137  instance = RegPtr(InstanceReg);
   8138 #endif
   8139 
   8140  RegPtr allocSite = loadAllocSiteInstanceData(allocSiteIndex);
   8141  RegPtr temp1 = needPtr();
   8142 
   8143  size_t offsetOfTypeDefData = wasm::Instance::offsetInData(
   8144      codeMeta_.offsetOfTypeDefInstanceData(typeIndex));
   8145 
   8146  Label success;
   8147  Label fail;
   8148  {
   8149    ScratchPtr scratch(*this);
   8150    masm.wasmNewArrayObjectFixed(instance, object, allocSite, temp1, scratch,
   8151                                 offsetOfTypeDefData, &fail, numElements,
   8152                                 storageBytes, ZeroFields);
   8153  }
   8154  freePtr(temp1);
   8155  masm.jump(&success);
   8156 
   8157  masm.bind(&fail);
   8158 #ifndef RABALDR_PIN_INSTANCE
   8159  freePtr(instance);
   8160 #endif
   8161  freeRef(object);
   8162  pushI32(numElements);
   8163  pushI32(int32_t(typeIndex));
   8164  pushPtr(allocSite);
   8165  if (!emitInstanceCall(fun)) {
   8166    return false;
   8167  }
   8168  popRef(object);
   8169 
   8170  masm.bind(&success);
   8171 
   8172  return true;
   8173 }
   8174 
   8175 bool BaseCompiler::emitArrayNew() {
   8176  uint32_t typeIndex;
   8177  Nothing nothing;
   8178  if (!iter_.readArrayNew(&typeIndex, &nothing, &nothing)) {
   8179    return false;
   8180  }
   8181 
   8182  uint32_t allocSiteIndex;
   8183  if (!readAllocSiteIndex(&allocSiteIndex)) {
   8184    return false;
   8185  }
   8186 
   8187  if (deadCode_) {
   8188    return true;
   8189  }
   8190 
   8191  const ArrayType& arrayType = (*codeMeta_.types)[typeIndex].arrayType();
   8192 
   8193  // Reserve this register early if we will need it so that it is not taken by
   8194  // any register used in this function.
   8195  if (arrayType.elementType().isRefRepr()) {
   8196    needPtr(RegPtr(PreBarrierReg));
   8197  }
   8198 
   8199  RegRef object = needRef();
   8200  RegI32 numElements = popI32();
   8201  if (!emitArrayAlloc<false>(typeIndex, object, numElements,
   8202                             arrayType.elementType().size(), allocSiteIndex)) {
   8203    return false;
   8204  }
   8205 
   8206  AnyReg value = popAny();
   8207 
   8208  // Acquire the data pointer from the object
   8209  RegPtr rdata = emitGcArrayGetData<NoNullCheck>(object);
   8210 
   8211  // Acquire the number of elements again
   8212  numElements = emitGcArrayGetNumElements<NoNullCheck>(object);
   8213 
   8214  // Free the barrier reg after we've allocated all registers
   8215  if (arrayType.elementType().isRefRepr()) {
   8216    freePtr(RegPtr(PreBarrierReg));
   8217  }
   8218 
   8219  // Perform an initialization loop using `numElements` as the loop variable,
   8220  // counting down to zero.
   8221  Label done;
   8222  Label loop;
   8223  // Skip initialization if numElements = 0
   8224  masm.branch32(Assembler::Equal, numElements, Imm32(0), &done);
   8225  masm.bind(&loop);
   8226 
   8227  // Move to the next element
   8228  masm.sub32(Imm32(1), numElements);
   8229 
   8230  // Assign value to array[numElements]. All registers are preserved
   8231  if (!emitGcArraySet(object, rdata, numElements, arrayType, value,
   8232                      PreBarrierKind::None, PostBarrierKind::None)) {
   8233    return false;
   8234  }
   8235 
   8236  // Loop back if there are still elements to initialize
   8237  masm.branch32(Assembler::GreaterThan, numElements, Imm32(0), &loop);
   8238  masm.bind(&done);
   8239 
   8240  if (arrayType.elementType().isRefRepr()) {
   8241    // Emit one whole-cell post barrier for the whole array, since there is just
   8242    // one object and one value. Reuses rdata as a temp register.
   8243    if (!emitPostBarrierWholeCell(object, value.ref(), rdata)) {
   8244      return false;
   8245    }
   8246  } else {
   8247    freePtr(rdata);
   8248  }
   8249 
   8250  freeI32(numElements);
   8251  freeAny(value);
   8252  pushRef(object);
   8253 
   8254  return true;
   8255 }
   8256 
   8257 bool BaseCompiler::emitArrayNewFixed() {
   8258  uint32_t typeIndex, numElements;
   8259  BaseNothingVector nothings{};
   8260  if (!iter_.readArrayNewFixed(&typeIndex, &numElements, &nothings)) {
   8261    return false;
   8262  }
   8263 
   8264  uint32_t allocSiteIndex;
   8265  if (!readAllocSiteIndex(&allocSiteIndex)) {
   8266    return false;
   8267  }
   8268 
   8269  if (deadCode_) {
   8270    return true;
   8271  }
   8272 
   8273  const ArrayType& arrayType = (*codeMeta_.types)[typeIndex].arrayType();
   8274 
   8275  // Reserve this register early if we will need it so that it is not taken by
   8276  // any register used in this function.
   8277  bool avoidPreBarrierReg = arrayType.elementType().isRefRepr();
   8278  if (avoidPreBarrierReg) {
   8279    needPtr(RegPtr(PreBarrierReg));
   8280  }
   8281 
   8282  RegRef object = needRef();
   8283  if (!emitArrayAllocFixed<false>(typeIndex, object, numElements,
   8284                                  arrayType.elementType().size(),
   8285                                  allocSiteIndex)) {
   8286    return false;
   8287  }
   8288 
   8289  // Acquire the data pointer from the object
   8290  RegPtr rdata = emitGcArrayGetData<NoNullCheck>(object);
   8291 
   8292  // Free the barrier reg if we previously reserved it.
   8293  if (avoidPreBarrierReg) {
   8294    freePtr(RegPtr(PreBarrierReg));
   8295  }
   8296 
   8297  // These together ensure that the max value of `index` in the loop below
   8298  // remains comfortably below the 2^31 boundary.  See comments on equivalent
   8299  // assertions in EmitArrayNewFixed in WasmIonCompile.cpp for explanation.
   8300  static_assert(16 /* sizeof v128 */ * MaxFunctionBytes <=
   8301                MaxArrayPayloadBytes);
   8302  MOZ_RELEASE_ASSERT(numElements <= MaxFunctionBytes);
   8303 
   8304  // Generate straight-line initialization code.  We could do better here if
   8305  // there was a version of ::emitGcArraySet that took `index` as a `uint32_t`
   8306  // rather than a general value-in-a-reg.
   8307  for (uint32_t forwardIndex = 0; forwardIndex < numElements; forwardIndex++) {
   8308    uint32_t reverseIndex = numElements - forwardIndex - 1;
   8309    if (avoidPreBarrierReg) {
   8310      needPtr(RegPtr(PreBarrierReg));
   8311    }
   8312    AnyReg value = popAny();
   8313    pushI32(reverseIndex);
   8314    RegI32 index = popI32();
   8315    if (avoidPreBarrierReg) {
   8316      freePtr(RegPtr(PreBarrierReg));
   8317    }
   8318    if (!emitGcArraySet(object, rdata, index, arrayType, value,
   8319                        PreBarrierKind::None, PostBarrierKind::WholeCell)) {
   8320      return false;
   8321    }
   8322    freeI32(index);
   8323    freeAny(value);
   8324  }
   8325 
   8326  freePtr(rdata);
   8327 
   8328  pushRef(object);
   8329  return true;
   8330 }
   8331 
   8332 bool BaseCompiler::emitArrayNewDefault() {
   8333  uint32_t typeIndex;
   8334  Nothing nothing;
   8335  if (!iter_.readArrayNewDefault(&typeIndex, &nothing)) {
   8336    return false;
   8337  }
   8338 
   8339  uint32_t allocSiteIndex;
   8340  if (!readAllocSiteIndex(&allocSiteIndex)) {
   8341    return false;
   8342  }
   8343 
   8344  if (deadCode_) {
   8345    return true;
   8346  }
   8347 
   8348  const ArrayType& arrayType = (*codeMeta_.types)[typeIndex].arrayType();
   8349 
   8350  RegRef object = needRef();
   8351  RegI32 numElements = popI32();
   8352  if (!emitArrayAlloc<true>(typeIndex, object, numElements,
   8353                            arrayType.elementType().size(), allocSiteIndex)) {
   8354    return false;
   8355  }
   8356 
   8357  pushRef(object);
   8358  return true;
   8359 }
   8360 
   8361 bool BaseCompiler::emitArrayNewData() {
   8362  uint32_t typeIndex, segIndex;
   8363  Nothing nothing;
   8364  if (!iter_.readArrayNewData(&typeIndex, &segIndex, &nothing, &nothing)) {
   8365    return false;
   8366  }
   8367 
   8368  uint32_t allocSiteIndex;
   8369  if (!readAllocSiteIndex(&allocSiteIndex)) {
   8370    return false;
   8371  }
   8372 
   8373  if (deadCode_) {
   8374    return true;
   8375  }
   8376 
   8377  pushI32(int32_t(typeIndex));
   8378  pushPtr(loadAllocSiteInstanceData(allocSiteIndex));
   8379  pushI32(int32_t(segIndex));
   8380 
   8381  // The call removes 4 items from the stack: the segment byte offset and
   8382  // number of elements (operands to array.new_data), and the type data and
   8383  // seg index as pushed above.
   8384  return emitInstanceCall(SASigArrayNewData);
   8385 }
   8386 
   8387 bool BaseCompiler::emitArrayNewElem() {
   8388  uint32_t typeIndex, segIndex;
   8389  Nothing nothing;
   8390  if (!iter_.readArrayNewElem(&typeIndex, &segIndex, &nothing, &nothing)) {
   8391    return false;
   8392  }
   8393 
   8394  uint32_t allocSiteIndex;
   8395  if (!readAllocSiteIndex(&allocSiteIndex)) {
   8396    return false;
   8397  }
   8398 
   8399  if (deadCode_) {
   8400    return true;
   8401  }
   8402 
   8403  pushI32(int32_t(typeIndex));
   8404  pushPtr(loadAllocSiteInstanceData(allocSiteIndex));
   8405  pushI32(int32_t(segIndex));
   8406 
   8407  // The call removes 4 items from the stack: the segment element offset and
   8408  // number of elements (operands to array.new_elem), and the type data and
   8409  // seg index as pushed above.
   8410  return emitInstanceCall(SASigArrayNewElem);
   8411 }
   8412 
   8413 bool BaseCompiler::emitArrayInitData() {
   8414  uint32_t unusedTypeIndex, segIndex;
   8415  Nothing nothing;
   8416  if (!iter_.readArrayInitData(&unusedTypeIndex, &segIndex, &nothing, &nothing,
   8417                               &nothing, &nothing)) {
   8418    return false;
   8419  }
   8420 
   8421  if (deadCode_) {
   8422    return true;
   8423  }
   8424 
   8425  pushI32(int32_t(segIndex));
   8426 
   8427  // The call removes 5 items from the stack: the array, array index, segment
   8428  // byte offset, and number of elements (operands to array.init_data), and the
   8429  // seg index as pushed above. TypeDefInstanceData is not necessary for this
   8430  // call because the array object has a reference to its type.
   8431  return emitInstanceCall(SASigArrayInitData);
   8432 }
   8433 
   8434 bool BaseCompiler::emitArrayInitElem() {
   8435  uint32_t typeIndex, segIndex;
   8436  Nothing nothing;
   8437  if (!iter_.readArrayInitElem(&typeIndex, &segIndex, &nothing, &nothing,
   8438                               &nothing, &nothing)) {
   8439    return false;
   8440  }
   8441 
   8442  if (deadCode_) {
   8443    return true;
   8444  }
   8445 
   8446  pushI32(int32_t(typeIndex));
   8447  pushI32(int32_t(segIndex));
   8448 
   8449  // The call removes 6 items from the stack: the array, array index, segment
   8450  // offset, and number of elements (operands to array.init_elem), and the type
   8451  // data and seg index as pushed above.
   8452  return emitInstanceCall(SASigArrayInitElem);
   8453 }
   8454 
   8455 bool BaseCompiler::emitArrayGet(FieldWideningOp wideningOp) {
   8456  uint32_t typeIndex;
   8457  Nothing nothing;
   8458  if (!iter_.readArrayGet(&typeIndex, wideningOp, &nothing, &nothing)) {
   8459    return false;
   8460  }
   8461 
   8462  if (deadCode_) {
   8463    return true;
   8464  }
   8465 
   8466  const ArrayType& arrayType = (*codeMeta_.types)[typeIndex].arrayType();
   8467 
   8468  RegI32 index = popI32();
   8469  RegRef rp = popRef();
   8470 
   8471  // Acquire the number of elements
   8472  RegI32 numElements = emitGcArrayGetNumElements<SignalNullCheck>(rp);
   8473 
   8474  // Bounds check the index
   8475  emitGcArrayBoundsCheck(index, numElements);
   8476  freeI32(numElements);
   8477 
   8478  // Acquire the data pointer from the object
   8479  RegPtr rdata = emitGcArrayGetData<NoNullCheck>(rp);
   8480 
   8481  // Load the value
   8482  uint32_t shift = arrayType.elementType().indexingShift();
   8483  if (IsShiftInScaleRange(shift)) {
   8484    emitGcGet<BaseIndex, NoNullCheck>(
   8485        arrayType.elementType(), wideningOp,
   8486        BaseIndex(rdata, index, ShiftToScale(shift), 0));
   8487  } else {
   8488    masm.lshiftPtr(Imm32(shift), index);
   8489    emitGcGet<BaseIndex, NoNullCheck>(arrayType.elementType(), wideningOp,
   8490                                      BaseIndex(rdata, index, TimesOne, 0));
   8491  }
   8492 
   8493  freePtr(rdata);
   8494  freeRef(rp);
   8495  freeI32(index);
   8496 
   8497  return true;
   8498 }
   8499 
   8500 bool BaseCompiler::emitArraySet() {
   8501  uint32_t typeIndex;
   8502  Nothing nothing;
   8503  if (!iter_.readArraySet(&typeIndex, &nothing, &nothing, &nothing)) {
   8504    return false;
   8505  }
   8506 
   8507  if (deadCode_) {
   8508    return true;
   8509  }
   8510 
   8511  const ArrayType& arrayType = (*codeMeta_.types)[typeIndex].arrayType();
   8512 
   8513  // Reserve this register early if we will need it so that it is not taken by
   8514  // any register used in this function.
   8515  if (arrayType.elementType().isRefRepr()) {
   8516    needPtr(RegPtr(PreBarrierReg));
   8517  }
   8518 
   8519  AnyReg value = popAny();
   8520  RegI32 index = popI32();
   8521  RegRef rp = popRef();
   8522 
   8523  // Acquire the number of elements
   8524  RegI32 numElements = emitGcArrayGetNumElements<SignalNullCheck>(rp);
   8525 
   8526  // Bounds check the index
   8527  emitGcArrayBoundsCheck(index, numElements);
   8528  freeI32(numElements);
   8529 
   8530  // Acquire the data pointer from the object
   8531  RegPtr rdata = emitGcArrayGetData<NoNullCheck>(rp);
   8532 
   8533  // Free the barrier reg after we've allocated all registers
   8534  if (arrayType.elementType().isRefRepr()) {
   8535    freePtr(RegPtr(PreBarrierReg));
   8536  }
   8537 
   8538  // All registers are preserved. This isn't strictly necessary, as we'll just
   8539  // be freeing them all after this is done. But this is needed for repeated
   8540  // assignments used in array.new/new_default.
   8541  if (!emitGcArraySet(rp, rdata, index, arrayType, value,
   8542                      PreBarrierKind::Normal, PostBarrierKind::Imprecise)) {
   8543    return false;
   8544  }
   8545 
   8546  freePtr(rdata);
   8547  freeRef(rp);
   8548  freeI32(index);
   8549  freeAny(value);
   8550 
   8551  return true;
   8552 }
   8553 
   8554 bool BaseCompiler::emitArrayLen() {
   8555  Nothing nothing;
   8556  if (!iter_.readArrayLen(&nothing)) {
   8557    return false;
   8558  }
   8559 
   8560  if (deadCode_) {
   8561    return true;
   8562  }
   8563 
   8564  RegRef rp = popRef();
   8565 
   8566  // Acquire the number of elements
   8567  RegI32 numElements = emitGcArrayGetNumElements<SignalNullCheck>(rp);
   8568  pushI32(numElements);
   8569 
   8570  freeRef(rp);
   8571 
   8572  return true;
   8573 }
   8574 
   8575 bool BaseCompiler::emitArrayCopy() {
   8576  uint32_t dstArrayTypeIndex;
   8577  uint32_t srcArrayTypeIndex;
   8578  Nothing nothing;
   8579  if (!iter_.readArrayCopy(&dstArrayTypeIndex, &srcArrayTypeIndex, &nothing,
   8580                           &nothing, &nothing, &nothing, &nothing)) {
   8581    return false;
   8582  }
   8583 
   8584  if (deadCode_) {
   8585    return true;
   8586  }
   8587 
   8588  const ArrayType& dstArrayType =
   8589      codeMeta_.types->type(dstArrayTypeIndex).arrayType();
   8590  StorageType dstElemType = dstArrayType.elementType();
   8591  int32_t elemSize = int32_t(dstElemType.size());
   8592  bool elemsAreRefTyped = dstElemType.isRefType();
   8593 
   8594  // The helper needs to know the element size. If copying ref values, the size
   8595  // is negated to signal to the helper that it needs to do GC barriers and
   8596  // such.
   8597  pushI32(elemsAreRefTyped ? -elemSize : elemSize);
   8598 
   8599  return emitInstanceCall(SASigArrayCopy);
   8600 }
   8601 
   8602 bool BaseCompiler::emitArrayFill() {
   8603  AutoCreatedBy acb(masm, "(wasm)BaseCompiler::emitArrayFill");
   8604  uint32_t typeIndex;
   8605  Nothing nothing;
   8606  if (!iter_.readArrayFill(&typeIndex, &nothing, &nothing, &nothing,
   8607                           &nothing)) {
   8608    return false;
   8609  }
   8610 
   8611  if (deadCode_) {
   8612    return true;
   8613  }
   8614 
   8615  const TypeDef& typeDef = codeMeta_.types->type(typeIndex);
   8616  const ArrayType& arrayType = typeDef.arrayType();
   8617  StorageType elementType = arrayType.elementType();
   8618 
   8619  // On x86 (32-bit), we are very short of registers, hence the code
   8620  // generation scheme is less straightforward than it might otherwise be.
   8621  //
   8622  // Comment lines below of the form
   8623  //
   8624  //   3: foo bar xyzzy
   8625  //
   8626  // mean "at this point there are 3 integer regs in use (not including the
   8627  // possible 2 needed for `value` in the worst case), and those 3 regs hold
   8628  // the values for `foo`, `bar` and `xyzzy`.
   8629  //
   8630  // On x86, the worst case, we only have 3 int regs available (not including
   8631  // `value`), thusly:
   8632  //
   8633  // - as a basis, we have: eax ebx ecx edx esi edi
   8634  //
   8635  // - ebx is "kind of" not available, since it is reserved as a wasm-baseline
   8636  //   scratch register (called `RabaldrScratchI32` on most targets, but
   8637  //   acquired below using `ScratchI32(..)`).
   8638  //
   8639  // - `value` isn't needed till the initialisation loop itself, hence it
   8640  //   would seem attractive to spill it across the range-check and setup code
   8641  //   that precedes the loop.  However, it has variable type and regclass
   8642  //   (eg, it could be v128 or f32 or f64), which make spilling it somewhat
   8643  //   complex, so we bite the bullet and just allocate it at the start of the
   8644  //   routine.
   8645  //
   8646  // - Consequently we have the following two cases as worst-cases:
   8647  //
   8648  //   * `value` is I64, so uses two registers on x86.
   8649  //   * `value` is reftyped, using one register, but also making
   8650  //     PreBarrierReg unavailable.
   8651  //
   8652  // - As a result of all of the above, we have only three registers, and
   8653  //   RabaldrScratchI32, to work with.  And 4 spill-slot words; however ..
   8654  //
   8655  // - .. to spill/reload from a spill slot, we need a register to point at
   8656  //   the instance.  That makes it even worse on x86 since there's no
   8657  //   reserved instance reg; hence we have to use one of our 3 for it.  This
   8658  //   is indicated explicitly in the code below.
   8659  //
   8660  // There are many comment lines indicating the current disposition of the 3
   8661  // regs.
   8662  //
   8663  // This generates somewhat clunky code for the setup and bounds test, but
   8664  // the actual initialisation loop still has everything in registers, so
   8665  // should run fast.
   8666  //
   8667  // The same scheme is used for all targets.  Hence they all get clunky setup
   8668  // code.  Considering that this is a baseline compiler and also that the
   8669  // loop itself is all-in-regs, this seems like a not-bad compromise compared
   8670  // to having two different implementations for x86 vs everything else.
   8671 
   8672  // Reserve this register early if we will need it so that it is not taken by
   8673  // any register used in this function.
   8674  if (elementType.isRefRepr()) {
   8675    needPtr(RegPtr(PreBarrierReg));
   8676  }
   8677 
   8678  // Set up a pointer to the Instance, so we can do manual spills/reloads
   8679 #ifdef RABALDR_PIN_INSTANCE
   8680  RegPtr instancePtr = RegPtr(InstanceReg);
   8681 #else
   8682  RegPtr instancePtr = needPtr();
   8683  fr.loadInstancePtr(instancePtr);
   8684 #endif
   8685 
   8686  // Pull operands off the instance stack and stash the non-Any ones
   8687  RegI32 numElements = popI32();
   8688  stashWord(instancePtr, 0, RegPtr(numElements));
   8689  freeI32(numElements);
   8690  numElements = RegI32::Invalid();
   8691 
   8692  AnyReg value = popAny();
   8693 
   8694  RegI32 index = popI32();
   8695  stashWord(instancePtr, 1, RegPtr(index));
   8696  freeI32(index);
   8697  index = RegI32::Invalid();
   8698 
   8699  RegRef rp = popRef();
   8700  stashWord(instancePtr, 2, RegPtr(rp));
   8701  // 2: instancePtr rp
   8702 
   8703  // Acquire the actual length of the array
   8704  RegI32 arrayNumElements = emitGcArrayGetNumElements<SignalNullCheck>(rp);
   8705  // 3: instancePtr rp arrayNumElements
   8706 
   8707  // Drop rp
   8708  freeRef(rp);
   8709  rp = RegRef::Invalid();
   8710  // 2: instancePtr arrayNumElements
   8711 
   8712  // Reload index
   8713  index = needI32();
   8714  unstashWord(instancePtr, 1, RegPtr(index));
   8715  // 3: instancePtr arrayNumElements index
   8716 
   8717  // Reload numElements into the reg that currently holds instancePtr
   8718 #ifdef RABALDR_PIN_INSTANCE
   8719  numElements = needI32();
   8720 #else
   8721  numElements = RegI32(instancePtr);
   8722 #endif
   8723  unstashWord(instancePtr, 0, RegPtr(numElements));
   8724  instancePtr = RegPtr::Invalid();
   8725  // 3: arrayNumElements index numElements
   8726 
   8727  // Do the bounds check.  For this we will need to get hold of the
   8728  // wasm-baseline's scratch register.
   8729  {
   8730    ScratchI32 scratch(*this);
   8731    MOZ_ASSERT(RegI32(scratch) != arrayNumElements);
   8732    MOZ_ASSERT(RegI32(scratch) != index);
   8733    MOZ_ASSERT(RegI32(scratch) != numElements);
   8734    masm.wasmBoundsCheckRange32(index, numElements, arrayNumElements, scratch,
   8735                                trapSiteDesc());
   8736  }
   8737  // 3: arrayNumElements index numElements
   8738 
   8739  // Drop arrayNumElements and numElements
   8740  freeI32(arrayNumElements);
   8741  arrayNumElements = RegI32::Invalid();
   8742  freeI32(numElements);
   8743  numElements = RegI32::Invalid();
   8744  // 1: index
   8745 
   8746  // Re-set-up the instance pointer; we had to ditch it earlier.
   8747 #ifdef RABALDR_PIN_INSTANCE
   8748  instancePtr = RegPtr(InstanceReg);
   8749 #else
   8750  instancePtr = needPtr();
   8751  fr.loadInstancePtr(instancePtr);
   8752 #endif
   8753  // 2: index instancePtr
   8754 
   8755  // Reload rp
   8756  rp = needRef();
   8757  unstashWord(instancePtr, 2, RegPtr(rp));
   8758  // 3: index instancePtr rp
   8759 
   8760  // Drop instancePtr
   8761 #ifdef RABALDR_PIN_INSTANCE
   8762  instancePtr = RegPtr::Invalid();
   8763 #else
   8764  freePtr(instancePtr);
   8765  instancePtr = RegPtr::Invalid();
   8766 #endif
   8767  // 2: index rp
   8768 
   8769  // Acquire the data pointer from the object
   8770  RegPtr rdata = emitGcArrayGetData<NoNullCheck>(rp);
   8771  // 3: index rp rdata
   8772 
   8773  // Currently `rdata` points at the start of the array data area.  Move it
   8774  // forwards by `index` units so as to make it point at the start of the area
   8775  // to be filled.
   8776  uint32_t shift = arrayType.elementType().indexingShift();
   8777  if (shift > 0) {
   8778    masm.lshift32(Imm32(shift), index);
   8779    // `index` is a 32 bit value, so we must zero-extend it to 64 bits before
   8780    // adding it on to `rdata`.
   8781 #ifdef JS_64BIT
   8782    masm.move32To64ZeroExtend(index, widenI32(index));
   8783 #endif
   8784  }
   8785  masm.addPtr(index, rdata);
   8786  // `index` is not used after this point.
   8787 
   8788  // 3: index rp rdata
   8789  // index is now (more or less) meaningless
   8790  // rdata now points exactly at the start of the fill area
   8791  // rp points at the array object
   8792 
   8793  // Drop `index`; we no longer need it.
   8794  freeI32(index);
   8795  index = RegI32::Invalid();
   8796  // 2: rp rdata
   8797 
   8798  // Re-re-set-up the instance pointer; we had to ditch it earlier.
   8799 #ifdef RABALDR_PIN_INSTANCE
   8800  instancePtr = RegPtr(InstanceReg);
   8801 #else
   8802  instancePtr = needPtr();
   8803  fr.loadInstancePtr(instancePtr);
   8804 #endif
   8805  // 3: rp rdata instancePtr
   8806 
   8807  // And reload numElements.
   8808 #ifdef RABALDR_PIN_INSTANCE
   8809  numElements = needI32();
   8810  unstashWord(instancePtr, 0, RegPtr(numElements));
   8811  instancePtr = RegPtr::Invalid();
   8812 #else
   8813  numElements = RegI32(instancePtr);
   8814  unstashWord(instancePtr, 0, RegPtr(numElements));
   8815  instancePtr = RegPtr::Invalid();
   8816 #endif
   8817  // 3: numElements rp rdata
   8818 
   8819  // Free the barrier reg after we've allocated all registers
   8820  if (elementType.isRefRepr()) {
   8821    freePtr(RegPtr(PreBarrierReg));
   8822  }
   8823 
   8824  // Perform an initialization loop using `numElements` as the loop variable,
   8825  // starting at `numElements` and counting down to zero.
   8826  Label done;
   8827  Label loop;
   8828  // Skip initialization if numElements = 0
   8829  masm.branch32(Assembler::Equal, numElements, Imm32(0), &done);
   8830  masm.bind(&loop);
   8831 
   8832  // Move to the next element
   8833  masm.sub32(Imm32(1), numElements);
   8834 
   8835  // Assign value to rdata[numElements]. All registers are preserved.
   8836  if (!emitGcArraySet(rp, rdata, numElements, arrayType, value,
   8837                      PreBarrierKind::None, PostBarrierKind::Imprecise)) {
   8838    return false;
   8839  }
   8840 
   8841  // Loop back if there are still elements to initialize
   8842  masm.branch32(Assembler::NotEqual, numElements, Imm32(0), &loop);
   8843  masm.bind(&done);
   8844 
   8845  freePtr(rdata);
   8846  freeRef(rp);
   8847  freeI32(numElements);
   8848  freeAny(value);
   8849  MOZ_ASSERT(index == RegPtr::Invalid());
   8850  MOZ_ASSERT(instancePtr == RegPtr::Invalid());
   8851  MOZ_ASSERT(arrayNumElements == RegI32::Invalid());
   8852 
   8853  return true;
   8854 }
   8855 
   8856 bool BaseCompiler::emitRefI31() {
   8857  Nothing value;
   8858  if (!iter_.readConversion(ValType::I32,
   8859                            ValType(RefType::i31().asNonNullable()), &value)) {
   8860    return false;
   8861  }
   8862 
   8863  if (deadCode_) {
   8864    return true;
   8865  }
   8866 
   8867  RegI32 intValue = popI32();
   8868  RegRef i31Value = needRef();
   8869  masm.truncate32ToWasmI31Ref(intValue, i31Value);
   8870  freeI32(intValue);
   8871  pushRef(i31Value);
   8872  return true;
   8873 }
   8874 
   8875 bool BaseCompiler::emitI31Get(FieldWideningOp wideningOp) {
   8876  MOZ_ASSERT(wideningOp != FieldWideningOp::None);
   8877 
   8878  Nothing value;
   8879  if (!iter_.readConversion(ValType(RefType::i31()), ValType::I32, &value)) {
   8880    return false;
   8881  }
   8882 
   8883  if (deadCode_) {
   8884    return true;
   8885  }
   8886 
   8887  RegRef i31Value = popRef();
   8888  RegI32 intValue = needI32();
   8889 
   8890  Label success;
   8891  masm.branchWasmAnyRefIsNull(false, i31Value, &success);
   8892  trap(Trap::NullPointerDereference);
   8893  masm.bind(&success);
   8894 
   8895  if (wideningOp == FieldWideningOp::Signed) {
   8896    masm.convertWasmI31RefTo32Signed(i31Value, intValue);
   8897  } else {
   8898    masm.convertWasmI31RefTo32Unsigned(i31Value, intValue);
   8899  }
   8900  freeRef(i31Value);
   8901  pushI32(intValue);
   8902  return true;
   8903 }
   8904 
   8905 BranchIfRefSubtypeRegisters BaseCompiler::allocRegistersForBranchIfRefSubtype(
   8906    RefType destType) {
   8907  BranchWasmRefIsSubtypeRegisters needs =
   8908      MacroAssembler::regsForBranchWasmRefIsSubtype(destType);
   8909  return BranchIfRefSubtypeRegisters{
   8910      .superSTV = needs.needSuperSTV
   8911                      ? loadSuperTypeVector(
   8912                            codeMeta_.types->indexOf(*destType.typeDef()))
   8913                      : RegPtr::Invalid(),
   8914      .scratch1 = needs.needScratch1 ? needI32() : RegI32::Invalid(),
   8915      .scratch2 = needs.needScratch2 ? needI32() : RegI32::Invalid(),
   8916  };
   8917 }
   8918 
   8919 void BaseCompiler::freeRegistersForBranchIfRefSubtype(
   8920    const BranchIfRefSubtypeRegisters& regs) {
   8921  if (regs.superSTV.isValid()) {
   8922    freePtr(regs.superSTV);
   8923  }
   8924  if (regs.scratch1.isValid()) {
   8925    freeI32(regs.scratch1);
   8926  }
   8927  if (regs.scratch2.isValid()) {
   8928    freeI32(regs.scratch2);
   8929  }
   8930 }
   8931 
   8932 bool BaseCompiler::emitRefTest(bool nullable) {
   8933  Nothing nothing;
   8934  RefType sourceType;
   8935  RefType destType;
   8936  if (!iter_.readRefTest(nullable, &sourceType, &destType, &nothing)) {
   8937    return false;
   8938  }
   8939 
   8940  if (deadCode_) {
   8941    return true;
   8942  }
   8943 
   8944  Label success;
   8945  Label join;
   8946  RegRef ref = popRef();
   8947  RegI32 result = needI32();
   8948 
   8949  BranchIfRefSubtypeRegisters regs =
   8950      allocRegistersForBranchIfRefSubtype(destType);
   8951  masm.branchWasmRefIsSubtype(ref, MaybeRefType(sourceType), destType, &success,
   8952                              /*onSuccess=*/true, /*signalNullChecks=*/false,
   8953                              regs.superSTV, regs.scratch1, regs.scratch2);
   8954  freeRegistersForBranchIfRefSubtype(regs);
   8955 
   8956  masm.xor32(result, result);
   8957  masm.jump(&join);
   8958  masm.bind(&success);
   8959  masm.move32(Imm32(1), result);
   8960  masm.bind(&join);
   8961 
   8962  pushI32(result);
   8963  freeRef(ref);
   8964 
   8965  return true;
   8966 }
   8967 
   8968 bool BaseCompiler::emitRefCast(bool nullable) {
   8969  Nothing nothing;
   8970  RefType sourceType;
   8971  RefType destType;
   8972  if (!iter_.readRefCast(nullable, &sourceType, &destType, &nothing)) {
   8973    return false;
   8974  }
   8975 
   8976  if (deadCode_) {
   8977    return true;
   8978  }
   8979 
   8980  RegRef ref = popRef();
   8981 
   8982  OutOfLineCode* ool = addOutOfLineCode(
   8983      new (alloc_) OutOfLineAbortingTrap(Trap::BadCast, trapSiteDesc()));
   8984  if (!ool) {
   8985    return false;
   8986  }
   8987 
   8988  BranchIfRefSubtypeRegisters regs =
   8989      allocRegistersForBranchIfRefSubtype(destType);
   8990  FaultingCodeOffset fco = masm.branchWasmRefIsSubtype(
   8991      ref, MaybeRefType(sourceType), destType, ool->entry(),
   8992      /*onSuccess=*/false, /*signalNullChecks=*/true, regs.superSTV,
   8993      regs.scratch1, regs.scratch2);
   8994  if (fco.isValid()) {
   8995    masm.append(wasm::Trap::BadCast, wasm::TrapMachineInsnForLoadWord(),
   8996                fco.get(), trapSiteDesc());
   8997  }
   8998  freeRegistersForBranchIfRefSubtype(regs);
   8999 
   9000  pushRef(ref);
   9001 
   9002  return true;
   9003 }
   9004 
   9005 bool BaseCompiler::emitBrOnCastCommon(bool onSuccess,
   9006                                      uint32_t labelRelativeDepth,
   9007                                      const ResultType& labelType,
   9008                                      MaybeRefType sourceType,
   9009                                      RefType destType) {
   9010  Control& target = controlItem(labelRelativeDepth);
   9011  target.bceSafeOnExit &= bceSafe_;
   9012 
   9013  // 3. br_if $l : [T*, ref] -> [T*, ref]
   9014  BranchState b(&target.label, target.stackHeight, InvertBranch(false),
   9015                labelType);
   9016 
   9017  // Don't allocate the result register used in the branch
   9018  if (b.hasBlockResults()) {
   9019    needIntegerResultRegisters(b.resultType);
   9020  }
   9021 
   9022  // Get the ref from the top of the stack
   9023  RegRef refCondition = popRef();
   9024 
   9025  // Create a copy of the ref for passing to the on_cast label,
   9026  // the original ref is used in the condition.
   9027  RegRef ref = needRef();
   9028  moveRef(refCondition, ref);
   9029  pushRef(ref);
   9030 
   9031  if (b.hasBlockResults()) {
   9032    freeIntegerResultRegisters(b.resultType);
   9033  }
   9034 
   9035  if (!jumpConditionalWithResults(&b, refCondition, sourceType, destType,
   9036                                  onSuccess)) {
   9037    return false;
   9038  }
   9039  freeRef(refCondition);
   9040 
   9041  return true;
   9042 }
   9043 
   9044 bool BaseCompiler::emitBrOnCast(bool onSuccess) {
   9045  MOZ_ASSERT(!hasLatentOp());
   9046 
   9047  uint32_t labelRelativeDepth;
   9048  RefType sourceType;
   9049  RefType destType;
   9050  ResultType labelType;
   9051  BaseNothingVector unused_values{};
   9052  if (!iter_.readBrOnCast(onSuccess, &labelRelativeDepth, &sourceType,
   9053                          &destType, &labelType, &unused_values)) {
   9054    return false;
   9055  }
   9056 
   9057  if (deadCode_) {
   9058    return true;
   9059  }
   9060 
   9061  return emitBrOnCastCommon(onSuccess, labelRelativeDepth, labelType,
   9062                            MaybeRefType(sourceType), destType);
   9063 }
   9064 
   9065 bool BaseCompiler::emitAnyConvertExtern() {
   9066  // any.convert_extern is a no-op because anyref and extern share the same
   9067  // representation
   9068  Nothing nothing;
   9069  return iter_.readRefConversion(RefType::extern_(), RefType::any(), &nothing);
   9070 }
   9071 
   9072 bool BaseCompiler::emitExternConvertAny() {
   9073  // extern.convert_any is a no-op because anyref and extern share the same
   9074  // representation
   9075  Nothing nothing;
   9076  return iter_.readRefConversion(RefType::any(), RefType::extern_(), &nothing);
   9077 }
   9078 
   9079 //////////////////////////////////////////////////////////////////////////////
   9080 //
   9081 // SIMD and Relaxed SIMD.
   9082 
   9083 #ifdef ENABLE_WASM_SIMD
   9084 
   9085 // Emitter trampolines used by abstracted SIMD operations.  Naming here follows
   9086 // the SIMD spec pretty closely.
   9087 
   9088 static void AndV128(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9089  masm.bitwiseAndSimd128(rs, rsd);
   9090 }
   9091 
   9092 static void OrV128(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9093  masm.bitwiseOrSimd128(rs, rsd);
   9094 }
   9095 
   9096 static void XorV128(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9097  masm.bitwiseXorSimd128(rs, rsd);
   9098 }
   9099 
   9100 static void AddI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9101  masm.addInt8x16(rsd, rs, rsd);
   9102 }
   9103 
   9104 static void AddI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9105  masm.addInt16x8(rsd, rs, rsd);
   9106 }
   9107 
   9108 static void AddI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9109  masm.addInt32x4(rsd, rs, rsd);
   9110 }
   9111 
   9112 static void AddF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9113  masm.addFloat32x4(rsd, rs, rsd);
   9114 }
   9115 
   9116 static void AddI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9117  masm.addInt64x2(rsd, rs, rsd);
   9118 }
   9119 
   9120 static void AddF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9121  masm.addFloat64x2(rsd, rs, rsd);
   9122 }
   9123 
   9124 static void AddSatI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9125  masm.addSatInt8x16(rsd, rs, rsd);
   9126 }
   9127 
   9128 static void AddSatUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9129  masm.unsignedAddSatInt8x16(rsd, rs, rsd);
   9130 }
   9131 
   9132 static void AddSatI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9133  masm.addSatInt16x8(rsd, rs, rsd);
   9134 }
   9135 
   9136 static void AddSatUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9137  masm.unsignedAddSatInt16x8(rsd, rs, rsd);
   9138 }
   9139 
   9140 static void SubI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9141  masm.subInt8x16(rsd, rs, rsd);
   9142 }
   9143 
   9144 static void SubI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9145  masm.subInt16x8(rsd, rs, rsd);
   9146 }
   9147 
   9148 static void SubI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9149  masm.subInt32x4(rsd, rs, rsd);
   9150 }
   9151 
   9152 static void SubF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9153  masm.subFloat32x4(rsd, rs, rsd);
   9154 }
   9155 
   9156 static void SubI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9157  masm.subInt64x2(rsd, rs, rsd);
   9158 }
   9159 
   9160 static void SubF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9161  masm.subFloat64x2(rsd, rs, rsd);
   9162 }
   9163 
   9164 static void SubSatI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9165  masm.subSatInt8x16(rsd, rs, rsd);
   9166 }
   9167 
   9168 static void SubSatUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9169  masm.unsignedSubSatInt8x16(rsd, rs, rsd);
   9170 }
   9171 
   9172 static void SubSatI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9173  masm.subSatInt16x8(rsd, rs, rsd);
   9174 }
   9175 
   9176 static void SubSatUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9177  masm.unsignedSubSatInt16x8(rsd, rs, rsd);
   9178 }
   9179 
   9180 static void MulI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9181  masm.mulInt16x8(rsd, rs, rsd);
   9182 }
   9183 
   9184 static void MulI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9185  masm.mulInt32x4(rsd, rs, rsd);
   9186 }
   9187 
   9188 static void MulF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9189  masm.mulFloat32x4(rsd, rs, rsd);
   9190 }
   9191 
   9192 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   9193 static void MulI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9194                     RegV128 temp) {
   9195  masm.mulInt64x2(rsd, rs, rsd, temp);
   9196 }
   9197 #  elif defined(JS_CODEGEN_ARM64)
   9198 static void MulI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9199                     RegV128 temp1, RegV128 temp2) {
   9200  masm.mulInt64x2(rsd, rs, rsd, temp1, temp2);
   9201 }
   9202 #  endif
   9203 
   9204 static void MulF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9205  masm.mulFloat64x2(rsd, rs, rsd);
   9206 }
   9207 
   9208 static void DivF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9209  masm.divFloat32x4(rsd, rs, rsd);
   9210 }
   9211 
   9212 static void DivF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9213  masm.divFloat64x2(rsd, rs, rsd);
   9214 }
   9215 
   9216 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   9217 static void MinF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9218                     RegV128 temp1, RegV128 temp2) {
   9219  masm.minFloat32x4(rsd, rs, rsd, temp1, temp2);
   9220 }
   9221 
   9222 static void MinF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9223                     RegV128 temp1, RegV128 temp2) {
   9224  masm.minFloat64x2(rsd, rs, rsd, temp1, temp2);
   9225 }
   9226 
   9227 static void MaxF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9228                     RegV128 temp1, RegV128 temp2) {
   9229  masm.maxFloat32x4(rsd, rs, rsd, temp1, temp2);
   9230 }
   9231 
   9232 static void MaxF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd,
   9233                     RegV128 temp1, RegV128 temp2) {
   9234  masm.maxFloat64x2(rsd, rs, rsd, temp1, temp2);
   9235 }
   9236 
   9237 static void PMinF32x4(MacroAssembler& masm, RegV128 rsd, RegV128 rs,
   9238                      RhsDestOp) {
   9239  masm.pseudoMinFloat32x4(rsd, rs);
   9240 }
   9241 
   9242 static void PMinF64x2(MacroAssembler& masm, RegV128 rsd, RegV128 rs,
   9243                      RhsDestOp) {
   9244  masm.pseudoMinFloat64x2(rsd, rs);
   9245 }
   9246 
   9247 static void PMaxF32x4(MacroAssembler& masm, RegV128 rsd, RegV128 rs,
   9248                      RhsDestOp) {
   9249  masm.pseudoMaxFloat32x4(rsd, rs);
   9250 }
   9251 
   9252 static void PMaxF64x2(MacroAssembler& masm, RegV128 rsd, RegV128 rs,
   9253                      RhsDestOp) {
   9254  masm.pseudoMaxFloat64x2(rsd, rs);
   9255 }
   9256 #  elif defined(JS_CODEGEN_ARM64)
   9257 static void MinF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9258  masm.minFloat32x4(rs, rsd);
   9259 }
   9260 
   9261 static void MinF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9262  masm.minFloat64x2(rs, rsd);
   9263 }
   9264 
   9265 static void MaxF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9266  masm.maxFloat32x4(rs, rsd);
   9267 }
   9268 
   9269 static void MaxF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9270  masm.maxFloat64x2(rs, rsd);
   9271 }
   9272 
   9273 static void PMinF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9274  masm.pseudoMinFloat32x4(rs, rsd);
   9275 }
   9276 
   9277 static void PMinF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9278  masm.pseudoMinFloat64x2(rs, rsd);
   9279 }
   9280 
   9281 static void PMaxF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9282  masm.pseudoMaxFloat32x4(rs, rsd);
   9283 }
   9284 
   9285 static void PMaxF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9286  masm.pseudoMaxFloat64x2(rs, rsd);
   9287 }
   9288 #  endif
   9289 
   9290 static void DotI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9291  masm.widenDotInt16x8(rsd, rs, rsd);
   9292 }
   9293 
   9294 static void ExtMulLowI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9295  masm.extMulLowInt8x16(rsd, rs, rsd);
   9296 }
   9297 
   9298 static void ExtMulHighI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9299  masm.extMulHighInt8x16(rsd, rs, rsd);
   9300 }
   9301 
   9302 static void ExtMulLowUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9303  masm.unsignedExtMulLowInt8x16(rsd, rs, rsd);
   9304 }
   9305 
   9306 static void ExtMulHighUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9307  masm.unsignedExtMulHighInt8x16(rsd, rs, rsd);
   9308 }
   9309 
   9310 static void ExtMulLowI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9311  masm.extMulLowInt16x8(rsd, rs, rsd);
   9312 }
   9313 
   9314 static void ExtMulHighI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9315  masm.extMulHighInt16x8(rsd, rs, rsd);
   9316 }
   9317 
   9318 static void ExtMulLowUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9319  masm.unsignedExtMulLowInt16x8(rsd, rs, rsd);
   9320 }
   9321 
   9322 static void ExtMulHighUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9323  masm.unsignedExtMulHighInt16x8(rsd, rs, rsd);
   9324 }
   9325 
   9326 static void ExtMulLowI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9327  masm.extMulLowInt32x4(rsd, rs, rsd);
   9328 }
   9329 
   9330 static void ExtMulHighI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9331  masm.extMulHighInt32x4(rsd, rs, rsd);
   9332 }
   9333 
   9334 static void ExtMulLowUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9335  masm.unsignedExtMulLowInt32x4(rsd, rs, rsd);
   9336 }
   9337 
   9338 static void ExtMulHighUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9339  masm.unsignedExtMulHighInt32x4(rsd, rs, rsd);
   9340 }
   9341 
   9342 static void Q15MulrSatS(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9343  masm.q15MulrSatInt16x8(rsd, rs, rsd);
   9344 }
   9345 
   9346 static void CmpI8x16(MacroAssembler& masm, Assembler::Condition cond,
   9347                     RegV128 rs, RegV128 rsd) {
   9348  masm.compareInt8x16(cond, rs, rsd);
   9349 }
   9350 
   9351 static void CmpI16x8(MacroAssembler& masm, Assembler::Condition cond,
   9352                     RegV128 rs, RegV128 rsd) {
   9353  masm.compareInt16x8(cond, rs, rsd);
   9354 }
   9355 
   9356 static void CmpI32x4(MacroAssembler& masm, Assembler::Condition cond,
   9357                     RegV128 rs, RegV128 rsd) {
   9358  masm.compareInt32x4(cond, rs, rsd);
   9359 }
   9360 
   9361 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   9362 static void CmpI64x2ForEquality(MacroAssembler& masm, Assembler::Condition cond,
   9363                                RegV128 rs, RegV128 rsd) {
   9364  masm.compareForEqualityInt64x2(cond, rsd, rs, rsd);
   9365 }
   9366 
   9367 static void CmpI64x2ForOrdering(MacroAssembler& masm, Assembler::Condition cond,
   9368                                RegV128 rs, RegV128 rsd, RegV128 temp1,
   9369                                RegV128 temp2) {
   9370  masm.compareForOrderingInt64x2(cond, rsd, rs, rsd, temp1, temp2);
   9371 }
   9372 #  else
   9373 static void CmpI64x2ForEquality(MacroAssembler& masm, Assembler::Condition cond,
   9374                                RegV128 rs, RegV128 rsd) {
   9375  masm.compareInt64x2(cond, rs, rsd);
   9376 }
   9377 
   9378 static void CmpI64x2ForOrdering(MacroAssembler& masm, Assembler::Condition cond,
   9379                                RegV128 rs, RegV128 rsd) {
   9380  masm.compareInt64x2(cond, rs, rsd);
   9381 }
   9382 #  endif  // JS_CODEGEN_X86 || JS_CODEGEN_X64
   9383 
   9384 static void CmpUI8x16(MacroAssembler& masm, Assembler::Condition cond,
   9385                      RegV128 rs, RegV128 rsd) {
   9386  masm.compareInt8x16(cond, rs, rsd);
   9387 }
   9388 
   9389 static void CmpUI16x8(MacroAssembler& masm, Assembler::Condition cond,
   9390                      RegV128 rs, RegV128 rsd) {
   9391  masm.compareInt16x8(cond, rs, rsd);
   9392 }
   9393 
   9394 static void CmpUI32x4(MacroAssembler& masm, Assembler::Condition cond,
   9395                      RegV128 rs, RegV128 rsd) {
   9396  masm.compareInt32x4(cond, rs, rsd);
   9397 }
   9398 
   9399 static void CmpF32x4(MacroAssembler& masm, Assembler::Condition cond,
   9400                     RegV128 rs, RegV128 rsd) {
   9401  masm.compareFloat32x4(cond, rs, rsd);
   9402 }
   9403 
   9404 static void CmpF64x2(MacroAssembler& masm, Assembler::Condition cond,
   9405                     RegV128 rs, RegV128 rsd) {
   9406  masm.compareFloat64x2(cond, rs, rsd);
   9407 }
   9408 
   9409 static void NegI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9410  masm.negInt8x16(rs, rd);
   9411 }
   9412 
   9413 static void NegI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9414  masm.negInt16x8(rs, rd);
   9415 }
   9416 
   9417 static void NegI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9418  masm.negInt32x4(rs, rd);
   9419 }
   9420 
   9421 static void NegI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9422  masm.negInt64x2(rs, rd);
   9423 }
   9424 
   9425 static void NegF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9426  masm.negFloat32x4(rs, rd);
   9427 }
   9428 
   9429 static void NegF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9430  masm.negFloat64x2(rs, rd);
   9431 }
   9432 
   9433 static void AbsF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9434  masm.absFloat32x4(rs, rd);
   9435 }
   9436 
   9437 static void AbsF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9438  masm.absFloat64x2(rs, rd);
   9439 }
   9440 
   9441 static void SqrtF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9442  masm.sqrtFloat32x4(rs, rd);
   9443 }
   9444 
   9445 static void SqrtF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9446  masm.sqrtFloat64x2(rs, rd);
   9447 }
   9448 
   9449 static void CeilF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9450  masm.ceilFloat32x4(rs, rd);
   9451 }
   9452 
   9453 static void FloorF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9454  masm.floorFloat32x4(rs, rd);
   9455 }
   9456 
   9457 static void TruncF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9458  masm.truncFloat32x4(rs, rd);
   9459 }
   9460 
   9461 static void NearestF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9462  masm.nearestFloat32x4(rs, rd);
   9463 }
   9464 
   9465 static void CeilF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9466  masm.ceilFloat64x2(rs, rd);
   9467 }
   9468 
   9469 static void FloorF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9470  masm.floorFloat64x2(rs, rd);
   9471 }
   9472 
   9473 static void TruncF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9474  masm.truncFloat64x2(rs, rd);
   9475 }
   9476 
   9477 static void NearestF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9478  masm.nearestFloat64x2(rs, rd);
   9479 }
   9480 
   9481 static void NotV128(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9482  masm.bitwiseNotSimd128(rs, rd);
   9483 }
   9484 
   9485 static void ExtAddPairwiseI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9486  masm.extAddPairwiseInt8x16(rs, rsd);
   9487 }
   9488 
   9489 static void ExtAddPairwiseUI8x16(MacroAssembler& masm, RegV128 rs,
   9490                                 RegV128 rsd) {
   9491  masm.unsignedExtAddPairwiseInt8x16(rs, rsd);
   9492 }
   9493 
   9494 static void ExtAddPairwiseI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9495  masm.extAddPairwiseInt16x8(rs, rsd);
   9496 }
   9497 
   9498 static void ExtAddPairwiseUI16x8(MacroAssembler& masm, RegV128 rs,
   9499                                 RegV128 rsd) {
   9500  masm.unsignedExtAddPairwiseInt16x8(rs, rsd);
   9501 }
   9502 
   9503 static void ShiftOpMask(MacroAssembler& masm, SimdOp op, RegI32 in,
   9504                        RegI32 out) {
   9505  int32_t maskBits;
   9506 
   9507  masm.mov(in, out);
   9508  if (MacroAssembler::MustMaskShiftCountSimd128(op, &maskBits)) {
   9509    masm.and32(Imm32(maskBits), out);
   9510  }
   9511 }
   9512 
   9513 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   9514 static void ShiftLeftI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9515                           RegI32 temp1, RegV128 temp2) {
   9516  ShiftOpMask(masm, SimdOp::I8x16Shl, rs, temp1);
   9517  masm.leftShiftInt8x16(temp1, rsd, temp2);
   9518 }
   9519 
   9520 static void ShiftLeftI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9521                           RegI32 temp) {
   9522  ShiftOpMask(masm, SimdOp::I16x8Shl, rs, temp);
   9523  masm.leftShiftInt16x8(temp, rsd);
   9524 }
   9525 
   9526 static void ShiftLeftI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9527                           RegI32 temp) {
   9528  ShiftOpMask(masm, SimdOp::I32x4Shl, rs, temp);
   9529  masm.leftShiftInt32x4(temp, rsd);
   9530 }
   9531 
   9532 static void ShiftLeftI64x2(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9533                           RegI32 temp) {
   9534  ShiftOpMask(masm, SimdOp::I64x2Shl, rs, temp);
   9535  masm.leftShiftInt64x2(temp, rsd);
   9536 }
   9537 
   9538 static void ShiftRightI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9539                            RegI32 temp1, RegV128 temp2) {
   9540  ShiftOpMask(masm, SimdOp::I8x16ShrS, rs, temp1);
   9541  masm.rightShiftInt8x16(temp1, rsd, temp2);
   9542 }
   9543 
   9544 static void ShiftRightUI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9545                             RegI32 temp1, RegV128 temp2) {
   9546  ShiftOpMask(masm, SimdOp::I8x16ShrU, rs, temp1);
   9547  masm.unsignedRightShiftInt8x16(temp1, rsd, temp2);
   9548 }
   9549 
   9550 static void ShiftRightI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9551                            RegI32 temp) {
   9552  ShiftOpMask(masm, SimdOp::I16x8ShrS, rs, temp);
   9553  masm.rightShiftInt16x8(temp, rsd);
   9554 }
   9555 
   9556 static void ShiftRightUI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9557                             RegI32 temp) {
   9558  ShiftOpMask(masm, SimdOp::I16x8ShrU, rs, temp);
   9559  masm.unsignedRightShiftInt16x8(temp, rsd);
   9560 }
   9561 
   9562 static void ShiftRightI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9563                            RegI32 temp) {
   9564  ShiftOpMask(masm, SimdOp::I32x4ShrS, rs, temp);
   9565  masm.rightShiftInt32x4(temp, rsd);
   9566 }
   9567 
   9568 static void ShiftRightUI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9569                             RegI32 temp) {
   9570  ShiftOpMask(masm, SimdOp::I32x4ShrU, rs, temp);
   9571  masm.unsignedRightShiftInt32x4(temp, rsd);
   9572 }
   9573 
   9574 static void ShiftRightUI64x2(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9575                             RegI32 temp) {
   9576  ShiftOpMask(masm, SimdOp::I64x2ShrU, rs, temp);
   9577  masm.unsignedRightShiftInt64x2(temp, rsd);
   9578 }
   9579 #  elif defined(JS_CODEGEN_ARM64)
   9580 static void ShiftLeftI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9581                           RegI32 temp) {
   9582  ShiftOpMask(masm, SimdOp::I8x16Shl, rs, temp);
   9583  masm.leftShiftInt8x16(rsd, temp, rsd);
   9584 }
   9585 
   9586 static void ShiftLeftI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9587                           RegI32 temp) {
   9588  ShiftOpMask(masm, SimdOp::I16x8Shl, rs, temp);
   9589  masm.leftShiftInt16x8(rsd, temp, rsd);
   9590 }
   9591 
   9592 static void ShiftLeftI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9593                           RegI32 temp) {
   9594  ShiftOpMask(masm, SimdOp::I32x4Shl, rs, temp);
   9595  masm.leftShiftInt32x4(rsd, temp, rsd);
   9596 }
   9597 
   9598 static void ShiftLeftI64x2(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9599                           RegI32 temp) {
   9600  ShiftOpMask(masm, SimdOp::I64x2Shl, rs, temp);
   9601  masm.leftShiftInt64x2(rsd, temp, rsd);
   9602 }
   9603 
   9604 static void ShiftRightI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9605                            RegI32 temp) {
   9606  ShiftOpMask(masm, SimdOp::I8x16ShrS, rs, temp);
   9607  masm.rightShiftInt8x16(rsd, temp, rsd);
   9608 }
   9609 
   9610 static void ShiftRightUI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9611                             RegI32 temp) {
   9612  ShiftOpMask(masm, SimdOp::I8x16ShrU, rs, temp);
   9613  masm.unsignedRightShiftInt8x16(rsd, temp, rsd);
   9614 }
   9615 
   9616 static void ShiftRightI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9617                            RegI32 temp) {
   9618  ShiftOpMask(masm, SimdOp::I16x8ShrS, rs, temp);
   9619  masm.rightShiftInt16x8(rsd, temp, rsd);
   9620 }
   9621 
   9622 static void ShiftRightUI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9623                             RegI32 temp) {
   9624  ShiftOpMask(masm, SimdOp::I16x8ShrU, rs, temp);
   9625  masm.unsignedRightShiftInt16x8(rsd, temp, rsd);
   9626 }
   9627 
   9628 static void ShiftRightI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9629                            RegI32 temp) {
   9630  ShiftOpMask(masm, SimdOp::I32x4ShrS, rs, temp);
   9631  masm.rightShiftInt32x4(rsd, temp, rsd);
   9632 }
   9633 
   9634 static void ShiftRightUI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9635                             RegI32 temp) {
   9636  ShiftOpMask(masm, SimdOp::I32x4ShrU, rs, temp);
   9637  masm.unsignedRightShiftInt32x4(rsd, temp, rsd);
   9638 }
   9639 
   9640 static void ShiftRightI64x2(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9641                            RegI32 temp) {
   9642  ShiftOpMask(masm, SimdOp::I64x2ShrS, rs, temp);
   9643  masm.rightShiftInt64x2(rsd, temp, rsd);
   9644 }
   9645 
   9646 static void ShiftRightUI64x2(MacroAssembler& masm, RegI32 rs, RegV128 rsd,
   9647                             RegI32 temp) {
   9648  ShiftOpMask(masm, SimdOp::I64x2ShrU, rs, temp);
   9649  masm.unsignedRightShiftInt64x2(rsd, temp, rsd);
   9650 }
   9651 #  endif
   9652 
   9653 static void AverageUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9654  masm.unsignedAverageInt8x16(rsd, rs, rsd);
   9655 }
   9656 
   9657 static void AverageUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9658  masm.unsignedAverageInt16x8(rsd, rs, rsd);
   9659 }
   9660 
   9661 static void MinI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9662  masm.minInt8x16(rsd, rs, rsd);
   9663 }
   9664 
   9665 static void MinUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9666  masm.unsignedMinInt8x16(rsd, rs, rsd);
   9667 }
   9668 
   9669 static void MaxI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9670  masm.maxInt8x16(rsd, rs, rsd);
   9671 }
   9672 
   9673 static void MaxUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9674  masm.unsignedMaxInt8x16(rsd, rs, rsd);
   9675 }
   9676 
   9677 static void MinI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9678  masm.minInt16x8(rsd, rs, rsd);
   9679 }
   9680 
   9681 static void MinUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9682  masm.unsignedMinInt16x8(rsd, rs, rsd);
   9683 }
   9684 
   9685 static void MaxI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9686  masm.maxInt16x8(rsd, rs, rsd);
   9687 }
   9688 
   9689 static void MaxUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9690  masm.unsignedMaxInt16x8(rsd, rs, rsd);
   9691 }
   9692 
   9693 static void MinI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9694  masm.minInt32x4(rsd, rs, rsd);
   9695 }
   9696 
   9697 static void MinUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9698  masm.unsignedMinInt32x4(rsd, rs, rsd);
   9699 }
   9700 
   9701 static void MaxI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9702  masm.maxInt32x4(rsd, rs, rsd);
   9703 }
   9704 
   9705 static void MaxUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9706  masm.unsignedMaxInt32x4(rsd, rs, rsd);
   9707 }
   9708 
   9709 static void NarrowI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9710  masm.narrowInt16x8(rsd, rs, rsd);
   9711 }
   9712 
   9713 static void NarrowUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9714  masm.unsignedNarrowInt16x8(rsd, rs, rsd);
   9715 }
   9716 
   9717 static void NarrowI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9718  masm.narrowInt32x4(rsd, rs, rsd);
   9719 }
   9720 
   9721 static void NarrowUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9722  masm.unsignedNarrowInt32x4(rsd, rs, rsd);
   9723 }
   9724 
   9725 static void WidenLowI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9726  masm.widenLowInt8x16(rs, rd);
   9727 }
   9728 
   9729 static void WidenHighI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9730  masm.widenHighInt8x16(rs, rd);
   9731 }
   9732 
   9733 static void WidenLowUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9734  masm.unsignedWidenLowInt8x16(rs, rd);
   9735 }
   9736 
   9737 static void WidenHighUI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9738  masm.unsignedWidenHighInt8x16(rs, rd);
   9739 }
   9740 
   9741 static void WidenLowI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9742  masm.widenLowInt16x8(rs, rd);
   9743 }
   9744 
   9745 static void WidenHighI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9746  masm.widenHighInt16x8(rs, rd);
   9747 }
   9748 
   9749 static void WidenLowUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9750  masm.unsignedWidenLowInt16x8(rs, rd);
   9751 }
   9752 
   9753 static void WidenHighUI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9754  masm.unsignedWidenHighInt16x8(rs, rd);
   9755 }
   9756 
   9757 static void WidenLowI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9758  masm.widenLowInt32x4(rs, rd);
   9759 }
   9760 
   9761 static void WidenHighI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9762  masm.widenHighInt32x4(rs, rd);
   9763 }
   9764 
   9765 static void WidenLowUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9766  masm.unsignedWidenLowInt32x4(rs, rd);
   9767 }
   9768 
   9769 static void WidenHighUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9770  masm.unsignedWidenHighInt32x4(rs, rd);
   9771 }
   9772 
   9773 #  if defined(JS_CODEGEN_ARM64)
   9774 static void PopcntI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9775  masm.popcntInt8x16(rs, rd);
   9776 }
   9777 #  else
   9778 static void PopcntI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd,
   9779                        RegV128 temp) {
   9780  masm.popcntInt8x16(rs, rd, temp);
   9781 }
   9782 #  endif  // JS_CODEGEN_ARM64
   9783 
   9784 static void AbsI8x16(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9785  masm.absInt8x16(rs, rd);
   9786 }
   9787 
   9788 static void AbsI16x8(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9789  masm.absInt16x8(rs, rd);
   9790 }
   9791 
   9792 static void AbsI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9793  masm.absInt32x4(rs, rd);
   9794 }
   9795 
   9796 static void AbsI64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9797  masm.absInt64x2(rs, rd);
   9798 }
   9799 
   9800 static void ExtractLaneI8x16(MacroAssembler& masm, uint32_t laneIndex,
   9801                             RegV128 rs, RegI32 rd) {
   9802  masm.extractLaneInt8x16(laneIndex, rs, rd);
   9803 }
   9804 
   9805 static void ExtractLaneUI8x16(MacroAssembler& masm, uint32_t laneIndex,
   9806                              RegV128 rs, RegI32 rd) {
   9807  masm.unsignedExtractLaneInt8x16(laneIndex, rs, rd);
   9808 }
   9809 
   9810 static void ExtractLaneI16x8(MacroAssembler& masm, uint32_t laneIndex,
   9811                             RegV128 rs, RegI32 rd) {
   9812  masm.extractLaneInt16x8(laneIndex, rs, rd);
   9813 }
   9814 
   9815 static void ExtractLaneUI16x8(MacroAssembler& masm, uint32_t laneIndex,
   9816                              RegV128 rs, RegI32 rd) {
   9817  masm.unsignedExtractLaneInt16x8(laneIndex, rs, rd);
   9818 }
   9819 
   9820 static void ExtractLaneI32x4(MacroAssembler& masm, uint32_t laneIndex,
   9821                             RegV128 rs, RegI32 rd) {
   9822  masm.extractLaneInt32x4(laneIndex, rs, rd);
   9823 }
   9824 
   9825 static void ExtractLaneI64x2(MacroAssembler& masm, uint32_t laneIndex,
   9826                             RegV128 rs, RegI64 rd) {
   9827  masm.extractLaneInt64x2(laneIndex, rs, rd);
   9828 }
   9829 
   9830 static void ExtractLaneF32x4(MacroAssembler& masm, uint32_t laneIndex,
   9831                             RegV128 rs, RegF32 rd) {
   9832  masm.extractLaneFloat32x4(laneIndex, rs, rd);
   9833 }
   9834 
   9835 static void ExtractLaneF64x2(MacroAssembler& masm, uint32_t laneIndex,
   9836                             RegV128 rs, RegF64 rd) {
   9837  masm.extractLaneFloat64x2(laneIndex, rs, rd);
   9838 }
   9839 
   9840 static void ReplaceLaneI8x16(MacroAssembler& masm, uint32_t laneIndex,
   9841                             RegI32 rs, RegV128 rsd) {
   9842  masm.replaceLaneInt8x16(laneIndex, rs, rsd);
   9843 }
   9844 
   9845 static void ReplaceLaneI16x8(MacroAssembler& masm, uint32_t laneIndex,
   9846                             RegI32 rs, RegV128 rsd) {
   9847  masm.replaceLaneInt16x8(laneIndex, rs, rsd);
   9848 }
   9849 
   9850 static void ReplaceLaneI32x4(MacroAssembler& masm, uint32_t laneIndex,
   9851                             RegI32 rs, RegV128 rsd) {
   9852  masm.replaceLaneInt32x4(laneIndex, rs, rsd);
   9853 }
   9854 
   9855 static void ReplaceLaneI64x2(MacroAssembler& masm, uint32_t laneIndex,
   9856                             RegI64 rs, RegV128 rsd) {
   9857  masm.replaceLaneInt64x2(laneIndex, rs, rsd);
   9858 }
   9859 
   9860 static void ReplaceLaneF32x4(MacroAssembler& masm, uint32_t laneIndex,
   9861                             RegF32 rs, RegV128 rsd) {
   9862  masm.replaceLaneFloat32x4(laneIndex, rs, rsd);
   9863 }
   9864 
   9865 static void ReplaceLaneF64x2(MacroAssembler& masm, uint32_t laneIndex,
   9866                             RegF64 rs, RegV128 rsd) {
   9867  masm.replaceLaneFloat64x2(laneIndex, rs, rsd);
   9868 }
   9869 
   9870 static void SplatI8x16(MacroAssembler& masm, RegI32 rs, RegV128 rd) {
   9871  masm.splatX16(rs, rd);
   9872 }
   9873 
   9874 static void SplatI16x8(MacroAssembler& masm, RegI32 rs, RegV128 rd) {
   9875  masm.splatX8(rs, rd);
   9876 }
   9877 
   9878 static void SplatI32x4(MacroAssembler& masm, RegI32 rs, RegV128 rd) {
   9879  masm.splatX4(rs, rd);
   9880 }
   9881 
   9882 static void SplatI64x2(MacroAssembler& masm, RegI64 rs, RegV128 rd) {
   9883  masm.splatX2(rs, rd);
   9884 }
   9885 
   9886 static void SplatF32x4(MacroAssembler& masm, RegF32 rs, RegV128 rd) {
   9887  masm.splatX4(rs, rd);
   9888 }
   9889 
   9890 static void SplatF64x2(MacroAssembler& masm, RegF64 rs, RegV128 rd) {
   9891  masm.splatX2(rs, rd);
   9892 }
   9893 
   9894 // This is the same op independent of lanes: it tests for any nonzero bit.
   9895 static void AnyTrue(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9896  masm.anyTrueSimd128(rs, rd);
   9897 }
   9898 
   9899 static void AllTrueI8x16(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9900  masm.allTrueInt8x16(rs, rd);
   9901 }
   9902 
   9903 static void AllTrueI16x8(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9904  masm.allTrueInt16x8(rs, rd);
   9905 }
   9906 
   9907 static void AllTrueI32x4(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9908  masm.allTrueInt32x4(rs, rd);
   9909 }
   9910 
   9911 static void AllTrueI64x2(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9912  masm.allTrueInt64x2(rs, rd);
   9913 }
   9914 
   9915 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
   9916 static void BitmaskI8x16(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9917  masm.bitmaskInt8x16(rs, rd);
   9918 }
   9919 
   9920 static void BitmaskI16x8(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9921  masm.bitmaskInt16x8(rs, rd);
   9922 }
   9923 
   9924 static void BitmaskI32x4(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9925  masm.bitmaskInt32x4(rs, rd);
   9926 }
   9927 
   9928 static void BitmaskI64x2(MacroAssembler& masm, RegV128 rs, RegI32 rd) {
   9929  masm.bitmaskInt64x2(rs, rd);
   9930 }
   9931 #  elif defined(JS_CODEGEN_ARM64)
   9932 static void BitmaskI8x16(MacroAssembler& masm, RegV128 rs, RegI32 rd,
   9933                         RegV128 temp) {
   9934  masm.bitmaskInt8x16(rs, rd, temp);
   9935 }
   9936 
   9937 static void BitmaskI16x8(MacroAssembler& masm, RegV128 rs, RegI32 rd,
   9938                         RegV128 temp) {
   9939  masm.bitmaskInt16x8(rs, rd, temp);
   9940 }
   9941 
   9942 static void BitmaskI32x4(MacroAssembler& masm, RegV128 rs, RegI32 rd,
   9943                         RegV128 temp) {
   9944  masm.bitmaskInt32x4(rs, rd, temp);
   9945 }
   9946 
   9947 static void BitmaskI64x2(MacroAssembler& masm, RegV128 rs, RegI32 rd,
   9948                         RegV128 temp) {
   9949  masm.bitmaskInt64x2(rs, rd, temp);
   9950 }
   9951 #  endif
   9952 
   9953 static void Swizzle(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
   9954  masm.swizzleInt8x16(rsd, rs, rsd);
   9955 }
   9956 
   9957 static void ConvertI32x4ToF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9958  masm.convertInt32x4ToFloat32x4(rs, rd);
   9959 }
   9960 
   9961 static void ConvertUI32x4ToF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9962  masm.unsignedConvertInt32x4ToFloat32x4(rs, rd);
   9963 }
   9964 
   9965 static void ConvertF32x4ToI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9966  masm.truncSatFloat32x4ToInt32x4(rs, rd);
   9967 }
   9968 
   9969 #  if defined(JS_CODEGEN_ARM64)
   9970 static void ConvertF32x4ToUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9971  masm.unsignedTruncSatFloat32x4ToInt32x4(rs, rd);
   9972 }
   9973 #  else
   9974 static void ConvertF32x4ToUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd,
   9975                                 RegV128 temp) {
   9976  masm.unsignedTruncSatFloat32x4ToInt32x4(rs, rd, temp);
   9977 }
   9978 #  endif  // JS_CODEGEN_ARM64
   9979 
   9980 static void ConvertI32x4ToF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9981  masm.convertInt32x4ToFloat64x2(rs, rd);
   9982 }
   9983 
   9984 static void ConvertUI32x4ToF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9985  masm.unsignedConvertInt32x4ToFloat64x2(rs, rd);
   9986 }
   9987 
   9988 static void ConvertF64x2ToI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd,
   9989                                RegV128 temp) {
   9990  masm.truncSatFloat64x2ToInt32x4(rs, rd, temp);
   9991 }
   9992 
   9993 static void ConvertF64x2ToUI32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd,
   9994                                 RegV128 temp) {
   9995  masm.unsignedTruncSatFloat64x2ToInt32x4(rs, rd, temp);
   9996 }
   9997 
   9998 static void DemoteF64x2ToF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
   9999  masm.convertFloat64x2ToFloat32x4(rs, rd);
  10000 }
  10001 
  10002 static void PromoteF32x4ToF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rd) {
  10003  masm.convertFloat32x4ToFloat64x2(rs, rd);
  10004 }
  10005 
  10006 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
  10007 static void BitselectV128(MacroAssembler& masm, RegV128 rhs, RegV128 control,
  10008                          RegV128 lhsDest, RegV128 temp) {
  10009  // Ideally, we would have temp=control, and we can probably get away with
  10010  // just doing that, but don't worry about it yet.
  10011  masm.bitwiseSelectSimd128(control, lhsDest, rhs, lhsDest, temp);
  10012 }
  10013 #  elif defined(JS_CODEGEN_ARM64)
  10014 static void BitselectV128(MacroAssembler& masm, RegV128 rhs, RegV128 control,
  10015                          RegV128 lhsDest, RegV128 temp) {
  10016  // The masm interface is not great for the baseline compiler here, but it's
  10017  // optimal for Ion, so just work around it.
  10018  masm.moveSimd128(control, temp);
  10019  masm.bitwiseSelectSimd128(lhsDest, rhs, temp);
  10020  masm.moveSimd128(temp, lhsDest);
  10021 }
  10022 #  endif
  10023 
  10024 #  ifdef ENABLE_WASM_RELAXED_SIMD
  10025 static void RelaxedMaddF32x4(MacroAssembler& masm, RegV128 rs1, RegV128 rs2,
  10026                             RegV128 rsd) {
  10027  masm.fmaFloat32x4(rs1, rs2, rsd);
  10028 }
  10029 
  10030 static void RelaxedNmaddF32x4(MacroAssembler& masm, RegV128 rs1, RegV128 rs2,
  10031                              RegV128 rsd) {
  10032  masm.fnmaFloat32x4(rs1, rs2, rsd);
  10033 }
  10034 
  10035 static void RelaxedMaddF64x2(MacroAssembler& masm, RegV128 rs1, RegV128 rs2,
  10036                             RegV128 rsd) {
  10037  masm.fmaFloat64x2(rs1, rs2, rsd);
  10038 }
  10039 
  10040 static void RelaxedNmaddF64x2(MacroAssembler& masm, RegV128 rs1, RegV128 rs2,
  10041                              RegV128 rsd) {
  10042  masm.fnmaFloat64x2(rs1, rs2, rsd);
  10043 }
  10044 
  10045 static void RelaxedSwizzle(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10046  masm.swizzleInt8x16Relaxed(rsd, rs, rsd);
  10047 }
  10048 
  10049 static void RelaxedMinF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10050  masm.minFloat32x4Relaxed(rs, rsd);
  10051 }
  10052 
  10053 static void RelaxedMaxF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10054  masm.maxFloat32x4Relaxed(rs, rsd);
  10055 }
  10056 
  10057 static void RelaxedMinF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10058  masm.minFloat64x2Relaxed(rs, rsd);
  10059 }
  10060 
  10061 static void RelaxedMaxF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10062  masm.maxFloat64x2Relaxed(rs, rsd);
  10063 }
  10064 
  10065 static void RelaxedConvertF32x4ToI32x4(MacroAssembler& masm, RegV128 rs,
  10066                                       RegV128 rd) {
  10067  masm.truncFloat32x4ToInt32x4Relaxed(rs, rd);
  10068 }
  10069 
  10070 static void RelaxedConvertF32x4ToUI32x4(MacroAssembler& masm, RegV128 rs,
  10071                                        RegV128 rd) {
  10072  masm.unsignedTruncFloat32x4ToInt32x4Relaxed(rs, rd);
  10073 }
  10074 
  10075 static void RelaxedConvertF64x2ToI32x4(MacroAssembler& masm, RegV128 rs,
  10076                                       RegV128 rd) {
  10077  masm.truncFloat64x2ToInt32x4Relaxed(rs, rd);
  10078 }
  10079 
  10080 static void RelaxedConvertF64x2ToUI32x4(MacroAssembler& masm, RegV128 rs,
  10081                                        RegV128 rd) {
  10082  masm.unsignedTruncFloat64x2ToInt32x4Relaxed(rs, rd);
  10083 }
  10084 
  10085 static void RelaxedQ15MulrS(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10086  masm.q15MulrInt16x8Relaxed(rsd, rs, rsd);
  10087 }
  10088 
  10089 static void DotI8x16I7x16S(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
  10090  masm.dotInt8x16Int7x16(rsd, rs, rsd);
  10091 }
  10092 
  10093 void BaseCompiler::emitDotI8x16I7x16AddS() {
  10094  RegV128 rsd = popV128();
  10095  RegV128 rs0, rs1;
  10096  pop2xV128(&rs0, &rs1);
  10097 #    if defined(JS_CODEGEN_ARM64)
  10098  RegV128 temp = needV128();
  10099  masm.dotInt8x16Int7x16ThenAdd(rs0, rs1, rsd, temp);
  10100  freeV128(temp);
  10101 #    else
  10102  masm.dotInt8x16Int7x16ThenAdd(rs0, rs1, rsd);
  10103 #    endif
  10104  freeV128(rs1);
  10105  freeV128(rs0);
  10106  pushV128(rsd);
  10107 }
  10108 #  endif  // ENABLE_WASM_RELAXED_SIMD
  10109 
  10110 void BaseCompiler::emitVectorAndNot() {
  10111  // We want x & ~y but the available operation is ~x & y, so reverse the
  10112  // operands.
  10113  RegV128 r, rs;
  10114  pop2xV128(&r, &rs);
  10115  masm.bitwiseNotAndSimd128(r, rs);
  10116  freeV128(r);
  10117  pushV128(rs);
  10118 }
  10119 
  10120 bool BaseCompiler::emitLoadSplat(Scalar::Type viewType) {
  10121  LinearMemoryAddress<Nothing> addr;
  10122  if (!iter_.readLoadSplat(Scalar::byteSize(viewType), &addr)) {
  10123    return false;
  10124  }
  10125  if (deadCode_) {
  10126    return true;
  10127  }
  10128  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
  10129                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
  10130  loadSplat(&access);
  10131  return true;
  10132 }
  10133 
  10134 bool BaseCompiler::emitLoadZero(Scalar::Type viewType) {
  10135  // LoadZero has the structure of LoadSplat, so reuse the reader.
  10136  LinearMemoryAddress<Nothing> addr;
  10137  if (!iter_.readLoadSplat(Scalar::byteSize(viewType), &addr)) {
  10138    return false;
  10139  }
  10140  if (deadCode_) {
  10141    return true;
  10142  }
  10143  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
  10144                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
  10145  loadZero(&access);
  10146  return true;
  10147 }
  10148 
  10149 bool BaseCompiler::emitLoadExtend(Scalar::Type viewType) {
  10150  LinearMemoryAddress<Nothing> addr;
  10151  if (!iter_.readLoadExtend(&addr)) {
  10152    return false;
  10153  }
  10154  if (deadCode_) {
  10155    return true;
  10156  }
  10157  MemoryAccessDesc access(addr.memoryIndex, Scalar::Int64, addr.align,
  10158                          addr.offset, trapSiteDesc(),
  10159                          hugeMemoryEnabled(addr.memoryIndex));
  10160  loadExtend(&access, viewType);
  10161  return true;
  10162 }
  10163 
  10164 bool BaseCompiler::emitLoadLane(uint32_t laneSize) {
  10165  Nothing nothing;
  10166  LinearMemoryAddress<Nothing> addr;
  10167  uint32_t laneIndex;
  10168  if (!iter_.readLoadLane(laneSize, &addr, &laneIndex, &nothing)) {
  10169    return false;
  10170  }
  10171  if (deadCode_) {
  10172    return true;
  10173  }
  10174  Scalar::Type viewType;
  10175  switch (laneSize) {
  10176    case 1:
  10177      viewType = Scalar::Uint8;
  10178      break;
  10179    case 2:
  10180      viewType = Scalar::Uint16;
  10181      break;
  10182    case 4:
  10183      viewType = Scalar::Int32;
  10184      break;
  10185    case 8:
  10186      viewType = Scalar::Int64;
  10187      break;
  10188    default:
  10189      MOZ_CRASH("unsupported laneSize");
  10190  }
  10191  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
  10192                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
  10193  loadLane(&access, laneIndex);
  10194  return true;
  10195 }
  10196 
  10197 bool BaseCompiler::emitStoreLane(uint32_t laneSize) {
  10198  Nothing nothing;
  10199  LinearMemoryAddress<Nothing> addr;
  10200  uint32_t laneIndex;
  10201  if (!iter_.readStoreLane(laneSize, &addr, &laneIndex, &nothing)) {
  10202    return false;
  10203  }
  10204  if (deadCode_) {
  10205    return true;
  10206  }
  10207  Scalar::Type viewType;
  10208  switch (laneSize) {
  10209    case 1:
  10210      viewType = Scalar::Uint8;
  10211      break;
  10212    case 2:
  10213      viewType = Scalar::Uint16;
  10214      break;
  10215    case 4:
  10216      viewType = Scalar::Int32;
  10217      break;
  10218    case 8:
  10219      viewType = Scalar::Int64;
  10220      break;
  10221    default:
  10222      MOZ_CRASH("unsupported laneSize");
  10223  }
  10224  MemoryAccessDesc access(addr.memoryIndex, viewType, addr.align, addr.offset,
  10225                          trapSiteDesc(), hugeMemoryEnabled(addr.memoryIndex));
  10226  storeLane(&access, laneIndex);
  10227  return true;
  10228 }
  10229 
  10230 bool BaseCompiler::emitVectorShuffle() {
  10231  Nothing unused_a, unused_b;
  10232  V128 shuffleMask;
  10233 
  10234  if (!iter_.readVectorShuffle(&unused_a, &unused_b, &shuffleMask)) {
  10235    return false;
  10236  }
  10237 
  10238  if (deadCode_) {
  10239    return true;
  10240  }
  10241 
  10242  RegV128 rd, rs;
  10243  pop2xV128(&rd, &rs);
  10244 
  10245  masm.shuffleInt8x16(shuffleMask.bytes, rs, rd);
  10246 
  10247  freeV128(rs);
  10248  pushV128(rd);
  10249 
  10250  return true;
  10251 }
  10252 
  10253 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
  10254 bool BaseCompiler::emitVectorShiftRightI64x2() {
  10255  Nothing unused_a, unused_b;
  10256 
  10257  if (!iter_.readVectorShift(&unused_a, &unused_b)) {
  10258    return false;
  10259  }
  10260 
  10261  if (deadCode_) {
  10262    return true;
  10263  }
  10264 
  10265  RegI32 count = popI32RhsForShiftI64();
  10266  RegV128 lhsDest = popV128();
  10267  RegI64 tmp = needI64();
  10268  masm.and32(Imm32(63), count);
  10269  masm.extractLaneInt64x2(0, lhsDest, tmp);
  10270  masm.rshift64Arithmetic(count, tmp);
  10271  masm.replaceLaneInt64x2(0, tmp, lhsDest);
  10272  masm.extractLaneInt64x2(1, lhsDest, tmp);
  10273  masm.rshift64Arithmetic(count, tmp);
  10274  masm.replaceLaneInt64x2(1, tmp, lhsDest);
  10275  freeI64(tmp);
  10276  freeI32(count);
  10277  pushV128(lhsDest);
  10278 
  10279  return true;
  10280 }
  10281 #  endif
  10282 
  10283 #  ifdef ENABLE_WASM_RELAXED_SIMD
  10284 bool BaseCompiler::emitVectorLaneSelect() {
  10285  Nothing unused_a, unused_b, unused_c;
  10286 
  10287  if (!iter_.readTernary(ValType::V128, &unused_a, &unused_b, &unused_c)) {
  10288    return false;
  10289  }
  10290 
  10291  if (deadCode_) {
  10292    return true;
  10293  }
  10294 
  10295 #    if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
  10296  RegV128 mask = popV128(RegV128(vmm0));
  10297  RegV128 rhsDest = popV128();
  10298  RegV128 lhs = popV128();
  10299  masm.laneSelectSimd128(mask, lhs, rhsDest, rhsDest);
  10300  freeV128(lhs);
  10301  freeV128(mask);
  10302  pushV128(rhsDest);
  10303 #    elif defined(JS_CODEGEN_ARM64)
  10304  RegV128 maskDest = popV128();
  10305  RegV128 rhs = popV128();
  10306  RegV128 lhs = popV128();
  10307  masm.laneSelectSimd128(maskDest, lhs, rhs, maskDest);
  10308  freeV128(lhs);
  10309  freeV128(rhs);
  10310  pushV128(maskDest);
  10311 #    endif
  10312 
  10313  return true;
  10314 }
  10315 #  endif  // ENABLE_WASM_RELAXED_SIMD
  10316 #endif    // ENABLE_WASM_SIMD
  10317 
  10318 //////////////////////////////////////////////////////////////////////////////
  10319 //
  10320 // "Builtin module funcs" - magically imported functions for internal use.
  10321 
  10322 bool BaseCompiler::emitCallBuiltinModuleFunc() {
  10323  const BuiltinModuleFunc* builtinModuleFunc;
  10324 
  10325  BaseNothingVector params;
  10326  if (!iter_.readCallBuiltinModuleFunc(&builtinModuleFunc, &params)) {
  10327    return false;
  10328  }
  10329 
  10330  if (deadCode_) {
  10331    return true;
  10332  }
  10333 
  10334  if (builtinModuleFunc->usesMemory()) {
  10335    // The final parameter of an builtinModuleFunc is implicitly the heap base
  10336    pushHeapBase(0);
  10337  }
  10338 
  10339  // Call the builtinModuleFunc
  10340  return emitInstanceCall(*builtinModuleFunc->sig());
  10341 }
  10342 
  10343 //////////////////////////////////////////////////////////////////////////////
  10344 //
  10345 // Function bodies - main opcode dispatch loop.
  10346 
  10347 bool BaseCompiler::emitBody() {
  10348  AutoCreatedBy acb(masm, "(wasm)BaseCompiler::emitBody");
  10349 
  10350  MOZ_ASSERT(stackMapGenerator_.framePushedAtEntryToBody.isSome());
  10351 
  10352  if (!iter_.startFunction(func_.index)) {
  10353    return false;
  10354  }
  10355 
  10356  initControl(controlItem(), ResultType::Empty());
  10357 
  10358 #ifdef JS_ION_PERF
  10359  bool spewerEnabled = perfSpewer_.needsToRecordInstruction();
  10360 #else
  10361  bool spewerEnabled = false;
  10362 #endif
  10363  bool debugEnabled = compilerEnv_.debugEnabled();
  10364  // Fold the debug and profiler checks into a single bool.
  10365  bool hasPerInstrCheck = spewerEnabled || debugEnabled;
  10366 
  10367  for (;;) {
  10368    Nothing unused_a, unused_b, unused_c;
  10369    (void)unused_a;
  10370    (void)unused_b;
  10371    (void)unused_c;
  10372 
  10373 #ifdef DEBUG
  10374    performRegisterLeakCheck();
  10375    assertStackInvariants();
  10376 #endif
  10377 
  10378 #define dispatchBinary0(doEmit, type)             \
  10379  iter_.readBinary(type, &unused_a, &unused_b) && \
  10380      (deadCode_ || (doEmit(), true))
  10381 
  10382 #define dispatchBinary1(arg1, type)               \
  10383  iter_.readBinary(type, &unused_a, &unused_b) && \
  10384      (deadCode_ || (emitBinop(arg1), true))
  10385 
  10386 #define dispatchBinary2(arg1, arg2, type)         \
  10387  iter_.readBinary(type, &unused_a, &unused_b) && \
  10388      (deadCode_ || (emitBinop(arg1, arg2), true))
  10389 
  10390 #define dispatchBinary3(arg1, arg2, arg3, type)   \
  10391  iter_.readBinary(type, &unused_a, &unused_b) && \
  10392      (deadCode_ || (emitBinop(arg1, arg2, arg3), true))
  10393 
  10394 #define dispatchUnary0(doEmit, type) \
  10395  iter_.readUnary(type, &unused_a) && (deadCode_ || (doEmit(), true))
  10396 
  10397 #define dispatchUnary1(arg1, type) \
  10398  iter_.readUnary(type, &unused_a) && (deadCode_ || (emitUnop(arg1), true))
  10399 
  10400 #define dispatchUnary2(arg1, arg2, type) \
  10401  iter_.readUnary(type, &unused_a) &&    \
  10402      (deadCode_ || (emitUnop(arg1, arg2), true))
  10403 
  10404 #define dispatchTernary0(doEmit, type)                        \
  10405  iter_.readTernary(type, &unused_a, &unused_b, &unused_c) && \
  10406      (deadCode_ || (doEmit(), true))
  10407 
  10408 #define dispatchTernary1(arg1, type)                          \
  10409  iter_.readTernary(type, &unused_a, &unused_b, &unused_c) && \
  10410      (deadCode_ || (emitTernary(arg1), true))
  10411 
  10412 #define dispatchTernary2(arg1, type)                          \
  10413  iter_.readTernary(type, &unused_a, &unused_b, &unused_c) && \
  10414      (deadCode_ || (emitTernaryResultLast(arg1), true))
  10415 
  10416 #define dispatchComparison0(doEmit, operandType, compareOp)  \
  10417  iter_.readComparison(operandType, &unused_a, &unused_b) && \
  10418      (deadCode_ || (doEmit(compareOp, operandType), true))
  10419 
  10420 #define dispatchConversion0(doEmit, inType, outType)  \
  10421  iter_.readConversion(inType, outType, &unused_a) && \
  10422      (deadCode_ || (doEmit(), true))
  10423 
  10424 #define dispatchConversion1(arg1, inType, outType)    \
  10425  iter_.readConversion(inType, outType, &unused_a) && \
  10426      (deadCode_ || (emitUnop(arg1), true))
  10427 
  10428 #define dispatchConversionOOM(doEmit, inType, outType) \
  10429  iter_.readConversion(inType, outType, &unused_a) && (deadCode_ || doEmit())
  10430 
  10431 #define dispatchCalloutConversionOOM(doEmit, symbol, inType, outType) \
  10432  iter_.readConversion(inType, outType, &unused_a) &&                 \
  10433      (deadCode_ || doEmit(symbol, inType, outType))
  10434 
  10435 #define dispatchIntDivCallout(doEmit, symbol, type) \
  10436  iter_.readBinary(type, &unused_a, &unused_b) &&   \
  10437      (deadCode_ || doEmit(symbol, type))
  10438 
  10439 #define dispatchVectorBinary(op)                           \
  10440  iter_.readBinary(ValType::V128, &unused_a, &unused_b) && \
  10441      (deadCode_ || (emitBinop(op), true))
  10442 
  10443 #define dispatchVectorUnary(op)                \
  10444  iter_.readUnary(ValType::V128, &unused_a) && \
  10445      (deadCode_ || (emitUnop(op), true))
  10446 
  10447 #define dispatchVectorComparison(op, compareOp)            \
  10448  iter_.readBinary(ValType::V128, &unused_a, &unused_b) && \
  10449      (deadCode_ || (emitBinop(compareOp, op), true))
  10450 
  10451 #define dispatchVectorVariableShift(op)          \
  10452  iter_.readVectorShift(&unused_a, &unused_b) && \
  10453      (deadCode_ || (emitBinop(op), true))
  10454 
  10455 #define dispatchExtractLane(op, outType, laneLimit)                   \
  10456  iter_.readExtractLane(outType, laneLimit, &laneIndex, &unused_a) && \
  10457      (deadCode_ || (emitUnop(laneIndex, op), true))
  10458 
  10459 #define dispatchReplaceLane(op, inType, laneLimit)                \
  10460  iter_.readReplaceLane(inType, laneLimit, &laneIndex, &unused_a, \
  10461                        &unused_b) &&                             \
  10462      (deadCode_ || (emitBinop(laneIndex, op), true))
  10463 
  10464 #define dispatchSplat(op, inType)                           \
  10465  iter_.readConversion(inType, ValType::V128, &unused_a) && \
  10466      (deadCode_ || (emitUnop(op), true))
  10467 
  10468 #define dispatchVectorReduction(op)                               \
  10469  iter_.readConversion(ValType::V128, ValType::I32, &unused_a) && \
  10470      (deadCode_ || (emitUnop(op), true))
  10471 
  10472 #ifdef DEBUG
  10473    // Check that the number of ref-typed entries in the operand stack matches
  10474    // reality.
  10475 #  define CHECK_POINTER_COUNT                                             \
  10476    do {                                                                  \
  10477      MOZ_ASSERT(countMemRefsOnStk() == stackMapGenerator_.memRefsOnStk); \
  10478    } while (0)
  10479 #else
  10480 #  define CHECK_POINTER_COUNT \
  10481    do {                      \
  10482    } while (0)
  10483 #endif
  10484 
  10485 #define CHECK(E) \
  10486  if (!(E)) return false
  10487 #define NEXT()           \
  10488  {                      \
  10489    CHECK_POINTER_COUNT; \
  10490    continue;            \
  10491  }
  10492 #define CHECK_NEXT(E)     \
  10493  if (!(E)) return false; \
  10494  {                       \
  10495    CHECK_POINTER_COUNT;  \
  10496    continue;             \
  10497  }
  10498 
  10499    // Opcodes that push more than MaxPushesPerOpcode (anything with multiple
  10500    // results) will perform additional reservation.
  10501    CHECK(stk_.reserve(stk_.length() + MaxPushesPerOpcode));
  10502 
  10503    OpBytes op{};
  10504    CHECK(iter_.readOp(&op));
  10505 
  10506    if (MOZ_UNLIKELY(hasPerInstrCheck)) {
  10507      // When compilerEnv_.debugEnabled(), some operators get a breakpoint site.
  10508      if (debugEnabled && op.shouldHaveBreakpoint() && !deadCode_) {
  10509        if (previousBreakablePoint_ != masm.currentOffset()) {
  10510          // TODO sync only registers that can be clobbered by the exit
  10511          // prologue/epilogue or disable these registers for use in
  10512          // baseline compiler when compilerEnv_.debugEnabled() is set.
  10513          //
  10514          // This will require the debug stub to save/restore allocatable
  10515          // registers.
  10516          sync();
  10517 
  10518          insertBreakablePoint(CallSiteKind::Breakpoint);
  10519          if (!createStackMap("debug: per-insn breakpoint")) {
  10520            return false;
  10521          }
  10522          previousBreakablePoint_ = masm.currentOffset();
  10523        }
  10524      }
  10525 
  10526 #ifdef JS_ION_PERF
  10527      if (spewerEnabled) {
  10528        perfSpewer_.recordInstruction(masm, op);
  10529      }
  10530 #endif
  10531    }
  10532 
  10533    // Going below framePushedAtEntryToBody would imply that we've
  10534    // popped off the machine stack, part of the frame created by
  10535    // beginFunction().
  10536    MOZ_ASSERT(masm.framePushed() >=
  10537               stackMapGenerator_.framePushedAtEntryToBody.value());
  10538 
  10539    // At this point we're definitely not generating code for a function call.
  10540    MOZ_ASSERT(
  10541        stackMapGenerator_.framePushedExcludingOutboundCallArgs.isNothing());
  10542 
  10543    switch (op.b0) {
  10544      case uint16_t(Op::End):
  10545        if (!emitEnd()) {
  10546          return false;
  10547        }
  10548        if (iter_.controlStackEmpty()) {
  10549          return true;
  10550        }
  10551        NEXT();
  10552 
  10553      // Control opcodes
  10554      case uint16_t(Op::Nop):
  10555        CHECK_NEXT(iter_.readNop());
  10556      case uint16_t(Op::Drop):
  10557        CHECK_NEXT(emitDrop());
  10558      case uint16_t(Op::Block):
  10559        CHECK_NEXT(emitBlock());
  10560      case uint16_t(Op::Loop):
  10561        CHECK_NEXT(emitLoop());
  10562      case uint16_t(Op::If):
  10563        CHECK_NEXT(emitIf());
  10564      case uint16_t(Op::Else):
  10565        CHECK_NEXT(emitElse());
  10566      case uint16_t(Op::Try):
  10567        CHECK_NEXT(emitTry());
  10568      case uint16_t(Op::Catch):
  10569        CHECK_NEXT(emitCatch());
  10570      case uint16_t(Op::CatchAll):
  10571        CHECK_NEXT(emitCatchAll());
  10572      case uint16_t(Op::Delegate):
  10573        CHECK(emitDelegate());
  10574        iter_.popDelegate();
  10575        NEXT();
  10576      case uint16_t(Op::Throw):
  10577        CHECK_NEXT(emitThrow());
  10578      case uint16_t(Op::Rethrow):
  10579        CHECK_NEXT(emitRethrow());
  10580      case uint16_t(Op::ThrowRef):
  10581        CHECK_NEXT(emitThrowRef());
  10582      case uint16_t(Op::TryTable):
  10583        CHECK_NEXT(emitTryTable());
  10584      case uint16_t(Op::Br):
  10585        CHECK_NEXT(emitBr());
  10586      case uint16_t(Op::BrIf):
  10587        CHECK_NEXT(emitBrIf());
  10588      case uint16_t(Op::BrTable):
  10589        CHECK_NEXT(emitBrTable());
  10590      case uint16_t(Op::Return):
  10591        CHECK_NEXT(emitReturn());
  10592      case uint16_t(Op::Unreachable):
  10593        CHECK(iter_.readUnreachable());
  10594        if (!deadCode_) {
  10595          trap(Trap::Unreachable);
  10596          deadCode_ = true;
  10597        }
  10598        NEXT();
  10599 
  10600      // Calls
  10601      case uint16_t(Op::Call):
  10602        CHECK_NEXT(emitCall());
  10603      case uint16_t(Op::CallIndirect):
  10604        CHECK_NEXT(emitCallIndirect());
  10605      case uint16_t(Op::ReturnCall):
  10606        CHECK_NEXT(emitReturnCall());
  10607      case uint16_t(Op::ReturnCallIndirect):
  10608        CHECK_NEXT(emitReturnCallIndirect());
  10609      case uint16_t(Op::CallRef):
  10610        CHECK_NEXT(emitCallRef());
  10611      case uint16_t(Op::ReturnCallRef):
  10612        CHECK_NEXT(emitReturnCallRef());
  10613 
  10614      // Locals and globals
  10615      case uint16_t(Op::LocalGet):
  10616        CHECK_NEXT(emitGetLocal());
  10617      case uint16_t(Op::LocalSet):
  10618        CHECK_NEXT(emitSetLocal());
  10619      case uint16_t(Op::LocalTee):
  10620        CHECK_NEXT(emitTeeLocal());
  10621      case uint16_t(Op::GlobalGet):
  10622        CHECK_NEXT(emitGetGlobal());
  10623      case uint16_t(Op::GlobalSet):
  10624        CHECK_NEXT(emitSetGlobal());
  10625      case uint16_t(Op::TableGet):
  10626        CHECK_NEXT(emitTableGet());
  10627      case uint16_t(Op::TableSet):
  10628        CHECK_NEXT(emitTableSet());
  10629 
  10630      // Select
  10631      case uint16_t(Op::SelectNumeric):
  10632        CHECK_NEXT(emitSelect(/*typed*/ false));
  10633      case uint16_t(Op::SelectTyped):
  10634        CHECK_NEXT(emitSelect(/*typed*/ true));
  10635 
  10636      // I32
  10637      case uint16_t(Op::I32Const): {
  10638        int32_t i32;
  10639        CHECK(iter_.readI32Const(&i32));
  10640        if (!deadCode_) {
  10641          pushI32(i32);
  10642        }
  10643        NEXT();
  10644      }
  10645      case uint16_t(Op::I32Add):
  10646        CHECK_NEXT(dispatchBinary2(AddI32, AddImmI32, ValType::I32));
  10647      case uint16_t(Op::I32Sub):
  10648        CHECK_NEXT(dispatchBinary2(SubI32, SubImmI32, ValType::I32));
  10649      case uint16_t(Op::I32Mul):
  10650        CHECK_NEXT(dispatchBinary1(MulI32, ValType::I32));
  10651      case uint16_t(Op::I32DivS):
  10652        CHECK_NEXT(dispatchBinary0(emitQuotientI32, ValType::I32));
  10653      case uint16_t(Op::I32DivU):
  10654        CHECK_NEXT(dispatchBinary0(emitQuotientU32, ValType::I32));
  10655      case uint16_t(Op::I32RemS):
  10656        CHECK_NEXT(dispatchBinary0(emitRemainderI32, ValType::I32));
  10657      case uint16_t(Op::I32RemU):
  10658        CHECK_NEXT(dispatchBinary0(emitRemainderU32, ValType::I32));
  10659      case uint16_t(Op::I32Eqz):
  10660        CHECK_NEXT(dispatchConversion0(emitEqzI32, ValType::I32, ValType::I32));
  10661      case uint16_t(Op::I32TruncF32S):
  10662        CHECK_NEXT(dispatchConversionOOM(emitTruncateF32ToI32<0>, ValType::F32,
  10663                                         ValType::I32));
  10664      case uint16_t(Op::I32TruncF32U):
  10665        CHECK_NEXT(dispatchConversionOOM(emitTruncateF32ToI32<TRUNC_UNSIGNED>,
  10666                                         ValType::F32, ValType::I32));
  10667      case uint16_t(Op::I32TruncF64S):
  10668        CHECK_NEXT(dispatchConversionOOM(emitTruncateF64ToI32<0>, ValType::F64,
  10669                                         ValType::I32));
  10670      case uint16_t(Op::I32TruncF64U):
  10671        CHECK_NEXT(dispatchConversionOOM(emitTruncateF64ToI32<TRUNC_UNSIGNED>,
  10672                                         ValType::F64, ValType::I32));
  10673      case uint16_t(Op::I32WrapI64):
  10674        CHECK_NEXT(
  10675            dispatchConversion1(WrapI64ToI32, ValType::I64, ValType::I32));
  10676      case uint16_t(Op::I32ReinterpretF32):
  10677        CHECK_NEXT(dispatchConversion1(ReinterpretF32AsI32, ValType::F32,
  10678                                       ValType::I32));
  10679      case uint16_t(Op::I32Clz):
  10680        CHECK_NEXT(dispatchUnary1(ClzI32, ValType::I32));
  10681      case uint16_t(Op::I32Ctz):
  10682        CHECK_NEXT(dispatchUnary1(CtzI32, ValType::I32));
  10683      case uint16_t(Op::I32Popcnt):
  10684        CHECK_NEXT(dispatchUnary2(PopcntI32, PopcntTemp, ValType::I32));
  10685      case uint16_t(Op::I32Or):
  10686        CHECK_NEXT(dispatchBinary2(OrI32, OrImmI32, ValType::I32));
  10687      case uint16_t(Op::I32And):
  10688        CHECK_NEXT(dispatchBinary2(AndI32, AndImmI32, ValType::I32));
  10689      case uint16_t(Op::I32Xor):
  10690        CHECK_NEXT(dispatchBinary2(XorI32, XorImmI32, ValType::I32));
  10691      case uint16_t(Op::I32Shl):
  10692        CHECK_NEXT(dispatchBinary3(
  10693            ShlI32, ShlImmI32, &BaseCompiler::popI32RhsForShift, ValType::I32));
  10694      case uint16_t(Op::I32ShrS):
  10695        CHECK_NEXT(dispatchBinary3(
  10696            ShrI32, ShrImmI32, &BaseCompiler::popI32RhsForShift, ValType::I32));
  10697      case uint16_t(Op::I32ShrU):
  10698        CHECK_NEXT(dispatchBinary3(ShrUI32, ShrUImmI32,
  10699                                   &BaseCompiler::popI32RhsForShift,
  10700                                   ValType::I32));
  10701      case uint16_t(Op::I32Load8S):
  10702        CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int8));
  10703      case uint16_t(Op::I32Load8U):
  10704        CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint8));
  10705      case uint16_t(Op::I32Load16S):
  10706        CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int16));
  10707      case uint16_t(Op::I32Load16U):
  10708        CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint16));
  10709      case uint16_t(Op::I32Load):
  10710        CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int32));
  10711      case uint16_t(Op::I32Store8):
  10712        CHECK_NEXT(emitStore(ValType::I32, Scalar::Int8));
  10713      case uint16_t(Op::I32Store16):
  10714        CHECK_NEXT(emitStore(ValType::I32, Scalar::Int16));
  10715      case uint16_t(Op::I32Store):
  10716        CHECK_NEXT(emitStore(ValType::I32, Scalar::Int32));
  10717      case uint16_t(Op::I32Rotr):
  10718        CHECK_NEXT(dispatchBinary3(RotrI32, RotrImmI32,
  10719                                   &BaseCompiler::popI32RhsForRotate,
  10720                                   ValType::I32));
  10721      case uint16_t(Op::I32Rotl):
  10722        CHECK_NEXT(dispatchBinary3(RotlI32, RotlImmI32,
  10723                                   &BaseCompiler::popI32RhsForRotate,
  10724                                   ValType::I32));
  10725 
  10726      // I64
  10727      case uint16_t(Op::I64Const): {
  10728        int64_t i64;
  10729        CHECK(iter_.readI64Const(&i64));
  10730        if (!deadCode_) {
  10731          pushI64(i64);
  10732        }
  10733        NEXT();
  10734      }
  10735      case uint16_t(Op::I64Add):
  10736        CHECK_NEXT(dispatchBinary2(AddI64, AddImmI64, ValType::I64));
  10737      case uint16_t(Op::I64Sub):
  10738        CHECK_NEXT(dispatchBinary2(SubI64, SubImmI64, ValType::I64));
  10739      case uint16_t(Op::I64Mul):
  10740        CHECK_NEXT(dispatchBinary0(emitMultiplyI64, ValType::I64));
  10741      case uint16_t(Op::I64DivS):
  10742 #ifdef RABALDR_INT_DIV_I64_CALLOUT
  10743        CHECK_NEXT(dispatchIntDivCallout(
  10744            emitDivOrModI64BuiltinCall, SymbolicAddress::DivI64, ValType::I64));
  10745 #else
  10746        CHECK_NEXT(dispatchBinary0(emitQuotientI64, ValType::I64));
  10747 #endif
  10748      case uint16_t(Op::I64DivU):
  10749 #ifdef RABALDR_INT_DIV_I64_CALLOUT
  10750        CHECK_NEXT(dispatchIntDivCallout(emitDivOrModI64BuiltinCall,
  10751                                         SymbolicAddress::UDivI64,
  10752                                         ValType::I64));
  10753 #else
  10754        CHECK_NEXT(dispatchBinary0(emitQuotientU64, ValType::I64));
  10755 #endif
  10756      case uint16_t(Op::I64RemS):
  10757 #ifdef RABALDR_INT_DIV_I64_CALLOUT
  10758        CHECK_NEXT(dispatchIntDivCallout(
  10759            emitDivOrModI64BuiltinCall, SymbolicAddress::ModI64, ValType::I64));
  10760 #else
  10761        CHECK_NEXT(dispatchBinary0(emitRemainderI64, ValType::I64));
  10762 #endif
  10763      case uint16_t(Op::I64RemU):
  10764 #ifdef RABALDR_INT_DIV_I64_CALLOUT
  10765        CHECK_NEXT(dispatchIntDivCallout(emitDivOrModI64BuiltinCall,
  10766                                         SymbolicAddress::UModI64,
  10767                                         ValType::I64));
  10768 #else
  10769        CHECK_NEXT(dispatchBinary0(emitRemainderU64, ValType::I64));
  10770 #endif
  10771      case uint16_t(Op::I64TruncF32S):
  10772 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  10773        CHECK_NEXT(
  10774            dispatchCalloutConversionOOM(emitConvertFloatingToInt64Callout,
  10775                                         SymbolicAddress::TruncateDoubleToInt64,
  10776                                         ValType::F32, ValType::I64));
  10777 #else
  10778        CHECK_NEXT(dispatchConversionOOM(emitTruncateF32ToI64<0>, ValType::F32,
  10779                                         ValType::I64));
  10780 #endif
  10781      case uint16_t(Op::I64TruncF32U):
  10782 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  10783        CHECK_NEXT(dispatchCalloutConversionOOM(
  10784            emitConvertFloatingToInt64Callout,
  10785            SymbolicAddress::TruncateDoubleToUint64, ValType::F32,
  10786            ValType::I64));
  10787 #else
  10788        CHECK_NEXT(dispatchConversionOOM(emitTruncateF32ToI64<TRUNC_UNSIGNED>,
  10789                                         ValType::F32, ValType::I64));
  10790 #endif
  10791      case uint16_t(Op::I64TruncF64S):
  10792 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  10793        CHECK_NEXT(
  10794            dispatchCalloutConversionOOM(emitConvertFloatingToInt64Callout,
  10795                                         SymbolicAddress::TruncateDoubleToInt64,
  10796                                         ValType::F64, ValType::I64));
  10797 #else
  10798        CHECK_NEXT(dispatchConversionOOM(emitTruncateF64ToI64<0>, ValType::F64,
  10799                                         ValType::I64));
  10800 #endif
  10801      case uint16_t(Op::I64TruncF64U):
  10802 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  10803        CHECK_NEXT(dispatchCalloutConversionOOM(
  10804            emitConvertFloatingToInt64Callout,
  10805            SymbolicAddress::TruncateDoubleToUint64, ValType::F64,
  10806            ValType::I64));
  10807 #else
  10808        CHECK_NEXT(dispatchConversionOOM(emitTruncateF64ToI64<TRUNC_UNSIGNED>,
  10809                                         ValType::F64, ValType::I64));
  10810 #endif
  10811      case uint16_t(Op::I64ExtendI32S):
  10812        CHECK_NEXT(dispatchConversion0(emitExtendI32ToI64, ValType::I32,
  10813                                       ValType::I64));
  10814      case uint16_t(Op::I64ExtendI32U):
  10815        CHECK_NEXT(dispatchConversion0(emitExtendU32ToI64, ValType::I32,
  10816                                       ValType::I64));
  10817      case uint16_t(Op::I64ReinterpretF64):
  10818        CHECK_NEXT(dispatchConversion1(ReinterpretF64AsI64, ValType::F64,
  10819                                       ValType::I64));
  10820      case uint16_t(Op::I64Or):
  10821        CHECK_NEXT(dispatchBinary2(OrI64, OrImmI64, ValType::I64));
  10822      case uint16_t(Op::I64And):
  10823        CHECK_NEXT(dispatchBinary2(AndI64, AndImmI64, ValType::I64));
  10824      case uint16_t(Op::I64Xor):
  10825        CHECK_NEXT(dispatchBinary2(XorI64, XorImmI64, ValType::I64));
  10826      case uint16_t(Op::I64Shl):
  10827        CHECK_NEXT(dispatchBinary3(
  10828            ShlI64, ShlImmI64, &BaseCompiler::popI64RhsForShift, ValType::I64));
  10829      case uint16_t(Op::I64ShrS):
  10830        CHECK_NEXT(dispatchBinary3(
  10831            ShrI64, ShrImmI64, &BaseCompiler::popI64RhsForShift, ValType::I64));
  10832      case uint16_t(Op::I64ShrU):
  10833        CHECK_NEXT(dispatchBinary3(ShrUI64, ShrUImmI64,
  10834                                   &BaseCompiler::popI64RhsForShift,
  10835                                   ValType::I64));
  10836      case uint16_t(Op::I64Rotr):
  10837        CHECK_NEXT(dispatchBinary0(emitRotrI64, ValType::I64));
  10838      case uint16_t(Op::I64Rotl):
  10839        CHECK_NEXT(dispatchBinary0(emitRotlI64, ValType::I64));
  10840      case uint16_t(Op::I64Clz):
  10841        CHECK_NEXT(dispatchUnary1(ClzI64, ValType::I64));
  10842      case uint16_t(Op::I64Ctz):
  10843        CHECK_NEXT(dispatchUnary1(CtzI64, ValType::I64));
  10844      case uint16_t(Op::I64Popcnt):
  10845        CHECK_NEXT(dispatchUnary2(PopcntI64, PopcntTemp, ValType::I64));
  10846      case uint16_t(Op::I64Eqz):
  10847        CHECK_NEXT(dispatchConversion0(emitEqzI64, ValType::I64, ValType::I32));
  10848      case uint16_t(Op::I64Load8S):
  10849        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int8));
  10850      case uint16_t(Op::I64Load16S):
  10851        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int16));
  10852      case uint16_t(Op::I64Load32S):
  10853        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int32));
  10854      case uint16_t(Op::I64Load8U):
  10855        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint8));
  10856      case uint16_t(Op::I64Load16U):
  10857        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint16));
  10858      case uint16_t(Op::I64Load32U):
  10859        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint32));
  10860      case uint16_t(Op::I64Load):
  10861        CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int64));
  10862      case uint16_t(Op::I64Store8):
  10863        CHECK_NEXT(emitStore(ValType::I64, Scalar::Int8));
  10864      case uint16_t(Op::I64Store16):
  10865        CHECK_NEXT(emitStore(ValType::I64, Scalar::Int16));
  10866      case uint16_t(Op::I64Store32):
  10867        CHECK_NEXT(emitStore(ValType::I64, Scalar::Int32));
  10868      case uint16_t(Op::I64Store):
  10869        CHECK_NEXT(emitStore(ValType::I64, Scalar::Int64));
  10870 
  10871      // F32
  10872      case uint16_t(Op::F32Const): {
  10873        float f32;
  10874        CHECK(iter_.readF32Const(&f32));
  10875        if (!deadCode_) {
  10876          pushF32(f32);
  10877        }
  10878        NEXT();
  10879      }
  10880      case uint16_t(Op::F32Add):
  10881        CHECK_NEXT(dispatchBinary1(AddF32, ValType::F32))
  10882      case uint16_t(Op::F32Sub):
  10883        CHECK_NEXT(dispatchBinary1(SubF32, ValType::F32));
  10884      case uint16_t(Op::F32Mul):
  10885        CHECK_NEXT(dispatchBinary1(MulF32, ValType::F32));
  10886      case uint16_t(Op::F32Div):
  10887        CHECK_NEXT(dispatchBinary1(DivF32, ValType::F32));
  10888      case uint16_t(Op::F32Min):
  10889        CHECK_NEXT(dispatchBinary1(MinF32, ValType::F32));
  10890      case uint16_t(Op::F32Max):
  10891        CHECK_NEXT(dispatchBinary1(MaxF32, ValType::F32));
  10892      case uint16_t(Op::F32Neg):
  10893        CHECK_NEXT(dispatchUnary1(NegateF32, ValType::F32));
  10894      case uint16_t(Op::F32Abs):
  10895        CHECK_NEXT(dispatchUnary1(AbsF32, ValType::F32));
  10896      case uint16_t(Op::F32Sqrt):
  10897        CHECK_NEXT(dispatchUnary1(SqrtF32, ValType::F32));
  10898      case uint16_t(Op::F32Ceil):
  10899        CHECK_NEXT(
  10900            emitUnaryMathBuiltinCall(SymbolicAddress::CeilF, ValType::F32));
  10901      case uint16_t(Op::F32Floor):
  10902        CHECK_NEXT(
  10903            emitUnaryMathBuiltinCall(SymbolicAddress::FloorF, ValType::F32));
  10904      case uint16_t(Op::F32DemoteF64):
  10905        CHECK_NEXT(
  10906            dispatchConversion1(ConvertF64ToF32, ValType::F64, ValType::F32));
  10907      case uint16_t(Op::F32ConvertI32S):
  10908        CHECK_NEXT(
  10909            dispatchConversion1(ConvertI32ToF32, ValType::I32, ValType::F32));
  10910      case uint16_t(Op::F32ConvertI32U):
  10911        CHECK_NEXT(
  10912            dispatchConversion1(ConvertU32ToF32, ValType::I32, ValType::F32));
  10913      case uint16_t(Op::F32ConvertI64S):
  10914 #ifdef RABALDR_I64_TO_FLOAT_CALLOUT
  10915        CHECK_NEXT(dispatchCalloutConversionOOM(
  10916            emitConvertInt64ToFloatingCallout, SymbolicAddress::Int64ToFloat32,
  10917            ValType::I64, ValType::F32));
  10918 #else
  10919        CHECK_NEXT(
  10920            dispatchConversion1(ConvertI64ToF32, ValType::I64, ValType::F32));
  10921 #endif
  10922      case uint16_t(Op::F32ConvertI64U):
  10923 #ifdef RABALDR_I64_TO_FLOAT_CALLOUT
  10924        CHECK_NEXT(dispatchCalloutConversionOOM(
  10925            emitConvertInt64ToFloatingCallout, SymbolicAddress::Uint64ToFloat32,
  10926            ValType::I64, ValType::F32));
  10927 #else
  10928        CHECK_NEXT(dispatchConversion0(emitConvertU64ToF32, ValType::I64,
  10929                                       ValType::F32));
  10930 #endif
  10931      case uint16_t(Op::F32ReinterpretI32):
  10932        CHECK_NEXT(dispatchConversion1(ReinterpretI32AsF32, ValType::I32,
  10933                                       ValType::F32));
  10934      case uint16_t(Op::F32Load):
  10935        CHECK_NEXT(emitLoad(ValType::F32, Scalar::Float32));
  10936      case uint16_t(Op::F32Store):
  10937        CHECK_NEXT(emitStore(ValType::F32, Scalar::Float32));
  10938      case uint16_t(Op::F32CopySign):
  10939        CHECK_NEXT(dispatchBinary1(CopysignF32, ValType::F32));
  10940      case uint16_t(Op::F32Nearest):
  10941        CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntF,
  10942                                            ValType::F32));
  10943      case uint16_t(Op::F32Trunc):
  10944        CHECK_NEXT(
  10945            emitUnaryMathBuiltinCall(SymbolicAddress::TruncF, ValType::F32));
  10946 
  10947      // F64
  10948      case uint16_t(Op::F64Const): {
  10949        double f64;
  10950        CHECK(iter_.readF64Const(&f64));
  10951        if (!deadCode_) {
  10952          pushF64(f64);
  10953        }
  10954        NEXT();
  10955      }
  10956      case uint16_t(Op::F64Add):
  10957        CHECK_NEXT(dispatchBinary1(AddF64, ValType::F64))
  10958      case uint16_t(Op::F64Sub):
  10959        CHECK_NEXT(dispatchBinary1(SubF64, ValType::F64));
  10960      case uint16_t(Op::F64Mul):
  10961        CHECK_NEXT(dispatchBinary1(MulF64, ValType::F64));
  10962      case uint16_t(Op::F64Div):
  10963        CHECK_NEXT(dispatchBinary1(DivF64, ValType::F64));
  10964      case uint16_t(Op::F64Min):
  10965        CHECK_NEXT(dispatchBinary1(MinF64, ValType::F64));
  10966      case uint16_t(Op::F64Max):
  10967        CHECK_NEXT(dispatchBinary1(MaxF64, ValType::F64));
  10968      case uint16_t(Op::F64Neg):
  10969        CHECK_NEXT(dispatchUnary1(NegateF64, ValType::F64));
  10970      case uint16_t(Op::F64Abs):
  10971        CHECK_NEXT(dispatchUnary1(AbsF64, ValType::F64));
  10972      case uint16_t(Op::F64Sqrt):
  10973        CHECK_NEXT(dispatchUnary1(SqrtF64, ValType::F64));
  10974      case uint16_t(Op::F64Ceil):
  10975        CHECK_NEXT(
  10976            emitUnaryMathBuiltinCall(SymbolicAddress::CeilD, ValType::F64));
  10977      case uint16_t(Op::F64Floor):
  10978        CHECK_NEXT(
  10979            emitUnaryMathBuiltinCall(SymbolicAddress::FloorD, ValType::F64));
  10980      case uint16_t(Op::F64PromoteF32):
  10981        CHECK_NEXT(
  10982            dispatchConversion1(ConvertF32ToF64, ValType::F32, ValType::F64));
  10983      case uint16_t(Op::F64ConvertI32S):
  10984        CHECK_NEXT(
  10985            dispatchConversion1(ConvertI32ToF64, ValType::I32, ValType::F64));
  10986      case uint16_t(Op::F64ConvertI32U):
  10987        CHECK_NEXT(
  10988            dispatchConversion1(ConvertU32ToF64, ValType::I32, ValType::F64));
  10989      case uint16_t(Op::F64ConvertI64S):
  10990 #ifdef RABALDR_I64_TO_FLOAT_CALLOUT
  10991        CHECK_NEXT(dispatchCalloutConversionOOM(
  10992            emitConvertInt64ToFloatingCallout, SymbolicAddress::Int64ToDouble,
  10993            ValType::I64, ValType::F64));
  10994 #else
  10995        CHECK_NEXT(
  10996            dispatchConversion1(ConvertI64ToF64, ValType::I64, ValType::F64));
  10997 #endif
  10998      case uint16_t(Op::F64ConvertI64U):
  10999 #ifdef RABALDR_I64_TO_FLOAT_CALLOUT
  11000        CHECK_NEXT(dispatchCalloutConversionOOM(
  11001            emitConvertInt64ToFloatingCallout, SymbolicAddress::Uint64ToDouble,
  11002            ValType::I64, ValType::F64));
  11003 #else
  11004        CHECK_NEXT(dispatchConversion0(emitConvertU64ToF64, ValType::I64,
  11005                                       ValType::F64));
  11006 #endif
  11007      case uint16_t(Op::F64Load):
  11008        CHECK_NEXT(emitLoad(ValType::F64, Scalar::Float64));
  11009      case uint16_t(Op::F64Store):
  11010        CHECK_NEXT(emitStore(ValType::F64, Scalar::Float64));
  11011      case uint16_t(Op::F64ReinterpretI64):
  11012        CHECK_NEXT(dispatchConversion1(ReinterpretI64AsF64, ValType::I64,
  11013                                       ValType::F64));
  11014      case uint16_t(Op::F64CopySign):
  11015        CHECK_NEXT(dispatchBinary1(CopysignF64, ValType::F64));
  11016      case uint16_t(Op::F64Nearest):
  11017        CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntD,
  11018                                            ValType::F64));
  11019      case uint16_t(Op::F64Trunc):
  11020        CHECK_NEXT(
  11021            emitUnaryMathBuiltinCall(SymbolicAddress::TruncD, ValType::F64));
  11022 
  11023      // Comparisons
  11024      case uint16_t(Op::I32Eq):
  11025        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11026                                       Assembler::Equal));
  11027      case uint16_t(Op::I32Ne):
  11028        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11029                                       Assembler::NotEqual));
  11030      case uint16_t(Op::I32LtS):
  11031        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11032                                       Assembler::LessThan));
  11033      case uint16_t(Op::I32LeS):
  11034        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11035                                       Assembler::LessThanOrEqual));
  11036      case uint16_t(Op::I32GtS):
  11037        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11038                                       Assembler::GreaterThan));
  11039      case uint16_t(Op::I32GeS):
  11040        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11041                                       Assembler::GreaterThanOrEqual));
  11042      case uint16_t(Op::I32LtU):
  11043        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11044                                       Assembler::Below));
  11045      case uint16_t(Op::I32LeU):
  11046        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11047                                       Assembler::BelowOrEqual));
  11048      case uint16_t(Op::I32GtU):
  11049        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11050                                       Assembler::Above));
  11051      case uint16_t(Op::I32GeU):
  11052        CHECK_NEXT(dispatchComparison0(emitCompareI32, ValType::I32,
  11053                                       Assembler::AboveOrEqual));
  11054      case uint16_t(Op::I64Eq):
  11055        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11056                                       Assembler::Equal));
  11057      case uint16_t(Op::I64Ne):
  11058        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11059                                       Assembler::NotEqual));
  11060      case uint16_t(Op::I64LtS):
  11061        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11062                                       Assembler::LessThan));
  11063      case uint16_t(Op::I64LeS):
  11064        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11065                                       Assembler::LessThanOrEqual));
  11066      case uint16_t(Op::I64GtS):
  11067        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11068                                       Assembler::GreaterThan));
  11069      case uint16_t(Op::I64GeS):
  11070        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11071                                       Assembler::GreaterThanOrEqual));
  11072      case uint16_t(Op::I64LtU):
  11073        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11074                                       Assembler::Below));
  11075      case uint16_t(Op::I64LeU):
  11076        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11077                                       Assembler::BelowOrEqual));
  11078      case uint16_t(Op::I64GtU):
  11079        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11080                                       Assembler::Above));
  11081      case uint16_t(Op::I64GeU):
  11082        CHECK_NEXT(dispatchComparison0(emitCompareI64, ValType::I64,
  11083                                       Assembler::AboveOrEqual));
  11084      case uint16_t(Op::F32Eq):
  11085        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11086                                       Assembler::DoubleEqual));
  11087      case uint16_t(Op::F32Ne):
  11088        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11089                                       Assembler::DoubleNotEqualOrUnordered));
  11090      case uint16_t(Op::F32Lt):
  11091        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11092                                       Assembler::DoubleLessThan));
  11093      case uint16_t(Op::F32Le):
  11094        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11095                                       Assembler::DoubleLessThanOrEqual));
  11096      case uint16_t(Op::F32Gt):
  11097        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11098                                       Assembler::DoubleGreaterThan));
  11099      case uint16_t(Op::F32Ge):
  11100        CHECK_NEXT(dispatchComparison0(emitCompareF32, ValType::F32,
  11101                                       Assembler::DoubleGreaterThanOrEqual));
  11102      case uint16_t(Op::F64Eq):
  11103        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11104                                       Assembler::DoubleEqual));
  11105      case uint16_t(Op::F64Ne):
  11106        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11107                                       Assembler::DoubleNotEqualOrUnordered));
  11108      case uint16_t(Op::F64Lt):
  11109        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11110                                       Assembler::DoubleLessThan));
  11111      case uint16_t(Op::F64Le):
  11112        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11113                                       Assembler::DoubleLessThanOrEqual));
  11114      case uint16_t(Op::F64Gt):
  11115        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11116                                       Assembler::DoubleGreaterThan));
  11117      case uint16_t(Op::F64Ge):
  11118        CHECK_NEXT(dispatchComparison0(emitCompareF64, ValType::F64,
  11119                                       Assembler::DoubleGreaterThanOrEqual));
  11120 
  11121      // Sign extensions
  11122      case uint16_t(Op::I32Extend8S):
  11123        CHECK_NEXT(
  11124            dispatchConversion1(ExtendI32_8, ValType::I32, ValType::I32));
  11125      case uint16_t(Op::I32Extend16S):
  11126        CHECK_NEXT(
  11127            dispatchConversion1(ExtendI32_16, ValType::I32, ValType::I32));
  11128      case uint16_t(Op::I64Extend8S):
  11129        CHECK_NEXT(
  11130            dispatchConversion0(emitExtendI64_8, ValType::I64, ValType::I64));
  11131      case uint16_t(Op::I64Extend16S):
  11132        CHECK_NEXT(
  11133            dispatchConversion0(emitExtendI64_16, ValType::I64, ValType::I64));
  11134      case uint16_t(Op::I64Extend32S):
  11135        CHECK_NEXT(
  11136            dispatchConversion0(emitExtendI64_32, ValType::I64, ValType::I64));
  11137 
  11138      // Memory Related
  11139      case uint16_t(Op::MemoryGrow):
  11140        CHECK_NEXT(emitMemoryGrow());
  11141      case uint16_t(Op::MemorySize):
  11142        CHECK_NEXT(emitMemorySize());
  11143 
  11144      case uint16_t(Op::RefAsNonNull):
  11145        CHECK_NEXT(emitRefAsNonNull());
  11146      case uint16_t(Op::BrOnNull):
  11147        CHECK_NEXT(emitBrOnNull());
  11148      case uint16_t(Op::BrOnNonNull):
  11149        CHECK_NEXT(emitBrOnNonNull());
  11150      case uint16_t(Op::RefEq):
  11151        CHECK_NEXT(dispatchComparison0(emitCompareRef, RefType::eq(),
  11152                                       Assembler::Equal));
  11153      case uint16_t(Op::RefFunc):
  11154        CHECK_NEXT(emitRefFunc());
  11155        break;
  11156      case uint16_t(Op::RefNull):
  11157        CHECK_NEXT(emitRefNull());
  11158        break;
  11159      case uint16_t(Op::RefIsNull):
  11160        CHECK_NEXT(emitRefIsNull());
  11161        break;
  11162 
  11163      // "GC" operations
  11164      case uint16_t(Op::GcPrefix): {
  11165        switch (op.b1) {
  11166          case uint32_t(GcOp::StructNew):
  11167            CHECK_NEXT(emitStructNew());
  11168          case uint32_t(GcOp::StructNewDefault):
  11169            CHECK_NEXT(emitStructNewDefault());
  11170          case uint32_t(GcOp::StructGet):
  11171            CHECK_NEXT(emitStructGet(FieldWideningOp::None));
  11172          case uint32_t(GcOp::StructGetS):
  11173            CHECK_NEXT(emitStructGet(FieldWideningOp::Signed));
  11174          case uint32_t(GcOp::StructGetU):
  11175            CHECK_NEXT(emitStructGet(FieldWideningOp::Unsigned));
  11176          case uint32_t(GcOp::StructSet):
  11177            CHECK_NEXT(emitStructSet());
  11178          case uint32_t(GcOp::ArrayNew):
  11179            CHECK_NEXT(emitArrayNew());
  11180          case uint32_t(GcOp::ArrayNewFixed):
  11181            CHECK_NEXT(emitArrayNewFixed());
  11182          case uint32_t(GcOp::ArrayNewDefault):
  11183            CHECK_NEXT(emitArrayNewDefault());
  11184          case uint32_t(GcOp::ArrayNewData):
  11185            CHECK_NEXT(emitArrayNewData());
  11186          case uint32_t(GcOp::ArrayNewElem):
  11187            CHECK_NEXT(emitArrayNewElem());
  11188          case uint32_t(GcOp::ArrayInitData):
  11189            CHECK_NEXT(emitArrayInitData());
  11190          case uint32_t(GcOp::ArrayInitElem):
  11191            CHECK_NEXT(emitArrayInitElem());
  11192          case uint32_t(GcOp::ArrayGet):
  11193            CHECK_NEXT(emitArrayGet(FieldWideningOp::None));
  11194          case uint32_t(GcOp::ArrayGetS):
  11195            CHECK_NEXT(emitArrayGet(FieldWideningOp::Signed));
  11196          case uint32_t(GcOp::ArrayGetU):
  11197            CHECK_NEXT(emitArrayGet(FieldWideningOp::Unsigned));
  11198          case uint32_t(GcOp::ArraySet):
  11199            CHECK_NEXT(emitArraySet());
  11200          case uint32_t(GcOp::ArrayLen):
  11201            CHECK_NEXT(emitArrayLen());
  11202          case uint32_t(GcOp::ArrayCopy):
  11203            CHECK_NEXT(emitArrayCopy());
  11204          case uint32_t(GcOp::ArrayFill):
  11205            CHECK_NEXT(emitArrayFill());
  11206          case uint32_t(GcOp::RefI31):
  11207            CHECK_NEXT(emitRefI31());
  11208          case uint32_t(GcOp::I31GetS):
  11209            CHECK_NEXT(emitI31Get(FieldWideningOp::Signed));
  11210          case uint32_t(GcOp::I31GetU):
  11211            CHECK_NEXT(emitI31Get(FieldWideningOp::Unsigned));
  11212          case uint32_t(GcOp::RefTest):
  11213            CHECK_NEXT(emitRefTest(/*nullable=*/false));
  11214          case uint32_t(GcOp::RefTestNull):
  11215            CHECK_NEXT(emitRefTest(/*nullable=*/true));
  11216          case uint32_t(GcOp::RefCast):
  11217            CHECK_NEXT(emitRefCast(/*nullable=*/false));
  11218          case uint32_t(GcOp::RefCastNull):
  11219            CHECK_NEXT(emitRefCast(/*nullable=*/true));
  11220          case uint32_t(GcOp::BrOnCast):
  11221            CHECK_NEXT(emitBrOnCast(/*onSuccess=*/true));
  11222          case uint32_t(GcOp::BrOnCastFail):
  11223            CHECK_NEXT(emitBrOnCast(/*onSuccess=*/false));
  11224          case uint16_t(GcOp::AnyConvertExtern):
  11225            CHECK_NEXT(emitAnyConvertExtern());
  11226          case uint16_t(GcOp::ExternConvertAny):
  11227            CHECK_NEXT(emitExternConvertAny());
  11228          default:
  11229            break;
  11230        }  // switch (op.b1)
  11231        return iter_.unrecognizedOpcode(&op);
  11232      }
  11233 
  11234 #ifdef ENABLE_WASM_SIMD
  11235      // SIMD operations
  11236      case uint16_t(Op::SimdPrefix): {
  11237        uint32_t laneIndex;
  11238        if (!codeMeta_.simdAvailable()) {
  11239          return iter_.unrecognizedOpcode(&op);
  11240        }
  11241        switch (op.b1) {
  11242          case uint32_t(SimdOp::I8x16ExtractLaneS):
  11243            CHECK_NEXT(dispatchExtractLane(ExtractLaneI8x16, ValType::I32, 16));
  11244          case uint32_t(SimdOp::I8x16ExtractLaneU):
  11245            CHECK_NEXT(
  11246                dispatchExtractLane(ExtractLaneUI8x16, ValType::I32, 16));
  11247          case uint32_t(SimdOp::I16x8ExtractLaneS):
  11248            CHECK_NEXT(dispatchExtractLane(ExtractLaneI16x8, ValType::I32, 8));
  11249          case uint32_t(SimdOp::I16x8ExtractLaneU):
  11250            CHECK_NEXT(dispatchExtractLane(ExtractLaneUI16x8, ValType::I32, 8));
  11251          case uint32_t(SimdOp::I32x4ExtractLane):
  11252            CHECK_NEXT(dispatchExtractLane(ExtractLaneI32x4, ValType::I32, 4));
  11253          case uint32_t(SimdOp::I64x2ExtractLane):
  11254            CHECK_NEXT(dispatchExtractLane(ExtractLaneI64x2, ValType::I64, 2));
  11255          case uint32_t(SimdOp::F32x4ExtractLane):
  11256            CHECK_NEXT(dispatchExtractLane(ExtractLaneF32x4, ValType::F32, 4));
  11257          case uint32_t(SimdOp::F64x2ExtractLane):
  11258            CHECK_NEXT(dispatchExtractLane(ExtractLaneF64x2, ValType::F64, 2));
  11259          case uint32_t(SimdOp::I8x16Splat):
  11260            CHECK_NEXT(dispatchSplat(SplatI8x16, ValType::I32));
  11261          case uint32_t(SimdOp::I16x8Splat):
  11262            CHECK_NEXT(dispatchSplat(SplatI16x8, ValType::I32));
  11263          case uint32_t(SimdOp::I32x4Splat):
  11264            CHECK_NEXT(dispatchSplat(SplatI32x4, ValType::I32));
  11265          case uint32_t(SimdOp::I64x2Splat):
  11266            CHECK_NEXT(dispatchSplat(SplatI64x2, ValType::I64));
  11267          case uint32_t(SimdOp::F32x4Splat):
  11268            CHECK_NEXT(dispatchSplat(SplatF32x4, ValType::F32));
  11269          case uint32_t(SimdOp::F64x2Splat):
  11270            CHECK_NEXT(dispatchSplat(SplatF64x2, ValType::F64));
  11271          case uint32_t(SimdOp::V128AnyTrue):
  11272            CHECK_NEXT(dispatchVectorReduction(AnyTrue));
  11273          case uint32_t(SimdOp::I8x16AllTrue):
  11274            CHECK_NEXT(dispatchVectorReduction(AllTrueI8x16));
  11275          case uint32_t(SimdOp::I16x8AllTrue):
  11276            CHECK_NEXT(dispatchVectorReduction(AllTrueI16x8));
  11277          case uint32_t(SimdOp::I32x4AllTrue):
  11278            CHECK_NEXT(dispatchVectorReduction(AllTrueI32x4));
  11279          case uint32_t(SimdOp::I64x2AllTrue):
  11280            CHECK_NEXT(dispatchVectorReduction(AllTrueI64x2));
  11281          case uint32_t(SimdOp::I8x16Bitmask):
  11282            CHECK_NEXT(dispatchVectorReduction(BitmaskI8x16));
  11283          case uint32_t(SimdOp::I16x8Bitmask):
  11284            CHECK_NEXT(dispatchVectorReduction(BitmaskI16x8));
  11285          case uint32_t(SimdOp::I32x4Bitmask):
  11286            CHECK_NEXT(dispatchVectorReduction(BitmaskI32x4));
  11287          case uint32_t(SimdOp::I64x2Bitmask):
  11288            CHECK_NEXT(dispatchVectorReduction(BitmaskI64x2));
  11289          case uint32_t(SimdOp::I8x16ReplaceLane):
  11290            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneI8x16, ValType::I32, 16));
  11291          case uint32_t(SimdOp::I16x8ReplaceLane):
  11292            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneI16x8, ValType::I32, 8));
  11293          case uint32_t(SimdOp::I32x4ReplaceLane):
  11294            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneI32x4, ValType::I32, 4));
  11295          case uint32_t(SimdOp::I64x2ReplaceLane):
  11296            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneI64x2, ValType::I64, 2));
  11297          case uint32_t(SimdOp::F32x4ReplaceLane):
  11298            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneF32x4, ValType::F32, 4));
  11299          case uint32_t(SimdOp::F64x2ReplaceLane):
  11300            CHECK_NEXT(dispatchReplaceLane(ReplaceLaneF64x2, ValType::F64, 2));
  11301          case uint32_t(SimdOp::I8x16Eq):
  11302            CHECK_NEXT(dispatchVectorComparison(CmpI8x16, Assembler::Equal));
  11303          case uint32_t(SimdOp::I8x16Ne):
  11304            CHECK_NEXT(dispatchVectorComparison(CmpI8x16, Assembler::NotEqual));
  11305          case uint32_t(SimdOp::I8x16LtS):
  11306            CHECK_NEXT(dispatchVectorComparison(CmpI8x16, Assembler::LessThan));
  11307          case uint32_t(SimdOp::I8x16LtU):
  11308            CHECK_NEXT(dispatchVectorComparison(CmpUI8x16, Assembler::Below));
  11309          case uint32_t(SimdOp::I8x16GtS):
  11310            CHECK_NEXT(
  11311                dispatchVectorComparison(CmpI8x16, Assembler::GreaterThan));
  11312          case uint32_t(SimdOp::I8x16GtU):
  11313            CHECK_NEXT(dispatchVectorComparison(CmpUI8x16, Assembler::Above));
  11314          case uint32_t(SimdOp::I8x16LeS):
  11315            CHECK_NEXT(
  11316                dispatchVectorComparison(CmpI8x16, Assembler::LessThanOrEqual));
  11317          case uint32_t(SimdOp::I8x16LeU):
  11318            CHECK_NEXT(
  11319                dispatchVectorComparison(CmpUI8x16, Assembler::BelowOrEqual));
  11320          case uint32_t(SimdOp::I8x16GeS):
  11321            CHECK_NEXT(dispatchVectorComparison(CmpI8x16,
  11322                                                Assembler::GreaterThanOrEqual));
  11323          case uint32_t(SimdOp::I8x16GeU):
  11324            CHECK_NEXT(
  11325                dispatchVectorComparison(CmpUI8x16, Assembler::AboveOrEqual));
  11326          case uint32_t(SimdOp::I16x8Eq):
  11327            CHECK_NEXT(dispatchVectorComparison(CmpI16x8, Assembler::Equal));
  11328          case uint32_t(SimdOp::I16x8Ne):
  11329            CHECK_NEXT(dispatchVectorComparison(CmpI16x8, Assembler::NotEqual));
  11330          case uint32_t(SimdOp::I16x8LtS):
  11331            CHECK_NEXT(dispatchVectorComparison(CmpI16x8, Assembler::LessThan));
  11332          case uint32_t(SimdOp::I16x8LtU):
  11333            CHECK_NEXT(dispatchVectorComparison(CmpUI16x8, Assembler::Below));
  11334          case uint32_t(SimdOp::I16x8GtS):
  11335            CHECK_NEXT(
  11336                dispatchVectorComparison(CmpI16x8, Assembler::GreaterThan));
  11337          case uint32_t(SimdOp::I16x8GtU):
  11338            CHECK_NEXT(dispatchVectorComparison(CmpUI16x8, Assembler::Above));
  11339          case uint32_t(SimdOp::I16x8LeS):
  11340            CHECK_NEXT(
  11341                dispatchVectorComparison(CmpI16x8, Assembler::LessThanOrEqual));
  11342          case uint32_t(SimdOp::I16x8LeU):
  11343            CHECK_NEXT(
  11344                dispatchVectorComparison(CmpUI16x8, Assembler::BelowOrEqual));
  11345          case uint32_t(SimdOp::I16x8GeS):
  11346            CHECK_NEXT(dispatchVectorComparison(CmpI16x8,
  11347                                                Assembler::GreaterThanOrEqual));
  11348          case uint32_t(SimdOp::I16x8GeU):
  11349            CHECK_NEXT(
  11350                dispatchVectorComparison(CmpUI16x8, Assembler::AboveOrEqual));
  11351          case uint32_t(SimdOp::I32x4Eq):
  11352            CHECK_NEXT(dispatchVectorComparison(CmpI32x4, Assembler::Equal));
  11353          case uint32_t(SimdOp::I32x4Ne):
  11354            CHECK_NEXT(dispatchVectorComparison(CmpI32x4, Assembler::NotEqual));
  11355          case uint32_t(SimdOp::I32x4LtS):
  11356            CHECK_NEXT(dispatchVectorComparison(CmpI32x4, Assembler::LessThan));
  11357          case uint32_t(SimdOp::I32x4LtU):
  11358            CHECK_NEXT(dispatchVectorComparison(CmpUI32x4, Assembler::Below));
  11359          case uint32_t(SimdOp::I32x4GtS):
  11360            CHECK_NEXT(
  11361                dispatchVectorComparison(CmpI32x4, Assembler::GreaterThan));
  11362          case uint32_t(SimdOp::I32x4GtU):
  11363            CHECK_NEXT(dispatchVectorComparison(CmpUI32x4, Assembler::Above));
  11364          case uint32_t(SimdOp::I32x4LeS):
  11365            CHECK_NEXT(
  11366                dispatchVectorComparison(CmpI32x4, Assembler::LessThanOrEqual));
  11367          case uint32_t(SimdOp::I32x4LeU):
  11368            CHECK_NEXT(
  11369                dispatchVectorComparison(CmpUI32x4, Assembler::BelowOrEqual));
  11370          case uint32_t(SimdOp::I32x4GeS):
  11371            CHECK_NEXT(dispatchVectorComparison(CmpI32x4,
  11372                                                Assembler::GreaterThanOrEqual));
  11373          case uint32_t(SimdOp::I32x4GeU):
  11374            CHECK_NEXT(
  11375                dispatchVectorComparison(CmpUI32x4, Assembler::AboveOrEqual));
  11376          case uint32_t(SimdOp::I64x2Eq):
  11377            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForEquality,
  11378                                                Assembler::Equal));
  11379          case uint32_t(SimdOp::I64x2Ne):
  11380            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForEquality,
  11381                                                Assembler::NotEqual));
  11382          case uint32_t(SimdOp::I64x2LtS):
  11383            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForOrdering,
  11384                                                Assembler::LessThan));
  11385          case uint32_t(SimdOp::I64x2GtS):
  11386            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForOrdering,
  11387                                                Assembler::GreaterThan));
  11388          case uint32_t(SimdOp::I64x2LeS):
  11389            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForOrdering,
  11390                                                Assembler::LessThanOrEqual));
  11391          case uint32_t(SimdOp::I64x2GeS):
  11392            CHECK_NEXT(dispatchVectorComparison(CmpI64x2ForOrdering,
  11393                                                Assembler::GreaterThanOrEqual));
  11394          case uint32_t(SimdOp::F32x4Eq):
  11395            CHECK_NEXT(dispatchVectorComparison(CmpF32x4, Assembler::Equal));
  11396          case uint32_t(SimdOp::F32x4Ne):
  11397            CHECK_NEXT(dispatchVectorComparison(CmpF32x4, Assembler::NotEqual));
  11398          case uint32_t(SimdOp::F32x4Lt):
  11399            CHECK_NEXT(dispatchVectorComparison(CmpF32x4, Assembler::LessThan));
  11400          case uint32_t(SimdOp::F32x4Gt):
  11401            CHECK_NEXT(
  11402                dispatchVectorComparison(CmpF32x4, Assembler::GreaterThan));
  11403          case uint32_t(SimdOp::F32x4Le):
  11404            CHECK_NEXT(
  11405                dispatchVectorComparison(CmpF32x4, Assembler::LessThanOrEqual));
  11406          case uint32_t(SimdOp::F32x4Ge):
  11407            CHECK_NEXT(dispatchVectorComparison(CmpF32x4,
  11408                                                Assembler::GreaterThanOrEqual));
  11409          case uint32_t(SimdOp::F64x2Eq):
  11410            CHECK_NEXT(dispatchVectorComparison(CmpF64x2, Assembler::Equal));
  11411          case uint32_t(SimdOp::F64x2Ne):
  11412            CHECK_NEXT(dispatchVectorComparison(CmpF64x2, Assembler::NotEqual));
  11413          case uint32_t(SimdOp::F64x2Lt):
  11414            CHECK_NEXT(dispatchVectorComparison(CmpF64x2, Assembler::LessThan));
  11415          case uint32_t(SimdOp::F64x2Gt):
  11416            CHECK_NEXT(
  11417                dispatchVectorComparison(CmpF64x2, Assembler::GreaterThan));
  11418          case uint32_t(SimdOp::F64x2Le):
  11419            CHECK_NEXT(
  11420                dispatchVectorComparison(CmpF64x2, Assembler::LessThanOrEqual));
  11421          case uint32_t(SimdOp::F64x2Ge):
  11422            CHECK_NEXT(dispatchVectorComparison(CmpF64x2,
  11423                                                Assembler::GreaterThanOrEqual));
  11424          case uint32_t(SimdOp::V128And):
  11425            CHECK_NEXT(dispatchVectorBinary(AndV128));
  11426          case uint32_t(SimdOp::V128Or):
  11427            CHECK_NEXT(dispatchVectorBinary(OrV128));
  11428          case uint32_t(SimdOp::V128Xor):
  11429            CHECK_NEXT(dispatchVectorBinary(XorV128));
  11430          case uint32_t(SimdOp::V128AndNot):
  11431            CHECK_NEXT(dispatchBinary0(emitVectorAndNot, ValType::V128));
  11432          case uint32_t(SimdOp::I8x16AvgrU):
  11433            CHECK_NEXT(dispatchVectorBinary(AverageUI8x16));
  11434          case uint32_t(SimdOp::I16x8AvgrU):
  11435            CHECK_NEXT(dispatchVectorBinary(AverageUI16x8));
  11436          case uint32_t(SimdOp::I8x16Add):
  11437            CHECK_NEXT(dispatchVectorBinary(AddI8x16));
  11438          case uint32_t(SimdOp::I8x16AddSatS):
  11439            CHECK_NEXT(dispatchVectorBinary(AddSatI8x16));
  11440          case uint32_t(SimdOp::I8x16AddSatU):
  11441            CHECK_NEXT(dispatchVectorBinary(AddSatUI8x16));
  11442          case uint32_t(SimdOp::I8x16Sub):
  11443            CHECK_NEXT(dispatchVectorBinary(SubI8x16));
  11444          case uint32_t(SimdOp::I8x16SubSatS):
  11445            CHECK_NEXT(dispatchVectorBinary(SubSatI8x16));
  11446          case uint32_t(SimdOp::I8x16SubSatU):
  11447            CHECK_NEXT(dispatchVectorBinary(SubSatUI8x16));
  11448          case uint32_t(SimdOp::I8x16MinS):
  11449            CHECK_NEXT(dispatchVectorBinary(MinI8x16));
  11450          case uint32_t(SimdOp::I8x16MinU):
  11451            CHECK_NEXT(dispatchVectorBinary(MinUI8x16));
  11452          case uint32_t(SimdOp::I8x16MaxS):
  11453            CHECK_NEXT(dispatchVectorBinary(MaxI8x16));
  11454          case uint32_t(SimdOp::I8x16MaxU):
  11455            CHECK_NEXT(dispatchVectorBinary(MaxUI8x16));
  11456          case uint32_t(SimdOp::I16x8Add):
  11457            CHECK_NEXT(dispatchVectorBinary(AddI16x8));
  11458          case uint32_t(SimdOp::I16x8AddSatS):
  11459            CHECK_NEXT(dispatchVectorBinary(AddSatI16x8));
  11460          case uint32_t(SimdOp::I16x8AddSatU):
  11461            CHECK_NEXT(dispatchVectorBinary(AddSatUI16x8));
  11462          case uint32_t(SimdOp::I16x8Sub):
  11463            CHECK_NEXT(dispatchVectorBinary(SubI16x8));
  11464          case uint32_t(SimdOp::I16x8SubSatS):
  11465            CHECK_NEXT(dispatchVectorBinary(SubSatI16x8));
  11466          case uint32_t(SimdOp::I16x8SubSatU):
  11467            CHECK_NEXT(dispatchVectorBinary(SubSatUI16x8));
  11468          case uint32_t(SimdOp::I16x8Mul):
  11469            CHECK_NEXT(dispatchVectorBinary(MulI16x8));
  11470          case uint32_t(SimdOp::I16x8MinS):
  11471            CHECK_NEXT(dispatchVectorBinary(MinI16x8));
  11472          case uint32_t(SimdOp::I16x8MinU):
  11473            CHECK_NEXT(dispatchVectorBinary(MinUI16x8));
  11474          case uint32_t(SimdOp::I16x8MaxS):
  11475            CHECK_NEXT(dispatchVectorBinary(MaxI16x8));
  11476          case uint32_t(SimdOp::I16x8MaxU):
  11477            CHECK_NEXT(dispatchVectorBinary(MaxUI16x8));
  11478          case uint32_t(SimdOp::I32x4Add):
  11479            CHECK_NEXT(dispatchVectorBinary(AddI32x4));
  11480          case uint32_t(SimdOp::I32x4Sub):
  11481            CHECK_NEXT(dispatchVectorBinary(SubI32x4));
  11482          case uint32_t(SimdOp::I32x4Mul):
  11483            CHECK_NEXT(dispatchVectorBinary(MulI32x4));
  11484          case uint32_t(SimdOp::I32x4MinS):
  11485            CHECK_NEXT(dispatchVectorBinary(MinI32x4));
  11486          case uint32_t(SimdOp::I32x4MinU):
  11487            CHECK_NEXT(dispatchVectorBinary(MinUI32x4));
  11488          case uint32_t(SimdOp::I32x4MaxS):
  11489            CHECK_NEXT(dispatchVectorBinary(MaxI32x4));
  11490          case uint32_t(SimdOp::I32x4MaxU):
  11491            CHECK_NEXT(dispatchVectorBinary(MaxUI32x4));
  11492          case uint32_t(SimdOp::I64x2Add):
  11493            CHECK_NEXT(dispatchVectorBinary(AddI64x2));
  11494          case uint32_t(SimdOp::I64x2Sub):
  11495            CHECK_NEXT(dispatchVectorBinary(SubI64x2));
  11496          case uint32_t(SimdOp::I64x2Mul):
  11497            CHECK_NEXT(dispatchVectorBinary(MulI64x2));
  11498          case uint32_t(SimdOp::F32x4Add):
  11499            CHECK_NEXT(dispatchVectorBinary(AddF32x4));
  11500          case uint32_t(SimdOp::F32x4Sub):
  11501            CHECK_NEXT(dispatchVectorBinary(SubF32x4));
  11502          case uint32_t(SimdOp::F32x4Mul):
  11503            CHECK_NEXT(dispatchVectorBinary(MulF32x4));
  11504          case uint32_t(SimdOp::F32x4Div):
  11505            CHECK_NEXT(dispatchVectorBinary(DivF32x4));
  11506          case uint32_t(SimdOp::F32x4Min):
  11507            CHECK_NEXT(dispatchVectorBinary(MinF32x4));
  11508          case uint32_t(SimdOp::F32x4Max):
  11509            CHECK_NEXT(dispatchVectorBinary(MaxF32x4));
  11510          case uint32_t(SimdOp::F64x2Add):
  11511            CHECK_NEXT(dispatchVectorBinary(AddF64x2));
  11512          case uint32_t(SimdOp::F64x2Sub):
  11513            CHECK_NEXT(dispatchVectorBinary(SubF64x2));
  11514          case uint32_t(SimdOp::F64x2Mul):
  11515            CHECK_NEXT(dispatchVectorBinary(MulF64x2));
  11516          case uint32_t(SimdOp::F64x2Div):
  11517            CHECK_NEXT(dispatchVectorBinary(DivF64x2));
  11518          case uint32_t(SimdOp::F64x2Min):
  11519            CHECK_NEXT(dispatchVectorBinary(MinF64x2));
  11520          case uint32_t(SimdOp::F64x2Max):
  11521            CHECK_NEXT(dispatchVectorBinary(MaxF64x2));
  11522          case uint32_t(SimdOp::I8x16NarrowI16x8S):
  11523            CHECK_NEXT(dispatchVectorBinary(NarrowI16x8));
  11524          case uint32_t(SimdOp::I8x16NarrowI16x8U):
  11525            CHECK_NEXT(dispatchVectorBinary(NarrowUI16x8));
  11526          case uint32_t(SimdOp::I16x8NarrowI32x4S):
  11527            CHECK_NEXT(dispatchVectorBinary(NarrowI32x4));
  11528          case uint32_t(SimdOp::I16x8NarrowI32x4U):
  11529            CHECK_NEXT(dispatchVectorBinary(NarrowUI32x4));
  11530          case uint32_t(SimdOp::I8x16Swizzle):
  11531            CHECK_NEXT(dispatchVectorBinary(Swizzle));
  11532          case uint32_t(SimdOp::F32x4PMax):
  11533            CHECK_NEXT(dispatchVectorBinary(PMaxF32x4));
  11534          case uint32_t(SimdOp::F32x4PMin):
  11535            CHECK_NEXT(dispatchVectorBinary(PMinF32x4));
  11536          case uint32_t(SimdOp::F64x2PMax):
  11537            CHECK_NEXT(dispatchVectorBinary(PMaxF64x2));
  11538          case uint32_t(SimdOp::F64x2PMin):
  11539            CHECK_NEXT(dispatchVectorBinary(PMinF64x2));
  11540          case uint32_t(SimdOp::I32x4DotI16x8S):
  11541            CHECK_NEXT(dispatchVectorBinary(DotI16x8));
  11542          case uint32_t(SimdOp::I16x8ExtmulLowI8x16S):
  11543            CHECK_NEXT(dispatchVectorBinary(ExtMulLowI8x16));
  11544          case uint32_t(SimdOp::I16x8ExtmulHighI8x16S):
  11545            CHECK_NEXT(dispatchVectorBinary(ExtMulHighI8x16));
  11546          case uint32_t(SimdOp::I16x8ExtmulLowI8x16U):
  11547            CHECK_NEXT(dispatchVectorBinary(ExtMulLowUI8x16));
  11548          case uint32_t(SimdOp::I16x8ExtmulHighI8x16U):
  11549            CHECK_NEXT(dispatchVectorBinary(ExtMulHighUI8x16));
  11550          case uint32_t(SimdOp::I32x4ExtmulLowI16x8S):
  11551            CHECK_NEXT(dispatchVectorBinary(ExtMulLowI16x8));
  11552          case uint32_t(SimdOp::I32x4ExtmulHighI16x8S):
  11553            CHECK_NEXT(dispatchVectorBinary(ExtMulHighI16x8));
  11554          case uint32_t(SimdOp::I32x4ExtmulLowI16x8U):
  11555            CHECK_NEXT(dispatchVectorBinary(ExtMulLowUI16x8));
  11556          case uint32_t(SimdOp::I32x4ExtmulHighI16x8U):
  11557            CHECK_NEXT(dispatchVectorBinary(ExtMulHighUI16x8));
  11558          case uint32_t(SimdOp::I64x2ExtmulLowI32x4S):
  11559            CHECK_NEXT(dispatchVectorBinary(ExtMulLowI32x4));
  11560          case uint32_t(SimdOp::I64x2ExtmulHighI32x4S):
  11561            CHECK_NEXT(dispatchVectorBinary(ExtMulHighI32x4));
  11562          case uint32_t(SimdOp::I64x2ExtmulLowI32x4U):
  11563            CHECK_NEXT(dispatchVectorBinary(ExtMulLowUI32x4));
  11564          case uint32_t(SimdOp::I64x2ExtmulHighI32x4U):
  11565            CHECK_NEXT(dispatchVectorBinary(ExtMulHighUI32x4));
  11566          case uint32_t(SimdOp::I16x8Q15MulrSatS):
  11567            CHECK_NEXT(dispatchVectorBinary(Q15MulrSatS));
  11568          case uint32_t(SimdOp::I8x16Neg):
  11569            CHECK_NEXT(dispatchVectorUnary(NegI8x16));
  11570          case uint32_t(SimdOp::I16x8Neg):
  11571            CHECK_NEXT(dispatchVectorUnary(NegI16x8));
  11572          case uint32_t(SimdOp::I16x8ExtendLowI8x16S):
  11573            CHECK_NEXT(dispatchVectorUnary(WidenLowI8x16));
  11574          case uint32_t(SimdOp::I16x8ExtendHighI8x16S):
  11575            CHECK_NEXT(dispatchVectorUnary(WidenHighI8x16));
  11576          case uint32_t(SimdOp::I16x8ExtendLowI8x16U):
  11577            CHECK_NEXT(dispatchVectorUnary(WidenLowUI8x16));
  11578          case uint32_t(SimdOp::I16x8ExtendHighI8x16U):
  11579            CHECK_NEXT(dispatchVectorUnary(WidenHighUI8x16));
  11580          case uint32_t(SimdOp::I32x4Neg):
  11581            CHECK_NEXT(dispatchVectorUnary(NegI32x4));
  11582          case uint32_t(SimdOp::I32x4ExtendLowI16x8S):
  11583            CHECK_NEXT(dispatchVectorUnary(WidenLowI16x8));
  11584          case uint32_t(SimdOp::I32x4ExtendHighI16x8S):
  11585            CHECK_NEXT(dispatchVectorUnary(WidenHighI16x8));
  11586          case uint32_t(SimdOp::I32x4ExtendLowI16x8U):
  11587            CHECK_NEXT(dispatchVectorUnary(WidenLowUI16x8));
  11588          case uint32_t(SimdOp::I32x4ExtendHighI16x8U):
  11589            CHECK_NEXT(dispatchVectorUnary(WidenHighUI16x8));
  11590          case uint32_t(SimdOp::I32x4TruncSatF32x4S):
  11591            CHECK_NEXT(dispatchVectorUnary(ConvertF32x4ToI32x4));
  11592          case uint32_t(SimdOp::I32x4TruncSatF32x4U):
  11593            CHECK_NEXT(dispatchVectorUnary(ConvertF32x4ToUI32x4));
  11594          case uint32_t(SimdOp::I64x2Neg):
  11595            CHECK_NEXT(dispatchVectorUnary(NegI64x2));
  11596          case uint32_t(SimdOp::I64x2ExtendLowI32x4S):
  11597            CHECK_NEXT(dispatchVectorUnary(WidenLowI32x4));
  11598          case uint32_t(SimdOp::I64x2ExtendHighI32x4S):
  11599            CHECK_NEXT(dispatchVectorUnary(WidenHighI32x4));
  11600          case uint32_t(SimdOp::I64x2ExtendLowI32x4U):
  11601            CHECK_NEXT(dispatchVectorUnary(WidenLowUI32x4));
  11602          case uint32_t(SimdOp::I64x2ExtendHighI32x4U):
  11603            CHECK_NEXT(dispatchVectorUnary(WidenHighUI32x4));
  11604          case uint32_t(SimdOp::F32x4Abs):
  11605            CHECK_NEXT(dispatchVectorUnary(AbsF32x4));
  11606          case uint32_t(SimdOp::F32x4Neg):
  11607            CHECK_NEXT(dispatchVectorUnary(NegF32x4));
  11608          case uint32_t(SimdOp::F32x4Sqrt):
  11609            CHECK_NEXT(dispatchVectorUnary(SqrtF32x4));
  11610          case uint32_t(SimdOp::F32x4ConvertI32x4S):
  11611            CHECK_NEXT(dispatchVectorUnary(ConvertI32x4ToF32x4));
  11612          case uint32_t(SimdOp::F32x4ConvertI32x4U):
  11613            CHECK_NEXT(dispatchVectorUnary(ConvertUI32x4ToF32x4));
  11614          case uint32_t(SimdOp::F32x4DemoteF64x2Zero):
  11615            CHECK_NEXT(dispatchVectorUnary(DemoteF64x2ToF32x4));
  11616          case uint32_t(SimdOp::F64x2PromoteLowF32x4):
  11617            CHECK_NEXT(dispatchVectorUnary(PromoteF32x4ToF64x2));
  11618          case uint32_t(SimdOp::F64x2ConvertLowI32x4S):
  11619            CHECK_NEXT(dispatchVectorUnary(ConvertI32x4ToF64x2));
  11620          case uint32_t(SimdOp::F64x2ConvertLowI32x4U):
  11621            CHECK_NEXT(dispatchVectorUnary(ConvertUI32x4ToF64x2));
  11622          case uint32_t(SimdOp::I32x4TruncSatF64x2SZero):
  11623            CHECK_NEXT(dispatchVectorUnary(ConvertF64x2ToI32x4));
  11624          case uint32_t(SimdOp::I32x4TruncSatF64x2UZero):
  11625            CHECK_NEXT(dispatchVectorUnary(ConvertF64x2ToUI32x4));
  11626          case uint32_t(SimdOp::F64x2Abs):
  11627            CHECK_NEXT(dispatchVectorUnary(AbsF64x2));
  11628          case uint32_t(SimdOp::F64x2Neg):
  11629            CHECK_NEXT(dispatchVectorUnary(NegF64x2));
  11630          case uint32_t(SimdOp::F64x2Sqrt):
  11631            CHECK_NEXT(dispatchVectorUnary(SqrtF64x2));
  11632          case uint32_t(SimdOp::V128Not):
  11633            CHECK_NEXT(dispatchVectorUnary(NotV128));
  11634          case uint32_t(SimdOp::I8x16Popcnt):
  11635            CHECK_NEXT(dispatchVectorUnary(PopcntI8x16));
  11636          case uint32_t(SimdOp::I8x16Abs):
  11637            CHECK_NEXT(dispatchVectorUnary(AbsI8x16));
  11638          case uint32_t(SimdOp::I16x8Abs):
  11639            CHECK_NEXT(dispatchVectorUnary(AbsI16x8));
  11640          case uint32_t(SimdOp::I32x4Abs):
  11641            CHECK_NEXT(dispatchVectorUnary(AbsI32x4));
  11642          case uint32_t(SimdOp::I64x2Abs):
  11643            CHECK_NEXT(dispatchVectorUnary(AbsI64x2));
  11644          case uint32_t(SimdOp::F32x4Ceil):
  11645            CHECK_NEXT(dispatchVectorUnary(CeilF32x4));
  11646          case uint32_t(SimdOp::F32x4Floor):
  11647            CHECK_NEXT(dispatchVectorUnary(FloorF32x4));
  11648          case uint32_t(SimdOp::F32x4Trunc):
  11649            CHECK_NEXT(dispatchVectorUnary(TruncF32x4));
  11650          case uint32_t(SimdOp::F32x4Nearest):
  11651            CHECK_NEXT(dispatchVectorUnary(NearestF32x4));
  11652          case uint32_t(SimdOp::F64x2Ceil):
  11653            CHECK_NEXT(dispatchVectorUnary(CeilF64x2));
  11654          case uint32_t(SimdOp::F64x2Floor):
  11655            CHECK_NEXT(dispatchVectorUnary(FloorF64x2));
  11656          case uint32_t(SimdOp::F64x2Trunc):
  11657            CHECK_NEXT(dispatchVectorUnary(TruncF64x2));
  11658          case uint32_t(SimdOp::F64x2Nearest):
  11659            CHECK_NEXT(dispatchVectorUnary(NearestF64x2));
  11660          case uint32_t(SimdOp::I16x8ExtaddPairwiseI8x16S):
  11661            CHECK_NEXT(dispatchVectorUnary(ExtAddPairwiseI8x16));
  11662          case uint32_t(SimdOp::I16x8ExtaddPairwiseI8x16U):
  11663            CHECK_NEXT(dispatchVectorUnary(ExtAddPairwiseUI8x16));
  11664          case uint32_t(SimdOp::I32x4ExtaddPairwiseI16x8S):
  11665            CHECK_NEXT(dispatchVectorUnary(ExtAddPairwiseI16x8));
  11666          case uint32_t(SimdOp::I32x4ExtaddPairwiseI16x8U):
  11667            CHECK_NEXT(dispatchVectorUnary(ExtAddPairwiseUI16x8));
  11668          case uint32_t(SimdOp::I8x16Shl):
  11669            CHECK_NEXT(dispatchVectorVariableShift(ShiftLeftI8x16));
  11670          case uint32_t(SimdOp::I8x16ShrS):
  11671            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightI8x16));
  11672          case uint32_t(SimdOp::I8x16ShrU):
  11673            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightUI8x16));
  11674          case uint32_t(SimdOp::I16x8Shl):
  11675            CHECK_NEXT(dispatchVectorVariableShift(ShiftLeftI16x8));
  11676          case uint32_t(SimdOp::I16x8ShrS):
  11677            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightI16x8));
  11678          case uint32_t(SimdOp::I16x8ShrU):
  11679            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightUI16x8));
  11680          case uint32_t(SimdOp::I32x4Shl):
  11681            CHECK_NEXT(dispatchVectorVariableShift(ShiftLeftI32x4));
  11682          case uint32_t(SimdOp::I32x4ShrS):
  11683            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightI32x4));
  11684          case uint32_t(SimdOp::I32x4ShrU):
  11685            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightUI32x4));
  11686          case uint32_t(SimdOp::I64x2Shl):
  11687            CHECK_NEXT(dispatchVectorVariableShift(ShiftLeftI64x2));
  11688          case uint32_t(SimdOp::I64x2ShrS):
  11689 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
  11690            CHECK_NEXT(emitVectorShiftRightI64x2());
  11691 #  else
  11692            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightI64x2));
  11693 #  endif
  11694          case uint32_t(SimdOp::I64x2ShrU):
  11695            CHECK_NEXT(dispatchVectorVariableShift(ShiftRightUI64x2));
  11696          case uint32_t(SimdOp::V128Bitselect):
  11697            CHECK_NEXT(dispatchTernary1(BitselectV128, ValType::V128));
  11698          case uint32_t(SimdOp::I8x16Shuffle):
  11699            CHECK_NEXT(emitVectorShuffle());
  11700          case uint32_t(SimdOp::V128Const): {
  11701            V128 v128;
  11702            CHECK(iter_.readV128Const(&v128));
  11703            if (!deadCode_) {
  11704              pushV128(v128);
  11705            }
  11706            NEXT();
  11707          }
  11708          case uint32_t(SimdOp::V128Load):
  11709            CHECK_NEXT(emitLoad(ValType::V128, Scalar::Simd128));
  11710          case uint32_t(SimdOp::V128Load8Splat):
  11711            CHECK_NEXT(emitLoadSplat(Scalar::Uint8));
  11712          case uint32_t(SimdOp::V128Load16Splat):
  11713            CHECK_NEXT(emitLoadSplat(Scalar::Uint16));
  11714          case uint32_t(SimdOp::V128Load32Splat):
  11715            CHECK_NEXT(emitLoadSplat(Scalar::Uint32));
  11716          case uint32_t(SimdOp::V128Load64Splat):
  11717            CHECK_NEXT(emitLoadSplat(Scalar::Int64));
  11718          case uint32_t(SimdOp::V128Load8x8S):
  11719            CHECK_NEXT(emitLoadExtend(Scalar::Int8));
  11720          case uint32_t(SimdOp::V128Load8x8U):
  11721            CHECK_NEXT(emitLoadExtend(Scalar::Uint8));
  11722          case uint32_t(SimdOp::V128Load16x4S):
  11723            CHECK_NEXT(emitLoadExtend(Scalar::Int16));
  11724          case uint32_t(SimdOp::V128Load16x4U):
  11725            CHECK_NEXT(emitLoadExtend(Scalar::Uint16));
  11726          case uint32_t(SimdOp::V128Load32x2S):
  11727            CHECK_NEXT(emitLoadExtend(Scalar::Int32));
  11728          case uint32_t(SimdOp::V128Load32x2U):
  11729            CHECK_NEXT(emitLoadExtend(Scalar::Uint32));
  11730          case uint32_t(SimdOp::V128Load32Zero):
  11731            CHECK_NEXT(emitLoadZero(Scalar::Float32));
  11732          case uint32_t(SimdOp::V128Load64Zero):
  11733            CHECK_NEXT(emitLoadZero(Scalar::Float64));
  11734          case uint32_t(SimdOp::V128Store):
  11735            CHECK_NEXT(emitStore(ValType::V128, Scalar::Simd128));
  11736          case uint32_t(SimdOp::V128Load8Lane):
  11737            CHECK_NEXT(emitLoadLane(1));
  11738          case uint32_t(SimdOp::V128Load16Lane):
  11739            CHECK_NEXT(emitLoadLane(2));
  11740          case uint32_t(SimdOp::V128Load32Lane):
  11741            CHECK_NEXT(emitLoadLane(4));
  11742          case uint32_t(SimdOp::V128Load64Lane):
  11743            CHECK_NEXT(emitLoadLane(8));
  11744          case uint32_t(SimdOp::V128Store8Lane):
  11745            CHECK_NEXT(emitStoreLane(1));
  11746          case uint32_t(SimdOp::V128Store16Lane):
  11747            CHECK_NEXT(emitStoreLane(2));
  11748          case uint32_t(SimdOp::V128Store32Lane):
  11749            CHECK_NEXT(emitStoreLane(4));
  11750          case uint32_t(SimdOp::V128Store64Lane):
  11751            CHECK_NEXT(emitStoreLane(8));
  11752 #  ifdef ENABLE_WASM_RELAXED_SIMD
  11753          case uint32_t(SimdOp::F32x4RelaxedMadd):
  11754            if (!codeMeta_.v128RelaxedEnabled()) {
  11755              return iter_.unrecognizedOpcode(&op);
  11756            }
  11757            CHECK_NEXT(dispatchTernary2(RelaxedMaddF32x4, ValType::V128));
  11758          case uint32_t(SimdOp::F32x4RelaxedNmadd):
  11759            if (!codeMeta_.v128RelaxedEnabled()) {
  11760              return iter_.unrecognizedOpcode(&op);
  11761            }
  11762            CHECK_NEXT(dispatchTernary2(RelaxedNmaddF32x4, ValType::V128));
  11763          case uint32_t(SimdOp::F64x2RelaxedMadd):
  11764            if (!codeMeta_.v128RelaxedEnabled()) {
  11765              return iter_.unrecognizedOpcode(&op);
  11766            }
  11767            CHECK_NEXT(dispatchTernary2(RelaxedMaddF64x2, ValType::V128));
  11768          case uint32_t(SimdOp::F64x2RelaxedNmadd):
  11769            if (!codeMeta_.v128RelaxedEnabled()) {
  11770              return iter_.unrecognizedOpcode(&op);
  11771            }
  11772            CHECK_NEXT(dispatchTernary2(RelaxedNmaddF64x2, ValType::V128));
  11773            break;
  11774          case uint32_t(SimdOp::I8x16RelaxedLaneSelect):
  11775          case uint32_t(SimdOp::I16x8RelaxedLaneSelect):
  11776          case uint32_t(SimdOp::I32x4RelaxedLaneSelect):
  11777          case uint32_t(SimdOp::I64x2RelaxedLaneSelect):
  11778            if (!codeMeta_.v128RelaxedEnabled()) {
  11779              return iter_.unrecognizedOpcode(&op);
  11780            }
  11781            CHECK_NEXT(emitVectorLaneSelect());
  11782          case uint32_t(SimdOp::F32x4RelaxedMin):
  11783            if (!codeMeta_.v128RelaxedEnabled()) {
  11784              return iter_.unrecognizedOpcode(&op);
  11785            }
  11786            CHECK_NEXT(dispatchVectorBinary(RelaxedMinF32x4));
  11787          case uint32_t(SimdOp::F32x4RelaxedMax):
  11788            if (!codeMeta_.v128RelaxedEnabled()) {
  11789              return iter_.unrecognizedOpcode(&op);
  11790            }
  11791            CHECK_NEXT(dispatchVectorBinary(RelaxedMaxF32x4));
  11792          case uint32_t(SimdOp::F64x2RelaxedMin):
  11793            if (!codeMeta_.v128RelaxedEnabled()) {
  11794              return iter_.unrecognizedOpcode(&op);
  11795            }
  11796            CHECK_NEXT(dispatchVectorBinary(RelaxedMinF64x2));
  11797          case uint32_t(SimdOp::F64x2RelaxedMax):
  11798            if (!codeMeta_.v128RelaxedEnabled()) {
  11799              return iter_.unrecognizedOpcode(&op);
  11800            }
  11801            CHECK_NEXT(dispatchVectorBinary(RelaxedMaxF64x2));
  11802          case uint32_t(SimdOp::I32x4RelaxedTruncF32x4S):
  11803            if (!codeMeta_.v128RelaxedEnabled()) {
  11804              return iter_.unrecognizedOpcode(&op);
  11805            }
  11806            CHECK_NEXT(dispatchVectorUnary(RelaxedConvertF32x4ToI32x4));
  11807          case uint32_t(SimdOp::I32x4RelaxedTruncF32x4U):
  11808            if (!codeMeta_.v128RelaxedEnabled()) {
  11809              return iter_.unrecognizedOpcode(&op);
  11810            }
  11811            CHECK_NEXT(dispatchVectorUnary(RelaxedConvertF32x4ToUI32x4));
  11812          case uint32_t(SimdOp::I32x4RelaxedTruncF64x2SZero):
  11813            if (!codeMeta_.v128RelaxedEnabled()) {
  11814              return iter_.unrecognizedOpcode(&op);
  11815            }
  11816            CHECK_NEXT(dispatchVectorUnary(RelaxedConvertF64x2ToI32x4));
  11817          case uint32_t(SimdOp::I32x4RelaxedTruncF64x2UZero):
  11818            if (!codeMeta_.v128RelaxedEnabled()) {
  11819              return iter_.unrecognizedOpcode(&op);
  11820            }
  11821            CHECK_NEXT(dispatchVectorUnary(RelaxedConvertF64x2ToUI32x4));
  11822          case uint32_t(SimdOp::I8x16RelaxedSwizzle):
  11823            if (!codeMeta_.v128RelaxedEnabled()) {
  11824              return iter_.unrecognizedOpcode(&op);
  11825            }
  11826            CHECK_NEXT(dispatchVectorBinary(RelaxedSwizzle));
  11827          case uint32_t(SimdOp::I16x8RelaxedQ15MulrS):
  11828            if (!codeMeta_.v128RelaxedEnabled()) {
  11829              return iter_.unrecognizedOpcode(&op);
  11830            }
  11831            CHECK_NEXT(dispatchVectorBinary(RelaxedQ15MulrS));
  11832          case uint32_t(SimdOp::I16x8RelaxedDotI8x16I7x16S):
  11833            if (!codeMeta_.v128RelaxedEnabled()) {
  11834              return iter_.unrecognizedOpcode(&op);
  11835            }
  11836            CHECK_NEXT(dispatchVectorBinary(DotI8x16I7x16S));
  11837          case uint32_t(SimdOp::I32x4RelaxedDotI8x16I7x16AddS):
  11838            if (!codeMeta_.v128RelaxedEnabled()) {
  11839              return iter_.unrecognizedOpcode(&op);
  11840            }
  11841            CHECK_NEXT(dispatchTernary0(emitDotI8x16I7x16AddS, ValType::V128));
  11842 #  endif
  11843          default:
  11844            break;
  11845        }  // switch (op.b1)
  11846        return iter_.unrecognizedOpcode(&op);
  11847      }
  11848 #endif  // ENABLE_WASM_SIMD
  11849 
  11850      // "Miscellaneous" operations
  11851      case uint16_t(Op::MiscPrefix): {
  11852        switch (op.b1) {
  11853          case uint32_t(MiscOp::I32TruncSatF32S):
  11854            CHECK_NEXT(
  11855                dispatchConversionOOM(emitTruncateF32ToI32<TRUNC_SATURATING>,
  11856                                      ValType::F32, ValType::I32));
  11857          case uint32_t(MiscOp::I32TruncSatF32U):
  11858            CHECK_NEXT(dispatchConversionOOM(
  11859                emitTruncateF32ToI32<TRUNC_UNSIGNED | TRUNC_SATURATING>,
  11860                ValType::F32, ValType::I32));
  11861          case uint32_t(MiscOp::I32TruncSatF64S):
  11862            CHECK_NEXT(
  11863                dispatchConversionOOM(emitTruncateF64ToI32<TRUNC_SATURATING>,
  11864                                      ValType::F64, ValType::I32));
  11865          case uint32_t(MiscOp::I32TruncSatF64U):
  11866            CHECK_NEXT(dispatchConversionOOM(
  11867                emitTruncateF64ToI32<TRUNC_UNSIGNED | TRUNC_SATURATING>,
  11868                ValType::F64, ValType::I32));
  11869          case uint32_t(MiscOp::I64TruncSatF32S):
  11870 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  11871            CHECK_NEXT(dispatchCalloutConversionOOM(
  11872                emitConvertFloatingToInt64Callout,
  11873                SymbolicAddress::SaturatingTruncateDoubleToInt64, ValType::F32,
  11874                ValType::I64));
  11875 #else
  11876            CHECK_NEXT(
  11877                dispatchConversionOOM(emitTruncateF32ToI64<TRUNC_SATURATING>,
  11878                                      ValType::F32, ValType::I64));
  11879 #endif
  11880          case uint32_t(MiscOp::I64TruncSatF32U):
  11881 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  11882            CHECK_NEXT(dispatchCalloutConversionOOM(
  11883                emitConvertFloatingToInt64Callout,
  11884                SymbolicAddress::SaturatingTruncateDoubleToUint64, ValType::F32,
  11885                ValType::I64));
  11886 #else
  11887            CHECK_NEXT(dispatchConversionOOM(
  11888                emitTruncateF32ToI64<TRUNC_UNSIGNED | TRUNC_SATURATING>,
  11889                ValType::F32, ValType::I64));
  11890 #endif
  11891          case uint32_t(MiscOp::I64TruncSatF64S):
  11892 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  11893            CHECK_NEXT(dispatchCalloutConversionOOM(
  11894                emitConvertFloatingToInt64Callout,
  11895                SymbolicAddress::SaturatingTruncateDoubleToInt64, ValType::F64,
  11896                ValType::I64));
  11897 #else
  11898            CHECK_NEXT(
  11899                dispatchConversionOOM(emitTruncateF64ToI64<TRUNC_SATURATING>,
  11900                                      ValType::F64, ValType::I64));
  11901 #endif
  11902          case uint32_t(MiscOp::I64TruncSatF64U):
  11903 #ifdef RABALDR_FLOAT_TO_I64_CALLOUT
  11904            CHECK_NEXT(dispatchCalloutConversionOOM(
  11905                emitConvertFloatingToInt64Callout,
  11906                SymbolicAddress::SaturatingTruncateDoubleToUint64, ValType::F64,
  11907                ValType::I64));
  11908 #else
  11909            CHECK_NEXT(dispatchConversionOOM(
  11910                emitTruncateF64ToI64<TRUNC_UNSIGNED | TRUNC_SATURATING>,
  11911                ValType::F64, ValType::I64));
  11912 #endif
  11913          case uint32_t(MiscOp::MemoryCopy):
  11914            CHECK_NEXT(emitMemCopy());
  11915          case uint32_t(MiscOp::DataDrop):
  11916            CHECK_NEXT(emitDataOrElemDrop(/*isData=*/true));
  11917          case uint32_t(MiscOp::MemoryFill):
  11918            CHECK_NEXT(emitMemFill());
  11919 #ifdef ENABLE_WASM_MEMORY_CONTROL
  11920          case uint32_t(MiscOp::MemoryDiscard): {
  11921            if (!codeMeta_.memoryControlEnabled()) {
  11922              return iter_.unrecognizedOpcode(&op);
  11923            }
  11924            CHECK_NEXT(emitMemDiscard());
  11925          }
  11926 #endif
  11927          case uint32_t(MiscOp::MemoryInit):
  11928            CHECK_NEXT(emitMemInit());
  11929          case uint32_t(MiscOp::TableCopy):
  11930            CHECK_NEXT(emitTableCopy());
  11931          case uint32_t(MiscOp::ElemDrop):
  11932            CHECK_NEXT(emitDataOrElemDrop(/*isData=*/false));
  11933          case uint32_t(MiscOp::TableInit):
  11934            CHECK_NEXT(emitTableInit());
  11935          case uint32_t(MiscOp::TableFill):
  11936            CHECK_NEXT(emitTableFill());
  11937          case uint32_t(MiscOp::TableGrow):
  11938            CHECK_NEXT(emitTableGrow());
  11939          case uint32_t(MiscOp::TableSize):
  11940            CHECK_NEXT(emitTableSize());
  11941          default:
  11942            break;
  11943        }  // switch (op.b1)
  11944        return iter_.unrecognizedOpcode(&op);
  11945      }
  11946 
  11947      // Thread operations
  11948      case uint16_t(Op::ThreadPrefix): {
  11949        // Though thread ops can be used on nonshared memories, we make them
  11950        // unavailable if shared memory has been disabled in the prefs, for
  11951        // maximum predictability and safety and consistency with JS.
  11952        if (codeMeta_.sharedMemoryEnabled() == Shareable::False) {
  11953          return iter_.unrecognizedOpcode(&op);
  11954        }
  11955        switch (op.b1) {
  11956          case uint32_t(ThreadOp::Notify):
  11957            CHECK_NEXT(emitNotify());
  11958 
  11959          case uint32_t(ThreadOp::I32Wait):
  11960            CHECK_NEXT(emitWait(ValType::I32, 4));
  11961          case uint32_t(ThreadOp::I64Wait):
  11962            CHECK_NEXT(emitWait(ValType::I64, 8));
  11963          case uint32_t(ThreadOp::Fence):
  11964            CHECK_NEXT(emitFence());
  11965 
  11966          case uint32_t(ThreadOp::I32AtomicLoad):
  11967            CHECK_NEXT(emitAtomicLoad(ValType::I32, Scalar::Int32));
  11968          case uint32_t(ThreadOp::I64AtomicLoad):
  11969            CHECK_NEXT(emitAtomicLoad(ValType::I64, Scalar::Int64));
  11970          case uint32_t(ThreadOp::I32AtomicLoad8U):
  11971            CHECK_NEXT(emitAtomicLoad(ValType::I32, Scalar::Uint8));
  11972          case uint32_t(ThreadOp::I32AtomicLoad16U):
  11973            CHECK_NEXT(emitAtomicLoad(ValType::I32, Scalar::Uint16));
  11974          case uint32_t(ThreadOp::I64AtomicLoad8U):
  11975            CHECK_NEXT(emitAtomicLoad(ValType::I64, Scalar::Uint8));
  11976          case uint32_t(ThreadOp::I64AtomicLoad16U):
  11977            CHECK_NEXT(emitAtomicLoad(ValType::I64, Scalar::Uint16));
  11978          case uint32_t(ThreadOp::I64AtomicLoad32U):
  11979            CHECK_NEXT(emitAtomicLoad(ValType::I64, Scalar::Uint32));
  11980 
  11981          case uint32_t(ThreadOp::I32AtomicStore):
  11982            CHECK_NEXT(emitAtomicStore(ValType::I32, Scalar::Int32));
  11983          case uint32_t(ThreadOp::I64AtomicStore):
  11984            CHECK_NEXT(emitAtomicStore(ValType::I64, Scalar::Int64));
  11985          case uint32_t(ThreadOp::I32AtomicStore8U):
  11986            CHECK_NEXT(emitAtomicStore(ValType::I32, Scalar::Uint8));
  11987          case uint32_t(ThreadOp::I32AtomicStore16U):
  11988            CHECK_NEXT(emitAtomicStore(ValType::I32, Scalar::Uint16));
  11989          case uint32_t(ThreadOp::I64AtomicStore8U):
  11990            CHECK_NEXT(emitAtomicStore(ValType::I64, Scalar::Uint8));
  11991          case uint32_t(ThreadOp::I64AtomicStore16U):
  11992            CHECK_NEXT(emitAtomicStore(ValType::I64, Scalar::Uint16));
  11993          case uint32_t(ThreadOp::I64AtomicStore32U):
  11994            CHECK_NEXT(emitAtomicStore(ValType::I64, Scalar::Uint32));
  11995 
  11996          case uint32_t(ThreadOp::I32AtomicAdd):
  11997            CHECK_NEXT(
  11998                emitAtomicRMW(ValType::I32, Scalar::Int32, AtomicOp::Add));
  11999          case uint32_t(ThreadOp::I64AtomicAdd):
  12000            CHECK_NEXT(
  12001                emitAtomicRMW(ValType::I64, Scalar::Int64, AtomicOp::Add));
  12002          case uint32_t(ThreadOp::I32AtomicAdd8U):
  12003            CHECK_NEXT(
  12004                emitAtomicRMW(ValType::I32, Scalar::Uint8, AtomicOp::Add));
  12005          case uint32_t(ThreadOp::I32AtomicAdd16U):
  12006            CHECK_NEXT(
  12007                emitAtomicRMW(ValType::I32, Scalar::Uint16, AtomicOp::Add));
  12008          case uint32_t(ThreadOp::I64AtomicAdd8U):
  12009            CHECK_NEXT(
  12010                emitAtomicRMW(ValType::I64, Scalar::Uint8, AtomicOp::Add));
  12011          case uint32_t(ThreadOp::I64AtomicAdd16U):
  12012            CHECK_NEXT(
  12013                emitAtomicRMW(ValType::I64, Scalar::Uint16, AtomicOp::Add));
  12014          case uint32_t(ThreadOp::I64AtomicAdd32U):
  12015            CHECK_NEXT(
  12016                emitAtomicRMW(ValType::I64, Scalar::Uint32, AtomicOp::Add));
  12017 
  12018          case uint32_t(ThreadOp::I32AtomicSub):
  12019            CHECK_NEXT(
  12020                emitAtomicRMW(ValType::I32, Scalar::Int32, AtomicOp::Sub));
  12021          case uint32_t(ThreadOp::I64AtomicSub):
  12022            CHECK_NEXT(
  12023                emitAtomicRMW(ValType::I64, Scalar::Int64, AtomicOp::Sub));
  12024          case uint32_t(ThreadOp::I32AtomicSub8U):
  12025            CHECK_NEXT(
  12026                emitAtomicRMW(ValType::I32, Scalar::Uint8, AtomicOp::Sub));
  12027          case uint32_t(ThreadOp::I32AtomicSub16U):
  12028            CHECK_NEXT(
  12029                emitAtomicRMW(ValType::I32, Scalar::Uint16, AtomicOp::Sub));
  12030          case uint32_t(ThreadOp::I64AtomicSub8U):
  12031            CHECK_NEXT(
  12032                emitAtomicRMW(ValType::I64, Scalar::Uint8, AtomicOp::Sub));
  12033          case uint32_t(ThreadOp::I64AtomicSub16U):
  12034            CHECK_NEXT(
  12035                emitAtomicRMW(ValType::I64, Scalar::Uint16, AtomicOp::Sub));
  12036          case uint32_t(ThreadOp::I64AtomicSub32U):
  12037            CHECK_NEXT(
  12038                emitAtomicRMW(ValType::I64, Scalar::Uint32, AtomicOp::Sub));
  12039 
  12040          case uint32_t(ThreadOp::I32AtomicAnd):
  12041            CHECK_NEXT(
  12042                emitAtomicRMW(ValType::I32, Scalar::Int32, AtomicOp::And));
  12043          case uint32_t(ThreadOp::I64AtomicAnd):
  12044            CHECK_NEXT(
  12045                emitAtomicRMW(ValType::I64, Scalar::Int64, AtomicOp::And));
  12046          case uint32_t(ThreadOp::I32AtomicAnd8U):
  12047            CHECK_NEXT(
  12048                emitAtomicRMW(ValType::I32, Scalar::Uint8, AtomicOp::And));
  12049          case uint32_t(ThreadOp::I32AtomicAnd16U):
  12050            CHECK_NEXT(
  12051                emitAtomicRMW(ValType::I32, Scalar::Uint16, AtomicOp::And));
  12052          case uint32_t(ThreadOp::I64AtomicAnd8U):
  12053            CHECK_NEXT(
  12054                emitAtomicRMW(ValType::I64, Scalar::Uint8, AtomicOp::And));
  12055          case uint32_t(ThreadOp::I64AtomicAnd16U):
  12056            CHECK_NEXT(
  12057                emitAtomicRMW(ValType::I64, Scalar::Uint16, AtomicOp::And));
  12058          case uint32_t(ThreadOp::I64AtomicAnd32U):
  12059            CHECK_NEXT(
  12060                emitAtomicRMW(ValType::I64, Scalar::Uint32, AtomicOp::And));
  12061 
  12062          case uint32_t(ThreadOp::I32AtomicOr):
  12063            CHECK_NEXT(
  12064                emitAtomicRMW(ValType::I32, Scalar::Int32, AtomicOp::Or));
  12065          case uint32_t(ThreadOp::I64AtomicOr):
  12066            CHECK_NEXT(
  12067                emitAtomicRMW(ValType::I64, Scalar::Int64, AtomicOp::Or));
  12068          case uint32_t(ThreadOp::I32AtomicOr8U):
  12069            CHECK_NEXT(
  12070                emitAtomicRMW(ValType::I32, Scalar::Uint8, AtomicOp::Or));
  12071          case uint32_t(ThreadOp::I32AtomicOr16U):
  12072            CHECK_NEXT(
  12073                emitAtomicRMW(ValType::I32, Scalar::Uint16, AtomicOp::Or));
  12074          case uint32_t(ThreadOp::I64AtomicOr8U):
  12075            CHECK_NEXT(
  12076                emitAtomicRMW(ValType::I64, Scalar::Uint8, AtomicOp::Or));
  12077          case uint32_t(ThreadOp::I64AtomicOr16U):
  12078            CHECK_NEXT(
  12079                emitAtomicRMW(ValType::I64, Scalar::Uint16, AtomicOp::Or));
  12080          case uint32_t(ThreadOp::I64AtomicOr32U):
  12081            CHECK_NEXT(
  12082                emitAtomicRMW(ValType::I64, Scalar::Uint32, AtomicOp::Or));
  12083 
  12084          case uint32_t(ThreadOp::I32AtomicXor):
  12085            CHECK_NEXT(
  12086                emitAtomicRMW(ValType::I32, Scalar::Int32, AtomicOp::Xor));
  12087          case uint32_t(ThreadOp::I64AtomicXor):
  12088            CHECK_NEXT(
  12089                emitAtomicRMW(ValType::I64, Scalar::Int64, AtomicOp::Xor));
  12090          case uint32_t(ThreadOp::I32AtomicXor8U):
  12091            CHECK_NEXT(
  12092                emitAtomicRMW(ValType::I32, Scalar::Uint8, AtomicOp::Xor));
  12093          case uint32_t(ThreadOp::I32AtomicXor16U):
  12094            CHECK_NEXT(
  12095                emitAtomicRMW(ValType::I32, Scalar::Uint16, AtomicOp::Xor));
  12096          case uint32_t(ThreadOp::I64AtomicXor8U):
  12097            CHECK_NEXT(
  12098                emitAtomicRMW(ValType::I64, Scalar::Uint8, AtomicOp::Xor));
  12099          case uint32_t(ThreadOp::I64AtomicXor16U):
  12100            CHECK_NEXT(
  12101                emitAtomicRMW(ValType::I64, Scalar::Uint16, AtomicOp::Xor));
  12102          case uint32_t(ThreadOp::I64AtomicXor32U):
  12103            CHECK_NEXT(
  12104                emitAtomicRMW(ValType::I64, Scalar::Uint32, AtomicOp::Xor));
  12105 
  12106          case uint32_t(ThreadOp::I32AtomicXchg):
  12107            CHECK_NEXT(emitAtomicXchg(ValType::I32, Scalar::Int32));
  12108          case uint32_t(ThreadOp::I64AtomicXchg):
  12109            CHECK_NEXT(emitAtomicXchg(ValType::I64, Scalar::Int64));
  12110          case uint32_t(ThreadOp::I32AtomicXchg8U):
  12111            CHECK_NEXT(emitAtomicXchg(ValType::I32, Scalar::Uint8));
  12112          case uint32_t(ThreadOp::I32AtomicXchg16U):
  12113            CHECK_NEXT(emitAtomicXchg(ValType::I32, Scalar::Uint16));
  12114          case uint32_t(ThreadOp::I64AtomicXchg8U):
  12115            CHECK_NEXT(emitAtomicXchg(ValType::I64, Scalar::Uint8));
  12116          case uint32_t(ThreadOp::I64AtomicXchg16U):
  12117            CHECK_NEXT(emitAtomicXchg(ValType::I64, Scalar::Uint16));
  12118          case uint32_t(ThreadOp::I64AtomicXchg32U):
  12119            CHECK_NEXT(emitAtomicXchg(ValType::I64, Scalar::Uint32));
  12120 
  12121          case uint32_t(ThreadOp::I32AtomicCmpXchg):
  12122            CHECK_NEXT(emitAtomicCmpXchg(ValType::I32, Scalar::Int32));
  12123          case uint32_t(ThreadOp::I64AtomicCmpXchg):
  12124            CHECK_NEXT(emitAtomicCmpXchg(ValType::I64, Scalar::Int64));
  12125          case uint32_t(ThreadOp::I32AtomicCmpXchg8U):
  12126            CHECK_NEXT(emitAtomicCmpXchg(ValType::I32, Scalar::Uint8));
  12127          case uint32_t(ThreadOp::I32AtomicCmpXchg16U):
  12128            CHECK_NEXT(emitAtomicCmpXchg(ValType::I32, Scalar::Uint16));
  12129          case uint32_t(ThreadOp::I64AtomicCmpXchg8U):
  12130            CHECK_NEXT(emitAtomicCmpXchg(ValType::I64, Scalar::Uint8));
  12131          case uint32_t(ThreadOp::I64AtomicCmpXchg16U):
  12132            CHECK_NEXT(emitAtomicCmpXchg(ValType::I64, Scalar::Uint16));
  12133          case uint32_t(ThreadOp::I64AtomicCmpXchg32U):
  12134            CHECK_NEXT(emitAtomicCmpXchg(ValType::I64, Scalar::Uint32));
  12135 
  12136          default:
  12137            return iter_.unrecognizedOpcode(&op);
  12138        }
  12139        break;
  12140      }
  12141 
  12142      // asm.js and other private operations
  12143      case uint16_t(Op::MozPrefix): {
  12144        if (op.b1 != uint32_t(MozOp::CallBuiltinModuleFunc) ||
  12145            !codeMeta_.isBuiltinModule()) {
  12146          return iter_.unrecognizedOpcode(&op);
  12147        }
  12148        // Call a private builtin module func
  12149        CHECK_NEXT(emitCallBuiltinModuleFunc());
  12150      }
  12151 
  12152      default:
  12153        return iter_.unrecognizedOpcode(&op);
  12154    }
  12155 
  12156 #undef CHECK
  12157 #undef NEXT
  12158 #undef CHECK_NEXT
  12159 #undef CHECK_POINTER_COUNT
  12160 #undef dispatchBinary0
  12161 #undef dispatchBinary1
  12162 #undef dispatchBinary2
  12163 #undef dispatchBinary3
  12164 #undef dispatchUnary0
  12165 #undef dispatchUnary1
  12166 #undef dispatchUnary2
  12167 #undef dispatchComparison0
  12168 #undef dispatchConversion0
  12169 #undef dispatchConversion1
  12170 #undef dispatchConversionOOM
  12171 #undef dispatchCalloutConversionOOM
  12172 #undef dispatchIntDivCallout
  12173 #undef dispatchVectorBinary
  12174 #undef dispatchVectorUnary
  12175 #undef dispatchVectorComparison
  12176 #undef dispatchExtractLane
  12177 #undef dispatchReplaceLane
  12178 #undef dispatchSplat
  12179 #undef dispatchVectorReduction
  12180 
  12181    MOZ_CRASH("unreachable");
  12182  }
  12183 
  12184  MOZ_CRASH("unreachable");
  12185 }
  12186 
  12187 //////////////////////////////////////////////////////////////////////////////
  12188 //
  12189 // Various helpers.
  12190 
  12191 void BaseCompiler::assertResultRegistersAvailable(ResultType type) {
  12192 #ifdef DEBUG
  12193  for (ABIResultIter iter(type); !iter.done(); iter.next()) {
  12194    ABIResult result = iter.cur();
  12195    if (!result.inRegister()) {
  12196      return;
  12197    }
  12198    switch (result.type().kind()) {
  12199      case ValType::I32:
  12200        MOZ_ASSERT(isAvailableI32(RegI32(result.gpr())));
  12201        break;
  12202      case ValType::I64:
  12203        MOZ_ASSERT(isAvailableI64(RegI64(result.gpr64())));
  12204        break;
  12205      case ValType::V128:
  12206 #  ifdef ENABLE_WASM_SIMD
  12207        MOZ_ASSERT(isAvailableV128(RegV128(result.fpr())));
  12208        break;
  12209 #  else
  12210        MOZ_CRASH("No SIMD support");
  12211 #  endif
  12212      case ValType::F32:
  12213        MOZ_ASSERT(isAvailableF32(RegF32(result.fpr())));
  12214        break;
  12215      case ValType::F64:
  12216        MOZ_ASSERT(isAvailableF64(RegF64(result.fpr())));
  12217        break;
  12218      case ValType::Ref:
  12219        MOZ_ASSERT(isAvailableRef(RegRef(result.gpr())));
  12220        break;
  12221    }
  12222  }
  12223 #endif
  12224 }
  12225 
  12226 void BaseCompiler::saveTempPtr(const RegPtr& r) {
  12227  MOZ_ASSERT(!ra.isAvailablePtr(r));
  12228  fr.pushGPR(r);
  12229  ra.freePtr(r);
  12230  MOZ_ASSERT(ra.isAvailablePtr(r));
  12231 }
  12232 
  12233 void BaseCompiler::restoreTempPtr(const RegPtr& r) {
  12234  MOZ_ASSERT(ra.isAvailablePtr(r));
  12235  ra.needPtr(r);
  12236  fr.popGPR(r);
  12237  MOZ_ASSERT(!ra.isAvailablePtr(r));
  12238 }
  12239 
  12240 #ifdef DEBUG
  12241 void BaseCompiler::performRegisterLeakCheck() {
  12242  BaseRegAlloc::LeakCheck check(ra);
  12243  for (auto& item : stk_) {
  12244    switch (item.kind_) {
  12245      case Stk::RegisterI32:
  12246        check.addKnownI32(item.i32reg());
  12247        break;
  12248      case Stk::RegisterI64:
  12249        check.addKnownI64(item.i64reg());
  12250        break;
  12251      case Stk::RegisterF32:
  12252        check.addKnownF32(item.f32reg());
  12253        break;
  12254      case Stk::RegisterF64:
  12255        check.addKnownF64(item.f64reg());
  12256        break;
  12257 #  ifdef ENABLE_WASM_SIMD
  12258      case Stk::RegisterV128:
  12259        check.addKnownV128(item.v128reg());
  12260        break;
  12261 #  endif
  12262      case Stk::RegisterRef:
  12263        check.addKnownRef(item.refReg());
  12264        break;
  12265      default:
  12266        break;
  12267    }
  12268  }
  12269 }
  12270 
  12271 void BaseCompiler::assertStackInvariants() const {
  12272  if (deadCode_) {
  12273    // Nonlocal control flow can pass values in stack locations in a way that
  12274    // isn't accounted for by the value stack.  In dead code, which occurs
  12275    // after unconditional non-local control flow, there is no invariant to
  12276    // assert.
  12277    return;
  12278  }
  12279  size_t size = 0;
  12280  for (const Stk& v : stk_) {
  12281    switch (v.kind()) {
  12282      case Stk::MemRef:
  12283        size += BaseStackFrame::StackSizeOfPtr;
  12284        break;
  12285      case Stk::MemI32:
  12286        size += BaseStackFrame::StackSizeOfPtr;
  12287        break;
  12288      case Stk::MemI64:
  12289        size += BaseStackFrame::StackSizeOfInt64;
  12290        break;
  12291      case Stk::MemF64:
  12292        size += BaseStackFrame::StackSizeOfDouble;
  12293        break;
  12294      case Stk::MemF32:
  12295        size += BaseStackFrame::StackSizeOfFloat;
  12296        break;
  12297 #  ifdef ENABLE_WASM_SIMD
  12298      case Stk::MemV128:
  12299        size += BaseStackFrame::StackSizeOfV128;
  12300        break;
  12301 #  endif
  12302      default:
  12303        MOZ_ASSERT(!v.isMem());
  12304        break;
  12305    }
  12306  }
  12307  MOZ_ASSERT(size == fr.dynamicHeight());
  12308 }
  12309 
  12310 void BaseCompiler::showStack(const char* who) const {
  12311  fprintf(stderr, "Stack at %s {{\n", who);
  12312  size_t n = 0;
  12313  for (const Stk& elem : stk_) {
  12314    fprintf(stderr, "  [%zu] ", n++);
  12315    elem.showStackElem();
  12316    fprintf(stderr, "\n");
  12317  }
  12318  fprintf(stderr, "}}\n");
  12319 }
  12320 #endif
  12321 
  12322 //////////////////////////////////////////////////////////////////////////////
  12323 //
  12324 // Main compilation logic.
  12325 
  12326 bool BaseCompiler::emitFunction() {
  12327  AutoCreatedBy acb(masm, "(wasm)BaseCompiler::emitFunction");
  12328 
  12329  if (!beginFunction()) {
  12330    return false;
  12331  }
  12332 
  12333  if (!emitBody()) {
  12334    return false;
  12335  }
  12336 
  12337  return endFunction();
  12338 }
  12339 
  12340 BaseCompiler::BaseCompiler(const CodeMetadata& codeMeta,
  12341                           const CompilerEnvironment& compilerEnv,
  12342                           const FuncCompileInput& func,
  12343                           const ValTypeVector& locals,
  12344                           const RegisterOffsets& trapExitLayout,
  12345                           size_t trapExitLayoutNumWords, Decoder& decoder,
  12346                           StkVector& stkSource, TempAllocator* alloc,
  12347                           MacroAssembler* masm, StackMaps* stackMaps)
  12348    :  // Environment
  12349      codeMeta_(codeMeta),
  12350      compilerEnv_(compilerEnv),
  12351      func_(func),
  12352      locals_(locals),
  12353      previousBreakablePoint_(UINT32_MAX),
  12354      stkSource_(stkSource),
  12355      // Output-only data structures
  12356      alloc_(alloc->fallible()),
  12357      masm(*masm),
  12358      // Compilation state
  12359      decoder_(decoder),
  12360      iter_(codeMeta, decoder, locals),
  12361      fr(*masm),
  12362      stackMaps_(stackMaps),
  12363      stackMapGenerator_(stackMaps, trapExitLayout, trapExitLayoutNumWords,
  12364                         *masm),
  12365      deadCode_(false),
  12366      // Init value is selected to ensure proper logic in finishTryNote.
  12367      mostRecentFinishedTryNoteIndex_(0),
  12368      bceSafe_(0),
  12369      latentOp_(LatentOp::None),
  12370      latentType_(ValType::I32),
  12371      latentIntCmp_(Assembler::Equal),
  12372      latentDoubleCmp_(Assembler::DoubleEqual) {
  12373  // Our caller, BaselineCompileFunctions, will lend us the vector contents to
  12374  // use for the eval stack.  To get hold of those contents, we'll temporarily
  12375  // installing an empty one in its place.
  12376  MOZ_ASSERT(stk_.empty());
  12377  stk_.swap(stkSource_);
  12378 
  12379  // Assuming that previously processed wasm functions are well formed, the
  12380  // eval stack should now be empty.  But empty it anyway; any non-emptyness
  12381  // at this point will cause chaos.
  12382  stk_.clear();
  12383 }
  12384 
  12385 BaseCompiler::~BaseCompiler() {
  12386  stk_.swap(stkSource_);
  12387  // We've returned the eval stack vector contents to our caller,
  12388  // BaselineCompileFunctions.  We expect the vector we get in return to be
  12389  // empty since that's what we swapped for the stack vector in our
  12390  // constructor.
  12391  MOZ_ASSERT(stk_.empty());
  12392 }
  12393 
  12394 bool BaseCompiler::init() {
  12395  // We may lift this restriction in the future.
  12396  for (uint32_t memoryIndex = 0; memoryIndex < codeMeta_.memories.length();
  12397       memoryIndex++) {
  12398    MOZ_ASSERT_IF(isMem64(memoryIndex),
  12399                  !codeMeta_.hugeMemoryEnabled(memoryIndex));
  12400  }
  12401  // asm.js is not supported in baseline
  12402  MOZ_ASSERT(!codeMeta_.isAsmJS());
  12403  // Only asm.js modules have call site line numbers
  12404  MOZ_ASSERT(func_.callSiteLineNums.empty());
  12405 
  12406  ra.init(this);
  12407 
  12408  if (!SigD_.append(ValType::F64)) {
  12409    return false;
  12410  }
  12411  if (!SigF_.append(ValType::F32)) {
  12412    return false;
  12413  }
  12414 
  12415  ArgTypeVector args(funcType());
  12416  return fr.setupLocals(locals_, args, compilerEnv_.debugEnabled(),
  12417                        &localInfo_);
  12418 }
  12419 
  12420 FuncOffsets BaseCompiler::finish() {
  12421  MOZ_ASSERT(iter_.done());
  12422  MOZ_ASSERT(stk_.empty());
  12423  MOZ_ASSERT(stackMapGenerator_.memRefsOnStk == 0);
  12424 
  12425  masm.flushBuffer();
  12426 
  12427  return offsets_;
  12428 }
  12429 
  12430 }  // namespace wasm
  12431 }  // namespace js
  12432 
  12433 bool js::wasm::BaselinePlatformSupport() {
  12434 #if defined(JS_CODEGEN_ARM)
  12435  // Simplifying assumption: require SDIV and UDIV.
  12436  //
  12437  // I have no good data on ARM populations allowing me to say that
  12438  // X% of devices in the market implement SDIV and UDIV.  However,
  12439  // they are definitely implemented on the Cortex-A7 and Cortex-A15
  12440  // and on all ARMv8 systems.
  12441  if (!ARMFlags::HasIDIV()) {
  12442    return false;
  12443  }
  12444 #endif
  12445 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) ||        \
  12446    defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) ||      \
  12447    defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \
  12448    defined(JS_CODEGEN_RISCV64)
  12449  return true;
  12450 #else
  12451  return false;
  12452 #endif
  12453 }
  12454 
  12455 bool js::wasm::BaselineCompileFunctions(const CodeMetadata& codeMeta,
  12456                                        const CompilerEnvironment& compilerEnv,
  12457                                        LifoAlloc& lifo,
  12458                                        const FuncCompileInputVector& inputs,
  12459                                        CompiledCode* code,
  12460                                        UniqueChars* error) {
  12461  MOZ_ASSERT(compilerEnv.tier() == Tier::Baseline);
  12462  MOZ_ASSERT(codeMeta.kind == ModuleKind::Wasm);
  12463 
  12464  // The MacroAssembler will sometimes access the jitContext.
  12465 
  12466  TempAllocator alloc(&lifo);
  12467  JitContext jitContext;
  12468  MOZ_ASSERT(IsCompilingWasm());
  12469  WasmMacroAssembler masm(alloc);
  12470 
  12471  // Swap in already-allocated empty vectors to avoid malloc/free.
  12472  MOZ_ASSERT(code->empty());
  12473  if (!code->swap(masm)) {
  12474    return false;
  12475  }
  12476 
  12477  // Create a description of the stack layout created by GenerateTrapExit().
  12478  RegisterOffsets trapExitLayout;
  12479  size_t trapExitLayoutNumWords;
  12480  GenerateTrapExitRegisterOffsets(&trapExitLayout, &trapExitLayoutNumWords);
  12481 
  12482  // The compiler's operand stack.  We reuse it across all functions so as to
  12483  // avoid malloc/free.  Presize it to 128 elements in the hope of avoiding
  12484  // reallocation later.
  12485  StkVector stk;
  12486  if (!stk.reserve(128)) {
  12487    return false;
  12488  }
  12489 
  12490  for (const FuncCompileInput& func : inputs) {
  12491    Decoder d(func.begin, func.end, func.lineOrBytecode, error);
  12492 
  12493    // Build the local types vector.
  12494 
  12495    ValTypeVector locals;
  12496    if (!DecodeLocalEntriesWithParams(d, codeMeta, func.index, &locals)) {
  12497      return false;
  12498    }
  12499 
  12500    size_t unwindInfoBefore = masm.codeRangeUnwindInfos().length();
  12501    size_t callRefMetricsBefore = masm.callRefMetricsPatches().length();
  12502    size_t allocSitesBefore = masm.allocSitesPatches().length();
  12503 
  12504    // One-pass baseline compilation.
  12505 
  12506    BaseCompiler f(codeMeta, compilerEnv, func, locals, trapExitLayout,
  12507                   trapExitLayoutNumWords, d, stk, &alloc, &masm,
  12508                   &code->stackMaps);
  12509    if (!f.init()) {
  12510      return false;
  12511    }
  12512    if (!f.emitFunction()) {
  12513      return false;
  12514    }
  12515    FuncOffsets offsets(f.finish());
  12516    bool hasUnwindInfo =
  12517        unwindInfoBefore != masm.codeRangeUnwindInfos().length();
  12518    size_t callRefMetricsAfter = masm.callRefMetricsPatches().length();
  12519    size_t callRefMetricsLength = callRefMetricsAfter - callRefMetricsBefore;
  12520    size_t allocSitesAfter = masm.allocSitesPatches().length();
  12521    size_t allocSitesLength = allocSitesAfter - allocSitesBefore;
  12522 
  12523    // Record this function's code range
  12524    if (!code->codeRanges.emplaceBack(func.index, offsets, hasUnwindInfo)) {
  12525      return false;
  12526    }
  12527 
  12528    // Record this function's specific feature usage
  12529    if (!code->funcs.emplaceBack(
  12530            func.index, f.iter_.featureUsage(),
  12531            CallRefMetricsRange(callRefMetricsBefore, callRefMetricsLength),
  12532            AllocSitesRange(allocSitesBefore, allocSitesLength))) {
  12533      return false;
  12534    }
  12535 
  12536    if (PerfEnabled()) {
  12537      if (!code->funcBaselineSpewers.emplaceBack(func.index,
  12538                                                 std::move(f.perfSpewer_))) {
  12539        return false;
  12540      }
  12541    }
  12542 
  12543    // Accumulate observed feature usage
  12544    code->featureUsage |= f.iter_.featureUsage();
  12545  }
  12546 
  12547  masm.finish();
  12548  if (masm.oom()) {
  12549    return false;
  12550  }
  12551 
  12552  return code->swap(masm);
  12553 }