LCOV - code coverage report
Current view: top level - js/src/wasm - WasmIonCompile.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1901 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 232 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2015 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             : #include "wasm/WasmIonCompile.h"
      20             : 
      21             : #include "mozilla/MathAlgorithms.h"
      22             : 
      23             : #include "jit/CodeGenerator.h"
      24             : 
      25             : #include "wasm/WasmBaselineCompile.h"
      26             : #include "wasm/WasmBinaryIterator.h"
      27             : #include "wasm/WasmGenerator.h"
      28             : #include "wasm/WasmSignalHandlers.h"
      29             : #include "wasm/WasmValidate.h"
      30             : 
      31             : using namespace js;
      32             : using namespace js::jit;
      33             : using namespace js::wasm;
      34             : 
      35             : using mozilla::DebugOnly;
      36             : using mozilla::IsPowerOfTwo;
      37             : using mozilla::Maybe;
      38             : using mozilla::Nothing;
      39             : using mozilla::Some;
      40             : 
      41             : namespace {
      42             : 
      43             : typedef Vector<MBasicBlock*, 8, SystemAllocPolicy> BlockVector;
      44             : 
      45           0 : struct IonCompilePolicy
      46             : {
      47             :     // We store SSA definitions in the value stack.
      48             :     typedef MDefinition* Value;
      49             : 
      50             :     // We store loop headers and then/else blocks in the control flow stack.
      51             :     typedef MBasicBlock* ControlItem;
      52             : };
      53             : 
      54             : typedef OpIter<IonCompilePolicy> IonOpIter;
      55             : 
      56             : class FunctionCompiler;
      57             : 
      58             : // CallCompileState describes a call that is being compiled. Due to expression
      59             : // nesting, multiple calls can be in the middle of compilation at the same time
      60             : // and these are tracked in a stack by FunctionCompiler.
      61             : 
      62           0 : class CallCompileState
      63             : {
      64             :     // The line or bytecode of the call.
      65             :     uint32_t lineOrBytecode_;
      66             : 
      67             :     // A generator object that is passed each argument as it is compiled.
      68             :     ABIArgGenerator abi_;
      69             : 
      70             :     // The maximum number of bytes used by "child" calls, i.e., calls that occur
      71             :     // while evaluating the arguments of the call represented by this
      72             :     // CallCompileState.
      73             :     uint32_t maxChildStackBytes_;
      74             : 
      75             :     // Set by FunctionCompiler::finishCall(), tells the MWasmCall by how
      76             :     // much to bump the stack pointer before making the call. See
      77             :     // FunctionCompiler::startCall() comment below.
      78             :     uint32_t spIncrement_;
      79             : 
      80             :     // Accumulates the register arguments while compiling arguments.
      81             :     MWasmCall::Args regArgs_;
      82             : 
      83             :     // Reserved argument for passing Instance* to builtin instance method calls.
      84             :     ABIArg instanceArg_;
      85             : 
      86             :     // Accumulates the stack arguments while compiling arguments. This is only
      87             :     // necessary to track when childClobbers_ is true so that the stack offsets
      88             :     // can be updated.
      89             :     Vector<MWasmStackArg*, 0, SystemAllocPolicy> stackArgs_;
      90             : 
      91             :     // Set by child calls (i.e., calls that execute while evaluating a parent's
      92             :     // operands) to indicate that the child and parent call cannot reuse the
      93             :     // same stack space -- the parent must store its stack arguments below the
      94             :     // child's and increment sp when performing its call.
      95             :     bool childClobbers_;
      96             : 
      97             :     // Only FunctionCompiler should be directly manipulating CallCompileState.
      98             :     friend class FunctionCompiler;
      99             : 
     100             :   public:
     101           0 :     CallCompileState(FunctionCompiler& f, uint32_t lineOrBytecode)
     102           0 :       : lineOrBytecode_(lineOrBytecode),
     103             :         maxChildStackBytes_(0),
     104             :         spIncrement_(0),
     105           0 :         childClobbers_(false)
     106           0 :     { }
     107             : };
     108             : 
     109             : // Encapsulates the compilation of a single function in an asm.js module. The
     110             : // function compiler handles the creation and final backend compilation of the
     111             : // MIR graph.
     112           0 : class FunctionCompiler
     113             : {
     114             :     struct ControlFlowPatch {
     115             :         MControlInstruction* ins;
     116             :         uint32_t index;
     117           0 :         ControlFlowPatch(MControlInstruction* ins, uint32_t index)
     118           0 :           : ins(ins),
     119           0 :             index(index)
     120           0 :         {}
     121             :     };
     122             : 
     123             :     typedef Vector<ControlFlowPatch, 0, SystemAllocPolicy> ControlFlowPatchVector;
     124             :     typedef Vector<ControlFlowPatchVector, 0, SystemAllocPolicy> ControlFlowPatchsVector;
     125             :     typedef Vector<CallCompileState*, 0, SystemAllocPolicy> CallCompileStateVector;
     126             : 
     127             :     const ModuleEnvironment&   env_;
     128             :     IonOpIter                  iter_;
     129             :     const FuncBytes&           func_;
     130             :     const ValTypeVector&       locals_;
     131             :     size_t                     lastReadCallSite_;
     132             : 
     133             :     TempAllocator&             alloc_;
     134             :     MIRGraph&                  graph_;
     135             :     const CompileInfo&         info_;
     136             :     MIRGenerator&              mirGen_;
     137             : 
     138             :     MBasicBlock*               curBlock_;
     139             :     CallCompileStateVector     callStack_;
     140             :     uint32_t                   maxStackArgBytes_;
     141             : 
     142             :     uint32_t                   loopDepth_;
     143             :     uint32_t                   blockDepth_;
     144             :     ControlFlowPatchsVector    blockPatches_;
     145             : 
     146             :     // TLS pointer argument to the current function.
     147             :     MWasmParameter*            tlsPointer_;
     148             : 
     149             :   public:
     150           0 :     FunctionCompiler(const ModuleEnvironment& env,
     151             :                      Decoder& decoder,
     152             :                      const FuncBytes& func,
     153             :                      const ValTypeVector& locals,
     154             :                      MIRGenerator& mirGen)
     155           0 :       : env_(env),
     156             :         iter_(env, decoder),
     157             :         func_(func),
     158             :         locals_(locals),
     159             :         lastReadCallSite_(0),
     160           0 :         alloc_(mirGen.alloc()),
     161           0 :         graph_(mirGen.graph()),
     162           0 :         info_(mirGen.info()),
     163             :         mirGen_(mirGen),
     164             :         curBlock_(nullptr),
     165             :         maxStackArgBytes_(0),
     166             :         loopDepth_(0),
     167             :         blockDepth_(0),
     168           0 :         tlsPointer_(nullptr)
     169           0 :     {}
     170             : 
     171           0 :     const ModuleEnvironment&   env() const   { return env_; }
     172           0 :     IonOpIter&                 iter()        { return iter_; }
     173           0 :     TempAllocator&             alloc() const { return alloc_; }
     174           0 :     const Sig&                 sig() const   { return func_.sig(); }
     175             : 
     176           0 :     BytecodeOffset bytecodeOffset() const {
     177           0 :         return iter_.bytecodeOffset();
     178             :     }
     179           0 :     Maybe<BytecodeOffset> bytecodeIfNotAsmJS() const {
     180           0 :         return env_.isAsmJS() ? Nothing() : Some(iter_.bytecodeOffset());
     181             :     }
     182             : 
     183           0 :     bool init()
     184             :     {
     185             :         // Prepare the entry block for MIR generation:
     186             : 
     187           0 :         const ValTypeVector& args = func_.sig().args();
     188             : 
     189           0 :         if (!mirGen_.ensureBallast())
     190           0 :             return false;
     191           0 :         if (!newBlock(/* prev */ nullptr, &curBlock_))
     192           0 :             return false;
     193             : 
     194           0 :         for (ABIArgValTypeIter i(args); !i.done(); i++) {
     195           0 :             MWasmParameter* ins = MWasmParameter::New(alloc(), *i, i.mirType());
     196           0 :             curBlock_->add(ins);
     197           0 :             curBlock_->initSlot(info().localSlot(i.index()), ins);
     198           0 :             if (!mirGen_.ensureBallast())
     199           0 :                 return false;
     200             :         }
     201             : 
     202             :         // Set up a parameter that receives the hidden TLS pointer argument.
     203           0 :         tlsPointer_ = MWasmParameter::New(alloc(), ABIArg(WasmTlsReg), MIRType::Pointer);
     204           0 :         curBlock_->add(tlsPointer_);
     205           0 :         if (!mirGen_.ensureBallast())
     206           0 :             return false;
     207             : 
     208           0 :         for (size_t i = args.length(); i < locals_.length(); i++) {
     209           0 :             MInstruction* ins = nullptr;
     210           0 :             switch (locals_[i]) {
     211             :               case ValType::I32:
     212           0 :                 ins = MConstant::New(alloc(), Int32Value(0), MIRType::Int32);
     213           0 :                 break;
     214             :               case ValType::I64:
     215           0 :                 ins = MConstant::NewInt64(alloc(), 0);
     216           0 :                 break;
     217             :               case ValType::F32:
     218           0 :                 ins = MConstant::New(alloc(), Float32Value(0.f), MIRType::Float32);
     219           0 :                 break;
     220             :               case ValType::F64:
     221           0 :                 ins = MConstant::New(alloc(), DoubleValue(0.0), MIRType::Double);
     222           0 :                 break;
     223             :               case ValType::I8x16:
     224           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Int8x16);
     225           0 :                 break;
     226             :               case ValType::I16x8:
     227           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Int16x8);
     228           0 :                 break;
     229             :               case ValType::I32x4:
     230           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Int32x4);
     231           0 :                 break;
     232             :               case ValType::F32x4:
     233           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0.f), MIRType::Float32x4);
     234           0 :                 break;
     235             :               case ValType::B8x16:
     236             :                 // Bool8x16 uses the same data layout as Int8x16.
     237           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX16(0), MIRType::Bool8x16);
     238           0 :                 break;
     239             :               case ValType::B16x8:
     240             :                 // Bool16x8 uses the same data layout as Int16x8.
     241           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX8(0), MIRType::Bool16x8);
     242           0 :                 break;
     243             :               case ValType::B32x4:
     244             :                 // Bool32x4 uses the same data layout as Int32x4.
     245           0 :                 ins = MSimdConstant::New(alloc(), SimdConstant::SplatX4(0), MIRType::Bool32x4);
     246           0 :                 break;
     247             :             }
     248             : 
     249           0 :             curBlock_->add(ins);
     250           0 :             curBlock_->initSlot(info().localSlot(i), ins);
     251           0 :             if (!mirGen_.ensureBallast())
     252           0 :                 return false;
     253             :         }
     254             : 
     255           0 :         addInterruptCheck();
     256             : 
     257           0 :         return true;
     258             :     }
     259             : 
     260           0 :     void finish()
     261             :     {
     262           0 :         mirGen().initWasmMaxStackArgBytes(maxStackArgBytes_);
     263             : 
     264           0 :         MOZ_ASSERT(callStack_.empty());
     265           0 :         MOZ_ASSERT(loopDepth_ == 0);
     266           0 :         MOZ_ASSERT(blockDepth_ == 0);
     267             : #ifdef DEBUG
     268           0 :         for (ControlFlowPatchVector& patches : blockPatches_)
     269           0 :             MOZ_ASSERT(patches.empty());
     270             : #endif
     271           0 :         MOZ_ASSERT(inDeadCode());
     272           0 :         MOZ_ASSERT(done(), "all bytes must be consumed");
     273           0 :         MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
     274           0 :     }
     275             : 
     276             :     /************************* Read-only interface (after local scope setup) */
     277             : 
     278           0 :     MIRGenerator&       mirGen() const     { return mirGen_; }
     279           0 :     MIRGraph&           mirGraph() const   { return graph_; }
     280           0 :     const CompileInfo&  info() const       { return info_; }
     281             : 
     282           0 :     MDefinition* getLocalDef(unsigned slot)
     283             :     {
     284           0 :         if (inDeadCode())
     285           0 :             return nullptr;
     286           0 :         return curBlock_->getSlot(info().localSlot(slot));
     287             :     }
     288             : 
     289           0 :     const ValTypeVector& locals() const { return locals_; }
     290             : 
     291             :     /***************************** Code generation (after local scope setup) */
     292             : 
     293           0 :     MDefinition* constant(const SimdConstant& v, MIRType type)
     294             :     {
     295           0 :         if (inDeadCode())
     296           0 :             return nullptr;
     297             :         MInstruction* constant;
     298           0 :         constant = MSimdConstant::New(alloc(), v, type);
     299           0 :         curBlock_->add(constant);
     300           0 :         return constant;
     301             :     }
     302             : 
     303           0 :     MDefinition* constant(const Value& v, MIRType type)
     304             :     {
     305           0 :         if (inDeadCode())
     306           0 :             return nullptr;
     307           0 :         MConstant* constant = MConstant::New(alloc(), v, type);
     308           0 :         curBlock_->add(constant);
     309           0 :         return constant;
     310             :     }
     311             : 
     312           0 :     MDefinition* constant(float f)
     313             :     {
     314           0 :         if (inDeadCode())
     315           0 :             return nullptr;
     316           0 :         auto* cst = MWasmFloatConstant::NewFloat32(alloc(), f);
     317           0 :         curBlock_->add(cst);
     318           0 :         return cst;
     319             :     }
     320             : 
     321           0 :     MDefinition* constant(double d)
     322             :     {
     323           0 :         if (inDeadCode())
     324           0 :             return nullptr;
     325           0 :         auto* cst = MWasmFloatConstant::NewDouble(alloc(), d);
     326           0 :         curBlock_->add(cst);
     327           0 :         return cst;
     328             :     }
     329             : 
     330           0 :     MDefinition* constant(int64_t i)
     331             :     {
     332           0 :         if (inDeadCode())
     333           0 :             return nullptr;
     334           0 :         MConstant* constant = MConstant::NewInt64(alloc(), i);
     335           0 :         curBlock_->add(constant);
     336           0 :         return constant;
     337             :     }
     338             : 
     339             :     template <class T>
     340           0 :     MDefinition* unary(MDefinition* op)
     341             :     {
     342           0 :         if (inDeadCode())
     343           0 :             return nullptr;
     344           0 :         T* ins = T::New(alloc(), op);
     345           0 :         curBlock_->add(ins);
     346           0 :         return ins;
     347             :     }
     348             : 
     349             :     template <class T>
     350           0 :     MDefinition* unary(MDefinition* op, MIRType type)
     351             :     {
     352           0 :         if (inDeadCode())
     353           0 :             return nullptr;
     354           0 :         T* ins = T::New(alloc(), op, type);
     355           0 :         curBlock_->add(ins);
     356           0 :         return ins;
     357             :     }
     358             : 
     359             :     template <class T>
     360             :     MDefinition* binary(MDefinition* lhs, MDefinition* rhs)
     361             :     {
     362             :         if (inDeadCode())
     363             :             return nullptr;
     364             :         T* ins = T::New(alloc(), lhs, rhs);
     365             :         curBlock_->add(ins);
     366             :         return ins;
     367             :     }
     368             : 
     369             :     template <class T>
     370           0 :     MDefinition* binary(MDefinition* lhs, MDefinition* rhs, MIRType type)
     371             :     {
     372           0 :         if (inDeadCode())
     373           0 :             return nullptr;
     374           0 :         T* ins = T::New(alloc(), lhs, rhs, type);
     375           0 :         curBlock_->add(ins);
     376           0 :         return ins;
     377             :     }
     378             : 
     379           0 :     bool mustPreserveNaN(MIRType type)
     380             :     {
     381           0 :         return IsFloatingPointType(type) && !env().isAsmJS();
     382             :     }
     383             : 
     384           0 :     MDefinition* sub(MDefinition* lhs, MDefinition* rhs, MIRType type)
     385             :     {
     386           0 :         if (inDeadCode())
     387           0 :             return nullptr;
     388             : 
     389             :         // wasm can't fold x - 0.0 because of NaN with custom payloads.
     390           0 :         MSub* ins = MSub::New(alloc(), lhs, rhs, type, mustPreserveNaN(type));
     391           0 :         curBlock_->add(ins);
     392           0 :         return ins;
     393             :     }
     394             : 
     395           0 :     MDefinition* nearbyInt(MDefinition* input, RoundingMode roundingMode)
     396             :     {
     397           0 :         if (inDeadCode())
     398           0 :             return nullptr;
     399             : 
     400           0 :         auto* ins = MNearbyInt::New(alloc(), input, input->type(), roundingMode);
     401           0 :         curBlock_->add(ins);
     402           0 :         return ins;
     403             :     }
     404             : 
     405           0 :     MDefinition* unarySimd(MDefinition* input, MSimdUnaryArith::Operation op, MIRType type)
     406             :     {
     407           0 :         if (inDeadCode())
     408           0 :             return nullptr;
     409             : 
     410           0 :         MOZ_ASSERT(IsSimdType(input->type()) && input->type() == type);
     411           0 :         MInstruction* ins = MSimdUnaryArith::New(alloc(), input, op);
     412           0 :         curBlock_->add(ins);
     413           0 :         return ins;
     414             :     }
     415             : 
     416           0 :     MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryArith::Operation op,
     417             :                             MIRType type)
     418             :     {
     419           0 :         if (inDeadCode())
     420           0 :             return nullptr;
     421             : 
     422           0 :         MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
     423           0 :         MOZ_ASSERT(lhs->type() == type);
     424           0 :         return MSimdBinaryArith::AddLegalized(alloc(), curBlock_, lhs, rhs, op);
     425             :     }
     426             : 
     427           0 :     MDefinition* binarySimd(MDefinition* lhs, MDefinition* rhs, MSimdBinaryBitwise::Operation op,
     428             :                             MIRType type)
     429             :     {
     430           0 :         if (inDeadCode())
     431           0 :             return nullptr;
     432             : 
     433           0 :         MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
     434           0 :         MOZ_ASSERT(lhs->type() == type);
     435           0 :         auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op);
     436           0 :         curBlock_->add(ins);
     437           0 :         return ins;
     438             :     }
     439             : 
     440           0 :     MDefinition* binarySimdComp(MDefinition* lhs, MDefinition* rhs, MSimdBinaryComp::Operation op,
     441             :                                 SimdSign sign)
     442             :     {
     443           0 :         if (inDeadCode())
     444           0 :             return nullptr;
     445             : 
     446           0 :         return MSimdBinaryComp::AddLegalized(alloc(), curBlock_, lhs, rhs, op, sign);
     447             :     }
     448             : 
     449           0 :     MDefinition* binarySimdSaturating(MDefinition* lhs, MDefinition* rhs,
     450             :                                       MSimdBinarySaturating::Operation op, SimdSign sign)
     451             :     {
     452           0 :         if (inDeadCode())
     453           0 :             return nullptr;
     454             : 
     455           0 :         auto* ins = MSimdBinarySaturating::New(alloc(), lhs, rhs, op, sign);
     456           0 :         curBlock_->add(ins);
     457           0 :         return ins;
     458             :     }
     459             : 
     460           0 :     MDefinition* binarySimdShift(MDefinition* lhs, MDefinition* rhs, MSimdShift::Operation op)
     461             :     {
     462           0 :         if (inDeadCode())
     463           0 :             return nullptr;
     464             : 
     465           0 :         return MSimdShift::AddLegalized(alloc(), curBlock_, lhs, rhs, op);
     466             :     }
     467             : 
     468           0 :     MDefinition* swizzleSimd(MDefinition* vector, const uint8_t lanes[], MIRType type)
     469             :     {
     470           0 :         if (inDeadCode())
     471           0 :             return nullptr;
     472             : 
     473           0 :         MOZ_ASSERT(vector->type() == type);
     474           0 :         MSimdSwizzle* ins = MSimdSwizzle::New(alloc(), vector, lanes);
     475           0 :         curBlock_->add(ins);
     476           0 :         return ins;
     477             :     }
     478             : 
     479           0 :     MDefinition* shuffleSimd(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[],
     480             :                              MIRType type)
     481             :     {
     482           0 :         if (inDeadCode())
     483           0 :             return nullptr;
     484             : 
     485           0 :         MOZ_ASSERT(lhs->type() == type);
     486           0 :         MInstruction* ins = MSimdShuffle::New(alloc(), lhs, rhs, lanes);
     487           0 :         curBlock_->add(ins);
     488           0 :         return ins;
     489             :     }
     490             : 
     491           0 :     MDefinition* insertElementSimd(MDefinition* vec, MDefinition* val, unsigned lane, MIRType type)
     492             :     {
     493           0 :         if (inDeadCode())
     494           0 :             return nullptr;
     495             : 
     496           0 :         MOZ_ASSERT(IsSimdType(vec->type()) && vec->type() == type);
     497           0 :         MOZ_ASSERT(SimdTypeToLaneArgumentType(vec->type()) == val->type());
     498           0 :         MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), vec, val, lane);
     499           0 :         curBlock_->add(ins);
     500           0 :         return ins;
     501             :     }
     502             : 
     503           0 :     MDefinition* selectSimd(MDefinition* mask, MDefinition* lhs, MDefinition* rhs, MIRType type)
     504             :     {
     505           0 :         if (inDeadCode())
     506           0 :             return nullptr;
     507             : 
     508           0 :         MOZ_ASSERT(IsSimdType(mask->type()));
     509           0 :         MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
     510           0 :         MOZ_ASSERT(lhs->type() == type);
     511           0 :         MSimdSelect* ins = MSimdSelect::New(alloc(), mask, lhs, rhs);
     512           0 :         curBlock_->add(ins);
     513           0 :         return ins;
     514             :     }
     515             : 
     516           0 :     MDefinition* simdAllTrue(MDefinition* boolVector)
     517             :     {
     518           0 :         if (inDeadCode())
     519           0 :             return nullptr;
     520             : 
     521           0 :         MSimdAllTrue* ins = MSimdAllTrue::New(alloc(), boolVector, MIRType::Int32);
     522           0 :         curBlock_->add(ins);
     523           0 :         return ins;
     524             :     }
     525             : 
     526           0 :     MDefinition* simdAnyTrue(MDefinition* boolVector)
     527             :     {
     528           0 :         if (inDeadCode())
     529           0 :             return nullptr;
     530             : 
     531           0 :         MSimdAnyTrue* ins = MSimdAnyTrue::New(alloc(), boolVector, MIRType::Int32);
     532           0 :         curBlock_->add(ins);
     533           0 :         return ins;
     534             :     }
     535             : 
     536             :     // fromXXXBits()
     537           0 :     MDefinition* bitcastSimd(MDefinition* vec, MIRType from, MIRType to)
     538             :     {
     539           0 :         if (inDeadCode())
     540           0 :             return nullptr;
     541             : 
     542           0 :         MOZ_ASSERT(vec->type() == from);
     543           0 :         MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
     544           0 :         auto* ins = MSimdReinterpretCast::New(alloc(), vec, to);
     545           0 :         curBlock_->add(ins);
     546           0 :         return ins;
     547             :     }
     548             : 
     549             :     // Int <--> Float conversions.
     550           0 :     MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to, SimdSign sign)
     551             :     {
     552           0 :         if (inDeadCode())
     553           0 :             return nullptr;
     554             : 
     555           0 :         MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
     556           0 :         return MSimdConvert::AddLegalized(alloc(), curBlock_, vec, to, sign, bytecodeOffset());
     557             :     }
     558             : 
     559           0 :     MDefinition* splatSimd(MDefinition* v, MIRType type)
     560             :     {
     561           0 :         if (inDeadCode())
     562           0 :             return nullptr;
     563             : 
     564           0 :         MOZ_ASSERT(IsSimdType(type));
     565           0 :         MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type());
     566           0 :         MSimdSplat* ins = MSimdSplat::New(alloc(), v, type);
     567           0 :         curBlock_->add(ins);
     568           0 :         return ins;
     569             :     }
     570             : 
     571           0 :     MDefinition* minMax(MDefinition* lhs, MDefinition* rhs, MIRType type, bool isMax) {
     572           0 :         if (inDeadCode())
     573           0 :             return nullptr;
     574             : 
     575           0 :         if (mustPreserveNaN(type)) {
     576             :             // Convert signaling NaN to quiet NaNs.
     577           0 :             MDefinition* zero = constant(DoubleValue(0.0), type);
     578           0 :             lhs = sub(lhs, zero, type);
     579           0 :             rhs = sub(rhs, zero, type);
     580             :         }
     581             : 
     582           0 :         MMinMax* ins = MMinMax::NewWasm(alloc(), lhs, rhs, type, isMax);
     583           0 :         curBlock_->add(ins);
     584           0 :         return ins;
     585             :     }
     586             : 
     587           0 :     MDefinition* mul(MDefinition* lhs, MDefinition* rhs, MIRType type, MMul::Mode mode)
     588             :     {
     589           0 :         if (inDeadCode())
     590           0 :             return nullptr;
     591             : 
     592             :         // wasm can't fold x * 1.0 because of NaN with custom payloads.
     593           0 :         auto* ins = MMul::NewWasm(alloc(), lhs, rhs, type, mode, mustPreserveNaN(type));
     594           0 :         curBlock_->add(ins);
     595           0 :         return ins;
     596             :     }
     597             : 
     598           0 :     MDefinition* div(MDefinition* lhs, MDefinition* rhs, MIRType type, bool unsignd)
     599             :     {
     600           0 :         if (inDeadCode())
     601           0 :             return nullptr;
     602           0 :         bool trapOnError = !env().isAsmJS();
     603           0 :         if (!unsignd && type == MIRType::Int32) {
     604             :             // Enforce the signedness of the operation by coercing the operands
     605             :             // to signed.  Otherwise, operands that "look" unsigned to Ion but
     606             :             // are not unsigned to Baldr (eg, unsigned right shifts) may lead to
     607             :             // the operation being executed unsigned.  Applies to mod() as well.
     608             :             //
     609             :             // Do this for Int32 only since Int64 is not subject to the same
     610             :             // issues.
     611             :             //
     612             :             // Note the offsets passed to MTruncateToInt32 are wrong here, but
     613             :             // it doesn't matter: they're not codegen'd to calls since inputs
     614             :             // already are int32.
     615           0 :             auto* lhs2 = MTruncateToInt32::New(alloc(), lhs);
     616           0 :             curBlock_->add(lhs2);
     617           0 :             lhs = lhs2;
     618           0 :             auto* rhs2 = MTruncateToInt32::New(alloc(), rhs);
     619           0 :             curBlock_->add(rhs2);
     620           0 :             rhs = rhs2;
     621             :         }
     622           0 :         auto* ins = MDiv::New(alloc(), lhs, rhs, type, unsignd, trapOnError, bytecodeOffset(),
     623           0 :                               mustPreserveNaN(type));
     624           0 :         curBlock_->add(ins);
     625           0 :         return ins;
     626             :     }
     627             : 
     628           0 :     MDefinition* mod(MDefinition* lhs, MDefinition* rhs, MIRType type, bool unsignd)
     629             :     {
     630           0 :         if (inDeadCode())
     631           0 :             return nullptr;
     632           0 :         bool trapOnError = !env().isAsmJS();
     633           0 :         if (!unsignd && type == MIRType::Int32) {
     634             :             // See block comment in div().
     635           0 :             auto* lhs2 = MTruncateToInt32::New(alloc(), lhs);
     636           0 :             curBlock_->add(lhs2);
     637           0 :             lhs = lhs2;
     638           0 :             auto* rhs2 = MTruncateToInt32::New(alloc(), rhs);
     639           0 :             curBlock_->add(rhs2);
     640           0 :             rhs = rhs2;
     641             :         }
     642           0 :         auto* ins = MMod::New(alloc(), lhs, rhs, type, unsignd, trapOnError, bytecodeOffset());
     643           0 :         curBlock_->add(ins);
     644           0 :         return ins;
     645             :     }
     646             : 
     647           0 :     MDefinition* bitnot(MDefinition* op)
     648             :     {
     649           0 :         if (inDeadCode())
     650           0 :             return nullptr;
     651           0 :         auto* ins = MBitNot::NewInt32(alloc(), op);
     652           0 :         curBlock_->add(ins);
     653           0 :         return ins;
     654             :     }
     655             : 
     656           0 :     MDefinition* select(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition* condExpr)
     657             :     {
     658           0 :         if (inDeadCode())
     659           0 :             return nullptr;
     660           0 :         auto* ins = MWasmSelect::New(alloc(), trueExpr, falseExpr, condExpr);
     661           0 :         curBlock_->add(ins);
     662           0 :         return ins;
     663             :     }
     664             : 
     665           0 :     MDefinition* extendI32(MDefinition* op, bool isUnsigned)
     666             :     {
     667           0 :         if (inDeadCode())
     668           0 :             return nullptr;
     669           0 :         auto* ins = MExtendInt32ToInt64::New(alloc(), op, isUnsigned);
     670           0 :         curBlock_->add(ins);
     671           0 :         return ins;
     672             :     }
     673             : 
     674           0 :     MDefinition* convertI64ToFloatingPoint(MDefinition* op, MIRType type, bool isUnsigned)
     675             :     {
     676           0 :         if (inDeadCode())
     677           0 :             return nullptr;
     678           0 :         auto* ins = MInt64ToFloatingPoint::New(alloc(), op, type, bytecodeOffset(), isUnsigned);
     679           0 :         curBlock_->add(ins);
     680           0 :         return ins;
     681             :     }
     682             : 
     683           0 :     MDefinition* rotate(MDefinition* input, MDefinition* count, MIRType type, bool left)
     684             :     {
     685           0 :         if (inDeadCode())
     686           0 :             return nullptr;
     687           0 :         auto* ins = MRotate::New(alloc(), input, count, type, left);
     688           0 :         curBlock_->add(ins);
     689           0 :         return ins;
     690             :     }
     691             : 
     692             :     template <class T>
     693           0 :     MDefinition* truncate(MDefinition* op, bool isUnsigned)
     694             :     {
     695           0 :         if (inDeadCode())
     696           0 :             return nullptr;
     697           0 :         auto* ins = T::New(alloc(), op, isUnsigned, bytecodeOffset());
     698           0 :         curBlock_->add(ins);
     699           0 :         return ins;
     700             :     }
     701             : 
     702           0 :     MDefinition* compare(MDefinition* lhs, MDefinition* rhs, JSOp op, MCompare::CompareType type)
     703             :     {
     704           0 :         if (inDeadCode())
     705           0 :             return nullptr;
     706           0 :         auto* ins = MCompare::New(alloc(), lhs, rhs, op, type);
     707           0 :         curBlock_->add(ins);
     708           0 :         return ins;
     709             :     }
     710             : 
     711           0 :     void assign(unsigned slot, MDefinition* def)
     712             :     {
     713           0 :         if (inDeadCode())
     714           0 :             return;
     715           0 :         curBlock_->setSlot(info().localSlot(slot), def);
     716             :     }
     717             : 
     718             :   private:
     719           0 :     MWasmLoadTls* maybeLoadMemoryBase() {
     720           0 :         MWasmLoadTls* load = nullptr;
     721             : #ifdef JS_CODEGEN_X86
     722             :         AliasSet aliases = env_.maxMemoryLength.isSome() ? AliasSet::None()
     723             :                                                          : AliasSet::Load(AliasSet::WasmHeapMeta);
     724             :         load = MWasmLoadTls::New(alloc(), tlsPointer_, offsetof(wasm::TlsData, memoryBase),
     725             :                                  MIRType::Pointer, aliases);
     726             :         curBlock_->add(load);
     727             : #endif
     728           0 :         return load;
     729             :     }
     730             : 
     731           0 :     MWasmLoadTls* maybeLoadBoundsCheckLimit() {
     732           0 :         MWasmLoadTls* load = nullptr;
     733             : #ifndef WASM_HUGE_MEMORY
     734             :         AliasSet aliases = env_.maxMemoryLength.isSome() ? AliasSet::None()
     735             :                                                          : AliasSet::Load(AliasSet::WasmHeapMeta);
     736             :         load = MWasmLoadTls::New(alloc(), tlsPointer_, offsetof(wasm::TlsData, boundsCheckLimit),
     737             :                                  MIRType::Int32, aliases);
     738             :         curBlock_->add(load);
     739             : #endif
     740           0 :         return load;
     741             :     }
     742             : 
     743           0 :     void checkOffsetAndBounds(MemoryAccessDesc* access, MDefinition** base)
     744             :     {
     745             :         // If the offset is bigger than the guard region, a separate instruction
     746             :         // is necessary to add the offset to the base and check for overflow.
     747           0 :         if (access->offset() >= OffsetGuardLimit || !JitOptions.wasmFoldOffsets) {
     748           0 :             auto* ins = MWasmAddOffset::New(alloc(), *base, access->offset(), bytecodeOffset());
     749           0 :             curBlock_->add(ins);
     750             : 
     751           0 :             *base = ins;
     752           0 :             access->clearOffset();
     753             :         }
     754             : 
     755           0 :         MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
     756           0 :         if (boundsCheckLimit)
     757           0 :             curBlock_->add(MWasmBoundsCheck::New(alloc(), *base, boundsCheckLimit, bytecodeOffset()));
     758           0 :     }
     759             : 
     760             :   public:
     761           0 :     MDefinition* load(MDefinition* base, MemoryAccessDesc* access, ValType result)
     762             :     {
     763           0 :         if (inDeadCode())
     764           0 :             return nullptr;
     765             : 
     766           0 :         MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
     767           0 :         MInstruction* load = nullptr;
     768           0 :         if (access->isPlainAsmJS()) {
     769           0 :             MOZ_ASSERT(access->offset() == 0);
     770           0 :             MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
     771           0 :             load = MAsmJSLoadHeap::New(alloc(), memoryBase, base, boundsCheckLimit, access->type());
     772             :         } else {
     773           0 :             checkOffsetAndBounds(access, &base);
     774           0 :             load = MWasmLoad::New(alloc(), memoryBase, base, *access, ToMIRType(result));
     775             :         }
     776             : 
     777           0 :         if (load)
     778           0 :             curBlock_->add(load);
     779             : 
     780           0 :         return load;
     781             :     }
     782             : 
     783           0 :     MOZ_MUST_USE bool store(MDefinition* base, MemoryAccessDesc* access, MDefinition* v)
     784             :     {
     785           0 :         if (inDeadCode())
     786           0 :             return true;
     787             : 
     788           0 :         MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
     789           0 :         MInstruction* store = nullptr;
     790           0 :         if (access->isPlainAsmJS()) {
     791           0 :             MOZ_ASSERT(access->offset() == 0);
     792           0 :             MWasmLoadTls* boundsCheckLimit = maybeLoadBoundsCheckLimit();
     793           0 :             store = MAsmJSStoreHeap::New(alloc(), memoryBase, base, boundsCheckLimit,
     794           0 :                                          access->type(), v);
     795             :         } else {
     796           0 :             checkOffsetAndBounds(access, &base);
     797           0 :             store = MWasmStore::New(alloc(), memoryBase, base, *access, v);
     798             :         }
     799             : 
     800           0 :         if (store)
     801           0 :             curBlock_->add(store);
     802             : 
     803           0 :         return !!store;
     804             :     }
     805             : 
     806           0 :     MDefinition* atomicCompareExchangeHeap(MDefinition* base, MemoryAccessDesc* access,
     807             :                                            MDefinition* oldv, MDefinition* newv)
     808             :     {
     809           0 :         if (inDeadCode())
     810           0 :             return nullptr;
     811             : 
     812           0 :         checkOffsetAndBounds(access, &base);
     813           0 :         MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
     814           0 :         auto* cas = MAsmJSCompareExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase, base,
     815           0 :                                                    *access, oldv, newv, tlsPointer_);
     816           0 :         if (cas)
     817           0 :             curBlock_->add(cas);
     818           0 :         return cas;
     819             :     }
     820             : 
     821           0 :     MDefinition* atomicExchangeHeap(MDefinition* base, MemoryAccessDesc* access,
     822             :                                     MDefinition* value)
     823             :     {
     824           0 :         if (inDeadCode())
     825           0 :             return nullptr;
     826             : 
     827           0 :         checkOffsetAndBounds(access, &base);
     828           0 :         MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
     829           0 :         auto* cas = MAsmJSAtomicExchangeHeap::New(alloc(), bytecodeOffset(), memoryBase, base,
     830           0 :                                                   *access, value, tlsPointer_);
     831           0 :         if (cas)
     832           0 :             curBlock_->add(cas);
     833           0 :         return cas;
     834             :     }
     835             : 
     836           0 :     MDefinition* atomicBinopHeap(js::jit::AtomicOp op,
     837             :                                  MDefinition* base, MemoryAccessDesc* access, MDefinition* v)
     838             :     {
     839           0 :         if (inDeadCode())
     840           0 :             return nullptr;
     841             : 
     842           0 :         checkOffsetAndBounds(access, &base);
     843           0 :         MWasmLoadTls* memoryBase = maybeLoadMemoryBase();
     844           0 :         auto* binop = MAsmJSAtomicBinopHeap::New(alloc(), bytecodeOffset(), op, memoryBase, base,
     845           0 :                                                  *access, v, tlsPointer_);
     846           0 :         if (binop)
     847           0 :             curBlock_->add(binop);
     848           0 :         return binop;
     849             :     }
     850             : 
     851           0 :     MDefinition* loadGlobalVar(unsigned globalDataOffset, bool isConst, MIRType type)
     852             :     {
     853           0 :         if (inDeadCode())
     854           0 :             return nullptr;
     855             : 
     856           0 :         auto* load = MWasmLoadGlobalVar::New(alloc(), type, globalDataOffset, isConst, tlsPointer_);
     857           0 :         curBlock_->add(load);
     858           0 :         return load;
     859             :     }
     860             : 
     861           0 :     void storeGlobalVar(uint32_t globalDataOffset, MDefinition* v)
     862             :     {
     863           0 :         if (inDeadCode())
     864           0 :             return;
     865           0 :         curBlock_->add(MWasmStoreGlobalVar::New(alloc(), globalDataOffset, v, tlsPointer_));
     866             :     }
     867             : 
     868           0 :     void addInterruptCheck()
     869             :     {
     870             :         // We rely on signal handlers for interrupts on Asm.JS/Wasm
     871           0 :         MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
     872           0 :     }
     873             : 
     874           0 :     MDefinition* extractSimdElement(unsigned lane, MDefinition* base, MIRType type, SimdSign sign)
     875             :     {
     876           0 :         if (inDeadCode())
     877           0 :             return nullptr;
     878             : 
     879           0 :         MOZ_ASSERT(IsSimdType(base->type()));
     880           0 :         MOZ_ASSERT(!IsSimdType(type));
     881           0 :         auto* ins = MSimdExtractElement::New(alloc(), base, type, lane, sign);
     882           0 :         curBlock_->add(ins);
     883           0 :         return ins;
     884             :     }
     885             : 
     886             :     template<typename T>
     887           0 :     MDefinition* constructSimd(MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w,
     888             :                                MIRType type)
     889             :     {
     890           0 :         if (inDeadCode())
     891           0 :             return nullptr;
     892             : 
     893           0 :         MOZ_ASSERT(IsSimdType(type));
     894           0 :         T* ins = T::New(alloc(), type, x, y, z, w);
     895           0 :         curBlock_->add(ins);
     896           0 :         return ins;
     897             :     }
     898             : 
     899             :     /***************************************************************** Calls */
     900             : 
     901             :     // The IonMonkey backend maintains a single stack offset (from the stack
     902             :     // pointer to the base of the frame) by adding the total amount of spill
     903             :     // space required plus the maximum stack required for argument passing.
     904             :     // Since we do not use IonMonkey's MPrepareCall/MPassArg/MCall, we must
     905             :     // manually accumulate, for the entire function, the maximum required stack
     906             :     // space for argument passing. (This is passed to the CodeGenerator via
     907             :     // MIRGenerator::maxWasmStackArgBytes.) Naively, this would just be the
     908             :     // maximum of the stack space required for each individual call (as
     909             :     // determined by the call ABI). However, as an optimization, arguments are
     910             :     // stored to the stack immediately after evaluation (to decrease live
     911             :     // ranges and reduce spilling). This introduces the complexity that,
     912             :     // between evaluating an argument and making the call, another argument
     913             :     // evaluation could perform a call that also needs to store to the stack.
     914             :     // When this occurs childClobbers_ = true and the parent expression's
     915             :     // arguments are stored above the maximum depth clobbered by a child
     916             :     // expression.
     917             : 
     918           0 :     bool startCall(CallCompileState* call)
     919             :     {
     920             :         // Always push calls to maintain the invariant that if we're inDeadCode
     921             :         // in finishCall, we have something to pop.
     922           0 :         return callStack_.append(call);
     923             :     }
     924             : 
     925           0 :     bool passInstance(CallCompileState* args)
     926             :     {
     927           0 :         if (inDeadCode())
     928           0 :             return true;
     929             : 
     930             :         // Should only pass an instance once.
     931           0 :         MOZ_ASSERT(args->instanceArg_ == ABIArg());
     932           0 :         args->instanceArg_ = args->abi_.next(MIRType::Pointer);
     933           0 :         return true;
     934             :     }
     935             : 
     936           0 :     bool passArg(MDefinition* argDef, ValType type, CallCompileState* call)
     937             :     {
     938           0 :         if (inDeadCode())
     939           0 :             return true;
     940             : 
     941           0 :         ABIArg arg = call->abi_.next(ToMIRType(type));
     942           0 :         switch (arg.kind()) {
     943             : #ifdef JS_CODEGEN_REGISTER_PAIR
     944             :           case ABIArg::GPR_PAIR: {
     945             :             auto mirLow = MWrapInt64ToInt32::New(alloc(), argDef, /* bottomHalf = */ true);
     946             :             curBlock_->add(mirLow);
     947             :             auto mirHigh = MWrapInt64ToInt32::New(alloc(), argDef, /* bottomHalf = */ false);
     948             :             curBlock_->add(mirHigh);
     949             :             return call->regArgs_.append(MWasmCall::Arg(AnyRegister(arg.gpr64().low), mirLow)) &&
     950             :                    call->regArgs_.append(MWasmCall::Arg(AnyRegister(arg.gpr64().high), mirHigh));
     951             :           }
     952             : #endif
     953             :           case ABIArg::GPR:
     954             :           case ABIArg::FPU:
     955           0 :             return call->regArgs_.append(MWasmCall::Arg(arg.reg(), argDef));
     956             :           case ABIArg::Stack: {
     957           0 :             auto* mir = MWasmStackArg::New(alloc(), arg.offsetFromArgBase(), argDef);
     958           0 :             curBlock_->add(mir);
     959           0 :             return call->stackArgs_.append(mir);
     960             :           }
     961             :           default:
     962           0 :             MOZ_CRASH("Unknown ABIArg kind.");
     963             :         }
     964             :     }
     965             : 
     966           0 :     void propagateMaxStackArgBytes(uint32_t stackBytes)
     967             :     {
     968           0 :         if (callStack_.empty()) {
     969             :             // Outermost call
     970           0 :             maxStackArgBytes_ = Max(maxStackArgBytes_, stackBytes);
     971           0 :             return;
     972             :         }
     973             : 
     974             :         // Non-outermost call
     975           0 :         CallCompileState* outer = callStack_.back();
     976           0 :         outer->maxChildStackBytes_ = Max(outer->maxChildStackBytes_, stackBytes);
     977           0 :         if (stackBytes && !outer->stackArgs_.empty())
     978           0 :             outer->childClobbers_ = true;
     979             :     }
     980             : 
     981           0 :     bool finishCall(CallCompileState* call)
     982             :     {
     983           0 :         MOZ_ALWAYS_TRUE(callStack_.popCopy() == call);
     984             : 
     985           0 :         if (inDeadCode()) {
     986           0 :             propagateMaxStackArgBytes(call->maxChildStackBytes_);
     987           0 :             return true;
     988             :         }
     989             : 
     990           0 :         if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_)))
     991           0 :             return false;
     992             : 
     993           0 :         uint32_t stackBytes = call->abi_.stackBytesConsumedSoFar();
     994           0 :         if (call->childClobbers_) {
     995           0 :             call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, WasmStackAlignment);
     996           0 :             for (MWasmStackArg* stackArg : call->stackArgs_)
     997           0 :                 stackArg->incrementOffset(call->spIncrement_);
     998             : 
     999             :             // If instanceArg_ is not initialized then instanceArg_.kind() != ABIArg::Stack
    1000           0 :             if (call->instanceArg_.kind() == ABIArg::Stack) {
    1001           0 :                 call->instanceArg_ = ABIArg(call->instanceArg_.offsetFromArgBase() +
    1002           0 :                                             call->spIncrement_);
    1003             :             }
    1004             : 
    1005           0 :             stackBytes += call->spIncrement_;
    1006             :         } else {
    1007           0 :             call->spIncrement_ = 0;
    1008           0 :             stackBytes = Max(stackBytes, call->maxChildStackBytes_);
    1009             :         }
    1010             : 
    1011           0 :         propagateMaxStackArgBytes(stackBytes);
    1012           0 :         return true;
    1013             :     }
    1014             : 
    1015           0 :     bool callDirect(const Sig& sig, uint32_t funcIndex, const CallCompileState& call,
    1016             :                     MDefinition** def)
    1017             :     {
    1018           0 :         if (inDeadCode()) {
    1019           0 :             *def = nullptr;
    1020           0 :             return true;
    1021             :         }
    1022             : 
    1023           0 :         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Func);
    1024           0 :         MIRType ret = ToMIRType(sig.ret());
    1025           0 :         auto callee = CalleeDesc::function(funcIndex);
    1026           0 :         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, call.spIncrement_);
    1027           0 :         if (!ins)
    1028           0 :             return false;
    1029             : 
    1030           0 :         curBlock_->add(ins);
    1031           0 :         *def = ins;
    1032           0 :         return true;
    1033             :     }
    1034             : 
    1035           0 :     bool callIndirect(uint32_t sigIndex, MDefinition* index, const CallCompileState& call,
    1036             :                       MDefinition** def)
    1037             :     {
    1038           0 :         if (inDeadCode()) {
    1039           0 :             *def = nullptr;
    1040           0 :             return true;
    1041             :         }
    1042             : 
    1043           0 :         const SigWithId& sig = env_.sigs[sigIndex];
    1044             : 
    1045           0 :         CalleeDesc callee;
    1046           0 :         if (env_.isAsmJS()) {
    1047           0 :             MOZ_ASSERT(sig.id.kind() == SigIdDesc::Kind::None);
    1048           0 :             const TableDesc& table = env_.tables[env_.asmJSSigToTableIndex[sigIndex]];
    1049           0 :             MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
    1050           0 :             MOZ_ASSERT(!table.external);
    1051             : 
    1052           0 :             MConstant* mask = MConstant::New(alloc(), Int32Value(table.limits.initial - 1));
    1053           0 :             curBlock_->add(mask);
    1054           0 :             MBitAnd* maskedIndex = MBitAnd::New(alloc(), index, mask, MIRType::Int32);
    1055           0 :             curBlock_->add(maskedIndex);
    1056             : 
    1057           0 :             index = maskedIndex;
    1058           0 :             callee = CalleeDesc::asmJSTable(table);
    1059             :         } else {
    1060           0 :             MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
    1061           0 :             MOZ_ASSERT(env_.tables.length() == 1);
    1062           0 :             const TableDesc& table = env_.tables[0];
    1063           0 :             callee = CalleeDesc::wasmTable(table, sig.id);
    1064             :         }
    1065             : 
    1066           0 :         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
    1067           0 :         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(sig.ret()),
    1068           0 :                                    call.spIncrement_, index);
    1069           0 :         if (!ins)
    1070           0 :             return false;
    1071             : 
    1072           0 :         curBlock_->add(ins);
    1073           0 :         *def = ins;
    1074           0 :         return true;
    1075             :     }
    1076             : 
    1077           0 :     bool callImport(unsigned globalDataOffset, const CallCompileState& call, ExprType ret,
    1078             :                     MDefinition** def)
    1079             :     {
    1080           0 :         if (inDeadCode()) {
    1081           0 :             *def = nullptr;
    1082           0 :             return true;
    1083             :         }
    1084             : 
    1085           0 :         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
    1086           0 :         auto callee = CalleeDesc::import(globalDataOffset);
    1087           0 :         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
    1088           0 :                                    call.spIncrement_);
    1089           0 :         if (!ins)
    1090           0 :             return false;
    1091             : 
    1092           0 :         curBlock_->add(ins);
    1093           0 :         *def = ins;
    1094           0 :         return true;
    1095             :     }
    1096             : 
    1097           0 :     bool builtinCall(SymbolicAddress builtin, const CallCompileState& call, ValType ret,
    1098             :                      MDefinition** def)
    1099             :     {
    1100           0 :         if (inDeadCode()) {
    1101           0 :             *def = nullptr;
    1102           0 :             return true;
    1103             :         }
    1104             : 
    1105           0 :         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
    1106           0 :         auto callee = CalleeDesc::builtin(builtin);
    1107           0 :         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
    1108           0 :                                    call.spIncrement_);
    1109           0 :         if (!ins)
    1110           0 :             return false;
    1111             : 
    1112           0 :         curBlock_->add(ins);
    1113           0 :         *def = ins;
    1114           0 :         return true;
    1115             :     }
    1116             : 
    1117           0 :     bool builtinInstanceMethodCall(SymbolicAddress builtin, const CallCompileState& call,
    1118             :                                    ValType ret, MDefinition** def)
    1119             :     {
    1120           0 :         if (inDeadCode()) {
    1121           0 :             *def = nullptr;
    1122           0 :             return true;
    1123             :         }
    1124             : 
    1125           0 :         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
    1126           0 :         auto* ins = MWasmCall::NewBuiltinInstanceMethodCall(alloc(), desc, builtin,
    1127             :                                                             call.instanceArg_, call.regArgs_,
    1128           0 :                                                             ToMIRType(ret), call.spIncrement_);
    1129           0 :         if (!ins)
    1130           0 :             return false;
    1131             : 
    1132           0 :         curBlock_->add(ins);
    1133           0 :         *def = ins;
    1134           0 :         return true;
    1135             :     }
    1136             : 
    1137             :     /*********************************************** Control flow generation */
    1138             : 
    1139           0 :     inline bool inDeadCode() const {
    1140           0 :         return curBlock_ == nullptr;
    1141             :     }
    1142             : 
    1143           0 :     void returnExpr(MDefinition* operand)
    1144             :     {
    1145           0 :         if (inDeadCode())
    1146           0 :             return;
    1147             : 
    1148           0 :         MWasmReturn* ins = MWasmReturn::New(alloc(), operand);
    1149           0 :         curBlock_->end(ins);
    1150           0 :         curBlock_ = nullptr;
    1151             :     }
    1152             : 
    1153           0 :     void returnVoid()
    1154             :     {
    1155           0 :         if (inDeadCode())
    1156           0 :             return;
    1157             : 
    1158           0 :         MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc());
    1159           0 :         curBlock_->end(ins);
    1160           0 :         curBlock_ = nullptr;
    1161             :     }
    1162             : 
    1163           0 :     void unreachableTrap()
    1164             :     {
    1165           0 :         if (inDeadCode())
    1166           0 :             return;
    1167             : 
    1168           0 :         auto* ins = MWasmTrap::New(alloc(), wasm::Trap::Unreachable, bytecodeOffset());
    1169           0 :         curBlock_->end(ins);
    1170           0 :         curBlock_ = nullptr;
    1171             :     }
    1172             : 
    1173             :   private:
    1174           0 :     static bool hasPushed(MBasicBlock* block)
    1175             :     {
    1176           0 :         uint32_t numPushed = block->stackDepth() - block->info().firstStackSlot();
    1177           0 :         MOZ_ASSERT(numPushed == 0 || numPushed == 1);
    1178           0 :         return numPushed;
    1179             :     }
    1180             : 
    1181             :   public:
    1182           0 :     void pushDef(MDefinition* def)
    1183             :     {
    1184           0 :         if (inDeadCode())
    1185           0 :             return;
    1186           0 :         MOZ_ASSERT(!hasPushed(curBlock_));
    1187           0 :         if (def && def->type() != MIRType::None)
    1188           0 :             curBlock_->push(def);
    1189             :     }
    1190             : 
    1191           0 :     MDefinition* popDefIfPushed()
    1192             :     {
    1193           0 :         if (!hasPushed(curBlock_))
    1194           0 :             return nullptr;
    1195           0 :         MDefinition* def = curBlock_->pop();
    1196           0 :         MOZ_ASSERT(def->type() != MIRType::Value);
    1197           0 :         return def;
    1198             :     }
    1199             : 
    1200             :   private:
    1201           0 :     void addJoinPredecessor(MDefinition* def, MBasicBlock** joinPred)
    1202             :     {
    1203           0 :         *joinPred = curBlock_;
    1204           0 :         if (inDeadCode())
    1205           0 :             return;
    1206           0 :         pushDef(def);
    1207             :     }
    1208             : 
    1209             :   public:
    1210           0 :     bool branchAndStartThen(MDefinition* cond, MBasicBlock** elseBlock)
    1211             :     {
    1212           0 :         if (inDeadCode()) {
    1213           0 :             *elseBlock = nullptr;
    1214             :         } else {
    1215             :             MBasicBlock* thenBlock;
    1216           0 :             if (!newBlock(curBlock_, &thenBlock))
    1217           0 :                 return false;
    1218           0 :             if (!newBlock(curBlock_, elseBlock))
    1219           0 :                 return false;
    1220             : 
    1221           0 :             curBlock_->end(MTest::New(alloc(), cond, thenBlock, *elseBlock));
    1222             : 
    1223           0 :             curBlock_ = thenBlock;
    1224           0 :             mirGraph().moveBlockToEnd(curBlock_);
    1225             :         }
    1226             : 
    1227           0 :         return startBlock();
    1228             :     }
    1229             : 
    1230           0 :     bool switchToElse(MBasicBlock* elseBlock, MBasicBlock** thenJoinPred)
    1231             :     {
    1232             :         MDefinition* ifDef;
    1233           0 :         if (!finishBlock(&ifDef))
    1234           0 :             return false;
    1235             : 
    1236           0 :         if (!elseBlock) {
    1237           0 :             *thenJoinPred = nullptr;
    1238             :         } else {
    1239           0 :             addJoinPredecessor(ifDef, thenJoinPred);
    1240             : 
    1241           0 :             curBlock_ = elseBlock;
    1242           0 :             mirGraph().moveBlockToEnd(curBlock_);
    1243             :         }
    1244             : 
    1245           0 :         return startBlock();
    1246             :     }
    1247             : 
    1248           0 :     bool joinIfElse(MBasicBlock* thenJoinPred, MDefinition** def)
    1249             :     {
    1250             :         MDefinition* elseDef;
    1251           0 :         if (!finishBlock(&elseDef))
    1252           0 :             return false;
    1253             : 
    1254           0 :         if (!thenJoinPred && inDeadCode()) {
    1255           0 :             *def = nullptr;
    1256             :         } else {
    1257             :             MBasicBlock* elseJoinPred;
    1258           0 :             addJoinPredecessor(elseDef, &elseJoinPred);
    1259             : 
    1260           0 :             mozilla::Array<MBasicBlock*, 2> blocks;
    1261           0 :             size_t numJoinPreds = 0;
    1262           0 :             if (thenJoinPred)
    1263           0 :                 blocks[numJoinPreds++] = thenJoinPred;
    1264           0 :             if (elseJoinPred)
    1265           0 :                 blocks[numJoinPreds++] = elseJoinPred;
    1266             : 
    1267           0 :             if (numJoinPreds == 0) {
    1268           0 :                 *def = nullptr;
    1269           0 :                 return true;
    1270             :             }
    1271             : 
    1272             :             MBasicBlock* join;
    1273           0 :             if (!goToNewBlock(blocks[0], &join))
    1274           0 :                 return false;
    1275           0 :             for (size_t i = 1; i < numJoinPreds; ++i) {
    1276           0 :                 if (!goToExistingBlock(blocks[i], join))
    1277           0 :                     return false;
    1278             :             }
    1279             : 
    1280           0 :             curBlock_ = join;
    1281           0 :             *def = popDefIfPushed();
    1282             :         }
    1283             : 
    1284           0 :         return true;
    1285             :     }
    1286             : 
    1287           0 :     bool startBlock()
    1288             :     {
    1289           0 :         MOZ_ASSERT_IF(blockDepth_ < blockPatches_.length(), blockPatches_[blockDepth_].empty());
    1290           0 :         blockDepth_++;
    1291           0 :         return true;
    1292             :     }
    1293             : 
    1294           0 :     bool finishBlock(MDefinition** def)
    1295             :     {
    1296           0 :         MOZ_ASSERT(blockDepth_);
    1297           0 :         uint32_t topLabel = --blockDepth_;
    1298           0 :         return bindBranches(topLabel, def);
    1299             :     }
    1300             : 
    1301           0 :     bool startLoop(MBasicBlock** loopHeader)
    1302             :     {
    1303           0 :         *loopHeader = nullptr;
    1304             : 
    1305           0 :         blockDepth_++;
    1306           0 :         loopDepth_++;
    1307             : 
    1308           0 :         if (inDeadCode())
    1309           0 :             return true;
    1310             : 
    1311             :         // Create the loop header.
    1312           0 :         MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_ - 1);
    1313           0 :         *loopHeader = MBasicBlock::New(mirGraph(), info(), curBlock_,
    1314             :                                        MBasicBlock::PENDING_LOOP_HEADER);
    1315           0 :         if (!*loopHeader)
    1316           0 :             return false;
    1317             : 
    1318           0 :         (*loopHeader)->setLoopDepth(loopDepth_);
    1319           0 :         mirGraph().addBlock(*loopHeader);
    1320           0 :         curBlock_->end(MGoto::New(alloc(), *loopHeader));
    1321             : 
    1322             :         MBasicBlock* body;
    1323           0 :         if (!goToNewBlock(*loopHeader, &body))
    1324           0 :             return false;
    1325           0 :         curBlock_ = body;
    1326           0 :         return true;
    1327             :     }
    1328             : 
    1329             :   private:
    1330           0 :     void fixupRedundantPhis(MBasicBlock* b)
    1331             :     {
    1332           0 :         for (size_t i = 0, depth = b->stackDepth(); i < depth; i++) {
    1333           0 :             MDefinition* def = b->getSlot(i);
    1334           0 :             if (def->isUnused())
    1335           0 :                 b->setSlot(i, def->toPhi()->getOperand(0));
    1336             :         }
    1337           0 :     }
    1338             : 
    1339           0 :     bool setLoopBackedge(MBasicBlock* loopEntry, MBasicBlock* loopBody, MBasicBlock* backedge)
    1340             :     {
    1341           0 :         if (!loopEntry->setBackedgeWasm(backedge))
    1342           0 :             return false;
    1343             : 
    1344             :         // Flag all redundant phis as unused.
    1345           0 :         for (MPhiIterator phi = loopEntry->phisBegin(); phi != loopEntry->phisEnd(); phi++) {
    1346           0 :             MOZ_ASSERT(phi->numOperands() == 2);
    1347           0 :             if (phi->getOperand(0) == phi->getOperand(1))
    1348           0 :                 phi->setUnused();
    1349             :         }
    1350             : 
    1351             :         // Fix up phis stored in the slots Vector of pending blocks.
    1352           0 :         for (ControlFlowPatchVector& patches : blockPatches_) {
    1353           0 :             for (ControlFlowPatch& p : patches) {
    1354           0 :                 MBasicBlock* block = p.ins->block();
    1355           0 :                 if (block->loopDepth() >= loopEntry->loopDepth())
    1356           0 :                     fixupRedundantPhis(block);
    1357             :             }
    1358             :         }
    1359             : 
    1360             :         // The loop body, if any, might be referencing recycled phis too.
    1361           0 :         if (loopBody)
    1362           0 :             fixupRedundantPhis(loopBody);
    1363             : 
    1364             :         // Discard redundant phis and add to the free list.
    1365           0 :         for (MPhiIterator phi = loopEntry->phisBegin(); phi != loopEntry->phisEnd(); ) {
    1366           0 :             MPhi* entryDef = *phi++;
    1367           0 :             if (!entryDef->isUnused())
    1368           0 :                 continue;
    1369             : 
    1370           0 :             entryDef->justReplaceAllUsesWith(entryDef->getOperand(0));
    1371           0 :             loopEntry->discardPhi(entryDef);
    1372           0 :             mirGraph().addPhiToFreeList(entryDef);
    1373             :         }
    1374             : 
    1375           0 :         return true;
    1376             :     }
    1377             : 
    1378             :   public:
    1379           0 :     bool closeLoop(MBasicBlock* loopHeader, MDefinition** loopResult)
    1380             :     {
    1381           0 :         MOZ_ASSERT(blockDepth_ >= 1);
    1382           0 :         MOZ_ASSERT(loopDepth_);
    1383             : 
    1384           0 :         uint32_t headerLabel = blockDepth_ - 1;
    1385             : 
    1386           0 :         if (!loopHeader) {
    1387           0 :             MOZ_ASSERT(inDeadCode());
    1388           0 :             MOZ_ASSERT(headerLabel >= blockPatches_.length() || blockPatches_[headerLabel].empty());
    1389           0 :             blockDepth_--;
    1390           0 :             loopDepth_--;
    1391           0 :             *loopResult = nullptr;
    1392           0 :             return true;
    1393             :         }
    1394             : 
    1395             :         // Op::Loop doesn't have an implicit backedge so temporarily set
    1396             :         // aside the end of the loop body to bind backedges.
    1397           0 :         MBasicBlock* loopBody = curBlock_;
    1398           0 :         curBlock_ = nullptr;
    1399             : 
    1400             :         // As explained in bug 1253544, Ion apparently has an invariant that
    1401             :         // there is only one backedge to loop headers. To handle wasm's ability
    1402             :         // to have multiple backedges to the same loop header, we bind all those
    1403             :         // branches as forward jumps to a single backward jump. This is
    1404             :         // unfortunate but the optimizer is able to fold these into single jumps
    1405             :         // to backedges.
    1406             :         MDefinition* _;
    1407           0 :         if (!bindBranches(headerLabel, &_))
    1408           0 :             return false;
    1409             : 
    1410           0 :         MOZ_ASSERT(loopHeader->loopDepth() == loopDepth_);
    1411             : 
    1412           0 :         if (curBlock_) {
    1413             :             // We're on the loop backedge block, created by bindBranches.
    1414           0 :             if (hasPushed(curBlock_))
    1415           0 :                 curBlock_->pop();
    1416             : 
    1417           0 :             MOZ_ASSERT(curBlock_->loopDepth() == loopDepth_);
    1418           0 :             curBlock_->end(MGoto::New(alloc(), loopHeader));
    1419           0 :             if (!setLoopBackedge(loopHeader, loopBody, curBlock_))
    1420           0 :                 return false;
    1421             :         }
    1422             : 
    1423           0 :         curBlock_ = loopBody;
    1424             : 
    1425           0 :         loopDepth_--;
    1426             : 
    1427             :         // If the loop depth still at the inner loop body, correct it.
    1428           0 :         if (curBlock_ && curBlock_->loopDepth() != loopDepth_) {
    1429             :             MBasicBlock* out;
    1430           0 :             if (!goToNewBlock(curBlock_, &out))
    1431           0 :                 return false;
    1432           0 :             curBlock_ = out;
    1433             :         }
    1434             : 
    1435           0 :         blockDepth_ -= 1;
    1436           0 :         *loopResult = inDeadCode() ? nullptr : popDefIfPushed();
    1437           0 :         return true;
    1438             :     }
    1439             : 
    1440           0 :     bool addControlFlowPatch(MControlInstruction* ins, uint32_t relative, uint32_t index) {
    1441           0 :         MOZ_ASSERT(relative < blockDepth_);
    1442           0 :         uint32_t absolute = blockDepth_ - 1 - relative;
    1443             : 
    1444           0 :         if (absolute >= blockPatches_.length() && !blockPatches_.resize(absolute + 1))
    1445           0 :             return false;
    1446             : 
    1447           0 :         return blockPatches_[absolute].append(ControlFlowPatch(ins, index));
    1448             :     }
    1449             : 
    1450           0 :     bool br(uint32_t relativeDepth, MDefinition* maybeValue)
    1451             :     {
    1452           0 :         if (inDeadCode())
    1453           0 :             return true;
    1454             : 
    1455           0 :         MGoto* jump = MGoto::New(alloc());
    1456           0 :         if (!addControlFlowPatch(jump, relativeDepth, MGoto::TargetIndex))
    1457           0 :             return false;
    1458             : 
    1459           0 :         pushDef(maybeValue);
    1460             : 
    1461           0 :         curBlock_->end(jump);
    1462           0 :         curBlock_ = nullptr;
    1463           0 :         return true;
    1464             :     }
    1465             : 
    1466           0 :     bool brIf(uint32_t relativeDepth, MDefinition* maybeValue, MDefinition* condition)
    1467             :     {
    1468           0 :         if (inDeadCode())
    1469           0 :             return true;
    1470             : 
    1471           0 :         MBasicBlock* joinBlock = nullptr;
    1472           0 :         if (!newBlock(curBlock_, &joinBlock))
    1473           0 :             return false;
    1474             : 
    1475           0 :         MTest* test = MTest::New(alloc(), condition, joinBlock);
    1476           0 :         if (!addControlFlowPatch(test, relativeDepth, MTest::TrueBranchIndex))
    1477           0 :             return false;
    1478             : 
    1479           0 :         pushDef(maybeValue);
    1480             : 
    1481           0 :         curBlock_->end(test);
    1482           0 :         curBlock_ = joinBlock;
    1483           0 :         return true;
    1484             :     }
    1485             : 
    1486           0 :     bool brTable(MDefinition* operand, uint32_t defaultDepth, const Uint32Vector& depths,
    1487             :                  MDefinition* maybeValue)
    1488             :     {
    1489           0 :         if (inDeadCode())
    1490           0 :             return true;
    1491             : 
    1492           0 :         size_t numCases = depths.length();
    1493           0 :         MOZ_ASSERT(numCases <= INT32_MAX);
    1494           0 :         MOZ_ASSERT(numCases);
    1495             : 
    1496           0 :         MTableSwitch* table = MTableSwitch::New(alloc(), operand, 0, int32_t(numCases - 1));
    1497             : 
    1498             :         size_t defaultIndex;
    1499           0 :         if (!table->addDefault(nullptr, &defaultIndex))
    1500           0 :             return false;
    1501           0 :         if (!addControlFlowPatch(table, defaultDepth, defaultIndex))
    1502           0 :             return false;
    1503             : 
    1504             :         typedef HashMap<uint32_t, uint32_t, DefaultHasher<uint32_t>, SystemAllocPolicy>
    1505             :             IndexToCaseMap;
    1506             : 
    1507           0 :         IndexToCaseMap indexToCase;
    1508           0 :         if (!indexToCase.init() || !indexToCase.put(defaultDepth, defaultIndex))
    1509           0 :             return false;
    1510             : 
    1511           0 :         for (size_t i = 0; i < numCases; i++) {
    1512           0 :             uint32_t depth = depths[i];
    1513             : 
    1514             :             size_t caseIndex;
    1515           0 :             IndexToCaseMap::AddPtr p = indexToCase.lookupForAdd(depth);
    1516           0 :             if (!p) {
    1517           0 :                 if (!table->addSuccessor(nullptr, &caseIndex))
    1518           0 :                     return false;
    1519           0 :                 if (!addControlFlowPatch(table, depth, caseIndex))
    1520           0 :                     return false;
    1521           0 :                 if (!indexToCase.add(p, depth, caseIndex))
    1522           0 :                     return false;
    1523             :             } else {
    1524           0 :                 caseIndex = p->value();
    1525             :             }
    1526             : 
    1527           0 :             if (!table->addCase(caseIndex))
    1528           0 :                 return false;
    1529             :         }
    1530             : 
    1531           0 :         pushDef(maybeValue);
    1532             : 
    1533           0 :         curBlock_->end(table);
    1534           0 :         curBlock_ = nullptr;
    1535             : 
    1536           0 :         return true;
    1537             :     }
    1538             : 
    1539             :     /************************************************************ DECODING ***/
    1540             : 
    1541           0 :     uint32_t readCallSiteLineOrBytecode() {
    1542           0 :         if (!func_.callSiteLineNums().empty())
    1543           0 :             return func_.callSiteLineNums()[lastReadCallSite_++];
    1544           0 :         return iter_.lastOpcodeOffset();
    1545             :     }
    1546             : 
    1547             : #if DEBUG
    1548           0 :     bool done() const { return iter_.done(); }
    1549             : #endif
    1550             : 
    1551             :     /*************************************************************************/
    1552             :   private:
    1553           0 :     bool newBlock(MBasicBlock* pred, MBasicBlock** block)
    1554             :     {
    1555           0 :         *block = MBasicBlock::New(mirGraph(), info(), pred, MBasicBlock::NORMAL);
    1556           0 :         if (!*block)
    1557           0 :             return false;
    1558           0 :         mirGraph().addBlock(*block);
    1559           0 :         (*block)->setLoopDepth(loopDepth_);
    1560           0 :         return true;
    1561             :     }
    1562             : 
    1563           0 :     bool goToNewBlock(MBasicBlock* pred, MBasicBlock** block)
    1564             :     {
    1565           0 :         if (!newBlock(pred, block))
    1566           0 :             return false;
    1567           0 :         pred->end(MGoto::New(alloc(), *block));
    1568           0 :         return true;
    1569             :     }
    1570             : 
    1571           0 :     bool goToExistingBlock(MBasicBlock* prev, MBasicBlock* next)
    1572             :     {
    1573           0 :         MOZ_ASSERT(prev);
    1574           0 :         MOZ_ASSERT(next);
    1575           0 :         prev->end(MGoto::New(alloc(), next));
    1576           0 :         return next->addPredecessor(alloc(), prev);
    1577             :     }
    1578             : 
    1579           0 :     bool bindBranches(uint32_t absolute, MDefinition** def)
    1580             :     {
    1581           0 :         if (absolute >= blockPatches_.length() || blockPatches_[absolute].empty()) {
    1582           0 :             *def = inDeadCode() ? nullptr : popDefIfPushed();
    1583           0 :             return true;
    1584             :         }
    1585             : 
    1586           0 :         ControlFlowPatchVector& patches = blockPatches_[absolute];
    1587           0 :         MControlInstruction* ins = patches[0].ins;
    1588           0 :         MBasicBlock* pred = ins->block();
    1589             : 
    1590           0 :         MBasicBlock* join = nullptr;
    1591           0 :         if (!newBlock(pred, &join))
    1592           0 :             return false;
    1593             : 
    1594           0 :         pred->mark();
    1595           0 :         ins->replaceSuccessor(patches[0].index, join);
    1596             : 
    1597           0 :         for (size_t i = 1; i < patches.length(); i++) {
    1598           0 :             ins = patches[i].ins;
    1599             : 
    1600           0 :             pred = ins->block();
    1601           0 :             if (!pred->isMarked()) {
    1602           0 :                 if (!join->addPredecessor(alloc(), pred))
    1603           0 :                     return false;
    1604           0 :                 pred->mark();
    1605             :             }
    1606             : 
    1607           0 :             ins->replaceSuccessor(patches[i].index, join);
    1608             :         }
    1609             : 
    1610           0 :         MOZ_ASSERT_IF(curBlock_, !curBlock_->isMarked());
    1611           0 :         for (uint32_t i = 0; i < join->numPredecessors(); i++)
    1612           0 :             join->getPredecessor(i)->unmark();
    1613             : 
    1614           0 :         if (curBlock_ && !goToExistingBlock(curBlock_, join))
    1615           0 :             return false;
    1616             : 
    1617           0 :         curBlock_ = join;
    1618             : 
    1619           0 :         *def = popDefIfPushed();
    1620             : 
    1621           0 :         patches.clear();
    1622           0 :         return true;
    1623             :     }
    1624             : };
    1625             : 
    1626             : template <>
    1627           0 : MDefinition* FunctionCompiler::unary<MToFloat32>(MDefinition* op)
    1628             : {
    1629           0 :     if (inDeadCode())
    1630           0 :         return nullptr;
    1631           0 :     auto* ins = MToFloat32::New(alloc(), op, mustPreserveNaN(op->type()));
    1632           0 :     curBlock_->add(ins);
    1633           0 :     return ins;
    1634             : }
    1635             : 
    1636             : template <>
    1637           0 : MDefinition* FunctionCompiler::unary<MTruncateToInt32>(MDefinition* op)
    1638             : {
    1639           0 :     if (inDeadCode())
    1640           0 :         return nullptr;
    1641           0 :     auto* ins = MTruncateToInt32::New(alloc(), op, bytecodeOffset());
    1642           0 :     curBlock_->add(ins);
    1643           0 :     return ins;
    1644             : }
    1645             : 
    1646             : template <>
    1647           0 : MDefinition* FunctionCompiler::unary<MNot>(MDefinition* op)
    1648             : {
    1649           0 :     if (inDeadCode())
    1650           0 :         return nullptr;
    1651           0 :     auto* ins = MNot::NewInt32(alloc(), op);
    1652           0 :     curBlock_->add(ins);
    1653           0 :     return ins;
    1654             : }
    1655             : 
    1656             : template <>
    1657           0 : MDefinition* FunctionCompiler::unary<MAbs>(MDefinition* op, MIRType type)
    1658             : {
    1659           0 :     if (inDeadCode())
    1660           0 :         return nullptr;
    1661           0 :     auto* ins = MAbs::NewWasm(alloc(), op, type);
    1662           0 :     curBlock_->add(ins);
    1663           0 :     return ins;
    1664             : }
    1665             : 
    1666             : } // end anonymous namespace
    1667             : 
    1668             : static bool
    1669           0 : EmitI32Const(FunctionCompiler& f)
    1670             : {
    1671             :     int32_t i32;
    1672           0 :     if (!f.iter().readI32Const(&i32))
    1673           0 :         return false;
    1674             : 
    1675           0 :     f.iter().setResult(f.constant(Int32Value(i32), MIRType::Int32));
    1676           0 :     return true;
    1677             : }
    1678             : 
    1679             : static bool
    1680           0 : EmitI64Const(FunctionCompiler& f)
    1681             : {
    1682             :     int64_t i64;
    1683           0 :     if (!f.iter().readI64Const(&i64))
    1684           0 :         return false;
    1685             : 
    1686           0 :     f.iter().setResult(f.constant(i64));
    1687           0 :     return true;
    1688             : }
    1689             : 
    1690             : static bool
    1691           0 : EmitF32Const(FunctionCompiler& f)
    1692             : {
    1693             :     float f32;
    1694           0 :     if (!f.iter().readF32Const(&f32))
    1695           0 :         return false;
    1696             : 
    1697           0 :     f.iter().setResult(f.constant(f32));
    1698           0 :     return true;
    1699             : }
    1700             : 
    1701             : static bool
    1702           0 : EmitF64Const(FunctionCompiler& f)
    1703             : {
    1704             :     double f64;
    1705           0 :     if (!f.iter().readF64Const(&f64))
    1706           0 :         return false;
    1707             : 
    1708           0 :     f.iter().setResult(f.constant(f64));
    1709           0 :     return true;
    1710             : }
    1711             : 
    1712             : static bool
    1713           0 : EmitI8x16Const(FunctionCompiler& f)
    1714             : {
    1715             :     I8x16 i8x16;
    1716           0 :     if (!f.iter().readI8x16Const(&i8x16))
    1717           0 :         return false;
    1718             : 
    1719           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Int8x16));
    1720           0 :     return true;
    1721             : }
    1722             : 
    1723             : static bool
    1724           0 : EmitI16x8Const(FunctionCompiler& f)
    1725             : {
    1726             :     I16x8 i16x8;
    1727           0 :     if (!f.iter().readI16x8Const(&i16x8))
    1728           0 :         return false;
    1729             : 
    1730           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Int16x8));
    1731           0 :     return true;
    1732             : }
    1733             : 
    1734             : static bool
    1735           0 : EmitI32x4Const(FunctionCompiler& f)
    1736             : {
    1737             :     I32x4 i32x4;
    1738           0 :     if (!f.iter().readI32x4Const(&i32x4))
    1739           0 :         return false;
    1740             : 
    1741           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Int32x4));
    1742           0 :     return true;
    1743             : }
    1744             : 
    1745             : static bool
    1746           0 : EmitF32x4Const(FunctionCompiler& f)
    1747             : {
    1748             :     F32x4 f32x4;
    1749           0 :     if (!f.iter().readF32x4Const(&f32x4))
    1750           0 :         return false;
    1751             : 
    1752           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX4(f32x4), MIRType::Float32x4));
    1753           0 :     return true;
    1754             : }
    1755             : 
    1756             : static bool
    1757           0 : EmitB8x16Const(FunctionCompiler& f)
    1758             : {
    1759             :     I8x16 i8x16;
    1760           0 :     if (!f.iter().readB8x16Const(&i8x16))
    1761           0 :         return false;
    1762             : 
    1763           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX16(i8x16), MIRType::Bool8x16));
    1764           0 :     return true;
    1765             : }
    1766             : 
    1767             : static bool
    1768           0 : EmitB16x8Const(FunctionCompiler& f)
    1769             : {
    1770             :     I16x8 i16x8;
    1771           0 :     if (!f.iter().readB16x8Const(&i16x8))
    1772           0 :         return false;
    1773             : 
    1774           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX8(i16x8), MIRType::Bool16x8));
    1775           0 :     return true;
    1776             : }
    1777             : 
    1778             : static bool
    1779           0 : EmitB32x4Const(FunctionCompiler& f)
    1780             : {
    1781             :     I32x4 i32x4;
    1782           0 :     if (!f.iter().readB32x4Const(&i32x4))
    1783           0 :         return false;
    1784             : 
    1785           0 :     f.iter().setResult(f.constant(SimdConstant::CreateX4(i32x4), MIRType::Bool32x4));
    1786           0 :     return true;
    1787             : }
    1788             : 
    1789             : static bool
    1790           0 : EmitBlock(FunctionCompiler& f)
    1791             : {
    1792           0 :     return f.iter().readBlock() &&
    1793           0 :            f.startBlock();
    1794             : }
    1795             : 
    1796             : static bool
    1797           0 : EmitLoop(FunctionCompiler& f)
    1798             : {
    1799           0 :     if (!f.iter().readLoop())
    1800           0 :         return false;
    1801             : 
    1802             :     MBasicBlock* loopHeader;
    1803           0 :     if (!f.startLoop(&loopHeader))
    1804           0 :         return false;
    1805             : 
    1806           0 :     f.addInterruptCheck();
    1807             : 
    1808           0 :     f.iter().controlItem() = loopHeader;
    1809           0 :     return true;
    1810             : }
    1811             : 
    1812             : static bool
    1813           0 : EmitIf(FunctionCompiler& f)
    1814             : {
    1815           0 :     MDefinition* condition = nullptr;
    1816           0 :     if (!f.iter().readIf(&condition))
    1817           0 :         return false;
    1818             : 
    1819             :     MBasicBlock* elseBlock;
    1820           0 :     if (!f.branchAndStartThen(condition, &elseBlock))
    1821           0 :         return false;
    1822             : 
    1823           0 :     f.iter().controlItem() = elseBlock;
    1824           0 :     return true;
    1825             : }
    1826             : 
    1827             : static bool
    1828           0 : EmitElse(FunctionCompiler& f)
    1829             : {
    1830             :     ExprType thenType;
    1831             :     MDefinition* thenValue;
    1832           0 :     if (!f.iter().readElse(&thenType, &thenValue))
    1833           0 :         return false;
    1834             : 
    1835           0 :     if (!IsVoid(thenType))
    1836           0 :         f.pushDef(thenValue);
    1837             : 
    1838           0 :     if (!f.switchToElse(f.iter().controlItem(), &f.iter().controlItem()))
    1839           0 :         return false;
    1840             : 
    1841           0 :     return true;
    1842             : }
    1843             : 
    1844             : static bool
    1845           0 : EmitEnd(FunctionCompiler& f)
    1846             : {
    1847             :     LabelKind kind;
    1848             :     ExprType type;
    1849             :     MDefinition* value;
    1850           0 :     if (!f.iter().readEnd(&kind, &type, &value))
    1851           0 :         return false;
    1852             : 
    1853           0 :     MBasicBlock* block = f.iter().controlItem();
    1854             : 
    1855           0 :     f.iter().popEnd();
    1856             : 
    1857           0 :     if (!IsVoid(type))
    1858           0 :         f.pushDef(value);
    1859             : 
    1860           0 :     MDefinition* def = nullptr;
    1861           0 :     switch (kind) {
    1862             :       case LabelKind::Block:
    1863           0 :         if (!f.finishBlock(&def))
    1864           0 :             return false;
    1865           0 :         break;
    1866             :       case LabelKind::Loop:
    1867           0 :         if (!f.closeLoop(block, &def))
    1868           0 :             return false;
    1869           0 :         break;
    1870             :       case LabelKind::Then:
    1871             :         // If we didn't see an Else, create a trivial else block so that we create
    1872             :         // a diamond anyway, to preserve Ion invariants.
    1873           0 :         if (!f.switchToElse(block, &block))
    1874           0 :             return false;
    1875             : 
    1876           0 :         if (!f.joinIfElse(block, &def))
    1877           0 :             return false;
    1878           0 :         break;
    1879             :       case LabelKind::Else:
    1880           0 :         if (!f.joinIfElse(block, &def))
    1881           0 :             return false;
    1882           0 :         break;
    1883             :     }
    1884             : 
    1885           0 :     if (!IsVoid(type)) {
    1886           0 :         MOZ_ASSERT_IF(!f.inDeadCode(), def);
    1887           0 :         f.iter().setResult(def);
    1888             :     }
    1889             : 
    1890           0 :     return true;
    1891             : }
    1892             : 
    1893             : static bool
    1894           0 : EmitBr(FunctionCompiler& f)
    1895             : {
    1896             :     uint32_t relativeDepth;
    1897             :     ExprType type;
    1898             :     MDefinition* value;
    1899           0 :     if (!f.iter().readBr(&relativeDepth, &type, &value))
    1900           0 :         return false;
    1901             : 
    1902           0 :     if (IsVoid(type)) {
    1903           0 :         if (!f.br(relativeDepth, nullptr))
    1904           0 :             return false;
    1905             :     } else {
    1906           0 :         if (!f.br(relativeDepth, value))
    1907           0 :             return false;
    1908             :     }
    1909             : 
    1910           0 :     return true;
    1911             : }
    1912             : 
    1913             : static bool
    1914           0 : EmitBrIf(FunctionCompiler& f)
    1915             : {
    1916             :     uint32_t relativeDepth;
    1917             :     ExprType type;
    1918             :     MDefinition* value;
    1919             :     MDefinition* condition;
    1920           0 :     if (!f.iter().readBrIf(&relativeDepth, &type, &value, &condition))
    1921           0 :         return false;
    1922             : 
    1923           0 :     if (IsVoid(type)) {
    1924           0 :         if (!f.brIf(relativeDepth, nullptr, condition))
    1925           0 :             return false;
    1926             :     } else {
    1927           0 :         if (!f.brIf(relativeDepth, value, condition))
    1928           0 :             return false;
    1929             :     }
    1930             : 
    1931           0 :     return true;
    1932             : }
    1933             : 
    1934             : static bool
    1935           0 : EmitBrTable(FunctionCompiler& f)
    1936             : {
    1937           0 :     Uint32Vector depths;
    1938             :     uint32_t defaultDepth;
    1939             :     ExprType branchValueType;
    1940             :     MDefinition* branchValue;
    1941             :     MDefinition* index;
    1942           0 :     if (!f.iter().readBrTable(&depths, &defaultDepth, &branchValueType, &branchValue, &index))
    1943           0 :         return false;
    1944             : 
    1945             :     // If all the targets are the same, or there are no targets, we can just
    1946             :     // use a goto. This is not just an optimization: MaybeFoldConditionBlock
    1947             :     // assumes that tables have more than one successor.
    1948           0 :     bool allSameDepth = true;
    1949           0 :     for (uint32_t depth : depths) {
    1950           0 :         if (depth != defaultDepth) {
    1951           0 :             allSameDepth = false;
    1952           0 :             break;
    1953             :         }
    1954             :     }
    1955             : 
    1956           0 :     if (allSameDepth)
    1957           0 :         return f.br(defaultDepth, branchValue);
    1958             : 
    1959           0 :     return f.brTable(index, defaultDepth, depths, branchValue);
    1960             : }
    1961             : 
    1962             : static bool
    1963           0 : EmitReturn(FunctionCompiler& f)
    1964             : {
    1965             :     MDefinition* value;
    1966           0 :     if (!f.iter().readReturn(&value))
    1967           0 :         return false;
    1968             : 
    1969           0 :     if (IsVoid(f.sig().ret())) {
    1970           0 :         f.returnVoid();
    1971           0 :         return true;
    1972             :     }
    1973             : 
    1974           0 :     f.returnExpr(value);
    1975           0 :     return true;
    1976             : }
    1977             : 
    1978             : static bool
    1979           0 : EmitUnreachable(FunctionCompiler& f)
    1980             : {
    1981           0 :     if (!f.iter().readUnreachable())
    1982           0 :         return false;
    1983             : 
    1984           0 :     f.unreachableTrap();
    1985           0 :     return true;
    1986             : }
    1987             : 
    1988             : typedef IonOpIter::ValueVector DefVector;
    1989             : 
    1990             : static bool
    1991           0 : EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, CallCompileState* call)
    1992             : {
    1993           0 :     if (!f.startCall(call))
    1994           0 :         return false;
    1995             : 
    1996           0 :     for (size_t i = 0, n = sig.args().length(); i < n; ++i) {
    1997           0 :         if (!f.passArg(args[i], sig.args()[i], call))
    1998           0 :             return false;
    1999             :     }
    2000             : 
    2001           0 :     return f.finishCall(call);
    2002             : }
    2003             : 
    2004             : static bool
    2005           0 : EmitCall(FunctionCompiler& f)
    2006             : {
    2007           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    2008             : 
    2009             :     uint32_t funcIndex;
    2010           0 :     DefVector args;
    2011           0 :     if (!f.iter().readCall(&funcIndex, &args))
    2012           0 :         return false;
    2013             : 
    2014           0 :     if (f.inDeadCode())
    2015           0 :         return true;
    2016             : 
    2017           0 :     const Sig& sig = *f.env().funcSigs[funcIndex];
    2018             : 
    2019           0 :     CallCompileState call(f, lineOrBytecode);
    2020           0 :     if (!EmitCallArgs(f, sig, args, &call))
    2021           0 :         return false;
    2022             : 
    2023             :     MDefinition* def;
    2024           0 :     if (f.env().funcIsImport(funcIndex)) {
    2025           0 :         uint32_t globalDataOffset = f.env().funcImportGlobalDataOffsets[funcIndex];
    2026           0 :         if (!f.callImport(globalDataOffset, call, sig.ret(), &def))
    2027           0 :             return false;
    2028             :     } else {
    2029           0 :         if (!f.callDirect(sig, funcIndex, call, &def))
    2030           0 :             return false;
    2031             :     }
    2032             : 
    2033           0 :     if (IsVoid(sig.ret()))
    2034           0 :         return true;
    2035             : 
    2036           0 :     f.iter().setResult(def);
    2037           0 :     return true;
    2038             : }
    2039             : 
    2040             : static bool
    2041           0 : EmitCallIndirect(FunctionCompiler& f, bool oldStyle)
    2042             : {
    2043           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    2044             : 
    2045             :     uint32_t sigIndex;
    2046             :     MDefinition* callee;
    2047           0 :     DefVector args;
    2048           0 :     if (oldStyle) {
    2049           0 :         if (!f.iter().readOldCallIndirect(&sigIndex, &callee, &args))
    2050           0 :             return false;
    2051             :     } else {
    2052           0 :         if (!f.iter().readCallIndirect(&sigIndex, &callee, &args))
    2053           0 :             return false;
    2054             :     }
    2055             : 
    2056           0 :     if (f.inDeadCode())
    2057           0 :         return true;
    2058             : 
    2059           0 :     const Sig& sig = f.env().sigs[sigIndex];
    2060             : 
    2061           0 :     CallCompileState call(f, lineOrBytecode);
    2062           0 :     if (!EmitCallArgs(f, sig, args, &call))
    2063           0 :         return false;
    2064             : 
    2065             :     MDefinition* def;
    2066           0 :     if (!f.callIndirect(sigIndex, callee, call, &def))
    2067           0 :         return false;
    2068             : 
    2069           0 :     if (IsVoid(sig.ret()))
    2070           0 :         return true;
    2071             : 
    2072           0 :     f.iter().setResult(def);
    2073           0 :     return true;
    2074             : }
    2075             : 
    2076             : static bool
    2077           0 : EmitGetLocal(FunctionCompiler& f)
    2078             : {
    2079             :     uint32_t id;
    2080           0 :     if (!f.iter().readGetLocal(f.locals(), &id))
    2081           0 :         return false;
    2082             : 
    2083           0 :     f.iter().setResult(f.getLocalDef(id));
    2084           0 :     return true;
    2085             : }
    2086             : 
    2087             : static bool
    2088           0 : EmitSetLocal(FunctionCompiler& f)
    2089             : {
    2090             :     uint32_t id;
    2091             :     MDefinition* value;
    2092           0 :     if (!f.iter().readSetLocal(f.locals(), &id, &value))
    2093           0 :         return false;
    2094             : 
    2095           0 :     f.assign(id, value);
    2096           0 :     return true;
    2097             : }
    2098             : 
    2099             : static bool
    2100           0 : EmitTeeLocal(FunctionCompiler& f)
    2101             : {
    2102             :     uint32_t id;
    2103             :     MDefinition* value;
    2104           0 :     if (!f.iter().readTeeLocal(f.locals(), &id, &value))
    2105           0 :         return false;
    2106             : 
    2107           0 :     f.assign(id, value);
    2108           0 :     return true;
    2109             : }
    2110             : 
    2111             : static bool
    2112           0 : EmitGetGlobal(FunctionCompiler& f)
    2113             : {
    2114             :     uint32_t id;
    2115           0 :     if (!f.iter().readGetGlobal(&id))
    2116           0 :         return false;
    2117             : 
    2118           0 :     const GlobalDesc& global = f.env().globals[id];
    2119           0 :     if (!global.isConstant()) {
    2120           0 :         f.iter().setResult(f.loadGlobalVar(global.offset(), !global.isMutable(),
    2121           0 :                                            ToMIRType(global.type())));
    2122           0 :         return true;
    2123             :     }
    2124             : 
    2125           0 :     Val value = global.constantValue();
    2126           0 :     MIRType mirType = ToMIRType(value.type());
    2127             : 
    2128             :     MDefinition* result;
    2129           0 :     switch (value.type()) {
    2130             :       case ValType::I32:
    2131           0 :         result = f.constant(Int32Value(value.i32()), mirType);
    2132           0 :         break;
    2133             :       case ValType::I64:
    2134           0 :         result = f.constant(int64_t(value.i64()));
    2135           0 :         break;
    2136             :       case ValType::F32:
    2137           0 :         result = f.constant(value.f32());
    2138           0 :         break;
    2139             :       case ValType::F64:
    2140           0 :         result = f.constant(value.f64());
    2141           0 :         break;
    2142             :       case ValType::I8x16:
    2143           0 :         result = f.constant(SimdConstant::CreateX16(value.i8x16()), mirType);
    2144           0 :         break;
    2145             :       case ValType::I16x8:
    2146           0 :         result = f.constant(SimdConstant::CreateX8(value.i16x8()), mirType);
    2147           0 :         break;
    2148             :       case ValType::I32x4:
    2149           0 :         result = f.constant(SimdConstant::CreateX4(value.i32x4()), mirType);
    2150           0 :         break;
    2151             :       case ValType::F32x4:
    2152           0 :         result = f.constant(SimdConstant::CreateX4(value.f32x4()), mirType);
    2153           0 :         break;
    2154             :       default:
    2155           0 :         MOZ_CRASH("unexpected type in EmitGetGlobal");
    2156             :     }
    2157             : 
    2158           0 :     f.iter().setResult(result);
    2159           0 :     return true;
    2160             : }
    2161             : 
    2162             : static bool
    2163           0 : EmitSetGlobal(FunctionCompiler& f)
    2164             : {
    2165             :     uint32_t id;
    2166             :     MDefinition* value;
    2167           0 :     if (!f.iter().readSetGlobal(&id, &value))
    2168           0 :         return false;
    2169             : 
    2170           0 :     const GlobalDesc& global = f.env().globals[id];
    2171           0 :     MOZ_ASSERT(global.isMutable());
    2172             : 
    2173           0 :     f.storeGlobalVar(global.offset(), value);
    2174           0 :     return true;
    2175             : }
    2176             : 
    2177             : static bool
    2178           0 : EmitTeeGlobal(FunctionCompiler& f)
    2179             : {
    2180             :     uint32_t id;
    2181             :     MDefinition* value;
    2182           0 :     if (!f.iter().readTeeGlobal(&id, &value))
    2183           0 :         return false;
    2184             : 
    2185           0 :     const GlobalDesc& global = f.env().globals[id];
    2186           0 :     MOZ_ASSERT(global.isMutable());
    2187             : 
    2188           0 :     f.storeGlobalVar(global.offset(), value);
    2189           0 :     return true;
    2190             : }
    2191             : 
    2192             : template <typename MIRClass>
    2193             : static bool
    2194             : EmitUnary(FunctionCompiler& f, ValType operandType)
    2195             : {
    2196             :     MDefinition* input;
    2197             :     if (!f.iter().readUnary(operandType, &input))
    2198             :         return false;
    2199             : 
    2200             :     f.iter().setResult(f.unary<MIRClass>(input));
    2201             :     return true;
    2202             : }
    2203             : 
    2204             : template <typename MIRClass>
    2205             : static bool
    2206           0 : EmitConversion(FunctionCompiler& f, ValType operandType, ValType resultType)
    2207             : {
    2208             :     MDefinition* input;
    2209           0 :     if (!f.iter().readConversion(operandType, resultType, &input))
    2210           0 :         return false;
    2211             : 
    2212           0 :     f.iter().setResult(f.unary<MIRClass>(input));
    2213           0 :     return true;
    2214             : }
    2215             : 
    2216             : template <typename MIRClass>
    2217             : static bool
    2218           0 : EmitUnaryWithType(FunctionCompiler& f, ValType operandType, MIRType mirType)
    2219             : {
    2220             :     MDefinition* input;
    2221           0 :     if (!f.iter().readUnary(operandType, &input))
    2222           0 :         return false;
    2223             : 
    2224           0 :     f.iter().setResult(f.unary<MIRClass>(input, mirType));
    2225           0 :     return true;
    2226             : }
    2227             : 
    2228             : template <typename MIRClass>
    2229             : static bool
    2230             : EmitConversionWithType(FunctionCompiler& f,
    2231             :                        ValType operandType, ValType resultType, MIRType mirType)
    2232             : {
    2233             :     MDefinition* input;
    2234             :     if (!f.iter().readConversion(operandType, resultType, &input))
    2235             :         return false;
    2236             : 
    2237             :     f.iter().setResult(f.unary<MIRClass>(input, mirType));
    2238             :     return true;
    2239             : }
    2240             : 
    2241             : static bool
    2242           0 : EmitTruncate(FunctionCompiler& f, ValType operandType, ValType resultType,
    2243             :              bool isUnsigned)
    2244             : {
    2245             :     MDefinition* input;
    2246           0 :     if (!f.iter().readConversion(operandType, resultType, &input))
    2247           0 :         return false;
    2248             : 
    2249           0 :     if (resultType == ValType::I32) {
    2250           0 :         if (f.env().isAsmJS())
    2251           0 :             f.iter().setResult(f.unary<MTruncateToInt32>(input));
    2252             :         else
    2253           0 :             f.iter().setResult(f.truncate<MWasmTruncateToInt32>(input, isUnsigned));
    2254             :     } else {
    2255           0 :         MOZ_ASSERT(resultType == ValType::I64);
    2256           0 :         MOZ_ASSERT(!f.env().isAsmJS());
    2257           0 :         f.iter().setResult(f.truncate<MWasmTruncateToInt64>(input, isUnsigned));
    2258             :     }
    2259           0 :     return true;
    2260             : }
    2261             : 
    2262             : static bool
    2263           0 : EmitExtendI32(FunctionCompiler& f, bool isUnsigned)
    2264             : {
    2265             :     MDefinition* input;
    2266           0 :     if (!f.iter().readConversion(ValType::I32, ValType::I64, &input))
    2267           0 :         return false;
    2268             : 
    2269           0 :     f.iter().setResult(f.extendI32(input, isUnsigned));
    2270           0 :     return true;
    2271             : }
    2272             : 
    2273             : static bool
    2274           0 : EmitConvertI64ToFloatingPoint(FunctionCompiler& f,
    2275             :                               ValType resultType, MIRType mirType, bool isUnsigned)
    2276             : {
    2277             :     MDefinition* input;
    2278           0 :     if (!f.iter().readConversion(ValType::I64, resultType, &input))
    2279           0 :         return false;
    2280             : 
    2281           0 :     f.iter().setResult(f.convertI64ToFloatingPoint(input, mirType, isUnsigned));
    2282           0 :     return true;
    2283             : }
    2284             : 
    2285             : static bool
    2286           0 : EmitReinterpret(FunctionCompiler& f, ValType resultType, ValType operandType, MIRType mirType)
    2287             : {
    2288             :     MDefinition* input;
    2289           0 :     if (!f.iter().readConversion(operandType, resultType, &input))
    2290           0 :         return false;
    2291             : 
    2292           0 :     f.iter().setResult(f.unary<MWasmReinterpret>(input, mirType));
    2293           0 :     return true;
    2294             : }
    2295             : 
    2296             : static bool
    2297           0 : EmitAdd(FunctionCompiler& f, ValType type, MIRType mirType)
    2298             : {
    2299             :     MDefinition* lhs;
    2300             :     MDefinition* rhs;
    2301           0 :     if (!f.iter().readBinary(type, &lhs, &rhs))
    2302           0 :         return false;
    2303             : 
    2304           0 :     f.iter().setResult(f.binary<MAdd>(lhs, rhs, mirType));
    2305           0 :     return true;
    2306             : }
    2307             : 
    2308             : static bool
    2309           0 : EmitSub(FunctionCompiler& f, ValType type, MIRType mirType)
    2310             : {
    2311             :     MDefinition* lhs;
    2312             :     MDefinition* rhs;
    2313           0 :     if (!f.iter().readBinary(type, &lhs, &rhs))
    2314           0 :         return false;
    2315             : 
    2316           0 :     f.iter().setResult(f.sub(lhs, rhs, mirType));
    2317           0 :     return true;
    2318             : }
    2319             : 
    2320             : static bool
    2321           0 : EmitRotate(FunctionCompiler& f, ValType type, bool isLeftRotation)
    2322             : {
    2323             :     MDefinition* lhs;
    2324             :     MDefinition* rhs;
    2325           0 :     if (!f.iter().readBinary(type, &lhs, &rhs))
    2326           0 :         return false;
    2327             : 
    2328           0 :     MDefinition* result = f.rotate(lhs, rhs, ToMIRType(type), isLeftRotation);
    2329           0 :     f.iter().setResult(result);
    2330           0 :     return true;
    2331             : }
    2332             : 
    2333             : static bool
    2334           0 : EmitBitNot(FunctionCompiler& f, ValType operandType)
    2335             : {
    2336             :     MDefinition* input;
    2337           0 :     if (!f.iter().readUnary(operandType, &input))
    2338           0 :         return false;
    2339             : 
    2340           0 :     f.iter().setResult(f.bitnot(input));
    2341           0 :     return true;
    2342             : }
    2343             : 
    2344             : template <typename MIRClass>
    2345             : static bool
    2346           0 : EmitBitwise(FunctionCompiler& f, ValType operandType, MIRType mirType)
    2347             : {
    2348             :     MDefinition* lhs;
    2349             :     MDefinition* rhs;
    2350           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2351           0 :         return false;
    2352             : 
    2353           0 :     f.iter().setResult(f.binary<MIRClass>(lhs, rhs, mirType));
    2354           0 :     return true;
    2355             : }
    2356             : 
    2357             : static bool
    2358           0 : EmitMul(FunctionCompiler& f, ValType operandType, MIRType mirType)
    2359             : {
    2360             :     MDefinition* lhs;
    2361             :     MDefinition* rhs;
    2362           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2363           0 :         return false;
    2364             : 
    2365           0 :     f.iter().setResult(f.mul(lhs, rhs, mirType,
    2366           0 :                        mirType == MIRType::Int32 ? MMul::Integer : MMul::Normal));
    2367           0 :     return true;
    2368             : }
    2369             : 
    2370             : static bool
    2371           0 : EmitDiv(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned)
    2372             : {
    2373             :     MDefinition* lhs;
    2374             :     MDefinition* rhs;
    2375           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2376           0 :         return false;
    2377             : 
    2378           0 :     f.iter().setResult(f.div(lhs, rhs, mirType, isUnsigned));
    2379           0 :     return true;
    2380             : }
    2381             : 
    2382             : static bool
    2383           0 : EmitRem(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isUnsigned)
    2384             : {
    2385             :     MDefinition* lhs;
    2386             :     MDefinition* rhs;
    2387           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2388           0 :         return false;
    2389             : 
    2390           0 :     f.iter().setResult(f.mod(lhs, rhs, mirType, isUnsigned));
    2391           0 :     return true;
    2392             : }
    2393             : 
    2394             : static bool
    2395           0 : EmitMinMax(FunctionCompiler& f, ValType operandType, MIRType mirType, bool isMax)
    2396             : {
    2397             :     MDefinition* lhs;
    2398             :     MDefinition* rhs;
    2399           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2400           0 :         return false;
    2401             : 
    2402           0 :     f.iter().setResult(f.minMax(lhs, rhs, mirType, isMax));
    2403           0 :     return true;
    2404             : }
    2405             : 
    2406             : static bool
    2407           0 : EmitCopySign(FunctionCompiler& f, ValType operandType)
    2408             : {
    2409             :     MDefinition* lhs;
    2410             :     MDefinition* rhs;
    2411           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2412           0 :         return false;
    2413             : 
    2414           0 :     f.iter().setResult(f.binary<MCopySign>(lhs, rhs, ToMIRType(operandType)));
    2415           0 :     return true;
    2416             : }
    2417             : 
    2418             : static bool
    2419           0 : EmitComparison(FunctionCompiler& f,
    2420             :                ValType operandType, JSOp compareOp, MCompare::CompareType compareType)
    2421             : {
    2422             :     MDefinition* lhs;
    2423             :     MDefinition* rhs;
    2424           0 :     if (!f.iter().readComparison(operandType, &lhs, &rhs))
    2425           0 :         return false;
    2426             : 
    2427           0 :     f.iter().setResult(f.compare(lhs, rhs, compareOp, compareType));
    2428           0 :     return true;
    2429             : }
    2430             : 
    2431             : static bool
    2432           0 : EmitSelect(FunctionCompiler& f)
    2433             : {
    2434             :     StackType type;
    2435             :     MDefinition* trueValue;
    2436             :     MDefinition* falseValue;
    2437             :     MDefinition* condition;
    2438           0 :     if (!f.iter().readSelect(&type, &trueValue, &falseValue, &condition))
    2439           0 :         return false;
    2440             : 
    2441           0 :     f.iter().setResult(f.select(trueValue, falseValue, condition));
    2442           0 :     return true;
    2443             : }
    2444             : 
    2445             : static bool
    2446           0 : EmitLoad(FunctionCompiler& f, ValType type, Scalar::Type viewType)
    2447             : {
    2448           0 :     LinearMemoryAddress<MDefinition*> addr;
    2449           0 :     if (!f.iter().readLoad(type, Scalar::byteSize(viewType), &addr))
    2450           0 :         return false;
    2451             : 
    2452           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
    2453           0 :     auto* ins = f.load(addr.base, &access, type);
    2454           0 :     if (!f.inDeadCode() && !ins)
    2455           0 :         return false;
    2456             : 
    2457           0 :     f.iter().setResult(ins);
    2458           0 :     return true;
    2459             : }
    2460             : 
    2461             : static bool
    2462           0 : EmitStore(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
    2463             : {
    2464           0 :     LinearMemoryAddress<MDefinition*> addr;
    2465             :     MDefinition* value;
    2466           0 :     if (!f.iter().readStore(resultType, Scalar::byteSize(viewType), &addr, &value))
    2467           0 :         return false;
    2468             : 
    2469           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
    2470             : 
    2471           0 :     return f.store(addr.base, &access, value);
    2472             : }
    2473             : 
    2474             : static bool
    2475           0 : EmitTeeStore(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
    2476             : {
    2477           0 :     LinearMemoryAddress<MDefinition*> addr;
    2478             :     MDefinition* value;
    2479           0 :     if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
    2480           0 :         return false;
    2481             : 
    2482           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
    2483             : 
    2484           0 :     return f.store(addr.base, &access, value);
    2485             : }
    2486             : 
    2487             : static bool
    2488           0 : EmitTeeStoreWithCoercion(FunctionCompiler& f, ValType resultType, Scalar::Type viewType)
    2489             : {
    2490           0 :     LinearMemoryAddress<MDefinition*> addr;
    2491             :     MDefinition* value;
    2492           0 :     if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
    2493           0 :         return false;
    2494             : 
    2495           0 :     if (resultType == ValType::F32 && viewType == Scalar::Float64)
    2496           0 :         value = f.unary<MToDouble>(value);
    2497           0 :     else if (resultType == ValType::F64 && viewType == Scalar::Float32)
    2498           0 :         value = f.unary<MToFloat32>(value);
    2499             :     else
    2500           0 :         MOZ_CRASH("unexpected coerced store");
    2501             : 
    2502           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, f.bytecodeIfNotAsmJS());
    2503             : 
    2504           0 :     return f.store(addr.base, &access, value);
    2505             : }
    2506             : 
    2507             : static bool
    2508           0 : TryInlineUnaryBuiltin(FunctionCompiler& f, SymbolicAddress callee, MDefinition* input)
    2509             : {
    2510           0 :     if (!input)
    2511           0 :         return false;
    2512             : 
    2513           0 :     MOZ_ASSERT(IsFloatingPointType(input->type()));
    2514             : 
    2515             :     RoundingMode mode;
    2516           0 :     if (!IsRoundingFunction(callee, &mode))
    2517           0 :         return false;
    2518             : 
    2519           0 :     if (!MNearbyInt::HasAssemblerSupport(mode))
    2520           0 :         return false;
    2521             : 
    2522           0 :     f.iter().setResult(f.nearbyInt(input, mode));
    2523           0 :     return true;
    2524             : }
    2525             : 
    2526             : static bool
    2527           0 : EmitUnaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType operandType)
    2528             : {
    2529           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    2530             : 
    2531             :     MDefinition* input;
    2532           0 :     if (!f.iter().readUnary(operandType, &input))
    2533           0 :         return false;
    2534             : 
    2535           0 :     if (TryInlineUnaryBuiltin(f, callee, input))
    2536           0 :         return true;
    2537             : 
    2538           0 :     CallCompileState call(f, lineOrBytecode);
    2539           0 :     if (!f.startCall(&call))
    2540           0 :         return false;
    2541             : 
    2542           0 :     if (!f.passArg(input, operandType, &call))
    2543           0 :         return false;
    2544             : 
    2545           0 :     if (!f.finishCall(&call))
    2546           0 :         return false;
    2547             : 
    2548             :     MDefinition* def;
    2549           0 :     if (!f.builtinCall(callee, call, operandType, &def))
    2550           0 :         return false;
    2551             : 
    2552           0 :     f.iter().setResult(def);
    2553           0 :     return true;
    2554             : }
    2555             : 
    2556             : static bool
    2557           0 : EmitBinaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType operandType)
    2558             : {
    2559           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    2560             : 
    2561           0 :     CallCompileState call(f, lineOrBytecode);
    2562           0 :     if (!f.startCall(&call))
    2563           0 :         return false;
    2564             : 
    2565             :     MDefinition* lhs;
    2566             :     MDefinition* rhs;
    2567           0 :     if (!f.iter().readBinary(operandType, &lhs, &rhs))
    2568           0 :         return false;
    2569             : 
    2570           0 :     if (!f.passArg(lhs, operandType, &call))
    2571           0 :         return false;
    2572             : 
    2573           0 :     if (!f.passArg(rhs, operandType, &call))
    2574           0 :         return false;
    2575             : 
    2576           0 :     if (!f.finishCall(&call))
    2577           0 :         return false;
    2578             : 
    2579             :     MDefinition* def;
    2580           0 :     if (!f.builtinCall(callee, call, operandType, &def))
    2581           0 :         return false;
    2582             : 
    2583           0 :     f.iter().setResult(def);
    2584           0 :     return true;
    2585             : }
    2586             : 
    2587             : static bool
    2588           0 : EmitAtomicsLoad(FunctionCompiler& f)
    2589             : {
    2590           0 :     LinearMemoryAddress<MDefinition*> addr;
    2591             :     Scalar::Type viewType;
    2592           0 :     if (!f.iter().readAtomicLoad(&addr, &viewType))
    2593           0 :         return false;
    2594             : 
    2595           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), 0,
    2596           0 :                             MembarBeforeLoad, MembarAfterLoad);
    2597             : 
    2598           0 :     auto* ins = f.load(addr.base, &access, ValType::I32);
    2599           0 :     if (!f.inDeadCode() && !ins)
    2600           0 :         return false;
    2601             : 
    2602           0 :     f.iter().setResult(ins);
    2603           0 :     return true;
    2604             : }
    2605             : 
    2606             : static bool
    2607           0 : EmitAtomicsStore(FunctionCompiler& f)
    2608             : {
    2609           0 :     LinearMemoryAddress<MDefinition*> addr;
    2610             :     Scalar::Type viewType;
    2611             :     MDefinition* value;
    2612           0 :     if (!f.iter().readAtomicStore(&addr, &viewType, &value))
    2613           0 :         return false;
    2614             : 
    2615           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), 0,
    2616           0 :                             MembarBeforeStore, MembarAfterStore);
    2617             : 
    2618           0 :     if (!f.store(addr.base, &access, value))
    2619           0 :         return false;
    2620             : 
    2621           0 :     f.iter().setResult(value);
    2622           0 :     return true;
    2623             : }
    2624             : 
    2625             : static bool
    2626           0 : EmitAtomicsBinOp(FunctionCompiler& f)
    2627             : {
    2628           0 :     LinearMemoryAddress<MDefinition*> addr;
    2629             :     Scalar::Type viewType;
    2630             :     jit::AtomicOp op;
    2631             :     MDefinition* value;
    2632           0 :     if (!f.iter().readAtomicBinOp(&addr, &viewType, &op, &value))
    2633           0 :         return false;
    2634             : 
    2635           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
    2636             : 
    2637           0 :     auto* ins = f.atomicBinopHeap(op, addr.base, &access, value);
    2638           0 :     if (!f.inDeadCode() && !ins)
    2639           0 :         return false;
    2640             : 
    2641           0 :     f.iter().setResult(ins);
    2642           0 :     return true;
    2643             : }
    2644             : 
    2645             : static bool
    2646           0 : EmitAtomicsCompareExchange(FunctionCompiler& f)
    2647             : {
    2648           0 :     LinearMemoryAddress<MDefinition*> addr;
    2649             :     Scalar::Type viewType;
    2650             :     MDefinition* oldValue;
    2651             :     MDefinition* newValue;
    2652           0 :     if (!f.iter().readAtomicCompareExchange(&addr, &viewType, &oldValue, &newValue))
    2653           0 :         return false;
    2654             : 
    2655           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
    2656             : 
    2657           0 :     auto* ins = f.atomicCompareExchangeHeap(addr.base, &access, oldValue, newValue);
    2658           0 :     if (!f.inDeadCode() && !ins)
    2659           0 :         return false;
    2660             : 
    2661           0 :     f.iter().setResult(ins);
    2662           0 :     return true;
    2663             : }
    2664             : 
    2665             : static bool
    2666           0 : EmitAtomicsExchange(FunctionCompiler& f)
    2667             : {
    2668           0 :     LinearMemoryAddress<MDefinition*> addr;
    2669             :     Scalar::Type viewType;
    2670             :     MDefinition* value;
    2671           0 :     if (!f.iter().readAtomicExchange(&addr, &viewType, &value))
    2672           0 :         return false;
    2673             : 
    2674           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()));
    2675             : 
    2676           0 :     auto* ins = f.atomicExchangeHeap(addr.base, &access, value);
    2677           0 :     if (!f.inDeadCode() && !ins)
    2678           0 :         return false;
    2679             : 
    2680           0 :     f.iter().setResult(ins);
    2681           0 :     return true;
    2682             : }
    2683             : 
    2684             : static bool
    2685           0 : EmitSimdUnary(FunctionCompiler& f, ValType type, SimdOperation simdOp)
    2686             : {
    2687             :     MSimdUnaryArith::Operation op;
    2688           0 :     switch (simdOp) {
    2689             :       case SimdOperation::Fn_abs:
    2690           0 :         op = MSimdUnaryArith::abs;
    2691           0 :         break;
    2692             :       case SimdOperation::Fn_neg:
    2693           0 :         op = MSimdUnaryArith::neg;
    2694           0 :         break;
    2695             :       case SimdOperation::Fn_not:
    2696           0 :         op = MSimdUnaryArith::not_;
    2697           0 :         break;
    2698             :       case SimdOperation::Fn_sqrt:
    2699           0 :         op = MSimdUnaryArith::sqrt;
    2700           0 :         break;
    2701             :       case SimdOperation::Fn_reciprocalApproximation:
    2702           0 :         op = MSimdUnaryArith::reciprocalApproximation;
    2703           0 :         break;
    2704             :       case SimdOperation::Fn_reciprocalSqrtApproximation:
    2705           0 :         op = MSimdUnaryArith::reciprocalSqrtApproximation;
    2706           0 :         break;
    2707             :       default:
    2708           0 :         MOZ_CRASH("not a simd unary arithmetic operation");
    2709             :     }
    2710             : 
    2711             :     MDefinition* input;
    2712           0 :     if (!f.iter().readUnary(type, &input))
    2713           0 :         return false;
    2714             : 
    2715           0 :     f.iter().setResult(f.unarySimd(input, op, ToMIRType(type)));
    2716           0 :     return true;
    2717             : }
    2718             : 
    2719             : template<class OpKind>
    2720             : inline bool
    2721           0 : EmitSimdBinary(FunctionCompiler& f, ValType type, OpKind op)
    2722             : {
    2723             :     MDefinition* lhs;
    2724             :     MDefinition* rhs;
    2725           0 :     if (!f.iter().readBinary(type, &lhs, &rhs))
    2726           0 :         return false;
    2727             : 
    2728           0 :     f.iter().setResult(f.binarySimd(lhs, rhs, op, ToMIRType(type)));
    2729           0 :     return true;
    2730             : }
    2731             : 
    2732             : static bool
    2733           0 : EmitSimdBinaryComp(FunctionCompiler& f, ValType operandType, MSimdBinaryComp::Operation op,
    2734             :                    SimdSign sign)
    2735             : {
    2736             :     MDefinition* lhs;
    2737             :     MDefinition* rhs;
    2738           0 :     if (!f.iter().readSimdComparison(operandType, &lhs, &rhs))
    2739           0 :         return false;
    2740             : 
    2741           0 :     f.iter().setResult(f.binarySimdComp(lhs, rhs, op, sign));
    2742           0 :     return true;
    2743             : }
    2744             : 
    2745             : static bool
    2746           0 : EmitSimdBinarySaturating(FunctionCompiler& f, ValType type, MSimdBinarySaturating::Operation op,
    2747             :                          SimdSign sign)
    2748             : {
    2749             :     MDefinition* lhs;
    2750             :     MDefinition* rhs;
    2751           0 :     if (!f.iter().readBinary(type, &lhs, &rhs))
    2752           0 :         return false;
    2753             : 
    2754           0 :     f.iter().setResult(f.binarySimdSaturating(lhs, rhs, op, sign));
    2755           0 :     return true;
    2756             : }
    2757             : 
    2758             : static bool
    2759           0 : EmitSimdShift(FunctionCompiler& f, ValType operandType, MSimdShift::Operation op)
    2760             : {
    2761             :     MDefinition* lhs;
    2762             :     MDefinition* rhs;
    2763           0 :     if (!f.iter().readSimdShiftByScalar(operandType, &lhs, &rhs))
    2764           0 :         return false;
    2765             : 
    2766           0 :     f.iter().setResult(f.binarySimdShift(lhs, rhs, op));
    2767           0 :     return true;
    2768             : }
    2769             : 
    2770             : static ValType
    2771           0 : SimdToLaneType(ValType type)
    2772             : {
    2773           0 :     switch (type) {
    2774             :       case ValType::I8x16:
    2775             :       case ValType::I16x8:
    2776           0 :       case ValType::I32x4:  return ValType::I32;
    2777           0 :       case ValType::F32x4:  return ValType::F32;
    2778             :       case ValType::B8x16:
    2779             :       case ValType::B16x8:
    2780           0 :       case ValType::B32x4:  return ValType::I32; // Boolean lanes are Int32 in asm.
    2781             :       case ValType::I32:
    2782             :       case ValType::I64:
    2783             :       case ValType::F32:
    2784             :       case ValType::F64:
    2785           0 :         break;
    2786             :     }
    2787           0 :     MOZ_CRASH("bad simd type");
    2788             : }
    2789             : 
    2790             : static bool
    2791           0 : EmitExtractLane(FunctionCompiler& f, ValType operandType, SimdSign sign)
    2792             : {
    2793             :     uint8_t lane;
    2794             :     MDefinition* vector;
    2795           0 :     if (!f.iter().readExtractLane(operandType, &lane, &vector))
    2796           0 :         return false;
    2797             : 
    2798           0 :     f.iter().setResult(f.extractSimdElement(lane, vector,
    2799           0 :                                             ToMIRType(SimdToLaneType(operandType)), sign));
    2800           0 :     return true;
    2801             : }
    2802             : 
    2803             : // Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
    2804             : static MDefinition*
    2805           0 : EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition* i32)
    2806             : {
    2807             :     // Compute !i32 - 1 to force the value range into {0, -1}.
    2808           0 :     MDefinition* noti32 = f.unary<MNot>(i32);
    2809           0 :     return f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType::Int32), MIRType::Int32);
    2810             : }
    2811             : 
    2812             : static bool
    2813           0 : EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType)
    2814             : {
    2815           0 :     if (IsSimdBoolType(simdType))
    2816           0 :         f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult()));
    2817             : 
    2818             :     uint8_t lane;
    2819             :     MDefinition* vector;
    2820             :     MDefinition* scalar;
    2821           0 :     if (!f.iter().readReplaceLane(simdType, &lane, &vector, &scalar))
    2822           0 :         return false;
    2823             : 
    2824           0 :     f.iter().setResult(f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType)));
    2825           0 :     return true;
    2826             : }
    2827             : 
    2828             : inline bool
    2829           0 : EmitSimdBitcast(FunctionCompiler& f, ValType fromType, ValType toType)
    2830             : {
    2831             :     MDefinition* input;
    2832           0 :     if (!f.iter().readConversion(fromType, toType, &input))
    2833           0 :         return false;
    2834             : 
    2835           0 :     f.iter().setResult(f.bitcastSimd(input, ToMIRType(fromType), ToMIRType(toType)));
    2836           0 :     return true;
    2837             : }
    2838             : 
    2839             : inline bool
    2840           0 : EmitSimdConvert(FunctionCompiler& f, ValType fromType, ValType toType, SimdSign sign)
    2841             : {
    2842             :     MDefinition* input;
    2843           0 :     if (!f.iter().readConversion(fromType, toType, &input))
    2844           0 :         return false;
    2845             : 
    2846           0 :     f.iter().setResult(f.convertSimd(input, ToMIRType(fromType), ToMIRType(toType), sign));
    2847           0 :     return true;
    2848             : }
    2849             : 
    2850             : static bool
    2851           0 : EmitSimdSwizzle(FunctionCompiler& f, ValType simdType)
    2852             : {
    2853             :     uint8_t lanes[16];
    2854             :     MDefinition* vector;
    2855           0 :     if (!f.iter().readSwizzle(simdType, &lanes, &vector))
    2856           0 :         return false;
    2857             : 
    2858           0 :     f.iter().setResult(f.swizzleSimd(vector, lanes, ToMIRType(simdType)));
    2859           0 :     return true;
    2860             : }
    2861             : 
    2862             : static bool
    2863           0 : EmitSimdShuffle(FunctionCompiler& f, ValType simdType)
    2864             : {
    2865             :     uint8_t lanes[16];
    2866             :     MDefinition* lhs;
    2867             :     MDefinition* rhs;
    2868           0 :     if (!f.iter().readShuffle(simdType, &lanes, &lhs, &rhs))
    2869           0 :         return false;
    2870             : 
    2871           0 :     f.iter().setResult(f.shuffleSimd(lhs, rhs, lanes, ToMIRType(simdType)));
    2872           0 :     return true;
    2873             : }
    2874             : 
    2875             : static inline Scalar::Type
    2876           0 : SimdExprTypeToViewType(ValType type, unsigned* defaultNumElems)
    2877             : {
    2878           0 :     switch (type) {
    2879           0 :         case ValType::I8x16: *defaultNumElems = 16; return Scalar::Int8x16;
    2880           0 :         case ValType::I16x8: *defaultNumElems = 8; return Scalar::Int16x8;
    2881           0 :         case ValType::I32x4: *defaultNumElems = 4; return Scalar::Int32x4;
    2882           0 :         case ValType::F32x4: *defaultNumElems = 4; return Scalar::Float32x4;
    2883           0 :         default:              break;
    2884             :     }
    2885           0 :     MOZ_CRASH("type not handled in SimdExprTypeToViewType");
    2886             : }
    2887             : 
    2888             : static bool
    2889           0 : EmitSimdLoad(FunctionCompiler& f, ValType resultType, unsigned numElems)
    2890             : {
    2891             :     unsigned defaultNumElems;
    2892           0 :     Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems);
    2893             : 
    2894           0 :     if (!numElems)
    2895           0 :         numElems = defaultNumElems;
    2896             : 
    2897           0 :     LinearMemoryAddress<MDefinition*> addr;
    2898           0 :     if (!f.iter().readLoad(resultType, Scalar::byteSize(viewType), &addr))
    2899           0 :         return false;
    2900             : 
    2901           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), numElems);
    2902             : 
    2903           0 :     auto* ins = f.load(addr.base, &access, resultType);
    2904           0 :     if (!f.inDeadCode() && !ins)
    2905           0 :         return false;
    2906             : 
    2907           0 :     f.iter().setResult(ins);
    2908           0 :     return true;
    2909             : }
    2910             : 
    2911             : static bool
    2912           0 : EmitSimdStore(FunctionCompiler& f, ValType resultType, unsigned numElems)
    2913             : {
    2914             :     unsigned defaultNumElems;
    2915           0 :     Scalar::Type viewType = SimdExprTypeToViewType(resultType, &defaultNumElems);
    2916             : 
    2917           0 :     if (!numElems)
    2918           0 :         numElems = defaultNumElems;
    2919             : 
    2920           0 :     LinearMemoryAddress<MDefinition*> addr;
    2921             :     MDefinition* value;
    2922           0 :     if (!f.iter().readTeeStore(resultType, Scalar::byteSize(viewType), &addr, &value))
    2923           0 :         return false;
    2924             : 
    2925           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(f.bytecodeOffset()), numElems);
    2926             : 
    2927           0 :     return f.store(addr.base, &access, value);
    2928             : }
    2929             : 
    2930             : static bool
    2931           0 : EmitSimdSelect(FunctionCompiler& f, ValType simdType)
    2932             : {
    2933             :     MDefinition* trueValue;
    2934             :     MDefinition* falseValue;
    2935             :     MDefinition* condition;
    2936           0 :     if (!f.iter().readSimdSelect(simdType, &trueValue, &falseValue, &condition))
    2937           0 :         return false;
    2938             : 
    2939           0 :     f.iter().setResult(f.selectSimd(condition, trueValue, falseValue,
    2940           0 :                                     ToMIRType(simdType)));
    2941           0 :     return true;
    2942             : }
    2943             : 
    2944             : static bool
    2945           0 : EmitSimdAllTrue(FunctionCompiler& f, ValType operandType)
    2946             : {
    2947             :     MDefinition* input;
    2948           0 :     if (!f.iter().readSimdBooleanReduction(operandType, &input))
    2949           0 :         return false;
    2950             : 
    2951           0 :     f.iter().setResult(f.simdAllTrue(input));
    2952           0 :     return true;
    2953             : }
    2954             : 
    2955             : static bool
    2956           0 : EmitSimdAnyTrue(FunctionCompiler& f, ValType operandType)
    2957             : {
    2958             :     MDefinition* input;
    2959           0 :     if (!f.iter().readSimdBooleanReduction(operandType, &input))
    2960           0 :         return false;
    2961             : 
    2962           0 :     f.iter().setResult(f.simdAnyTrue(input));
    2963           0 :     return true;
    2964             : }
    2965             : 
    2966             : static bool
    2967           0 : EmitSimdSplat(FunctionCompiler& f, ValType simdType)
    2968             : {
    2969           0 :     if (IsSimdBoolType(simdType))
    2970           0 :         f.iter().setResult(EmitSimdBooleanLaneExpr(f, f.iter().getResult()));
    2971             : 
    2972             :     MDefinition* input;
    2973           0 :     if (!f.iter().readSplat(simdType, &input))
    2974           0 :         return false;
    2975             : 
    2976           0 :     f.iter().setResult(f.splatSimd(input, ToMIRType(simdType)));
    2977           0 :     return true;
    2978             : }
    2979             : 
    2980             : // Build a SIMD vector by inserting lanes one at a time into an initial constant.
    2981             : static bool
    2982           0 : EmitSimdChainedCtor(FunctionCompiler& f, ValType valType, MIRType type, const SimdConstant& init)
    2983             : {
    2984           0 :     const unsigned length = SimdTypeToLength(type);
    2985             : 
    2986           0 :     DefVector args;
    2987           0 :     if (!f.iter().readSimdCtor(ValType::I32, length, valType, &args))
    2988           0 :         return false;
    2989             : 
    2990           0 :     MDefinition* val = f.constant(init, type);
    2991           0 :     for (unsigned i = 0; i < length; i++)
    2992           0 :         val = f.insertElementSimd(val, args[i], i, type);
    2993             : 
    2994           0 :     f.iter().setResult(val);
    2995           0 :     return true;
    2996             : }
    2997             : 
    2998             : // Build a boolean SIMD vector by inserting lanes one at a time into an initial constant.
    2999             : static bool
    3000           0 : EmitSimdBooleanChainedCtor(FunctionCompiler& f, ValType valType, MIRType type,
    3001             :                            const SimdConstant& init)
    3002             : {
    3003           0 :     const unsigned length = SimdTypeToLength(type);
    3004             : 
    3005           0 :     DefVector args;
    3006           0 :     if (!f.iter().readSimdCtor(ValType::I32, length, valType, &args))
    3007           0 :         return false;
    3008             : 
    3009           0 :     MDefinition* val = f.constant(init, type);
    3010           0 :     for (unsigned i = 0; i < length; i++)
    3011           0 :         val = f.insertElementSimd(val, EmitSimdBooleanLaneExpr(f, args[i]), i, type);
    3012             : 
    3013           0 :     f.iter().setResult(val);
    3014           0 :     return true;
    3015             : }
    3016             : 
    3017             : static bool
    3018           0 : EmitSimdCtor(FunctionCompiler& f, ValType type)
    3019             : {
    3020           0 :     switch (type) {
    3021             :       case ValType::I8x16:
    3022           0 :         return EmitSimdChainedCtor(f, type, MIRType::Int8x16, SimdConstant::SplatX16(0));
    3023             :       case ValType::I16x8:
    3024           0 :         return EmitSimdChainedCtor(f, type, MIRType::Int16x8, SimdConstant::SplatX8(0));
    3025             :       case ValType::I32x4: {
    3026           0 :         DefVector args;
    3027           0 :         if (!f.iter().readSimdCtor(ValType::I32, 4, type, &args))
    3028           0 :             return false;
    3029             : 
    3030           0 :         f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
    3031           0 :                                                          MIRType::Int32x4));
    3032           0 :         return true;
    3033             :       }
    3034             :       case ValType::F32x4: {
    3035           0 :         DefVector args;
    3036           0 :         if (!f.iter().readSimdCtor(ValType::F32, 4, type, &args))
    3037           0 :             return false;
    3038             : 
    3039           0 :         f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
    3040           0 :                            MIRType::Float32x4));
    3041           0 :         return true;
    3042             :       }
    3043             :       case ValType::B8x16:
    3044           0 :         return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool8x16, SimdConstant::SplatX16(0));
    3045             :       case ValType::B16x8:
    3046           0 :         return EmitSimdBooleanChainedCtor(f, type, MIRType::Bool16x8, SimdConstant::SplatX8(0));
    3047             :       case ValType::B32x4: {
    3048           0 :         DefVector args;
    3049           0 :         if (!f.iter().readSimdCtor(ValType::I32, 4, type, &args))
    3050           0 :             return false;
    3051             : 
    3052           0 :         MOZ_ASSERT(args.length() == 4);
    3053           0 :         for (unsigned i = 0; i < 4; i++)
    3054           0 :             args[i] = EmitSimdBooleanLaneExpr(f, args[i]);
    3055             : 
    3056           0 :         f.iter().setResult(f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3],
    3057           0 :                            MIRType::Bool32x4));
    3058           0 :         return true;
    3059             :       }
    3060             :       case ValType::I32:
    3061             :       case ValType::I64:
    3062             :       case ValType::F32:
    3063             :       case ValType::F64:
    3064           0 :         break;
    3065             :     }
    3066           0 :     MOZ_CRASH("unexpected SIMD type");
    3067             : }
    3068             : 
    3069             : static bool
    3070           0 : EmitSimdOp(FunctionCompiler& f, ValType type, SimdOperation op, SimdSign sign)
    3071             : {
    3072           0 :     switch (op) {
    3073             :       case SimdOperation::Constructor:
    3074           0 :         return EmitSimdCtor(f, type);
    3075             :       case SimdOperation::Fn_extractLane:
    3076           0 :         return EmitExtractLane(f, type, sign);
    3077             :       case SimdOperation::Fn_replaceLane:
    3078           0 :         return EmitSimdReplaceLane(f, type);
    3079             :       case SimdOperation::Fn_check:
    3080           0 :         MOZ_CRASH("only used in asm.js' type system");
    3081             :       case SimdOperation::Fn_splat:
    3082           0 :         return EmitSimdSplat(f, type);
    3083             :       case SimdOperation::Fn_select:
    3084           0 :         return EmitSimdSelect(f, type);
    3085             :       case SimdOperation::Fn_swizzle:
    3086           0 :         return EmitSimdSwizzle(f, type);
    3087             :       case SimdOperation::Fn_shuffle:
    3088           0 :         return EmitSimdShuffle(f, type);
    3089             :       case SimdOperation::Fn_load:
    3090           0 :         return EmitSimdLoad(f, type, 0);
    3091             :       case SimdOperation::Fn_load1:
    3092           0 :         return EmitSimdLoad(f, type, 1);
    3093             :       case SimdOperation::Fn_load2:
    3094           0 :         return EmitSimdLoad(f, type, 2);
    3095             :       case SimdOperation::Fn_store:
    3096           0 :         return EmitSimdStore(f, type, 0);
    3097             :       case SimdOperation::Fn_store1:
    3098           0 :         return EmitSimdStore(f, type, 1);
    3099             :       case SimdOperation::Fn_store2:
    3100           0 :         return EmitSimdStore(f, type, 2);
    3101             :       case SimdOperation::Fn_allTrue:
    3102           0 :         return EmitSimdAllTrue(f, type);
    3103             :       case SimdOperation::Fn_anyTrue:
    3104           0 :         return EmitSimdAnyTrue(f, type);
    3105             :       case SimdOperation::Fn_abs:
    3106             :       case SimdOperation::Fn_neg:
    3107             :       case SimdOperation::Fn_not:
    3108             :       case SimdOperation::Fn_sqrt:
    3109             :       case SimdOperation::Fn_reciprocalApproximation:
    3110             :       case SimdOperation::Fn_reciprocalSqrtApproximation:
    3111           0 :         return EmitSimdUnary(f, type, op);
    3112             :       case SimdOperation::Fn_shiftLeftByScalar:
    3113           0 :         return EmitSimdShift(f, type, MSimdShift::lsh);
    3114             :       case SimdOperation::Fn_shiftRightByScalar:
    3115           0 :         return EmitSimdShift(f, type, MSimdShift::rshForSign(sign));
    3116             : #define _CASE(OP) \
    3117             :       case SimdOperation::Fn_##OP: \
    3118             :         return EmitSimdBinaryComp(f, type, MSimdBinaryComp::OP, sign);
    3119           0 :         FOREACH_COMP_SIMD_OP(_CASE)
    3120             : #undef _CASE
    3121             :       case SimdOperation::Fn_and:
    3122           0 :         return EmitSimdBinary(f, type, MSimdBinaryBitwise::and_);
    3123             :       case SimdOperation::Fn_or:
    3124           0 :         return EmitSimdBinary(f, type, MSimdBinaryBitwise::or_);
    3125             :       case SimdOperation::Fn_xor:
    3126           0 :         return EmitSimdBinary(f, type, MSimdBinaryBitwise::xor_);
    3127             : #define _CASE(OP) \
    3128             :       case SimdOperation::Fn_##OP: \
    3129             :         return EmitSimdBinary(f, type, MSimdBinaryArith::Op_##OP);
    3130           0 :       FOREACH_NUMERIC_SIMD_BINOP(_CASE)
    3131           0 :       FOREACH_FLOAT_SIMD_BINOP(_CASE)
    3132             : #undef _CASE
    3133             :       case SimdOperation::Fn_addSaturate:
    3134           0 :         return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::add, sign);
    3135             :       case SimdOperation::Fn_subSaturate:
    3136           0 :         return EmitSimdBinarySaturating(f, type, MSimdBinarySaturating::sub, sign);
    3137             :       case SimdOperation::Fn_fromFloat32x4:
    3138           0 :         return EmitSimdConvert(f, ValType::F32x4, type, sign);
    3139             :       case SimdOperation::Fn_fromInt32x4:
    3140           0 :         return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Signed);
    3141             :       case SimdOperation::Fn_fromUint32x4:
    3142           0 :         return EmitSimdConvert(f, ValType::I32x4, type, SimdSign::Unsigned);
    3143             :       case SimdOperation::Fn_fromInt8x16Bits:
    3144             :       case SimdOperation::Fn_fromUint8x16Bits:
    3145           0 :         return EmitSimdBitcast(f, ValType::I8x16, type);
    3146             :       case SimdOperation::Fn_fromUint16x8Bits:
    3147             :       case SimdOperation::Fn_fromInt16x8Bits:
    3148           0 :         return EmitSimdBitcast(f, ValType::I16x8, type);
    3149             :       case SimdOperation::Fn_fromInt32x4Bits:
    3150             :       case SimdOperation::Fn_fromUint32x4Bits:
    3151           0 :         return EmitSimdBitcast(f, ValType::I32x4, type);
    3152             :       case SimdOperation::Fn_fromFloat32x4Bits:
    3153           0 :         return EmitSimdBitcast(f, ValType::F32x4, type);
    3154             :       case SimdOperation::Fn_load3:
    3155             :       case SimdOperation::Fn_store3:
    3156             :       case SimdOperation::Fn_fromFloat64x2Bits:
    3157           0 :         MOZ_CRASH("NYI");
    3158             :     }
    3159           0 :     MOZ_CRASH("unexpected opcode");
    3160             : }
    3161             : 
    3162             : static bool
    3163           0 : EmitGrowMemory(FunctionCompiler& f)
    3164             : {
    3165           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    3166             : 
    3167           0 :     CallCompileState args(f, lineOrBytecode);
    3168           0 :     if (!f.startCall(&args))
    3169           0 :         return false;
    3170             : 
    3171           0 :     if (!f.passInstance(&args))
    3172           0 :         return false;
    3173             : 
    3174             :     MDefinition* delta;
    3175           0 :     if (!f.iter().readGrowMemory(&delta))
    3176           0 :         return false;
    3177             : 
    3178           0 :     if (!f.passArg(delta, ValType::I32, &args))
    3179           0 :         return false;
    3180             : 
    3181           0 :     f.finishCall(&args);
    3182             : 
    3183             :     MDefinition* ret;
    3184           0 :     if (!f.builtinInstanceMethodCall(SymbolicAddress::GrowMemory, args, ValType::I32, &ret))
    3185           0 :         return false;
    3186             : 
    3187           0 :     f.iter().setResult(ret);
    3188           0 :     return true;
    3189             : }
    3190             : 
    3191             : static bool
    3192           0 : EmitCurrentMemory(FunctionCompiler& f)
    3193             : {
    3194           0 :     uint32_t lineOrBytecode = f.readCallSiteLineOrBytecode();
    3195             : 
    3196           0 :     CallCompileState args(f, lineOrBytecode);
    3197             : 
    3198           0 :     if (!f.iter().readCurrentMemory())
    3199           0 :         return false;
    3200             : 
    3201           0 :     if (!f.startCall(&args))
    3202           0 :         return false;
    3203             : 
    3204           0 :     if (!f.passInstance(&args))
    3205           0 :         return false;
    3206             : 
    3207           0 :     f.finishCall(&args);
    3208             : 
    3209             :     MDefinition* ret;
    3210           0 :     if (!f.builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, args, ValType::I32, &ret))
    3211           0 :         return false;
    3212             : 
    3213           0 :     f.iter().setResult(ret);
    3214           0 :     return true;
    3215             : }
    3216             : 
    3217             : static bool
    3218           0 : EmitBodyExprs(FunctionCompiler& f)
    3219             : {
    3220           0 :     if (!f.iter().readFunctionStart(f.sig().ret()))
    3221           0 :         return false;
    3222             : 
    3223             : #define CHECK(c)                                                              \
    3224             :     if (!(c))                                                                 \
    3225             :         return false;                                                         \
    3226             :     break
    3227             : 
    3228             : #define CHECK_ASMJS(c)                                                        \
    3229             :     if (!f.env().isAsmJS())                                                   \
    3230             :         return f.iter().unrecognizedOpcode(&op);                              \
    3231             :     if (!(c))                                                                 \
    3232             :         return false;                                                         \
    3233             :     break
    3234             : 
    3235             :     while (true) {
    3236           0 :         if (!f.mirGen().ensureBallast())
    3237           0 :             return false;
    3238             : 
    3239           0 :         OpBytes op;
    3240           0 :         if (!f.iter().readOp(&op))
    3241           0 :             return false;
    3242             : 
    3243           0 :         switch (op.b0) {
    3244             :           case uint16_t(Op::End):
    3245           0 :             if (!EmitEnd(f))
    3246           0 :                 return false;
    3247             : 
    3248           0 :             if (f.iter().controlStackEmpty()) {
    3249           0 :                 if (f.inDeadCode() || IsVoid(f.sig().ret()))
    3250           0 :                     f.returnVoid();
    3251             :                 else
    3252           0 :                     f.returnExpr(f.iter().getResult());
    3253           0 :                 return f.iter().readFunctionEnd(f.iter().end());
    3254             :             }
    3255           0 :             break;
    3256             : 
    3257             :           // Control opcodes
    3258             :           case uint16_t(Op::Unreachable):
    3259           0 :             CHECK(EmitUnreachable(f));
    3260             :           case uint16_t(Op::Nop):
    3261           0 :             CHECK(f.iter().readNop());
    3262             :           case uint16_t(Op::Block):
    3263           0 :             CHECK(EmitBlock(f));
    3264             :           case uint16_t(Op::Loop):
    3265           0 :             CHECK(EmitLoop(f));
    3266             :           case uint16_t(Op::If):
    3267           0 :             CHECK(EmitIf(f));
    3268             :           case uint16_t(Op::Else):
    3269           0 :             CHECK(EmitElse(f));
    3270             :           case uint16_t(Op::Br):
    3271           0 :             CHECK(EmitBr(f));
    3272             :           case uint16_t(Op::BrIf):
    3273           0 :             CHECK(EmitBrIf(f));
    3274             :           case uint16_t(Op::BrTable):
    3275           0 :             CHECK(EmitBrTable(f));
    3276             :           case uint16_t(Op::Return):
    3277           0 :             CHECK(EmitReturn(f));
    3278             : 
    3279             :           // Calls
    3280             :           case uint16_t(Op::Call):
    3281           0 :             CHECK(EmitCall(f));
    3282             :           case uint16_t(Op::CallIndirect):
    3283           0 :             CHECK(EmitCallIndirect(f, /* oldStyle = */ false));
    3284             : 
    3285             :           // Parametric operators
    3286             :           case uint16_t(Op::Drop):
    3287           0 :             CHECK(f.iter().readDrop());
    3288             :           case uint16_t(Op::Select):
    3289           0 :             CHECK(EmitSelect(f));
    3290             : 
    3291             :           // Locals and globals
    3292             :           case uint16_t(Op::GetLocal):
    3293           0 :             CHECK(EmitGetLocal(f));
    3294             :           case uint16_t(Op::SetLocal):
    3295           0 :             CHECK(EmitSetLocal(f));
    3296             :           case uint16_t(Op::TeeLocal):
    3297           0 :             CHECK(EmitTeeLocal(f));
    3298             :           case uint16_t(Op::GetGlobal):
    3299           0 :             CHECK(EmitGetGlobal(f));
    3300             :           case uint16_t(Op::SetGlobal):
    3301           0 :             CHECK(EmitSetGlobal(f));
    3302             : 
    3303             :           // Memory-related operators
    3304             :           case uint16_t(Op::I32Load):
    3305           0 :             CHECK(EmitLoad(f, ValType::I32, Scalar::Int32));
    3306             :           case uint16_t(Op::I64Load):
    3307           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Int64));
    3308             :           case uint16_t(Op::F32Load):
    3309           0 :             CHECK(EmitLoad(f, ValType::F32, Scalar::Float32));
    3310             :           case uint16_t(Op::F64Load):
    3311           0 :             CHECK(EmitLoad(f, ValType::F64, Scalar::Float64));
    3312             :           case uint16_t(Op::I32Load8S):
    3313           0 :             CHECK(EmitLoad(f, ValType::I32, Scalar::Int8));
    3314             :           case uint16_t(Op::I32Load8U):
    3315           0 :             CHECK(EmitLoad(f, ValType::I32, Scalar::Uint8));
    3316             :           case uint16_t(Op::I32Load16S):
    3317           0 :             CHECK(EmitLoad(f, ValType::I32, Scalar::Int16));
    3318             :           case uint16_t(Op::I32Load16U):
    3319           0 :             CHECK(EmitLoad(f, ValType::I32, Scalar::Uint16));
    3320             :           case uint16_t(Op::I64Load8S):
    3321           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Int8));
    3322             :           case uint16_t(Op::I64Load8U):
    3323           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Uint8));
    3324             :           case uint16_t(Op::I64Load16S):
    3325           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Int16));
    3326             :           case uint16_t(Op::I64Load16U):
    3327           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Uint16));
    3328             :           case uint16_t(Op::I64Load32S):
    3329           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Int32));
    3330             :           case uint16_t(Op::I64Load32U):
    3331           0 :             CHECK(EmitLoad(f, ValType::I64, Scalar::Uint32));
    3332             :           case uint16_t(Op::I32Store):
    3333           0 :             CHECK(EmitStore(f, ValType::I32, Scalar::Int32));
    3334             :           case uint16_t(Op::I64Store):
    3335           0 :             CHECK(EmitStore(f, ValType::I64, Scalar::Int64));
    3336             :           case uint16_t(Op::F32Store):
    3337           0 :             CHECK(EmitStore(f, ValType::F32, Scalar::Float32));
    3338             :           case uint16_t(Op::F64Store):
    3339           0 :             CHECK(EmitStore(f, ValType::F64, Scalar::Float64));
    3340             :           case uint16_t(Op::I32Store8):
    3341           0 :             CHECK(EmitStore(f, ValType::I32, Scalar::Int8));
    3342             :           case uint16_t(Op::I32Store16):
    3343           0 :             CHECK(EmitStore(f, ValType::I32, Scalar::Int16));
    3344             :           case uint16_t(Op::I64Store8):
    3345           0 :             CHECK(EmitStore(f, ValType::I64, Scalar::Int8));
    3346             :           case uint16_t(Op::I64Store16):
    3347           0 :             CHECK(EmitStore(f, ValType::I64, Scalar::Int16));
    3348             :           case uint16_t(Op::I64Store32):
    3349           0 :             CHECK(EmitStore(f, ValType::I64, Scalar::Int32));
    3350             :           case uint16_t(Op::CurrentMemory):
    3351           0 :             CHECK(EmitCurrentMemory(f));
    3352             :           case uint16_t(Op::GrowMemory):
    3353           0 :             CHECK(EmitGrowMemory(f));
    3354             : 
    3355             :           // Constants
    3356             :           case uint16_t(Op::I32Const):
    3357           0 :             CHECK(EmitI32Const(f));
    3358             :           case uint16_t(Op::I64Const):
    3359           0 :             CHECK(EmitI64Const(f));
    3360             :           case uint16_t(Op::F32Const):
    3361           0 :             CHECK(EmitF32Const(f));
    3362             :           case uint16_t(Op::F64Const):
    3363           0 :             CHECK(EmitF64Const(f));
    3364             : 
    3365             :           // Comparison operators
    3366             :           case uint16_t(Op::I32Eqz):
    3367           0 :             CHECK(EmitConversion<MNot>(f, ValType::I32, ValType::I32));
    3368             :           case uint16_t(Op::I32Eq):
    3369           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_EQ, MCompare::Compare_Int32));
    3370             :           case uint16_t(Op::I32Ne):
    3371           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_NE, MCompare::Compare_Int32));
    3372             :           case uint16_t(Op::I32LtS):
    3373           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_Int32));
    3374             :           case uint16_t(Op::I32LtU):
    3375           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_LT, MCompare::Compare_UInt32));
    3376             :           case uint16_t(Op::I32GtS):
    3377           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_Int32));
    3378             :           case uint16_t(Op::I32GtU):
    3379           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_GT, MCompare::Compare_UInt32));
    3380             :           case uint16_t(Op::I32LeS):
    3381           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_Int32));
    3382             :           case uint16_t(Op::I32LeU):
    3383           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_LE, MCompare::Compare_UInt32));
    3384             :           case uint16_t(Op::I32GeS):
    3385           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_Int32));
    3386             :           case uint16_t(Op::I32GeU):
    3387           0 :             CHECK(EmitComparison(f, ValType::I32, JSOP_GE, MCompare::Compare_UInt32));
    3388             :           case uint16_t(Op::I64Eqz):
    3389           0 :             CHECK(EmitConversion<MNot>(f, ValType::I64, ValType::I32));
    3390             :           case uint16_t(Op::I64Eq):
    3391           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_EQ, MCompare::Compare_Int64));
    3392             :           case uint16_t(Op::I64Ne):
    3393           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_NE, MCompare::Compare_Int64));
    3394             :           case uint16_t(Op::I64LtS):
    3395           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_Int64));
    3396             :           case uint16_t(Op::I64LtU):
    3397           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_LT, MCompare::Compare_UInt64));
    3398             :           case uint16_t(Op::I64GtS):
    3399           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_Int64));
    3400             :           case uint16_t(Op::I64GtU):
    3401           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_GT, MCompare::Compare_UInt64));
    3402             :           case uint16_t(Op::I64LeS):
    3403           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_Int64));
    3404             :           case uint16_t(Op::I64LeU):
    3405           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_LE, MCompare::Compare_UInt64));
    3406             :           case uint16_t(Op::I64GeS):
    3407           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_Int64));
    3408             :           case uint16_t(Op::I64GeU):
    3409           0 :             CHECK(EmitComparison(f, ValType::I64, JSOP_GE, MCompare::Compare_UInt64));
    3410             :           case uint16_t(Op::F32Eq):
    3411           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_EQ, MCompare::Compare_Float32));
    3412             :           case uint16_t(Op::F32Ne):
    3413           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_NE, MCompare::Compare_Float32));
    3414             :           case uint16_t(Op::F32Lt):
    3415           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_LT, MCompare::Compare_Float32));
    3416             :           case uint16_t(Op::F32Gt):
    3417           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_GT, MCompare::Compare_Float32));
    3418             :           case uint16_t(Op::F32Le):
    3419           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_LE, MCompare::Compare_Float32));
    3420             :           case uint16_t(Op::F32Ge):
    3421           0 :             CHECK(EmitComparison(f, ValType::F32, JSOP_GE, MCompare::Compare_Float32));
    3422             :           case uint16_t(Op::F64Eq):
    3423           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_EQ, MCompare::Compare_Double));
    3424             :           case uint16_t(Op::F64Ne):
    3425           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_NE, MCompare::Compare_Double));
    3426             :           case uint16_t(Op::F64Lt):
    3427           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_LT, MCompare::Compare_Double));
    3428             :           case uint16_t(Op::F64Gt):
    3429           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_GT, MCompare::Compare_Double));
    3430             :           case uint16_t(Op::F64Le):
    3431           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_LE, MCompare::Compare_Double));
    3432             :           case uint16_t(Op::F64Ge):
    3433           0 :             CHECK(EmitComparison(f, ValType::F64, JSOP_GE, MCompare::Compare_Double));
    3434             : 
    3435             :           // Numeric operators
    3436             :           case uint16_t(Op::I32Clz):
    3437           0 :             CHECK(EmitUnaryWithType<MClz>(f, ValType::I32, MIRType::Int32));
    3438             :           case uint16_t(Op::I32Ctz):
    3439           0 :             CHECK(EmitUnaryWithType<MCtz>(f, ValType::I32, MIRType::Int32));
    3440             :           case uint16_t(Op::I32Popcnt):
    3441           0 :             CHECK(EmitUnaryWithType<MPopcnt>(f, ValType::I32, MIRType::Int32));
    3442             :           case uint16_t(Op::I32Add):
    3443           0 :             CHECK(EmitAdd(f, ValType::I32, MIRType::Int32));
    3444             :           case uint16_t(Op::I32Sub):
    3445           0 :             CHECK(EmitSub(f, ValType::I32, MIRType::Int32));
    3446             :           case uint16_t(Op::I32Mul):
    3447           0 :             CHECK(EmitMul(f, ValType::I32, MIRType::Int32));
    3448             :           case uint16_t(Op::I32DivS):
    3449             :           case uint16_t(Op::I32DivU):
    3450           0 :             CHECK(EmitDiv(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32DivU));
    3451             :           case uint16_t(Op::I32RemS):
    3452             :           case uint16_t(Op::I32RemU):
    3453           0 :             CHECK(EmitRem(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32RemU));
    3454             :           case uint16_t(Op::I32And):
    3455           0 :             CHECK(EmitBitwise<MBitAnd>(f, ValType::I32, MIRType::Int32));
    3456             :           case uint16_t(Op::I32Or):
    3457           0 :             CHECK(EmitBitwise<MBitOr>(f, ValType::I32, MIRType::Int32));
    3458             :           case uint16_t(Op::I32Xor):
    3459           0 :             CHECK(EmitBitwise<MBitXor>(f, ValType::I32, MIRType::Int32));
    3460             :           case uint16_t(Op::I32Shl):
    3461           0 :             CHECK(EmitBitwise<MLsh>(f, ValType::I32, MIRType::Int32));
    3462             :           case uint16_t(Op::I32ShrS):
    3463           0 :             CHECK(EmitBitwise<MRsh>(f, ValType::I32, MIRType::Int32));
    3464             :           case uint16_t(Op::I32ShrU):
    3465           0 :             CHECK(EmitBitwise<MUrsh>(f, ValType::I32, MIRType::Int32));
    3466             :           case uint16_t(Op::I32Rotl):
    3467             :           case uint16_t(Op::I32Rotr):
    3468           0 :             CHECK(EmitRotate(f, ValType::I32, Op(op.b0) == Op::I32Rotl));
    3469             :           case uint16_t(Op::I64Clz):
    3470           0 :             CHECK(EmitUnaryWithType<MClz>(f, ValType::I64, MIRType::Int64));
    3471             :           case uint16_t(Op::I64Ctz):
    3472           0 :             CHECK(EmitUnaryWithType<MCtz>(f, ValType::I64, MIRType::Int64));
    3473             :           case uint16_t(Op::I64Popcnt):
    3474           0 :             CHECK(EmitUnaryWithType<MPopcnt>(f, ValType::I64, MIRType::Int64));
    3475             :           case uint16_t(Op::I64Add):
    3476           0 :             CHECK(EmitAdd(f, ValType::I64, MIRType::Int64));
    3477             :           case uint16_t(Op::I64Sub):
    3478           0 :             CHECK(EmitSub(f, ValType::I64, MIRType::Int64));
    3479             :           case uint16_t(Op::I64Mul):
    3480           0 :             CHECK(EmitMul(f, ValType::I64, MIRType::Int64));
    3481             :           case uint16_t(Op::I64DivS):
    3482             :           case uint16_t(Op::I64DivU):
    3483           0 :             CHECK(EmitDiv(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64DivU));
    3484             :           case uint16_t(Op::I64RemS):
    3485             :           case uint16_t(Op::I64RemU):
    3486           0 :             CHECK(EmitRem(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64RemU));
    3487             :           case uint16_t(Op::I64And):
    3488           0 :             CHECK(EmitBitwise<MBitAnd>(f, ValType::I64, MIRType::Int64));
    3489             :           case uint16_t(Op::I64Or):
    3490           0 :             CHECK(EmitBitwise<MBitOr>(f, ValType::I64, MIRType::Int64));
    3491             :           case uint16_t(Op::I64Xor):
    3492           0 :             CHECK(EmitBitwise<MBitXor>(f, ValType::I64, MIRType::Int64));
    3493             :           case uint16_t(Op::I64Shl):
    3494           0 :             CHECK(EmitBitwise<MLsh>(f, ValType::I64, MIRType::Int64));
    3495             :           case uint16_t(Op::I64ShrS):
    3496           0 :             CHECK(EmitBitwise<MRsh>(f, ValType::I64, MIRType::Int64));
    3497             :           case uint16_t(Op::I64ShrU):
    3498           0 :             CHECK(EmitBitwise<MUrsh>(f, ValType::I64, MIRType::Int64));
    3499             :           case uint16_t(Op::I64Rotl):
    3500             :           case uint16_t(Op::I64Rotr):
    3501           0 :             CHECK(EmitRotate(f, ValType::I64, Op(op.b0) == Op::I64Rotl));
    3502             :           case uint16_t(Op::F32Abs):
    3503           0 :             CHECK(EmitUnaryWithType<MAbs>(f, ValType::F32, MIRType::Float32));
    3504             :           case uint16_t(Op::F32Neg):
    3505           0 :             CHECK(EmitUnaryWithType<MWasmNeg>(f, ValType::F32, MIRType::Float32));
    3506             :           case uint16_t(Op::F32Ceil):
    3507           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CeilF, ValType::F32));
    3508             :           case uint16_t(Op::F32Floor):
    3509           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::FloorF, ValType::F32));
    3510             :           case uint16_t(Op::F32Trunc):
    3511           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TruncF, ValType::F32));
    3512             :           case uint16_t(Op::F32Nearest):
    3513           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::NearbyIntF, ValType::F32));
    3514             :           case uint16_t(Op::F32Sqrt):
    3515           0 :             CHECK(EmitUnaryWithType<MSqrt>(f, ValType::F32, MIRType::Float32));
    3516             :           case uint16_t(Op::F32Add):
    3517           0 :             CHECK(EmitAdd(f, ValType::F32, MIRType::Float32));
    3518             :           case uint16_t(Op::F32Sub):
    3519           0 :             CHECK(EmitSub(f, ValType::F32, MIRType::Float32));
    3520             :           case uint16_t(Op::F32Mul):
    3521           0 :             CHECK(EmitMul(f, ValType::F32, MIRType::Float32));
    3522             :           case uint16_t(Op::F32Div):
    3523           0 :             CHECK(EmitDiv(f, ValType::F32, MIRType::Float32, /* isUnsigned = */ false));
    3524             :           case uint16_t(Op::F32Min):
    3525             :           case uint16_t(Op::F32Max):
    3526           0 :             CHECK(EmitMinMax(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32Max));
    3527             :           case uint16_t(Op::F32CopySign):
    3528           0 :             CHECK(EmitCopySign(f, ValType::F32));
    3529             :           case uint16_t(Op::F64Abs):
    3530           0 :             CHECK(EmitUnaryWithType<MAbs>(f, ValType::F64, MIRType::Double));
    3531             :           case uint16_t(Op::F64Neg):
    3532           0 :             CHECK(EmitUnaryWithType<MWasmNeg>(f, ValType::F64, MIRType::Double));
    3533             :           case uint16_t(Op::F64Ceil):
    3534           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CeilD, ValType::F64));
    3535             :           case uint16_t(Op::F64Floor):
    3536           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::FloorD, ValType::F64));
    3537             :           case uint16_t(Op::F64Trunc):
    3538           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TruncD, ValType::F64));
    3539             :           case uint16_t(Op::F64Nearest):
    3540           0 :             CHECK(EmitUnaryMathBuiltinCall(f, SymbolicAddress::NearbyIntD, ValType::F64));
    3541             :           case uint16_t(Op::F64Sqrt):
    3542           0 :             CHECK(EmitUnaryWithType<MSqrt>(f, ValType::F64, MIRType::Double));
    3543             :           case uint16_t(Op::F64Add):
    3544           0 :             CHECK(EmitAdd(f, ValType::F64, MIRType::Double));
    3545             :           case uint16_t(Op::F64Sub):
    3546           0 :             CHECK(EmitSub(f, ValType::F64, MIRType::Double));
    3547             :           case uint16_t(Op::F64Mul):
    3548           0 :             CHECK(EmitMul(f, ValType::F64, MIRType::Double));
    3549             :           case uint16_t(Op::F64Div):
    3550           0 :             CHECK(EmitDiv(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false));
    3551             :           case uint16_t(Op::F64Min):
    3552             :           case uint16_t(Op::F64Max):
    3553           0 :             CHECK(EmitMinMax(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64Max));
    3554             :           case uint16_t(Op::F64CopySign):
    3555           0 :             CHECK(EmitCopySign(f, ValType::F64));
    3556             : 
    3557             :           // Conversions
    3558             :           case uint16_t(Op::I32WrapI64):
    3559           0 :             CHECK(EmitConversion<MWrapInt64ToInt32>(f, ValType::I64, ValType::I32));
    3560             :           case uint16_t(Op::I32TruncSF32):
    3561             :           case uint16_t(Op::I32TruncUF32):
    3562           0 :             CHECK(EmitTruncate(f, ValType::F32, ValType::I32, Op(op.b0) == Op::I32TruncUF32));
    3563             :           case uint16_t(Op::I32TruncSF64):
    3564             :           case uint16_t(Op::I32TruncUF64):
    3565           0 :             CHECK(EmitTruncate(f, ValType::F64, ValType::I32, Op(op.b0) == Op::I32TruncUF64));
    3566             :           case uint16_t(Op::I64ExtendSI32):
    3567             :           case uint16_t(Op::I64ExtendUI32):
    3568           0 :             CHECK(EmitExtendI32(f, Op(op.b0) == Op::I64ExtendUI32));
    3569             :           case uint16_t(Op::I64TruncSF32):
    3570             :           case uint16_t(Op::I64TruncUF32):
    3571           0 :             CHECK(EmitTruncate(f, ValType::F32, ValType::I64, Op(op.b0) == Op::I64TruncUF32));
    3572             :           case uint16_t(Op::I64TruncSF64):
    3573             :           case uint16_t(Op::I64TruncUF64):
    3574           0 :             CHECK(EmitTruncate(f, ValType::F64, ValType::I64, Op(op.b0) == Op::I64TruncUF64));
    3575             :           case uint16_t(Op::F32ConvertSI32):
    3576           0 :             CHECK(EmitConversion<MToFloat32>(f, ValType::I32, ValType::F32));
    3577             :           case uint16_t(Op::F32ConvertUI32):
    3578           0 :             CHECK(EmitConversion<MWasmUnsignedToFloat32>(f, ValType::I32, ValType::F32));
    3579             :           case uint16_t(Op::F32ConvertSI64):
    3580             :           case uint16_t(Op::F32ConvertUI64):
    3581           0 :             CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32ConvertUI64));
    3582             :           case uint16_t(Op::F32DemoteF64):
    3583           0 :             CHECK(EmitConversion<MToFloat32>(f, ValType::F64, ValType::F32));
    3584             :           case uint16_t(Op::F64ConvertSI32):
    3585           0 :             CHECK(EmitConversion<MToDouble>(f, ValType::I32, ValType::F64));
    3586             :           case uint16_t(Op::F64ConvertUI32):
    3587           0 :             CHECK(EmitConversion<MWasmUnsignedToDouble>(f, ValType::I32, ValType::F64));
    3588             :           case uint16_t(Op::F64ConvertSI64):
    3589             :           case uint16_t(Op::F64ConvertUI64):
    3590           0 :             CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64ConvertUI64));
    3591             :           case uint16_t(Op::F64PromoteF32):
    3592           0 :             CHECK(EmitConversion<MToDouble>(f, ValType::F32, ValType::F64));
    3593             : 
    3594             :           // Reinterpretations
    3595             :           case uint16_t(Op::I32ReinterpretF32):
    3596           0 :             CHECK(EmitReinterpret(f, ValType::I32, ValType::F32, MIRType::Int32));
    3597             :           case uint16_t(Op::I64ReinterpretF64):
    3598           0 :             CHECK(EmitReinterpret(f, ValType::I64, ValType::F64, MIRType::Int64));
    3599             :           case uint16_t(Op::F32ReinterpretI32):
    3600           0 :             CHECK(EmitReinterpret(f, ValType::F32, ValType::I32, MIRType::Float32));
    3601             :           case uint16_t(Op::F64ReinterpretI64):
    3602           0 :             CHECK(EmitReinterpret(f, ValType::F64, ValType::I64, MIRType::Double));
    3603             : 
    3604             :           // asm.js-specific operators
    3605             : 
    3606             :           case uint16_t(Op::MozPrefix): {
    3607           0 :             switch (op.b1) {
    3608             :               case uint16_t(MozOp::TeeGlobal):
    3609           0 :                 CHECK_ASMJS(EmitTeeGlobal(f));
    3610             :               case uint16_t(MozOp::I32Min):
    3611             :               case uint16_t(MozOp::I32Max):
    3612           0 :                 CHECK_ASMJS(EmitMinMax(f, ValType::I32, MIRType::Int32, MozOp(op.b1) == MozOp::I32Max));
    3613             :               case uint16_t(MozOp::I32Neg):
    3614           0 :                 CHECK_ASMJS(EmitUnaryWithType<MWasmNeg>(f, ValType::I32, MIRType::Int32));
    3615             :               case uint16_t(MozOp::I32BitNot):
    3616           0 :                 CHECK_ASMJS(EmitBitNot(f, ValType::I32));
    3617             :               case uint16_t(MozOp::I32Abs):
    3618           0 :                 CHECK_ASMJS(EmitUnaryWithType<MAbs>(f, ValType::I32, MIRType::Int32));
    3619             :               case uint16_t(MozOp::F32TeeStoreF64):
    3620           0 :                 CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F32, Scalar::Float64));
    3621             :               case uint16_t(MozOp::F64TeeStoreF32):
    3622           0 :                 CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F64, Scalar::Float32));
    3623             :               case uint16_t(MozOp::I32TeeStore8):
    3624           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int8));
    3625             :               case uint16_t(MozOp::I32TeeStore16):
    3626           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int16));
    3627             :               case uint16_t(MozOp::I64TeeStore8):
    3628           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int8));
    3629             :               case uint16_t(MozOp::I64TeeStore16):
    3630           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int16));
    3631             :               case uint16_t(MozOp::I64TeeStore32):
    3632           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int32));
    3633             :               case uint16_t(MozOp::I32TeeStore):
    3634           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int32));
    3635             :               case uint16_t(MozOp::I64TeeStore):
    3636           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int64));
    3637             :               case uint16_t(MozOp::F32TeeStore):
    3638           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::F32, Scalar::Float32));
    3639             :               case uint16_t(MozOp::F64TeeStore):
    3640           0 :                 CHECK_ASMJS(EmitTeeStore(f, ValType::F64, Scalar::Float64));
    3641             :               case uint16_t(MozOp::F64Mod):
    3642           0 :                 CHECK_ASMJS(EmitRem(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false));
    3643             :               case uint16_t(MozOp::F64Sin):
    3644           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::SinD, ValType::F64));
    3645             :               case uint16_t(MozOp::F64Cos):
    3646           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CosD, ValType::F64));
    3647             :               case uint16_t(MozOp::F64Tan):
    3648           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TanD, ValType::F64));
    3649             :               case uint16_t(MozOp::F64Asin):
    3650           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ASinD, ValType::F64));
    3651             :               case uint16_t(MozOp::F64Acos):
    3652           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ACosD, ValType::F64));
    3653             :               case uint16_t(MozOp::F64Atan):
    3654           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ATanD, ValType::F64));
    3655             :               case uint16_t(MozOp::F64Exp):
    3656           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ExpD, ValType::F64));
    3657             :               case uint16_t(MozOp::F64Log):
    3658           0 :                 CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::LogD, ValType::F64));
    3659             :               case uint16_t(MozOp::F64Pow):
    3660           0 :                 CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::PowD, ValType::F64));
    3661             :               case uint16_t(MozOp::F64Atan2):
    3662           0 :                 CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::ATan2D, ValType::F64));
    3663             :               case uint16_t(MozOp::OldCallIndirect):
    3664           0 :                 CHECK_ASMJS(EmitCallIndirect(f, /* oldStyle = */ true));
    3665             : 
    3666             :                 // Atomics
    3667             :               case uint16_t(MozOp::I32AtomicsLoad):
    3668           0 :                 CHECK_ASMJS(EmitAtomicsLoad(f));
    3669             :               case uint16_t(MozOp::I32AtomicsStore):
    3670           0 :                 CHECK_ASMJS(EmitAtomicsStore(f));
    3671             :               case uint16_t(MozOp::I32AtomicsBinOp):
    3672           0 :                 CHECK_ASMJS(EmitAtomicsBinOp(f));
    3673             :               case uint16_t(MozOp::I32AtomicsCompareExchange):
    3674           0 :                 CHECK_ASMJS(EmitAtomicsCompareExchange(f));
    3675             :               case uint16_t(MozOp::I32AtomicsExchange):
    3676           0 :                 CHECK_ASMJS(EmitAtomicsExchange(f));
    3677             : 
    3678             :                 // SIMD
    3679             : #define CASE(TYPE, OP, SIGN)                                          \
    3680             :               case uint16_t(MozOp::TYPE##OP):                         \
    3681             :                 CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN));
    3682             : #define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed)
    3683             : #define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed)
    3684             : #define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed)
    3685             : #define F32x4CASE(OP) CASE(F32x4, OP, SimdSign::NotApplicable)
    3686             : #define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable)
    3687             : #define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable)
    3688             : #define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable)
    3689             : #define ENUMERATE(TYPE, FORALL, DO)                                   \
    3690             :               case uint16_t(MozOp::TYPE##Constructor):                \
    3691             :                 CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable)); \
    3692             :                 FORALL(DO)
    3693             : 
    3694           0 :               ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE)
    3695           0 :               ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE)
    3696           0 :               ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE)
    3697           0 :               ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE)
    3698           0 :               ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE)
    3699           0 :               ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE)
    3700           0 :               ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE)
    3701             : 
    3702             : #undef CASE
    3703             : #undef I8x16CASE
    3704             : #undef I16x8CASE
    3705             : #undef I32x4CASE
    3706             : #undef F32x4CASE
    3707             : #undef B8x16CASE
    3708             : #undef B16x8CASE
    3709             : #undef B32x4CASE
    3710             : #undef ENUMERATE
    3711             : 
    3712             :               case uint16_t(MozOp::I8x16Const):
    3713           0 :                 CHECK_ASMJS(EmitI8x16Const(f));
    3714             :               case uint16_t(MozOp::I16x8Const):
    3715           0 :                 CHECK_ASMJS(EmitI16x8Const(f));
    3716             :               case uint16_t(MozOp::I32x4Const):
    3717           0 :                 CHECK_ASMJS(EmitI32x4Const(f));
    3718             :               case uint16_t(MozOp::F32x4Const):
    3719           0 :                 CHECK_ASMJS(EmitF32x4Const(f));
    3720             :               case uint16_t(MozOp::B8x16Const):
    3721           0 :                 CHECK_ASMJS(EmitB8x16Const(f));
    3722             :               case uint16_t(MozOp::B16x8Const):
    3723           0 :                 CHECK_ASMJS(EmitB16x8Const(f));
    3724             :               case uint16_t(MozOp::B32x4Const):
    3725           0 :                 CHECK_ASMJS(EmitB32x4Const(f));
    3726             : 
    3727             :               case uint16_t(MozOp::I8x16addSaturateU):
    3728           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_addSaturate, SimdSign::Unsigned));
    3729             :               case uint16_t(MozOp::I8x16subSaturateU):
    3730           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_subSaturate, SimdSign::Unsigned));
    3731             :               case uint16_t(MozOp::I8x16shiftRightByScalarU):
    3732           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
    3733             :               case uint16_t(MozOp::I8x16lessThanU):
    3734           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
    3735             :               case uint16_t(MozOp::I8x16lessThanOrEqualU):
    3736           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
    3737             :               case uint16_t(MozOp::I8x16greaterThanU):
    3738           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
    3739             :               case uint16_t(MozOp::I8x16greaterThanOrEqualU):
    3740           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
    3741             :               case uint16_t(MozOp::I8x16extractLaneU):
    3742           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_extractLane, SimdSign::Unsigned));
    3743             : 
    3744             :               case uint16_t(MozOp::I16x8addSaturateU):
    3745           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_addSaturate, SimdSign::Unsigned));
    3746             :               case uint16_t(MozOp::I16x8subSaturateU):
    3747           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_subSaturate, SimdSign::Unsigned));
    3748             :               case uint16_t(MozOp::I16x8shiftRightByScalarU):
    3749           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
    3750             :               case uint16_t(MozOp::I16x8lessThanU):
    3751           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
    3752             :               case uint16_t(MozOp::I16x8lessThanOrEqualU):
    3753           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
    3754             :               case uint16_t(MozOp::I16x8greaterThanU):
    3755           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
    3756             :               case uint16_t(MozOp::I16x8greaterThanOrEqualU):
    3757           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
    3758             :               case uint16_t(MozOp::I16x8extractLaneU):
    3759           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_extractLane, SimdSign::Unsigned));
    3760             : 
    3761             :               case uint16_t(MozOp::I32x4shiftRightByScalarU):
    3762           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned));
    3763             :               case uint16_t(MozOp::I32x4lessThanU):
    3764           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned));
    3765             :               case uint16_t(MozOp::I32x4lessThanOrEqualU):
    3766           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned));
    3767             :               case uint16_t(MozOp::I32x4greaterThanU):
    3768           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned));
    3769             :               case uint16_t(MozOp::I32x4greaterThanOrEqualU):
    3770           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned));
    3771             :               case uint16_t(MozOp::I32x4fromFloat32x4U):
    3772           0 :                 CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned));
    3773             : 
    3774             :               default:
    3775           0 :                 return f.iter().unrecognizedOpcode(&op);
    3776             :             }
    3777           0 :             break;
    3778             :           }
    3779             : 
    3780             :           default:
    3781           0 :             return f.iter().unrecognizedOpcode(&op);
    3782             :         }
    3783           0 :     }
    3784             : 
    3785             :     MOZ_CRASH("unreachable");
    3786             : 
    3787             : #undef CHECK
    3788             : #undef CHECK_ASMJS
    3789             : }
    3790             : 
    3791             : bool
    3792           0 : wasm::IonCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars* error)
    3793             : {
    3794           0 :     MOZ_ASSERT(task->tier() == Tier::Ion);
    3795             : 
    3796           0 :     const FuncBytes& func = unit->func();
    3797           0 :     const ModuleEnvironment& env = task->env();
    3798             : 
    3799           0 :     Decoder d(func.bytes().begin(), func.bytes().end(), func.lineOrBytecode(), error);
    3800             : 
    3801             :     // Build the local types vector.
    3802             : 
    3803           0 :     ValTypeVector locals;
    3804           0 :     if (!locals.appendAll(func.sig().args()))
    3805           0 :         return false;
    3806           0 :     if (!DecodeLocalEntries(d, env.kind, &locals))
    3807           0 :         return false;
    3808             : 
    3809             :     // Set up for Ion compilation.
    3810             : 
    3811           0 :     JitContext jitContext(&task->alloc());
    3812           0 :     const JitCompileOptions options;
    3813           0 :     MIRGraph graph(&task->alloc());
    3814           0 :     CompileInfo compileInfo(locals.length());
    3815           0 :     MIRGenerator mir(nullptr, options, &task->alloc(), &graph, &compileInfo,
    3816           0 :                      IonOptimizations.get(OptimizationLevel::Wasm));
    3817           0 :     mir.initMinWasmHeapLength(env.minMemoryLength);
    3818             : 
    3819             :     // Build MIR graph
    3820             :     {
    3821           0 :         FunctionCompiler f(env, d, func, locals, mir);
    3822           0 :         if (!f.init())
    3823           0 :             return false;
    3824             : 
    3825           0 :         if (!f.startBlock())
    3826           0 :             return false;
    3827             : 
    3828           0 :         if (!EmitBodyExprs(f))
    3829           0 :             return false;
    3830             : 
    3831           0 :         f.finish();
    3832             :     }
    3833             : 
    3834             :     // Compile MIR graph
    3835             :     {
    3836           0 :         jit::SpewBeginFunction(&mir, nullptr);
    3837           0 :         jit::AutoSpewEndFunction spewEndFunction(&mir);
    3838             : 
    3839           0 :         if (!OptimizeMIR(&mir))
    3840           0 :             return false;
    3841             : 
    3842           0 :         LIRGraph* lir = GenerateLIR(&mir);
    3843           0 :         if (!lir)
    3844           0 :             return false;
    3845             : 
    3846           0 :         SigIdDesc sigId = env.funcSigs[func.index()]->id;
    3847             : 
    3848           0 :         CodeGenerator codegen(&mir, lir, &task->masm());
    3849             : 
    3850           0 :         BytecodeOffset prologueTrapOffset(func.lineOrBytecode());
    3851           0 :         FuncOffsets offsets;
    3852           0 :         if (!codegen.generateWasm(sigId, prologueTrapOffset, &offsets))
    3853           0 :             return false;
    3854             : 
    3855           0 :         unit->finish(offsets);
    3856             :     }
    3857             : 
    3858           0 :     return true;
    3859             : }

Generated by: LCOV version 1.13