LCOV - code coverage report
Current view: top level - js/src/wasm - WasmBaselineCompile.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 3359 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 434 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 2016 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : /* WebAssembly baseline compiler ("RabaldrMonkey")
      20             :  *
      21             :  * General status notes:
      22             :  *
      23             :  * "FIXME" indicates a known or suspected bug.  Always has a bug#.
      24             :  *
      25             :  * "TODO" indicates an opportunity for a general improvement, with an additional
      26             :  * tag to indicate the area of improvement.  Usually has a bug#.
      27             :  *
      28             :  * Unimplemented functionality:
      29             :  *
      30             :  *  - Tiered compilation (bug 1277562)
      31             :  *
      32             :  * There are lots of machine dependencies here but they are pretty well isolated
      33             :  * to a segment of the compiler.  Many dependencies will eventually be factored
      34             :  * into the MacroAssembler layer and shared with other code generators.
      35             :  *
      36             :  *
      37             :  * High-value compiler performance improvements:
      38             :  *
      39             :  * - (Bug 1316802) The specific-register allocator (the needI32(r), needI64(r)
      40             :  *   etc methods) can avoid syncing the value stack if the specific register is
      41             :  *   in use but there is a free register to shuffle the specific register into.
      42             :  *   (This will also improve the generated code.)  The sync happens often enough
      43             :  *   here to show up in profiles, because it is triggered by integer multiply
      44             :  *   and divide.
      45             :  *
      46             :  *
      47             :  * High-value code generation improvements:
      48             :  *
      49             :  * - (Bug 1316804) brTable pessimizes by always dispatching to code that pops
      50             :  *   the stack and then jumps to the code for the target case.  If no cleanup is
      51             :  *   needed we could just branch conditionally to the target; if the same amount
      52             :  *   of cleanup is needed for all cases then the cleanup can be done before the
      53             :  *   dispatch.  Both are highly likely.
      54             :  *
      55             :  * - (Bug 1316806) Register management around calls: At the moment we sync the
      56             :  *   value stack unconditionally (this is simple) but there are probably many
      57             :  *   common cases where we could instead save/restore live caller-saves
      58             :  *   registers and perform parallel assignment into argument registers.  This
      59             :  *   may be important if we keep some locals in registers.
      60             :  *
      61             :  * - (Bug 1316808) Allocate some locals to registers on machines where there are
      62             :  *   enough registers.  This is probably hard to do well in a one-pass compiler
      63             :  *   but it might be that just keeping register arguments and the first few
      64             :  *   locals in registers is a viable strategy; another (more general) strategy
      65             :  *   is caching locals in registers in straight-line code.  Such caching could
      66             :  *   also track constant values in registers, if that is deemed valuable.  A
      67             :  *   combination of techniques may be desirable: parameters and the first few
      68             :  *   locals could be cached on entry to the function but not statically assigned
      69             :  *   to registers throughout.
      70             :  *
      71             :  *   (On a large corpus of code it should be possible to compute, for every
      72             :  *   signature comprising the types of parameters and locals, and using a static
      73             :  *   weight for loops, a list in priority order of which parameters and locals
      74             :  *   that should be assigned to registers.  Or something like that.  Wasm makes
      75             :  *   this simple.  Static assignments are desirable because they are not flushed
      76             :  *   to memory by the pre-block sync() call.)
      77             :  */
      78             : 
      79             : #include "wasm/WasmBaselineCompile.h"
      80             : 
      81             : #include "mozilla/MathAlgorithms.h"
      82             : 
      83             : #include "jit/AtomicOp.h"
      84             : #include "jit/IonTypes.h"
      85             : #include "jit/JitAllocPolicy.h"
      86             : #include "jit/Label.h"
      87             : #include "jit/MacroAssembler.h"
      88             : #include "jit/MIR.h"
      89             : #include "jit/Registers.h"
      90             : #include "jit/RegisterSets.h"
      91             : #if defined(JS_CODEGEN_ARM)
      92             : # include "jit/arm/Assembler-arm.h"
      93             : #endif
      94             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
      95             : # include "jit/x86-shared/Architecture-x86-shared.h"
      96             : # include "jit/x86-shared/Assembler-x86-shared.h"
      97             : #endif
      98             : 
      99             : #include "wasm/WasmBinaryIterator.h"
     100             : #include "wasm/WasmGenerator.h"
     101             : #include "wasm/WasmSignalHandlers.h"
     102             : #include "wasm/WasmValidate.h"
     103             : 
     104             : #include "jit/MacroAssembler-inl.h"
     105             : 
     106             : using mozilla::DebugOnly;
     107             : using mozilla::FloatingPoint;
     108             : using mozilla::FloorLog2;
     109             : using mozilla::IsPowerOfTwo;
     110             : using mozilla::SpecificNaN;
     111             : 
     112             : namespace js {
     113             : namespace wasm {
     114             : 
     115             : using namespace js::jit;
     116             : using JS::GenericNaN;
     117             : 
     118             : typedef bool HandleNaNSpecially;
     119             : typedef bool InvertBranch;
     120             : typedef bool IsKnownNotZero;
     121             : typedef bool IsSigned;
     122             : typedef bool IsUnsigned;
     123             : typedef bool NeedsBoundsCheck;
     124             : typedef bool PopStack;
     125             : typedef bool ZeroOnOverflow;
     126             : 
     127             : typedef unsigned ByteSize;
     128             : typedef unsigned BitSize;
     129             : 
     130             : // UseABI::Wasm implies that the Tls/Heap/Global registers are nonvolatile,
     131             : // except when InterModule::True is also set, when they are volatile.
     132             : //
     133             : // UseABI::System implies that the Tls/Heap/Global registers are volatile.
     134             : // Additionally, the parameter passing mechanism may be slightly different from
     135             : // the UseABI::Wasm convention.
     136             : //
     137             : // When the Tls/Heap/Global registers are not volatile, the baseline compiler
     138             : // will restore the Tls register from its save slot before the call, since the
     139             : // baseline compiler uses the Tls register for other things.
     140             : //
     141             : // When those registers are volatile, the baseline compiler will reload them
     142             : // after the call (it will restore the Tls register from the save slot and load
     143             : // the other two from the Tls data).
     144             : 
     145             : enum class UseABI { Wasm, System };
     146             : enum class InterModule { False = false, True = true };
     147             : 
     148             : #ifdef JS_CODEGEN_ARM64
     149             : // FIXME: This is not correct, indeed for ARM64 there is no reliable
     150             : // StackPointer and we'll need to change the abstractions that use
     151             : // SP-relative addressing.  There's a guard in emitFunction() below to
     152             : // prevent this workaround from having any consequence.  This hack
     153             : // exists only as a stopgap; there is no ARM64 JIT support yet.
     154             : static const Register StackPointer = RealStackPointer;
     155             : #endif
     156             : 
     157             : #ifdef JS_CODEGEN_X86
     158             : // The selection of EBX here steps gingerly around: the need for EDX
     159             : // to be allocatable for multiply/divide; ECX to be allocatable for
     160             : // shift/rotate; EAX (= ReturnReg) to be allocatable as the joinreg;
     161             : // EBX not being one of the WasmTableCall registers; and needing a
     162             : // temp register for load/store that has a single-byte persona.
     163             : static const Register ScratchRegX86 = ebx;
     164             : 
     165             : # define INT_DIV_I64_CALLOUT
     166             : #endif
     167             : 
     168             : #ifdef JS_CODEGEN_ARM
     169             : // We need a temp for funcPtrCall.  It can't be any of the
     170             : // WasmTableCall registers, an argument register, or a scratch
     171             : // register, and probably should not be ReturnReg.
     172             : static const Register FuncPtrCallTemp = CallTempReg1;
     173             : 
     174             : // We use our own scratch register, because the macro assembler uses
     175             : // the regular scratch register(s) pretty liberally.  We could
     176             : // work around that in several cases but the mess does not seem
     177             : // worth it yet.  CallTempReg2 seems safe.
     178             : static const Register ScratchRegARM = CallTempReg2;
     179             : 
     180             : # define INT_DIV_I64_CALLOUT
     181             : # define I64_TO_FLOAT_CALLOUT
     182             : # define FLOAT_TO_I64_CALLOUT
     183             : #endif
     184             : 
     185             : template<MIRType t>
     186             : struct RegTypeOf {
     187             :     static_assert(t == MIRType::Float32 || t == MIRType::Double, "Float mask type");
     188             : };
     189             : 
     190             : template<> struct RegTypeOf<MIRType::Float32> {
     191             :     static constexpr RegTypeName value = RegTypeName::Float32;
     192             : };
     193             : template<> struct RegTypeOf<MIRType::Double> {
     194             :     static constexpr RegTypeName value = RegTypeName::Float64;
     195             : };
     196             : 
     197           0 : BaseLocalIter::BaseLocalIter(const ValTypeVector& locals,
     198             :                              size_t argsLength,
     199           0 :                              bool debugEnabled)
     200             :   : locals_(locals),
     201             :     argsLength_(argsLength),
     202             :     argsRange_(locals.begin(), argsLength),
     203             :     argsIter_(argsRange_),
     204             :     index_(0),
     205           0 :     localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0),
     206           0 :     reservedSize_(localSize_),
     207           0 :     done_(false)
     208             : {
     209           0 :     MOZ_ASSERT(argsLength <= locals.length());
     210             : 
     211           0 :     settle();
     212           0 : }
     213             : 
     214             : int32_t
     215           0 : BaseLocalIter::pushLocal(size_t nbytes)
     216             : {
     217           0 :     if (nbytes == 8)
     218           0 :         localSize_ = AlignBytes(localSize_, 8u);
     219           0 :     else if (nbytes == 16)
     220           0 :         localSize_ = AlignBytes(localSize_, 16u);
     221           0 :     localSize_ += nbytes;
     222           0 :     return localSize_;          // Locals grow down so capture base address
     223             : }
     224             : 
     225             : void
     226           0 : BaseLocalIter::settle()
     227             : {
     228           0 :     if (index_ < argsLength_) {
     229           0 :         MOZ_ASSERT(!argsIter_.done());
     230           0 :         mirType_ = argsIter_.mirType();
     231           0 :         switch (mirType_) {
     232             :           case MIRType::Int32:
     233           0 :             if (argsIter_->argInRegister())
     234           0 :                 frameOffset_ = pushLocal(4);
     235             :             else
     236           0 :                 frameOffset_ = -(argsIter_->offsetFromArgBase() + sizeof(Frame));
     237           0 :             break;
     238             :           case MIRType::Int64:
     239           0 :             if (argsIter_->argInRegister())
     240           0 :                 frameOffset_ = pushLocal(8);
     241             :             else
     242           0 :                 frameOffset_ = -(argsIter_->offsetFromArgBase() + sizeof(Frame));
     243           0 :             break;
     244             :           case MIRType::Double:
     245           0 :             if (argsIter_->argInRegister())
     246           0 :                 frameOffset_ = pushLocal(8);
     247             :             else
     248           0 :                 frameOffset_ = -(argsIter_->offsetFromArgBase() + sizeof(Frame));
     249           0 :             break;
     250             :           case MIRType::Float32:
     251           0 :             if (argsIter_->argInRegister())
     252           0 :                 frameOffset_ = pushLocal(4);
     253             :             else
     254           0 :                 frameOffset_ = -(argsIter_->offsetFromArgBase() + sizeof(Frame));
     255           0 :             break;
     256             :           default:
     257           0 :             MOZ_CRASH("Argument type");
     258             :         }
     259           0 :         return;
     260             :     }
     261             : 
     262           0 :     MOZ_ASSERT(argsIter_.done());
     263           0 :     if (index_ < locals_.length()) {
     264           0 :         switch (locals_[index_]) {
     265             :           case ValType::I32:
     266           0 :             mirType_ = jit::MIRType::Int32;
     267           0 :             frameOffset_ = pushLocal(4);
     268           0 :             break;
     269             :           case ValType::F32:
     270           0 :             mirType_ = jit::MIRType::Float32;
     271           0 :             frameOffset_ = pushLocal(4);
     272           0 :             break;
     273             :           case ValType::F64:
     274           0 :             mirType_ = jit::MIRType::Double;
     275           0 :             frameOffset_ = pushLocal(8);
     276           0 :             break;
     277             :           case ValType::I64:
     278           0 :             mirType_ = jit::MIRType::Int64;
     279           0 :             frameOffset_ = pushLocal(8);
     280           0 :             break;
     281             :           default:
     282           0 :             MOZ_CRASH("Compiler bug: Unexpected local type");
     283             :         }
     284           0 :         return;
     285             :     }
     286             : 
     287           0 :     done_ = true;
     288             : }
     289             : 
     290             : void
     291           0 : BaseLocalIter::operator++(int)
     292             : {
     293           0 :     MOZ_ASSERT(!done_);
     294           0 :     index_++;
     295           0 :     if (!argsIter_.done())
     296           0 :         argsIter_++;
     297           0 :     settle();
     298           0 : }
     299             : 
     300           0 : class BaseCompiler
     301             : {
     302             :     // We define our own ScratchRegister abstractions, deferring to
     303             :     // the platform's when possible.
     304             : 
     305             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     306             :     typedef ScratchDoubleScope ScratchF64;
     307             : #else
     308             :     class ScratchF64
     309             :     {
     310             :       public:
     311             :         ScratchF64(BaseCompiler& b) {}
     312             :         operator FloatRegister() const {
     313             :             MOZ_CRASH("BaseCompiler platform hook - ScratchF64");
     314             :         }
     315             :     };
     316             : #endif
     317             : 
     318             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     319             :     typedef ScratchFloat32Scope ScratchF32;
     320             : #else
     321             :     class ScratchF32
     322             :     {
     323             :       public:
     324             :         ScratchF32(BaseCompiler& b) {}
     325             :         operator FloatRegister() const {
     326             :             MOZ_CRASH("BaseCompiler platform hook - ScratchF32");
     327             :         }
     328             :     };
     329             : #endif
     330             : 
     331             : #if defined(JS_CODEGEN_X64)
     332             :     typedef ScratchRegisterScope ScratchI32;
     333             : #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
     334             :     class ScratchI32
     335             :     {
     336             : # ifdef DEBUG
     337             :         BaseCompiler& bc;
     338             :       public:
     339             :         explicit ScratchI32(BaseCompiler& bc) : bc(bc) {
     340             :             MOZ_ASSERT(!bc.scratchRegisterTaken());
     341             :             bc.setScratchRegisterTaken(true);
     342             :         }
     343             :         ~ScratchI32() {
     344             :             MOZ_ASSERT(bc.scratchRegisterTaken());
     345             :             bc.setScratchRegisterTaken(false);
     346             :         }
     347             : # else
     348             :       public:
     349             :         explicit ScratchI32(BaseCompiler& bc) {}
     350             : # endif
     351             :         operator Register() const {
     352             : # ifdef JS_CODEGEN_X86
     353             :             return ScratchRegX86;
     354             : # else
     355             :             return ScratchRegARM;
     356             : # endif
     357             :         }
     358             :     };
     359             : #else
     360             :     class ScratchI32
     361             :     {
     362             :       public:
     363             :         ScratchI32(BaseCompiler& bc) {}
     364             :         operator Register() const {
     365             :             MOZ_CRASH("BaseCompiler platform hook - ScratchI32");
     366             :         }
     367             :     };
     368             : #endif
     369             : 
     370             :     typedef Vector<NonAssertingLabel, 8, SystemAllocPolicy> LabelVector;
     371             : 
     372             :     // The strongly typed register wrappers have saved my bacon a few
     373             :     // times; though they are largely redundant they stay, for now.
     374             : 
     375             :     struct RegI32 : public Register
     376             :     {
     377           0 :         RegI32() : Register(Register::Invalid()) {}
     378           0 :         explicit RegI32(Register reg) : Register(reg) {}
     379             :     };
     380             : 
     381             :     struct RegI64 : public Register64
     382             :     {
     383           0 :         RegI64() : Register64(Register64::Invalid()) {}
     384           0 :         explicit RegI64(Register64 reg) : Register64(reg) {}
     385             :     };
     386             : 
     387             :     struct RegF32 : public FloatRegister
     388             :     {
     389           0 :         RegF32() : FloatRegister() {}
     390           0 :         explicit RegF32(FloatRegister reg) : FloatRegister(reg) {}
     391             :     };
     392             : 
     393             :     struct RegF64 : public FloatRegister
     394             :     {
     395           0 :         RegF64() : FloatRegister() {}
     396           0 :         explicit RegF64(FloatRegister reg) : FloatRegister(reg) {}
     397             :     };
     398             : 
     399             :     struct AnyReg
     400             :     {
     401           0 :         AnyReg() { tag = NONE; }
     402           0 :         explicit AnyReg(RegI32 r) { tag = I32; i32_ = r; }
     403           0 :         explicit AnyReg(RegI64 r) { tag = I64; i64_ = r; }
     404           0 :         explicit AnyReg(RegF32 r) { tag = F32; f32_ = r; }
     405           0 :         explicit AnyReg(RegF64 r) { tag = F64; f64_ = r; }
     406             : 
     407           0 :         RegI32 i32() {
     408           0 :             MOZ_ASSERT(tag == I32);
     409           0 :             return i32_;
     410             :         }
     411           0 :         RegI64 i64() {
     412           0 :             MOZ_ASSERT(tag == I64);
     413           0 :             return i64_;
     414             :         }
     415           0 :         RegF32 f32() {
     416           0 :             MOZ_ASSERT(tag == F32);
     417           0 :             return f32_;
     418             :         }
     419           0 :         RegF64 f64() {
     420           0 :             MOZ_ASSERT(tag == F64);
     421           0 :             return f64_;
     422             :         }
     423           0 :         AnyRegister any() {
     424           0 :             switch (tag) {
     425           0 :               case F32: return AnyRegister(f32_);
     426           0 :               case F64: return AnyRegister(f64_);
     427           0 :               case I32: return AnyRegister(i32_);
     428             :               case I64:
     429             : #ifdef JS_PUNBOX64
     430           0 :                 return AnyRegister(i64_.reg);
     431             : #else
     432             :                 // The compiler is written so that this is never needed: any() is called
     433             :                 // on arbitrary registers for asm.js but asm.js does not have 64-bit ints.
     434             :                 // For wasm, any() is called on arbitrary registers only on 64-bit platforms.
     435             :                 MOZ_CRASH("AnyReg::any() on 32-bit platform");
     436             : #endif
     437             :               case NONE:
     438           0 :                 MOZ_CRASH("AnyReg::any() on NONE");
     439             :             }
     440             :             // Work around GCC 5 analysis/warning bug.
     441           0 :             MOZ_CRASH("AnyReg::any(): impossible case");
     442             :         }
     443             : 
     444             :         union {
     445             :             RegI32 i32_;
     446             :             RegI64 i64_;
     447             :             RegF32 f32_;
     448             :             RegF64 f64_;
     449             :         };
     450             :         enum { NONE, I32, I64, F32, F64 } tag;
     451             :     };
     452             : 
     453             :     struct Local
     454             :     {
     455           0 :         Local() : type_(MIRType::None), offs_(UINT32_MAX) {}
     456             :         Local(MIRType type, uint32_t offs) : type_(type), offs_(offs) {}
     457             : 
     458           0 :         void init(MIRType type_, uint32_t offs_) {
     459           0 :             this->type_ = type_;
     460           0 :             this->offs_ = offs_;
     461           0 :         }
     462             : 
     463             :         MIRType  type_;              // Type of the value, or MIRType::None
     464             :         uint32_t offs_;              // Zero-based frame offset of value, or UINT32_MAX
     465             : 
     466           0 :         MIRType type() const { MOZ_ASSERT(type_ != MIRType::None); return type_; }
     467           0 :         uint32_t offs() const { MOZ_ASSERT(offs_ != UINT32_MAX); return offs_; }
     468             :     };
     469             : 
     470             :     // Bit set used for simple bounds check elimination.  Capping this at 64
     471             :     // locals makes sense; even 32 locals would probably be OK in practice.
     472             :     //
     473             :     // For more information about BCE, see the block comment above
     474             :     // popMemoryAccess(), below.
     475             : 
     476             :     typedef uint64_t BCESet;
     477             : 
     478             :     // Control node, representing labels and stack heights at join points.
     479             : 
     480           0 :     struct Control
     481             :     {
     482           0 :         Control()
     483           0 :             : framePushed(UINT32_MAX),
     484             :               stackSize(UINT32_MAX),
     485             :               bceSafeOnEntry(0),
     486             :               bceSafeOnExit(~BCESet(0)),
     487             :               deadOnArrival(false),
     488           0 :               deadThenBranch(false)
     489           0 :         {}
     490             : 
     491             :         NonAssertingLabel label;        // The "exit" label
     492             :         NonAssertingLabel otherLabel;   // Used for the "else" branch of if-then-else
     493             :         uint32_t framePushed;           // From masm
     494             :         uint32_t stackSize;             // Value stack height
     495             :         BCESet bceSafeOnEntry;          // Bounds check info flowing into the item
     496             :         BCESet bceSafeOnExit;           // Bounds check info flowing out of the item
     497             :         bool deadOnArrival;             // deadCode_ was set on entry to the region
     498             :         bool deadThenBranch;            // deadCode_ was set on exit from "then"
     499             :     };
     500             : 
     501           0 :     struct BaseCompilePolicy
     502             :     {
     503             :         // The baseline compiler tracks values on a stack of its own -- it
     504             :         // needs to scan that stack for spilling -- and thus has no need
     505             :         // for the values maintained by the iterator.
     506             :         typedef Nothing Value;
     507             : 
     508             :         // The baseline compiler uses the iterator's control stack, attaching
     509             :         // its own control information.
     510             :         typedef Control ControlItem;
     511             :     };
     512             : 
     513             :     typedef OpIter<BaseCompilePolicy> BaseOpIter;
     514             : 
     515             :     // Volatile registers except ReturnReg.
     516             : 
     517             :     static LiveRegisterSet VolatileReturnGPR;
     518             : 
     519             :     // The baseline compiler will use OOL code more sparingly than
     520             :     // Baldr since our code is not high performance and frills like
     521             :     // code density and branch prediction friendliness will be less
     522             :     // important.
     523             : 
     524             :     class OutOfLineCode : public TempObject
     525             :     {
     526             :       private:
     527             :         NonAssertingLabel entry_;
     528             :         NonAssertingLabel rejoin_;
     529             :         uint32_t framePushed_;
     530             : 
     531             :       public:
     532           0 :         OutOfLineCode() : framePushed_(UINT32_MAX) {}
     533             : 
     534           0 :         Label* entry() { return &entry_; }
     535           0 :         Label* rejoin() { return &rejoin_; }
     536             : 
     537           0 :         void setFramePushed(uint32_t framePushed) {
     538           0 :             MOZ_ASSERT(framePushed_ == UINT32_MAX);
     539           0 :             framePushed_ = framePushed;
     540           0 :         }
     541             : 
     542           0 :         void bind(MacroAssembler& masm) {
     543           0 :             MOZ_ASSERT(framePushed_ != UINT32_MAX);
     544           0 :             masm.bind(&entry_);
     545           0 :             masm.setFramePushed(framePushed_);
     546           0 :         }
     547             : 
     548             :         // The generate() method must be careful about register use
     549             :         // because it will be invoked when there is a register
     550             :         // assignment in the BaseCompiler that does not correspond
     551             :         // to the available registers when the generated OOL code is
     552             :         // executed.  The register allocator *must not* be called.
     553             :         //
     554             :         // The best strategy is for the creator of the OOL object to
     555             :         // allocate all temps that the OOL code will need.
     556             :         //
     557             :         // Input, output, and temp registers are embedded in the OOL
     558             :         // object and are known to the code generator.
     559             :         //
     560             :         // Scratch registers are available to use in OOL code.
     561             :         //
     562             :         // All other registers must be explicitly saved and restored
     563             :         // by the OOL code before being used.
     564             : 
     565             :         virtual void generate(MacroAssembler& masm) = 0;
     566             :     };
     567             : 
     568             :     enum class LatentOp {
     569             :         None,
     570             :         Compare,
     571             :         Eqz
     572             :     };
     573             : 
     574             :     const ModuleEnvironment&    env_;
     575             :     BaseOpIter                  iter_;
     576             :     const FuncBytes&            func_;
     577             :     size_t                      lastReadCallSite_;
     578             :     TempAllocator&              alloc_;
     579             :     const ValTypeVector&        locals_;         // Types of parameters and locals
     580             :     int32_t                     localSize_;      // Size of local area in bytes (stable after beginFunction)
     581             :     int32_t                     varLow_;         // Low byte offset of local area for true locals (not parameters)
     582             :     int32_t                     varHigh_;        // High byte offset + 1 of local area for true locals
     583             :     int32_t                     maxFramePushed_; // Max value of masm.framePushed() observed
     584             :     bool                        deadCode_;       // Flag indicating we should decode & discard the opcode
     585             :     bool                        debugEnabled_;
     586             :     BCESet                      bceSafe_;        // Locals that have been bounds checked and not updated since
     587             :     ValTypeVector               SigI64I64_;
     588             :     ValTypeVector               SigD_;
     589             :     ValTypeVector               SigF_;
     590             :     MIRTypeVector               SigPI_;
     591             :     MIRTypeVector               SigP_;
     592             :     NonAssertingLabel           returnLabel_;
     593             :     NonAssertingLabel           stackOverflowLabel_;
     594             :     CodeOffset                  stackAddOffset_;
     595             : 
     596             :     LatentOp                    latentOp_;       // Latent operation for branch (seen next)
     597             :     ValType                     latentType_;     // Operand type, if latentOp_ is true
     598             :     Assembler::Condition        latentIntCmp_;   // Comparison operator, if latentOp_ == Compare, int types
     599             :     Assembler::DoubleCondition  latentDoubleCmp_;// Comparison operator, if latentOp_ == Compare, float types
     600             : 
     601             :     FuncOffsets                 offsets_;
     602             :     MacroAssembler&             masm;            // No '_' suffix - too tedious...
     603             : 
     604             :     AllocatableGeneralRegisterSet availGPR_;
     605             :     AllocatableFloatRegisterSet   availFPU_;
     606             : #ifdef DEBUG
     607             :     bool                          scratchRegisterTaken_;
     608             :     AllocatableGeneralRegisterSet allGPR_;       // The registers available to the compiler
     609             :     AllocatableFloatRegisterSet   allFPU_;       //   after removing ScratchReg, HeapReg, etc
     610             : #endif
     611             : 
     612             :     Vector<Local, 8, SystemAllocPolicy> localInfo_;
     613             :     Vector<OutOfLineCode*, 8, SystemAllocPolicy> outOfLine_;
     614             : 
     615             :     // On specific platforms we sometimes need to use specific registers.
     616             : 
     617             : #ifdef JS_CODEGEN_X64
     618             :     RegI64 specific_rax;
     619             :     RegI64 specific_rcx;
     620             :     RegI64 specific_rdx;
     621             : #endif
     622             : 
     623             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
     624             :     RegI32 specific_eax;
     625             :     RegI32 specific_ecx;
     626             :     RegI32 specific_edx;
     627             : #endif
     628             : 
     629             : #if defined(JS_CODEGEN_X86)
     630             :     AllocatableGeneralRegisterSet singleByteRegs_;
     631             : #endif
     632             : #if defined(JS_NUNBOX32)
     633             :     RegI64 abiReturnRegI64;
     634             : #endif
     635             : 
     636             :     // The join registers are used to carry values out of blocks.
     637             :     // JoinRegI32 and joinRegI64 must overlap: emitBrIf and
     638             :     // emitBrTable assume that.
     639             : 
     640             :     RegI32 joinRegI32;
     641             :     RegI64 joinRegI64;
     642             :     RegF32 joinRegF32;
     643             :     RegF64 joinRegF64;
     644             : 
     645             :     // There are more members scattered throughout.
     646             : 
     647             :   public:
     648             :     BaseCompiler(const ModuleEnvironment& env,
     649             :                  Decoder& decoder,
     650             :                  const FuncBytes& func,
     651             :                  const ValTypeVector& locals,
     652             :                  bool debugEnabled,
     653             :                  TempAllocator* alloc,
     654             :                  MacroAssembler* masm);
     655             : 
     656             :     MOZ_MUST_USE bool init();
     657             : 
     658             :     FuncOffsets finish();
     659             : 
     660             :     MOZ_MUST_USE bool emitFunction();
     661             : 
     662             :     // Used by some of the ScratchRegister implementations.
     663           0 :     operator MacroAssembler&() const { return masm; }
     664             : 
     665             : #ifdef DEBUG
     666             :     bool scratchRegisterTaken() const {
     667             :         return scratchRegisterTaken_;
     668             :     }
     669             :     void setScratchRegisterTaken(bool state) {
     670             :         scratchRegisterTaken_ = state;
     671             :     }
     672             : #endif
     673             : 
     674             :   private:
     675             : 
     676             :     ////////////////////////////////////////////////////////////
     677             :     //
     678             :     // Out of line code management.
     679             : 
     680           0 :     MOZ_MUST_USE OutOfLineCode* addOutOfLineCode(OutOfLineCode* ool) {
     681           0 :         if (!ool || !outOfLine_.append(ool))
     682           0 :             return nullptr;
     683           0 :         ool->setFramePushed(masm.framePushed());
     684           0 :         return ool;
     685             :     }
     686             : 
     687           0 :     MOZ_MUST_USE bool generateOutOfLineCode() {
     688           0 :         for (uint32_t i = 0; i < outOfLine_.length(); i++) {
     689           0 :             OutOfLineCode* ool = outOfLine_[i];
     690           0 :             ool->bind(masm);
     691           0 :             ool->generate(masm);
     692             :         }
     693             : 
     694           0 :         return !masm.oom();
     695             :     }
     696             : 
     697             :     ////////////////////////////////////////////////////////////
     698             :     //
     699             :     // The stack frame.
     700             : 
     701             :     // SP-relative load and store.
     702             : 
     703           0 :     int32_t localOffsetToSPOffset(int32_t offset) {
     704           0 :         return masm.framePushed() - offset;
     705             :     }
     706             : 
     707           0 :     void storeToFrameI32(Register r, int32_t offset) {
     708           0 :         masm.store32(r, Address(StackPointer, localOffsetToSPOffset(offset)));
     709           0 :     }
     710             : 
     711           0 :     void storeToFrameI64(Register64 r, int32_t offset) {
     712           0 :         masm.store64(r, Address(StackPointer, localOffsetToSPOffset(offset)));
     713           0 :     }
     714             : 
     715             :     void storeToFramePtr(Register r, int32_t offset) {
     716             :         masm.storePtr(r, Address(StackPointer, localOffsetToSPOffset(offset)));
     717             :     }
     718             : 
     719           0 :     void storeToFrameF64(FloatRegister r, int32_t offset) {
     720           0 :         masm.storeDouble(r, Address(StackPointer, localOffsetToSPOffset(offset)));
     721           0 :     }
     722             : 
     723           0 :     void storeToFrameF32(FloatRegister r, int32_t offset) {
     724           0 :         masm.storeFloat32(r, Address(StackPointer, localOffsetToSPOffset(offset)));
     725           0 :     }
     726             : 
     727           0 :     void loadFromFrameI32(Register r, int32_t offset) {
     728           0 :         masm.load32(Address(StackPointer, localOffsetToSPOffset(offset)), r);
     729           0 :     }
     730             : 
     731           0 :     void loadFromFrameI64(Register64 r, int32_t offset) {
     732           0 :         masm.load64(Address(StackPointer, localOffsetToSPOffset(offset)), r);
     733           0 :     }
     734             : 
     735             :     void loadFromFramePtr(Register r, int32_t offset) {
     736             :         masm.loadPtr(Address(StackPointer, localOffsetToSPOffset(offset)), r);
     737             :     }
     738             : 
     739           0 :     void loadFromFrameF64(FloatRegister r, int32_t offset) {
     740           0 :         masm.loadDouble(Address(StackPointer, localOffsetToSPOffset(offset)), r);
     741           0 :     }
     742             : 
     743           0 :     void loadFromFrameF32(FloatRegister r, int32_t offset) {
     744           0 :         masm.loadFloat32(Address(StackPointer, localOffsetToSPOffset(offset)), r);
     745           0 :     }
     746             : 
     747           0 :     int32_t frameOffsetFromSlot(uint32_t slot, MIRType type) {
     748           0 :         MOZ_ASSERT(localInfo_[slot].type() == type);
     749           0 :         return localInfo_[slot].offs();
     750             :     }
     751             : 
     752             :     ////////////////////////////////////////////////////////////
     753             :     //
     754             :     // Low-level register allocation.
     755             : 
     756           0 :     bool isAvailable(Register r) {
     757           0 :         return availGPR_.has(r);
     758             :     }
     759             : 
     760           0 :     bool hasGPR() {
     761           0 :         return !availGPR_.empty();
     762             :     }
     763             : 
     764           0 :     void allocGPR(Register r) {
     765           0 :         MOZ_ASSERT(isAvailable(r));
     766           0 :         availGPR_.take(r);
     767           0 :     }
     768             : 
     769           0 :     Register allocGPR() {
     770           0 :         MOZ_ASSERT(hasGPR());
     771           0 :         return availGPR_.takeAny();
     772             :     }
     773             : 
     774           0 :     void freeGPR(Register r) {
     775           0 :         availGPR_.add(r);
     776           0 :     }
     777             : 
     778           0 :     bool isAvailable(Register64 r) {
     779             : #ifdef JS_PUNBOX64
     780           0 :         return isAvailable(r.reg);
     781             : #else
     782             :         return isAvailable(r.low) && isAvailable(r.high);
     783             : #endif
     784             :     }
     785             : 
     786           0 :     bool hasInt64() {
     787             : #ifdef JS_PUNBOX64
     788           0 :         return !availGPR_.empty();
     789             : #else
     790             :         if (availGPR_.empty())
     791             :             return false;
     792             :         Register r = allocGPR();
     793             :         bool available = !availGPR_.empty();
     794             :         freeGPR(r);
     795             :         return available;
     796             : #endif
     797             :     }
     798             : 
     799           0 :     void allocInt64(Register64 r) {
     800           0 :         MOZ_ASSERT(isAvailable(r));
     801             : #ifdef JS_PUNBOX64
     802           0 :         availGPR_.take(r.reg);
     803             : #else
     804             :         availGPR_.take(r.low);
     805             :         availGPR_.take(r.high);
     806             : #endif
     807           0 :     }
     808             : 
     809           0 :     Register64 allocInt64() {
     810           0 :         MOZ_ASSERT(hasInt64());
     811             : #ifdef JS_PUNBOX64
     812           0 :         return Register64(availGPR_.takeAny());
     813             : #else
     814             :         Register high = availGPR_.takeAny();
     815             :         Register low = availGPR_.takeAny();
     816             :         return Register64(high, low);
     817             : #endif
     818             :     }
     819             : 
     820           0 :     void freeInt64(Register64 r) {
     821             : #ifdef JS_PUNBOX64
     822           0 :         availGPR_.add(r.reg);
     823             : #else
     824             :         availGPR_.add(r.low);
     825             :         availGPR_.add(r.high);
     826             : #endif
     827           0 :     }
     828             : 
     829             :     // Notes on float register allocation.
     830             :     //
     831             :     // The general rule in SpiderMonkey is that float registers can
     832             :     // alias double registers, but there are predicates to handle
     833             :     // exceptions to that rule: hasUnaliasedDouble() and
     834             :     // hasMultiAlias().  The way aliasing actually works is platform
     835             :     // dependent and exposed through the aliased(n, &r) predicate,
     836             :     // etc.
     837             :     //
     838             :     //  - hasUnaliasedDouble(): on ARM VFPv3-D32 there are double
     839             :     //    registers that cannot be treated as float.
     840             :     //  - hasMultiAlias(): on ARM and MIPS a double register aliases
     841             :     //    two float registers.
     842             :     //  - notes in Architecture-arm.h indicate that when we use a
     843             :     //    float register that aliases a double register we only use
     844             :     //    the low float register, never the high float register.  I
     845             :     //    think those notes lie, or at least are confusing.
     846             :     //  - notes in Architecture-mips32.h suggest that the MIPS port
     847             :     //    will use both low and high float registers except on the
     848             :     //    Longsoon, which may be the only MIPS that's being tested, so
     849             :     //    who knows what's working.
     850             :     //  - SIMD is not yet implemented on ARM or MIPS so constraints
     851             :     //    may change there.
     852             :     //
     853             :     // On some platforms (x86, x64, ARM64) but not all (ARM)
     854             :     // ScratchFloat32Register is the same as ScratchDoubleRegister.
     855             :     //
     856             :     // It's a basic invariant of the AllocatableRegisterSet that it
     857             :     // deals properly with aliasing of registers: if s0 or s1 are
     858             :     // allocated then d0 is not allocatable; if s0 and s1 are freed
     859             :     // individually then d0 becomes allocatable.
     860             : 
     861             :     template<MIRType t>
     862           0 :     bool hasFPU() {
     863           0 :         return availFPU_.hasAny<RegTypeOf<t>::value>();
     864             :     }
     865             : 
     866           0 :     bool isAvailable(FloatRegister r) {
     867           0 :         return availFPU_.has(r);
     868             :     }
     869             : 
     870           0 :     void allocFPU(FloatRegister r) {
     871           0 :         MOZ_ASSERT(isAvailable(r));
     872           0 :         availFPU_.take(r);
     873           0 :     }
     874             : 
     875             :     template<MIRType t>
     876           0 :     FloatRegister allocFPU() {
     877           0 :         return availFPU_.takeAny<RegTypeOf<t>::value>();
     878             :     }
     879             : 
     880           0 :     void freeFPU(FloatRegister r) {
     881           0 :         availFPU_.add(r);
     882           0 :     }
     883             : 
     884             :     ////////////////////////////////////////////////////////////
     885             :     //
     886             :     // Value stack and high-level register allocation.
     887             :     //
     888             :     // The value stack facilitates some on-the-fly register allocation
     889             :     // and immediate-constant use.  It tracks constants, latent
     890             :     // references to locals, register contents, and values on the CPU
     891             :     // stack.
     892             :     //
     893             :     // The stack can be flushed to memory using sync().  This is handy
     894             :     // to avoid problems with control flow and messy register usage
     895             :     // patterns.
     896             : 
     897             :     struct Stk
     898             :     {
     899             :         enum Kind
     900             :         {
     901             :             // The Mem opcodes are all clustered at the beginning to
     902             :             // allow for a quick test within sync().
     903             :             MemI32,               // 32-bit integer stack value ("offs")
     904             :             MemI64,               // 64-bit integer stack value ("offs")
     905             :             MemF32,               // 32-bit floating stack value ("offs")
     906             :             MemF64,               // 64-bit floating stack value ("offs")
     907             : 
     908             :             // The Local opcodes follow the Mem opcodes for a similar
     909             :             // quick test within hasLocal().
     910             :             LocalI32,             // Local int32 var ("slot")
     911             :             LocalI64,             // Local int64 var ("slot")
     912             :             LocalF32,             // Local float32 var ("slot")
     913             :             LocalF64,             // Local double var ("slot")
     914             : 
     915             :             RegisterI32,          // 32-bit integer register ("i32reg")
     916             :             RegisterI64,          // 64-bit integer register ("i64reg")
     917             :             RegisterF32,          // 32-bit floating register ("f32reg")
     918             :             RegisterF64,          // 64-bit floating register ("f64reg")
     919             : 
     920             :             ConstI32,             // 32-bit integer constant ("i32val")
     921             :             ConstI64,             // 64-bit integer constant ("i64val")
     922             :             ConstF32,             // 32-bit floating constant ("f32val")
     923             :             ConstF64,             // 64-bit floating constant ("f64val")
     924             : 
     925             :             None                  // Uninitialized or void
     926             :         };
     927             : 
     928             :         Kind kind_;
     929             : 
     930             :         static const Kind MemLast = MemF64;
     931             :         static const Kind LocalLast = LocalF64;
     932             : 
     933             :         union {
     934             :             RegI32   i32reg_;
     935             :             RegI64   i64reg_;
     936             :             RegF32   f32reg_;
     937             :             RegF64   f64reg_;
     938             :             int32_t  i32val_;
     939             :             int64_t  i64val_;
     940             :             float    f32val_;
     941             :             double   f64val_;
     942             :             uint32_t slot_;
     943             :             uint32_t offs_;
     944             :         };
     945             : 
     946           0 :         Stk() { kind_ = None; }
     947             : 
     948           0 :         Kind kind() const { return kind_; }
     949           0 :         bool isMem() const { return kind_ <= MemLast; }
     950             : 
     951           0 :         RegI32   i32reg() const { MOZ_ASSERT(kind_ == RegisterI32); return i32reg_; }
     952           0 :         RegI64   i64reg() const { MOZ_ASSERT(kind_ == RegisterI64); return i64reg_; }
     953           0 :         RegF32   f32reg() const { MOZ_ASSERT(kind_ == RegisterF32); return f32reg_; }
     954           0 :         RegF64   f64reg() const { MOZ_ASSERT(kind_ == RegisterF64); return f64reg_; }
     955           0 :         int32_t  i32val() const { MOZ_ASSERT(kind_ == ConstI32); return i32val_; }
     956           0 :         int64_t  i64val() const { MOZ_ASSERT(kind_ == ConstI64); return i64val_; }
     957             :         // For these two, use an out-param instead of simply returning, to
     958             :         // use the normal stack and not the x87 FP stack (which has effect on
     959             :         // NaNs with the signaling bit set).
     960           0 :         void     f32val(float* out) const { MOZ_ASSERT(kind_ == ConstF32); *out = f32val_; }
     961           0 :         void     f64val(double* out) const { MOZ_ASSERT(kind_ == ConstF64); *out = f64val_; }
     962           0 :         uint32_t slot() const { MOZ_ASSERT(kind_ > MemLast && kind_ <= LocalLast); return slot_; }
     963           0 :         uint32_t offs() const { MOZ_ASSERT(isMem()); return offs_; }
     964             : 
     965           0 :         void setI32Reg(RegI32 r) { kind_ = RegisterI32; i32reg_ = r; }
     966           0 :         void setI64Reg(RegI64 r) { kind_ = RegisterI64; i64reg_ = r; }
     967           0 :         void setF32Reg(RegF32 r) { kind_ = RegisterF32; f32reg_ = r; }
     968           0 :         void setF64Reg(RegF64 r) { kind_ = RegisterF64; f64reg_ = r; }
     969           0 :         void setI32Val(int32_t v) { kind_ = ConstI32; i32val_ = v; }
     970           0 :         void setI64Val(int64_t v) { kind_ = ConstI64; i64val_ = v; }
     971           0 :         void setF32Val(float v) { kind_ = ConstF32; f32val_ = v; }
     972           0 :         void setF64Val(double v) { kind_ = ConstF64; f64val_ = v; }
     973           0 :         void setSlot(Kind k, uint32_t v) { MOZ_ASSERT(k > MemLast && k <= LocalLast); kind_ = k; slot_ = v; }
     974           0 :         void setOffs(Kind k, uint32_t v) { MOZ_ASSERT(k <= MemLast); kind_ = k; offs_ = v; }
     975             :     };
     976             : 
     977             :     Vector<Stk, 8, SystemAllocPolicy> stk_;
     978             : 
     979           0 :     Stk& push() {
     980           0 :         stk_.infallibleEmplaceBack(Stk());
     981           0 :         return stk_.back();
     982             :     }
     983             : 
     984             :     Register64 invalidRegister64() {
     985             :         return Register64::Invalid();
     986             :     }
     987             : 
     988           0 :     RegI32 invalidI32() {
     989           0 :         return RegI32(Register::Invalid());
     990             :     }
     991             : 
     992             :     RegI64 invalidI64() {
     993             :         return RegI64(invalidRegister64());
     994             :     }
     995             : 
     996           0 :     RegF64 invalidF64() {
     997           0 :         return RegF64(InvalidFloatReg);
     998             :     }
     999             : 
    1000           0 :     RegI32 fromI64(RegI64 r) {
    1001           0 :         return RegI32(lowPart(r));
    1002             :     }
    1003             : 
    1004           0 :     RegI64 widenI32(RegI32 r) {
    1005           0 :         MOZ_ASSERT(!isAvailable(r));
    1006             : #ifdef JS_PUNBOX64
    1007           0 :         return RegI64(Register64(r));
    1008             : #else
    1009             :         RegI32 high = needI32();
    1010             :         return RegI64(Register64(high, r));
    1011             : #endif
    1012             :     }
    1013             : 
    1014           0 :     Register lowPart(RegI64 r) {
    1015             : #ifdef JS_PUNBOX64
    1016           0 :         return r.reg;
    1017             : #else
    1018             :         return r.low;
    1019             : #endif
    1020             :     }
    1021             : 
    1022           0 :     Register maybeHighPart(RegI64 r) {
    1023             : #ifdef JS_PUNBOX64
    1024           0 :         return Register::Invalid();
    1025             : #else
    1026             :         return r.high;
    1027             : #endif
    1028             :     }
    1029             : 
    1030           0 :     void maybeClearHighPart(RegI64 r) {
    1031             : #ifdef JS_NUNBOX32
    1032             :         masm.move32(Imm32(0), r.high);
    1033             : #endif
    1034           0 :     }
    1035             : 
    1036           0 :     void freeI32(RegI32 r) {
    1037           0 :         freeGPR(r);
    1038           0 :     }
    1039             : 
    1040           0 :     void freeI64(RegI64 r) {
    1041           0 :         freeInt64(r);
    1042           0 :     }
    1043             : 
    1044           0 :     void freeI64Except(RegI64 r, RegI32 except) {
    1045             : #ifdef JS_PUNBOX64
    1046           0 :         MOZ_ASSERT(r.reg == except);
    1047             : #else
    1048             :         MOZ_ASSERT(r.high == except || r.low == except);
    1049             :         freeI64(r);
    1050             :         needI32(except);
    1051             : #endif
    1052           0 :     }
    1053             : 
    1054           0 :     void freeF64(RegF64 r) {
    1055           0 :         freeFPU(r);
    1056           0 :     }
    1057             : 
    1058           0 :     void freeF32(RegF32 r) {
    1059           0 :         freeFPU(r);
    1060           0 :     }
    1061             : 
    1062           0 :     MOZ_MUST_USE RegI32 needI32() {
    1063           0 :         if (!hasGPR())
    1064           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1065           0 :         return RegI32(allocGPR());
    1066             :     }
    1067             : 
    1068           0 :     void needI32(RegI32 specific) {
    1069           0 :         if (!isAvailable(specific))
    1070           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1071           0 :         allocGPR(specific);
    1072           0 :     }
    1073             : 
    1074             :     // TODO / OPTIMIZE: need2xI32() can be optimized along with needI32()
    1075             :     // to avoid sync(). (Bug 1316802)
    1076             : 
    1077           0 :     void need2xI32(RegI32 r0, RegI32 r1) {
    1078           0 :         needI32(r0);
    1079           0 :         needI32(r1);
    1080           0 :     }
    1081             : 
    1082           0 :     MOZ_MUST_USE RegI64 needI64() {
    1083           0 :         if (!hasInt64())
    1084           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1085           0 :         return RegI64(allocInt64());
    1086             :     }
    1087             : 
    1088           0 :     void needI64(RegI64 specific) {
    1089           0 :         if (!isAvailable(specific))
    1090           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1091           0 :         allocInt64(specific);
    1092           0 :     }
    1093             : 
    1094           0 :     void need2xI64(RegI64 r0, RegI64 r1) {
    1095           0 :         needI64(r0);
    1096           0 :         needI64(r1);
    1097           0 :     }
    1098             : 
    1099           0 :     MOZ_MUST_USE RegF32 needF32() {
    1100           0 :         if (!hasFPU<MIRType::Float32>())
    1101           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1102           0 :         return RegF32(allocFPU<MIRType::Float32>());
    1103             :     }
    1104             : 
    1105           0 :     void needF32(RegF32 specific) {
    1106           0 :         if (!isAvailable(specific))
    1107           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1108           0 :         allocFPU(specific);
    1109           0 :     }
    1110             : 
    1111           0 :     MOZ_MUST_USE RegF64 needF64() {
    1112           0 :         if (!hasFPU<MIRType::Double>())
    1113           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1114           0 :         return RegF64(allocFPU<MIRType::Double>());
    1115             :     }
    1116             : 
    1117           0 :     void needF64(RegF64 specific) {
    1118           0 :         if (!isAvailable(specific))
    1119           0 :             sync();            // TODO / OPTIMIZE: improve this (Bug 1316802)
    1120           0 :         allocFPU(specific);
    1121           0 :     }
    1122             : 
    1123           0 :     void moveI32(RegI32 src, RegI32 dest) {
    1124           0 :         if (src != dest)
    1125           0 :             masm.move32(src, dest);
    1126           0 :     }
    1127             : 
    1128           0 :     void moveI64(RegI64 src, RegI64 dest) {
    1129           0 :         if (src != dest)
    1130           0 :             masm.move64(src, dest);
    1131           0 :     }
    1132             : 
    1133           0 :     void moveF64(RegF64 src, RegF64 dest) {
    1134           0 :         if (src != dest)
    1135           0 :             masm.moveDouble(src, dest);
    1136           0 :     }
    1137             : 
    1138           0 :     void moveF32(RegF32 src, RegF32 dest) {
    1139           0 :         if (src != dest)
    1140           0 :             masm.moveFloat32(src, dest);
    1141           0 :     }
    1142             : 
    1143             :     void setI64(int64_t v, RegI64 r) {
    1144             :         masm.move64(Imm64(v), r);
    1145             :     }
    1146             : 
    1147           0 :     void loadConstI32(Register r, Stk& src) {
    1148           0 :         masm.mov(ImmWord(uint32_t(src.i32val())), r);
    1149           0 :     }
    1150             : 
    1151           0 :     void loadConstI32(Register r, int32_t v) {
    1152           0 :         masm.mov(ImmWord(uint32_t(v)), r);
    1153           0 :     }
    1154             : 
    1155           0 :     void loadMemI32(Register r, Stk& src) {
    1156           0 :         loadFromFrameI32(r, src.offs());
    1157           0 :     }
    1158             : 
    1159           0 :     void loadLocalI32(Register r, Stk& src) {
    1160           0 :         loadFromFrameI32(r, frameOffsetFromSlot(src.slot(), MIRType::Int32));
    1161           0 :     }
    1162             : 
    1163           0 :     void loadRegisterI32(Register r, Stk& src) {
    1164           0 :         if (src.i32reg() != r)
    1165           0 :             masm.move32(src.i32reg(), r);
    1166           0 :     }
    1167             : 
    1168           0 :     void loadConstI64(Register64 r, Stk &src) {
    1169           0 :         masm.move64(Imm64(src.i64val()), r);
    1170           0 :     }
    1171             : 
    1172           0 :     void loadMemI64(Register64 r, Stk& src) {
    1173           0 :         loadFromFrameI64(r, src.offs());
    1174           0 :     }
    1175             : 
    1176           0 :     void loadLocalI64(Register64 r, Stk& src) {
    1177           0 :         loadFromFrameI64(r, frameOffsetFromSlot(src.slot(), MIRType::Int64));
    1178           0 :     }
    1179             : 
    1180           0 :     void loadRegisterI64(Register64 r, Stk& src) {
    1181           0 :         if (src.i64reg() != r)
    1182           0 :             masm.move64(src.i64reg(), r);
    1183           0 :     }
    1184             : 
    1185           0 :     void loadConstF64(FloatRegister r, Stk &src) {
    1186             :         double d;
    1187           0 :         src.f64val(&d);
    1188           0 :         masm.loadConstantDouble(d, r);
    1189           0 :     }
    1190             : 
    1191           0 :     void loadMemF64(FloatRegister r, Stk& src) {
    1192           0 :         loadFromFrameF64(r, src.offs());
    1193           0 :     }
    1194             : 
    1195           0 :     void loadLocalF64(FloatRegister r, Stk& src) {
    1196           0 :         loadFromFrameF64(r, frameOffsetFromSlot(src.slot(), MIRType::Double));
    1197           0 :     }
    1198             : 
    1199           0 :     void loadRegisterF64(FloatRegister r, Stk& src) {
    1200           0 :         if (src.f64reg() != r)
    1201           0 :             masm.moveDouble(src.f64reg(), r);
    1202           0 :     }
    1203             : 
    1204           0 :     void loadConstF32(FloatRegister r, Stk &src) {
    1205             :         float f;
    1206           0 :         src.f32val(&f);
    1207           0 :         masm.loadConstantFloat32(f, r);
    1208           0 :     }
    1209             : 
    1210           0 :     void loadMemF32(FloatRegister r, Stk& src) {
    1211           0 :         loadFromFrameF32(r, src.offs());
    1212           0 :     }
    1213             : 
    1214           0 :     void loadLocalF32(FloatRegister r, Stk& src) {
    1215           0 :         loadFromFrameF32(r, frameOffsetFromSlot(src.slot(), MIRType::Float32));
    1216           0 :     }
    1217             : 
    1218           0 :     void loadRegisterF32(FloatRegister r, Stk& src) {
    1219           0 :         if (src.f32reg() != r)
    1220           0 :             masm.moveFloat32(src.f32reg(), r);
    1221           0 :     }
    1222             : 
    1223           0 :     void loadI32(Register r, Stk& src) {
    1224           0 :         switch (src.kind()) {
    1225             :           case Stk::ConstI32:
    1226           0 :             loadConstI32(r, src);
    1227           0 :             break;
    1228             :           case Stk::MemI32:
    1229           0 :             loadMemI32(r, src);
    1230           0 :             break;
    1231             :           case Stk::LocalI32:
    1232           0 :             loadLocalI32(r, src);
    1233           0 :             break;
    1234             :           case Stk::RegisterI32:
    1235           0 :             loadRegisterI32(r, src);
    1236           0 :             break;
    1237             :           case Stk::None:
    1238             :           default:
    1239           0 :             MOZ_CRASH("Compiler bug: Expected I32 on stack");
    1240             :         }
    1241           0 :     }
    1242             : 
    1243           0 :     void loadI64(Register64 r, Stk& src) {
    1244           0 :         switch (src.kind()) {
    1245             :           case Stk::ConstI64:
    1246           0 :             loadConstI64(r, src);
    1247           0 :             break;
    1248             :           case Stk::MemI64:
    1249           0 :             loadMemI64(r, src);
    1250           0 :             break;
    1251             :           case Stk::LocalI64:
    1252           0 :             loadLocalI64(r, src);
    1253           0 :             break;
    1254             :           case Stk::RegisterI64:
    1255           0 :             loadRegisterI64(r, src);
    1256           0 :             break;
    1257             :           case Stk::None:
    1258             :           default:
    1259           0 :             MOZ_CRASH("Compiler bug: Expected I64 on stack");
    1260             :         }
    1261           0 :     }
    1262             : 
    1263             : #ifdef JS_NUNBOX32
    1264             :     void loadI64Low(Register r, Stk& src) {
    1265             :         switch (src.kind()) {
    1266             :           case Stk::ConstI64:
    1267             :             masm.move32(Imm64(src.i64val()).low(), r);
    1268             :             break;
    1269             :           case Stk::MemI64:
    1270             :             loadFromFrameI32(r, src.offs() - INT64LOW_OFFSET);
    1271             :             break;
    1272             :           case Stk::LocalI64:
    1273             :             loadFromFrameI32(r, frameOffsetFromSlot(src.slot(), MIRType::Int64) - INT64LOW_OFFSET);
    1274             :             break;
    1275             :           case Stk::RegisterI64:
    1276             :             if (src.i64reg().low != r)
    1277             :                 masm.move32(src.i64reg().low, r);
    1278             :             break;
    1279             :           case Stk::None:
    1280             :           default:
    1281             :             MOZ_CRASH("Compiler bug: Expected I64 on stack");
    1282             :         }
    1283             :     }
    1284             : 
    1285             :     void loadI64High(Register r, Stk& src) {
    1286             :         switch (src.kind()) {
    1287             :           case Stk::ConstI64:
    1288             :             masm.move32(Imm64(src.i64val()).hi(), r);
    1289             :             break;
    1290             :           case Stk::MemI64:
    1291             :             loadFromFrameI32(r, src.offs() - INT64HIGH_OFFSET);
    1292             :             break;
    1293             :           case Stk::LocalI64:
    1294             :             loadFromFrameI32(r, frameOffsetFromSlot(src.slot(), MIRType::Int64) - INT64HIGH_OFFSET);
    1295             :             break;
    1296             :           case Stk::RegisterI64:
    1297             :             if (src.i64reg().high != r)
    1298             :                 masm.move32(src.i64reg().high, r);
    1299             :             break;
    1300             :           case Stk::None:
    1301             :           default:
    1302             :             MOZ_CRASH("Compiler bug: Expected I64 on stack");
    1303             :         }
    1304             :     }
    1305             : #endif
    1306             : 
    1307           0 :     void loadF64(FloatRegister r, Stk& src) {
    1308           0 :         switch (src.kind()) {
    1309             :           case Stk::ConstF64:
    1310           0 :             loadConstF64(r, src);
    1311           0 :             break;
    1312             :           case Stk::MemF64:
    1313           0 :             loadMemF64(r, src);
    1314           0 :             break;
    1315             :           case Stk::LocalF64:
    1316           0 :             loadLocalF64(r, src);
    1317           0 :             break;
    1318             :           case Stk::RegisterF64:
    1319           0 :             loadRegisterF64(r, src);
    1320           0 :             break;
    1321             :           case Stk::None:
    1322             :           default:
    1323           0 :             MOZ_CRASH("Compiler bug: expected F64 on stack");
    1324             :         }
    1325           0 :     }
    1326             : 
    1327           0 :     void loadF32(FloatRegister r, Stk& src) {
    1328           0 :         switch (src.kind()) {
    1329             :           case Stk::ConstF32:
    1330           0 :             loadConstF32(r, src);
    1331           0 :             break;
    1332             :           case Stk::MemF32:
    1333           0 :             loadMemF32(r, src);
    1334           0 :             break;
    1335             :           case Stk::LocalF32:
    1336           0 :             loadLocalF32(r, src);
    1337           0 :             break;
    1338             :           case Stk::RegisterF32:
    1339           0 :             loadRegisterF32(r, src);
    1340           0 :             break;
    1341             :           case Stk::None:
    1342             :           default:
    1343           0 :             MOZ_CRASH("Compiler bug: expected F32 on stack");
    1344             :         }
    1345           0 :     }
    1346             : 
    1347             :     // Flush all local and register value stack elements to memory.
    1348             :     //
    1349             :     // TODO / OPTIMIZE: As this is fairly expensive and causes worse
    1350             :     // code to be emitted subsequently, it is useful to avoid calling
    1351             :     // it.  (Bug 1316802)
    1352             :     //
    1353             :     // Some optimization has been done already.  Remaining
    1354             :     // opportunities:
    1355             :     //
    1356             :     //  - It would be interesting to see if we can specialize it
    1357             :     //    before calls with particularly simple signatures, or where
    1358             :     //    we can do parallel assignment of register arguments, or
    1359             :     //    similar.  See notes in emitCall().
    1360             :     //
    1361             :     //  - Operations that need specific registers: multiply, quotient,
    1362             :     //    remainder, will tend to sync because the registers we need
    1363             :     //    will tend to be allocated.  We may be able to avoid that by
    1364             :     //    prioritizing registers differently (takeLast instead of
    1365             :     //    takeFirst) but we may also be able to allocate an unused
    1366             :     //    register on demand to free up one we need, thus avoiding the
    1367             :     //    sync.  That type of fix would go into needI32().
    1368             : 
    1369           0 :     void sync() {
    1370           0 :         size_t start = 0;
    1371           0 :         size_t lim = stk_.length();
    1372             : 
    1373           0 :         for (size_t i = lim; i > 0; i--) {
    1374             :             // Memory opcodes are first in the enum, single check against MemLast is fine.
    1375           0 :             if (stk_[i - 1].kind() <= Stk::MemLast) {
    1376           0 :                 start = i;
    1377           0 :                 break;
    1378             :             }
    1379             :         }
    1380             : 
    1381           0 :         for (size_t i = start; i < lim; i++) {
    1382           0 :             Stk& v = stk_[i];
    1383           0 :             switch (v.kind()) {
    1384             :               case Stk::LocalI32: {
    1385           0 :                 ScratchI32 scratch(*this);
    1386           0 :                 loadLocalI32(scratch, v);
    1387           0 :                 masm.Push(scratch);
    1388           0 :                 v.setOffs(Stk::MemI32, masm.framePushed());
    1389           0 :                 break;
    1390             :               }
    1391             :               case Stk::RegisterI32: {
    1392           0 :                 masm.Push(v.i32reg());
    1393           0 :                 freeI32(v.i32reg());
    1394           0 :                 v.setOffs(Stk::MemI32, masm.framePushed());
    1395           0 :                 break;
    1396             :               }
    1397             :               case Stk::LocalI64: {
    1398           0 :                 ScratchI32 scratch(*this);
    1399             : #ifdef JS_PUNBOX64
    1400           0 :                 loadI64(Register64(scratch), v);
    1401           0 :                 masm.Push(scratch);
    1402             : #else
    1403             :                 int32_t offset = frameOffsetFromSlot(v.slot(), MIRType::Int64);
    1404             :                 loadFromFrameI32(scratch, offset - INT64HIGH_OFFSET);
    1405             :                 masm.Push(scratch);
    1406             :                 loadFromFrameI32(scratch, offset - INT64LOW_OFFSET);
    1407             :                 masm.Push(scratch);
    1408             : #endif
    1409           0 :                 v.setOffs(Stk::MemI64, masm.framePushed());
    1410           0 :                 break;
    1411             :               }
    1412             :               case Stk::RegisterI64: {
    1413             : #ifdef JS_PUNBOX64
    1414           0 :                 masm.Push(v.i64reg().reg);
    1415           0 :                 freeI64(v.i64reg());
    1416             : #else
    1417             :                 masm.Push(v.i64reg().high);
    1418             :                 masm.Push(v.i64reg().low);
    1419             :                 freeI64(v.i64reg());
    1420             : #endif
    1421           0 :                 v.setOffs(Stk::MemI64, masm.framePushed());
    1422           0 :                 break;
    1423             :               }
    1424             :               case Stk::LocalF64: {
    1425           0 :                 ScratchF64 scratch(*this);
    1426           0 :                 loadF64(scratch, v);
    1427           0 :                 masm.Push(scratch);
    1428           0 :                 v.setOffs(Stk::MemF64, masm.framePushed());
    1429           0 :                 break;
    1430             :               }
    1431             :               case Stk::RegisterF64: {
    1432           0 :                 masm.Push(v.f64reg());
    1433           0 :                 freeF64(v.f64reg());
    1434           0 :                 v.setOffs(Stk::MemF64, masm.framePushed());
    1435           0 :                 break;
    1436             :               }
    1437             :               case Stk::LocalF32: {
    1438           0 :                 ScratchF32 scratch(*this);
    1439           0 :                 loadF32(scratch, v);
    1440           0 :                 masm.Push(scratch);
    1441           0 :                 v.setOffs(Stk::MemF32, masm.framePushed());
    1442           0 :                 break;
    1443             :               }
    1444             :               case Stk::RegisterF32: {
    1445           0 :                 masm.Push(v.f32reg());
    1446           0 :                 freeF32(v.f32reg());
    1447           0 :                 v.setOffs(Stk::MemF32, masm.framePushed());
    1448           0 :                 break;
    1449             :               }
    1450             :               default: {
    1451           0 :                 break;
    1452             :               }
    1453             :             }
    1454             :         }
    1455             : 
    1456           0 :         maxFramePushed_ = Max(maxFramePushed_, int32_t(masm.framePushed()));
    1457           0 :     }
    1458             : 
    1459             :     // This is an optimization used to avoid calling sync() for
    1460             :     // setLocal(): if the local does not exist unresolved on the stack
    1461             :     // then we can skip the sync.
    1462             : 
    1463           0 :     bool hasLocal(uint32_t slot) {
    1464           0 :         for (size_t i = stk_.length(); i > 0; i--) {
    1465             :             // Memory opcodes are first in the enum, single check against MemLast is fine.
    1466           0 :             Stk::Kind kind = stk_[i-1].kind();
    1467           0 :             if (kind <= Stk::MemLast)
    1468           0 :                 return false;
    1469             : 
    1470             :             // Local opcodes follow memory opcodes in the enum, single check against
    1471             :             // LocalLast is sufficient.
    1472           0 :             if (kind <= Stk::LocalLast && stk_[i-1].slot() == slot)
    1473           0 :                 return true;
    1474             :         }
    1475           0 :         return false;
    1476             :     }
    1477             : 
    1478           0 :     void syncLocal(uint32_t slot) {
    1479           0 :         if (hasLocal(slot))
    1480           0 :             sync();            // TODO / OPTIMIZE: Improve this?  (Bug 1316817)
    1481           0 :     }
    1482             : 
    1483             :     // Push the register r onto the stack.
    1484             : 
    1485           0 :     void pushI32(RegI32 r) {
    1486           0 :         MOZ_ASSERT(!isAvailable(r));
    1487           0 :         Stk& x = push();
    1488           0 :         x.setI32Reg(r);
    1489           0 :     }
    1490             : 
    1491           0 :     void pushI64(RegI64 r) {
    1492           0 :         MOZ_ASSERT(!isAvailable(r));
    1493           0 :         Stk& x = push();
    1494           0 :         x.setI64Reg(r);
    1495           0 :     }
    1496             : 
    1497           0 :     void pushF64(RegF64 r) {
    1498           0 :         MOZ_ASSERT(!isAvailable(r));
    1499           0 :         Stk& x = push();
    1500           0 :         x.setF64Reg(r);
    1501           0 :     }
    1502             : 
    1503           0 :     void pushF32(RegF32 r) {
    1504           0 :         MOZ_ASSERT(!isAvailable(r));
    1505           0 :         Stk& x = push();
    1506           0 :         x.setF32Reg(r);
    1507           0 :     }
    1508             : 
    1509             :     // Push the value onto the stack.
    1510             : 
    1511           0 :     void pushI32(int32_t v) {
    1512           0 :         Stk& x = push();
    1513           0 :         x.setI32Val(v);
    1514           0 :     }
    1515             : 
    1516           0 :     void pushI64(int64_t v) {
    1517           0 :         Stk& x = push();
    1518           0 :         x.setI64Val(v);
    1519           0 :     }
    1520             : 
    1521           0 :     void pushF64(double v) {
    1522           0 :         Stk& x = push();
    1523           0 :         x.setF64Val(v);
    1524           0 :     }
    1525             : 
    1526           0 :     void pushF32(float v) {
    1527           0 :         Stk& x = push();
    1528           0 :         x.setF32Val(v);
    1529           0 :     }
    1530             : 
    1531             :     // Push the local slot onto the stack.  The slot will not be read
    1532             :     // here; it will be read when it is consumed, or when a side
    1533             :     // effect to the slot forces its value to be saved.
    1534             : 
    1535           0 :     void pushLocalI32(uint32_t slot) {
    1536           0 :         Stk& x = push();
    1537           0 :         x.setSlot(Stk::LocalI32, slot);
    1538           0 :     }
    1539             : 
    1540           0 :     void pushLocalI64(uint32_t slot) {
    1541           0 :         Stk& x = push();
    1542           0 :         x.setSlot(Stk::LocalI64, slot);
    1543           0 :     }
    1544             : 
    1545           0 :     void pushLocalF64(uint32_t slot) {
    1546           0 :         Stk& x = push();
    1547           0 :         x.setSlot(Stk::LocalF64, slot);
    1548           0 :     }
    1549             : 
    1550           0 :     void pushLocalF32(uint32_t slot) {
    1551           0 :         Stk& x = push();
    1552           0 :         x.setSlot(Stk::LocalF32, slot);
    1553           0 :     }
    1554             : 
    1555             :     // PRIVATE.  Call only from other popI32() variants.
    1556             :     // v must be the stack top.
    1557             : 
    1558           0 :     void popI32(Stk& v, RegI32 r) {
    1559           0 :         switch (v.kind()) {
    1560             :           case Stk::ConstI32:
    1561           0 :             loadConstI32(r, v);
    1562           0 :             break;
    1563             :           case Stk::LocalI32:
    1564           0 :             loadLocalI32(r, v);
    1565           0 :             break;
    1566             :           case Stk::MemI32:
    1567           0 :             masm.Pop(r);
    1568           0 :             break;
    1569             :           case Stk::RegisterI32:
    1570           0 :             loadRegisterI32(r, v);
    1571           0 :             break;
    1572             :           case Stk::None:
    1573             :           default:
    1574           0 :             MOZ_CRASH("Compiler bug: expected int on stack");
    1575             :         }
    1576           0 :     }
    1577             : 
    1578           0 :     MOZ_MUST_USE RegI32 popI32() {
    1579           0 :         Stk& v = stk_.back();
    1580           0 :         RegI32 r;
    1581           0 :         if (v.kind() == Stk::RegisterI32)
    1582           0 :             r = v.i32reg();
    1583             :         else
    1584           0 :             popI32(v, (r = needI32()));
    1585           0 :         stk_.popBack();
    1586           0 :         return r;
    1587             :     }
    1588             : 
    1589           0 :     RegI32 popI32(RegI32 specific) {
    1590           0 :         Stk& v = stk_.back();
    1591             : 
    1592           0 :         if (!(v.kind() == Stk::RegisterI32 && v.i32reg() == specific)) {
    1593           0 :             needI32(specific);
    1594           0 :             popI32(v, specific);
    1595           0 :             if (v.kind() == Stk::RegisterI32)
    1596           0 :                 freeI32(v.i32reg());
    1597             :         }
    1598             : 
    1599           0 :         stk_.popBack();
    1600           0 :         return specific;
    1601             :     }
    1602             : 
    1603             :     // PRIVATE.  Call only from other popI64() variants.
    1604             :     // v must be the stack top.
    1605             : 
    1606           0 :     void popI64(Stk& v, RegI64 r) {
    1607           0 :         switch (v.kind()) {
    1608             :           case Stk::ConstI64:
    1609           0 :             loadConstI64(r, v);
    1610           0 :             break;
    1611             :           case Stk::LocalI64:
    1612           0 :             loadLocalI64(r, v);
    1613           0 :             break;
    1614             :           case Stk::MemI64:
    1615             : #ifdef JS_PUNBOX64
    1616           0 :             masm.Pop(r.reg);
    1617             : #else
    1618             :             masm.Pop(r.low);
    1619             :             masm.Pop(r.high);
    1620             : #endif
    1621           0 :             break;
    1622             :           case Stk::RegisterI64:
    1623           0 :             loadRegisterI64(r, v);
    1624           0 :             break;
    1625             :           case Stk::None:
    1626             :           default:
    1627           0 :             MOZ_CRASH("Compiler bug: expected long on stack");
    1628             :         }
    1629           0 :     }
    1630             : 
    1631           0 :     MOZ_MUST_USE RegI64 popI64() {
    1632           0 :         Stk& v = stk_.back();
    1633           0 :         RegI64 r;
    1634           0 :         if (v.kind() == Stk::RegisterI64)
    1635           0 :             r = v.i64reg();
    1636             :         else
    1637           0 :             popI64(v, (r = needI64()));
    1638           0 :         stk_.popBack();
    1639           0 :         return r;
    1640             :     }
    1641             : 
    1642             :     // Note, the stack top can be in one half of "specific" on 32-bit
    1643             :     // systems.  We can optimize, but for simplicity, if the register
    1644             :     // does not match exactly, then just force the stack top to memory
    1645             :     // and then read it back in.
    1646             : 
    1647           0 :     RegI64 popI64(RegI64 specific) {
    1648           0 :         Stk& v = stk_.back();
    1649             : 
    1650           0 :         if (!(v.kind() == Stk::RegisterI64 && v.i64reg() == specific)) {
    1651           0 :             needI64(specific);
    1652           0 :             popI64(v, specific);
    1653           0 :             if (v.kind() == Stk::RegisterI64)
    1654           0 :                 freeI64(v.i64reg());
    1655             :         }
    1656             : 
    1657           0 :         stk_.popBack();
    1658           0 :         return specific;
    1659             :     }
    1660             : 
    1661             :     // PRIVATE.  Call only from other popF64() variants.
    1662             :     // v must be the stack top.
    1663             : 
    1664           0 :     void popF64(Stk& v, RegF64 r) {
    1665           0 :         switch (v.kind()) {
    1666             :           case Stk::ConstF64:
    1667           0 :             loadConstF64(r, v);
    1668           0 :             break;
    1669             :           case Stk::LocalF64:
    1670           0 :             loadLocalF64(r, v);
    1671           0 :             break;
    1672             :           case Stk::MemF64:
    1673           0 :             masm.Pop(r);
    1674           0 :             break;
    1675             :           case Stk::RegisterF64:
    1676           0 :             loadRegisterF64(r, v);
    1677           0 :             break;
    1678             :           case Stk::None:
    1679             :           default:
    1680           0 :             MOZ_CRASH("Compiler bug: expected double on stack");
    1681             :         }
    1682           0 :     }
    1683             : 
    1684           0 :     MOZ_MUST_USE RegF64 popF64() {
    1685           0 :         Stk& v = stk_.back();
    1686           0 :         RegF64 r;
    1687           0 :         if (v.kind() == Stk::RegisterF64)
    1688           0 :             r = v.f64reg();
    1689             :         else
    1690           0 :             popF64(v, (r = needF64()));
    1691           0 :         stk_.popBack();
    1692           0 :         return r;
    1693             :     }
    1694             : 
    1695           0 :     RegF64 popF64(RegF64 specific) {
    1696           0 :         Stk& v = stk_.back();
    1697             : 
    1698           0 :         if (!(v.kind() == Stk::RegisterF64 && v.f64reg() == specific)) {
    1699           0 :             needF64(specific);
    1700           0 :             popF64(v, specific);
    1701           0 :             if (v.kind() == Stk::RegisterF64)
    1702           0 :                 freeF64(v.f64reg());
    1703             :         }
    1704             : 
    1705           0 :         stk_.popBack();
    1706           0 :         return specific;
    1707             :     }
    1708             : 
    1709             :     // PRIVATE.  Call only from other popF32() variants.
    1710             :     // v must be the stack top.
    1711             : 
    1712           0 :     void popF32(Stk& v, RegF32 r) {
    1713           0 :         switch (v.kind()) {
    1714             :           case Stk::ConstF32:
    1715           0 :             loadConstF32(r, v);
    1716           0 :             break;
    1717             :           case Stk::LocalF32:
    1718           0 :             loadLocalF32(r, v);
    1719           0 :             break;
    1720             :           case Stk::MemF32:
    1721           0 :             masm.Pop(r);
    1722           0 :             break;
    1723             :           case Stk::RegisterF32:
    1724           0 :             loadRegisterF32(r, v);
    1725           0 :             break;
    1726             :           case Stk::None:
    1727             :           default:
    1728           0 :             MOZ_CRASH("Compiler bug: expected float on stack");
    1729             :         }
    1730           0 :     }
    1731             : 
    1732           0 :     MOZ_MUST_USE RegF32 popF32() {
    1733           0 :         Stk& v = stk_.back();
    1734           0 :         RegF32 r;
    1735           0 :         if (v.kind() == Stk::RegisterF32)
    1736           0 :             r = v.f32reg();
    1737             :         else
    1738           0 :             popF32(v, (r = needF32()));
    1739           0 :         stk_.popBack();
    1740           0 :         return r;
    1741             :     }
    1742             : 
    1743           0 :     RegF32 popF32(RegF32 specific) {
    1744           0 :         Stk& v = stk_.back();
    1745             : 
    1746           0 :         if (!(v.kind() == Stk::RegisterF32 && v.f32reg() == specific)) {
    1747           0 :             needF32(specific);
    1748           0 :             popF32(v, specific);
    1749           0 :             if (v.kind() == Stk::RegisterF32)
    1750           0 :                 freeF32(v.f32reg());
    1751             :         }
    1752             : 
    1753           0 :         stk_.popBack();
    1754           0 :         return specific;
    1755             :     }
    1756             : 
    1757           0 :     MOZ_MUST_USE bool popConstI32(int32_t* c) {
    1758           0 :         Stk& v = stk_.back();
    1759           0 :         if (v.kind() != Stk::ConstI32)
    1760           0 :             return false;
    1761           0 :         *c = v.i32val();
    1762           0 :         stk_.popBack();
    1763           0 :         return true;
    1764             :     }
    1765             : 
    1766           0 :     MOZ_MUST_USE bool popConstI64(int64_t* c) {
    1767           0 :         Stk& v = stk_.back();
    1768           0 :         if (v.kind() != Stk::ConstI64)
    1769           0 :             return false;
    1770           0 :         *c = v.i64val();
    1771           0 :         stk_.popBack();
    1772           0 :         return true;
    1773             :     }
    1774             : 
    1775           0 :     MOZ_MUST_USE bool peekConstI32(int32_t* c) {
    1776           0 :         Stk& v = stk_.back();
    1777           0 :         if (v.kind() != Stk::ConstI32)
    1778           0 :             return false;
    1779           0 :         *c = v.i32val();
    1780           0 :         return true;
    1781             :     }
    1782             : 
    1783           0 :     MOZ_MUST_USE bool peekConstI64(int64_t* c) {
    1784           0 :         Stk& v = stk_.back();
    1785           0 :         if (v.kind() != Stk::ConstI64)
    1786           0 :             return false;
    1787           0 :         *c = v.i64val();
    1788           0 :         return true;
    1789             :     }
    1790             : 
    1791           0 :     MOZ_MUST_USE bool popConstPositivePowerOfTwoI32(int32_t* c,
    1792             :                                                     uint_fast8_t* power,
    1793             :                                                     int32_t cutoff)
    1794             :     {
    1795           0 :         Stk& v = stk_.back();
    1796           0 :         if (v.kind() != Stk::ConstI32)
    1797           0 :             return false;
    1798           0 :         *c = v.i32val();
    1799           0 :         if (*c <= cutoff || !IsPowerOfTwo(static_cast<uint32_t>(*c)))
    1800           0 :             return false;
    1801           0 :         *power = FloorLog2(*c);
    1802           0 :         stk_.popBack();
    1803           0 :         return true;
    1804             :     }
    1805             : 
    1806           0 :     MOZ_MUST_USE bool popConstPositivePowerOfTwoI64(int64_t* c,
    1807             :                                                     uint_fast8_t* power,
    1808             :                                                     int64_t cutoff)
    1809             :     {
    1810           0 :         Stk& v = stk_.back();
    1811           0 :         if (v.kind() != Stk::ConstI64)
    1812           0 :             return false;
    1813           0 :         *c = v.i64val();
    1814           0 :         if (*c <= cutoff || !IsPowerOfTwo(static_cast<uint64_t>(*c)))
    1815           0 :             return false;
    1816           0 :         *power = FloorLog2(*c);
    1817           0 :         stk_.popBack();
    1818           0 :         return true;
    1819             :     }
    1820             : 
    1821           0 :     MOZ_MUST_USE bool peekLocalI32(uint32_t* local) {
    1822           0 :         Stk& v = stk_.back();
    1823           0 :         if (v.kind() != Stk::LocalI32)
    1824           0 :             return false;
    1825           0 :         *local = v.slot();
    1826           0 :         return true;
    1827             :     }
    1828             : 
    1829             :     // TODO / OPTIMIZE (Bug 1316818): At the moment we use ReturnReg
    1830             :     // for JoinReg.  It is possible other choices would lead to better
    1831             :     // register allocation, as ReturnReg is often first in the
    1832             :     // register set and will be heavily wanted by the register
    1833             :     // allocator that uses takeFirst().
    1834             :     //
    1835             :     // Obvious options:
    1836             :     //  - pick a register at the back of the register set
    1837             :     //  - pick a random register per block (different blocks have
    1838             :     //    different join regs)
    1839             :     //
    1840             :     // On the other hand, we sync() before every block and only the
    1841             :     // JoinReg is live out of the block.  But on the way out, we
    1842             :     // currently pop the JoinReg before freeing regs to be discarded,
    1843             :     // so there is a real risk of some pointless shuffling there.  If
    1844             :     // we instead integrate the popping of the join reg into the
    1845             :     // popping of the stack we can just use the JoinReg as it will
    1846             :     // become available in that process.
    1847             : 
    1848           0 :     MOZ_MUST_USE AnyReg popJoinRegUnlessVoid(ExprType type) {
    1849           0 :         switch (type) {
    1850             :           case ExprType::Void: {
    1851           0 :             return AnyReg();
    1852             :           }
    1853             :           case ExprType::I32: {
    1854           0 :             DebugOnly<Stk::Kind> k(stk_.back().kind());
    1855           0 :             MOZ_ASSERT(k == Stk::RegisterI32 || k == Stk::ConstI32 || k == Stk::MemI32 ||
    1856             :                        k == Stk::LocalI32);
    1857           0 :             return AnyReg(popI32(joinRegI32));
    1858             :           }
    1859             :           case ExprType::I64: {
    1860           0 :             DebugOnly<Stk::Kind> k(stk_.back().kind());
    1861           0 :             MOZ_ASSERT(k == Stk::RegisterI64 || k == Stk::ConstI64 || k == Stk::MemI64 ||
    1862             :                        k == Stk::LocalI64);
    1863           0 :             return AnyReg(popI64(joinRegI64));
    1864             :           }
    1865             :           case ExprType::F64: {
    1866           0 :             DebugOnly<Stk::Kind> k(stk_.back().kind());
    1867           0 :             MOZ_ASSERT(k == Stk::RegisterF64 || k == Stk::ConstF64 || k == Stk::MemF64 ||
    1868             :                        k == Stk::LocalF64);
    1869           0 :             return AnyReg(popF64(joinRegF64));
    1870             :           }
    1871             :           case ExprType::F32: {
    1872           0 :             DebugOnly<Stk::Kind> k(stk_.back().kind());
    1873           0 :             MOZ_ASSERT(k == Stk::RegisterF32 || k == Stk::ConstF32 || k == Stk::MemF32 ||
    1874             :                        k == Stk::LocalF32);
    1875           0 :             return AnyReg(popF32(joinRegF32));
    1876             :           }
    1877             :           default: {
    1878           0 :             MOZ_CRASH("Compiler bug: unexpected expression type");
    1879             :           }
    1880             :         }
    1881             :     }
    1882             : 
    1883             :     // If we ever start not sync-ing on entry to Block (but instead try to sync
    1884             :     // lazily) then this may start asserting because it does not spill the
    1885             :     // joinreg if the joinreg is already allocated.  Note, it *can't* spill the
    1886             :     // joinreg in the contexts it's being used, so some other solution will need
    1887             :     // to be found.
    1888             : 
    1889           0 :     MOZ_MUST_USE AnyReg captureJoinRegUnlessVoid(ExprType type) {
    1890           0 :         switch (type) {
    1891             :           case ExprType::I32:
    1892           0 :             allocGPR(joinRegI32);
    1893           0 :             return AnyReg(joinRegI32);
    1894             :           case ExprType::I64:
    1895           0 :             allocInt64(joinRegI64);
    1896           0 :             return AnyReg(joinRegI64);
    1897             :           case ExprType::F32:
    1898           0 :             allocFPU(joinRegF32);
    1899           0 :             return AnyReg(joinRegF32);
    1900             :           case ExprType::F64:
    1901           0 :             allocFPU(joinRegF64);
    1902           0 :             return AnyReg(joinRegF64);
    1903             :           case ExprType::Void:
    1904           0 :             return AnyReg();
    1905             :           default:
    1906           0 :             MOZ_CRASH("Compiler bug: unexpected type");
    1907             :         }
    1908             :     }
    1909             : 
    1910           0 :     void pushJoinRegUnlessVoid(AnyReg r) {
    1911           0 :         switch (r.tag) {
    1912             :           case AnyReg::NONE:
    1913           0 :             break;
    1914             :           case AnyReg::I32:
    1915           0 :             pushI32(r.i32());
    1916           0 :             break;
    1917             :           case AnyReg::I64:
    1918           0 :             pushI64(r.i64());
    1919           0 :             break;
    1920             :           case AnyReg::F64:
    1921           0 :             pushF64(r.f64());
    1922           0 :             break;
    1923             :           case AnyReg::F32:
    1924           0 :             pushF32(r.f32());
    1925           0 :             break;
    1926             :         }
    1927           0 :     }
    1928             : 
    1929           0 :     void freeJoinRegUnlessVoid(AnyReg r) {
    1930           0 :         switch (r.tag) {
    1931             :           case AnyReg::NONE:
    1932           0 :             break;
    1933             :           case AnyReg::I32:
    1934           0 :             freeI32(r.i32());
    1935           0 :             break;
    1936             :           case AnyReg::I64:
    1937           0 :             freeI64(r.i64());
    1938           0 :             break;
    1939             :           case AnyReg::F64:
    1940           0 :             freeF64(r.f64());
    1941           0 :             break;
    1942             :           case AnyReg::F32:
    1943           0 :             freeF32(r.f32());
    1944           0 :             break;
    1945             :         }
    1946           0 :     }
    1947             : 
    1948           0 :     void maybeReserveJoinRegI(ExprType type) {
    1949           0 :         if (type == ExprType::I32)
    1950           0 :             needI32(joinRegI32);
    1951           0 :         else if (type == ExprType::I64)
    1952           0 :             needI64(joinRegI64);
    1953           0 :     }
    1954             : 
    1955           0 :     void maybeUnreserveJoinRegI(ExprType type) {
    1956           0 :         if (type == ExprType::I32)
    1957           0 :             freeI32(joinRegI32);
    1958           0 :         else if (type == ExprType::I64)
    1959           0 :             freeI64(joinRegI64);
    1960           0 :     }
    1961             : 
    1962           0 :     void maybeReserveJoinReg(ExprType type) {
    1963           0 :         switch (type) {
    1964             :           case ExprType::I32:
    1965           0 :             needI32(joinRegI32);
    1966           0 :             break;
    1967             :           case ExprType::I64:
    1968           0 :             needI64(joinRegI64);
    1969           0 :             break;
    1970             :           case ExprType::F32:
    1971           0 :             needF32(joinRegF32);
    1972           0 :             break;
    1973             :           case ExprType::F64:
    1974           0 :             needF64(joinRegF64);
    1975           0 :             break;
    1976             :           default:
    1977           0 :             break;
    1978             :         }
    1979           0 :     }
    1980             : 
    1981           0 :     void maybeUnreserveJoinReg(ExprType type) {
    1982           0 :         switch (type) {
    1983             :           case ExprType::I32:
    1984           0 :             freeI32(joinRegI32);
    1985           0 :             break;
    1986             :           case ExprType::I64:
    1987           0 :             freeI64(joinRegI64);
    1988           0 :             break;
    1989             :           case ExprType::F32:
    1990           0 :             freeF32(joinRegF32);
    1991           0 :             break;
    1992             :           case ExprType::F64:
    1993           0 :             freeF64(joinRegF64);
    1994           0 :             break;
    1995             :           default:
    1996           0 :             break;
    1997             :         }
    1998           0 :     }
    1999             : 
    2000             :     // Return the amount of execution stack consumed by the top numval
    2001             :     // values on the value stack.
    2002             : 
    2003           0 :     size_t stackConsumed(size_t numval) {
    2004           0 :         size_t size = 0;
    2005           0 :         MOZ_ASSERT(numval <= stk_.length());
    2006           0 :         for (uint32_t i = stk_.length() - 1; numval > 0; numval--, i--) {
    2007             :             // The size computations come from the implementation of Push() in
    2008             :             // MacroAssembler-x86-shared.cpp and MacroAssembler-arm-shared.cpp,
    2009             :             // and from VFPRegister::size() in Architecture-arm.h.
    2010             :             //
    2011             :             // On ARM unlike on x86 we push a single for float.
    2012             : 
    2013           0 :             Stk& v = stk_[i];
    2014           0 :             switch (v.kind()) {
    2015             :               case Stk::MemI32:
    2016             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    2017           0 :                 size += sizeof(intptr_t);
    2018             : #else
    2019             :                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed I32");
    2020             : #endif
    2021           0 :                 break;
    2022             :               case Stk::MemI64:
    2023             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    2024           0 :                 size += sizeof(int64_t);
    2025             : #else
    2026             :                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed I64");
    2027             : #endif
    2028           0 :                 break;
    2029             :               case Stk::MemF64:
    2030             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    2031           0 :                 size += sizeof(double);
    2032             : #else
    2033             :                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed F64");
    2034             : #endif
    2035           0 :                 break;
    2036             :               case Stk::MemF32:
    2037             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    2038           0 :                 size += sizeof(double);
    2039             : #elif defined(JS_CODEGEN_ARM)
    2040             :                 size += sizeof(float);
    2041             : #else
    2042             :                 MOZ_CRASH("BaseCompiler platform hook: stackConsumed F32");
    2043             : #endif
    2044           0 :                 break;
    2045             :               default:
    2046           0 :                 break;
    2047             :             }
    2048             :         }
    2049           0 :         return size;
    2050             :     }
    2051             : 
    2052           0 :     void popValueStackTo(uint32_t stackSize) {
    2053           0 :         for (uint32_t i = stk_.length(); i > stackSize; i--) {
    2054           0 :             Stk& v = stk_[i-1];
    2055           0 :             switch (v.kind()) {
    2056             :               case Stk::RegisterI32:
    2057           0 :                 freeI32(v.i32reg());
    2058           0 :                 break;
    2059             :               case Stk::RegisterI64:
    2060           0 :                 freeI64(v.i64reg());
    2061           0 :                 break;
    2062             :               case Stk::RegisterF64:
    2063           0 :                 freeF64(v.f64reg());
    2064           0 :                 break;
    2065             :               case Stk::RegisterF32:
    2066           0 :                 freeF32(v.f32reg());
    2067           0 :                 break;
    2068             :               default:
    2069           0 :                 break;
    2070             :             }
    2071             :         }
    2072           0 :         stk_.shrinkTo(stackSize);
    2073           0 :     }
    2074             : 
    2075           0 :     void popValueStackBy(uint32_t items) {
    2076           0 :         popValueStackTo(stk_.length() - items);
    2077           0 :     }
    2078             : 
    2079             :     // Before branching to an outer control label, pop the execution
    2080             :     // stack to the level expected by that region, but do not free the
    2081             :     // stack as that will happen as compilation leaves the block.
    2082             : 
    2083           0 :     void popStackBeforeBranch(uint32_t framePushed) {
    2084           0 :         uint32_t frameHere = masm.framePushed();
    2085           0 :         if (frameHere > framePushed)
    2086           0 :             masm.addPtr(ImmWord(frameHere - framePushed), StackPointer);
    2087           0 :     }
    2088             : 
    2089           0 :     bool willPopStackBeforeBranch(uint32_t framePushed) {
    2090           0 :         uint32_t frameHere = masm.framePushed();
    2091           0 :         return frameHere > framePushed;
    2092             :     }
    2093             : 
    2094             :     // Before exiting a nested control region, pop the execution stack
    2095             :     // to the level expected by the nesting region, and free the
    2096             :     // stack.
    2097             : 
    2098           0 :     void popStackOnBlockExit(uint32_t framePushed) {
    2099           0 :         uint32_t frameHere = masm.framePushed();
    2100           0 :         if (frameHere > framePushed) {
    2101           0 :             if (deadCode_)
    2102           0 :                 masm.adjustStack(frameHere - framePushed);
    2103             :             else
    2104           0 :                 masm.freeStack(frameHere - framePushed);
    2105             :         }
    2106           0 :     }
    2107             : 
    2108           0 :     void popStackIfMemory() {
    2109           0 :         if (peek(0).isMem())
    2110           0 :             masm.freeStack(stackConsumed(1));
    2111           0 :     }
    2112             : 
    2113             :     // Peek at the stack, for calls.
    2114             : 
    2115           0 :     Stk& peek(uint32_t relativeDepth) {
    2116           0 :         return stk_[stk_.length()-1-relativeDepth];
    2117             :     }
    2118             : 
    2119             : #ifdef DEBUG
    2120             :     // Check that we're not leaking registers by comparing the
    2121             :     // state of the stack + available registers with the set of
    2122             :     // all available registers.
    2123             : 
    2124             :     // Call this before compiling any code.
    2125           0 :     void setupRegisterLeakCheck() {
    2126           0 :         allGPR_ = availGPR_;
    2127           0 :         allFPU_ = availFPU_;
    2128           0 :     }
    2129             : 
    2130             :     // Call this between opcodes.
    2131           0 :     void performRegisterLeakCheck() {
    2132           0 :         AllocatableGeneralRegisterSet knownGPR_ = availGPR_;
    2133           0 :         AllocatableFloatRegisterSet knownFPU_ = availFPU_;
    2134           0 :         for (size_t i = 0 ; i < stk_.length() ; i++) {
    2135           0 :             Stk& item = stk_[i];
    2136           0 :             switch (item.kind_) {
    2137             :               case Stk::RegisterI32:
    2138           0 :                 knownGPR_.add(item.i32reg());
    2139           0 :                 break;
    2140             :               case Stk::RegisterI64:
    2141             : #ifdef JS_PUNBOX64
    2142           0 :                 knownGPR_.add(item.i64reg().reg);
    2143             : #else
    2144             :                 knownGPR_.add(item.i64reg().high);
    2145             :                 knownGPR_.add(item.i64reg().low);
    2146             : #endif
    2147           0 :                 break;
    2148             :               case Stk::RegisterF32:
    2149           0 :                 knownFPU_.add(item.f32reg());
    2150           0 :                 break;
    2151             :               case Stk::RegisterF64:
    2152           0 :                 knownFPU_.add(item.f64reg());
    2153           0 :                 break;
    2154             :               default:
    2155           0 :                 break;
    2156             :             }
    2157             :         }
    2158           0 :         MOZ_ASSERT(knownGPR_.bits() == allGPR_.bits());
    2159           0 :         MOZ_ASSERT(knownFPU_.bits() == allFPU_.bits());
    2160           0 :     }
    2161             : #endif
    2162             : 
    2163             :     ////////////////////////////////////////////////////////////
    2164             :     //
    2165             :     // Control stack
    2166             : 
    2167           0 :     void initControl(Control& item)
    2168             :     {
    2169             :         // Make sure the constructor was run properly
    2170           0 :         MOZ_ASSERT(item.framePushed == UINT32_MAX && item.stackSize == UINT32_MAX);
    2171             : 
    2172           0 :         item.framePushed = masm.framePushed();
    2173           0 :         item.stackSize = stk_.length();
    2174           0 :         item.deadOnArrival = deadCode_;
    2175           0 :         item.bceSafeOnEntry = bceSafe_;
    2176           0 :     }
    2177             : 
    2178           0 :     Control& controlItem() {
    2179           0 :         return iter_.controlItem();
    2180             :     }
    2181             : 
    2182           0 :     Control& controlItem(uint32_t relativeDepth) {
    2183           0 :         return iter_.controlItem(relativeDepth);
    2184             :     }
    2185             : 
    2186           0 :     Control& controlOutermost() {
    2187           0 :         return iter_.controlOutermost();
    2188             :     }
    2189             : 
    2190             :     ////////////////////////////////////////////////////////////
    2191             :     //
    2192             :     // Labels
    2193             : 
    2194           0 :     void insertBreakablePoint(CallSiteDesc::Kind kind) {
    2195             :         // The debug trap exit requires WasmTlsReg be loaded. However, since we
    2196             :         // are emitting millions of these breakable points inline, we push this
    2197             :         // loading of TLS into the FarJumpIsland created by patchCallSites.
    2198           0 :         masm.nopPatchableToCall(CallSiteDesc(iter_.lastOpcodeOffset(), kind));
    2199           0 :     }
    2200             : 
    2201             :     //////////////////////////////////////////////////////////////////////
    2202             :     //
    2203             :     // Function prologue and epilogue.
    2204             : 
    2205           0 :     void beginFunction() {
    2206           0 :         JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
    2207             : 
    2208           0 :         SigIdDesc sigId = env_.funcSigs[func_.index()]->id;
    2209           0 :         GenerateFunctionPrologue(masm, localSize_, sigId, &offsets_);
    2210             : 
    2211           0 :         MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_));
    2212             : 
    2213           0 :         maxFramePushed_ = localSize_;
    2214             : 
    2215           0 :         if (debugEnabled_) {
    2216             :             // Initialize funcIndex and flag fields of DebugFrame.
    2217           0 :             size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame();
    2218           0 :             masm.store32(Imm32(func_.index()),
    2219           0 :                          Address(masm.getStackPointer(), debugFrame + DebugFrame::offsetOfFuncIndex()));
    2220           0 :             masm.storePtr(ImmWord(0),
    2221           0 :                           Address(masm.getStackPointer(), debugFrame + DebugFrame::offsetOfFlagsWord()));
    2222             :         }
    2223             : 
    2224             :         // We won't know until after we've generated code how big the frame will
    2225             :         // be (we may need arbitrary spill slots and outgoing param slots) so
    2226             :         // emit a patchable add that is patched in endFunction().
    2227             :         //
    2228             :         // ScratchReg may be used by branchPtr(), so use ABINonArgReg0/1 for
    2229             :         // temporaries.
    2230             : 
    2231           0 :         stackAddOffset_ = masm.add32ToPtrWithPatch(StackPointer, ABINonArgReg0);
    2232           0 :         masm.wasmEmitStackCheck(ABINonArgReg0, ABINonArgReg1, &stackOverflowLabel_);
    2233             : 
    2234             :         // Copy arguments from registers to stack.
    2235             : 
    2236           0 :         const ValTypeVector& args = func_.sig().args();
    2237             : 
    2238           0 :         for (ABIArgIter<const ValTypeVector> i(args); !i.done(); i++) {
    2239           0 :             Local& l = localInfo_[i.index()];
    2240           0 :             switch (i.mirType()) {
    2241             :               case MIRType::Int32:
    2242           0 :                 if (i->argInRegister())
    2243           0 :                     storeToFrameI32(i->gpr(), l.offs());
    2244           0 :                 break;
    2245             :               case MIRType::Int64:
    2246           0 :                 if (i->argInRegister())
    2247           0 :                     storeToFrameI64(i->gpr64(), l.offs());
    2248           0 :                 break;
    2249             :               case MIRType::Double:
    2250           0 :                 if (i->argInRegister())
    2251           0 :                     storeToFrameF64(i->fpu(), l.offs());
    2252           0 :                 break;
    2253             :               case MIRType::Float32:
    2254           0 :                 if (i->argInRegister())
    2255           0 :                     storeToFrameF32(i->fpu(), l.offs());
    2256           0 :                 break;
    2257             :               default:
    2258           0 :                 MOZ_CRASH("Function argument type");
    2259             :             }
    2260             :         }
    2261             : 
    2262             :         // Initialize the stack locals to zero.
    2263             :         //
    2264             :         // The following are all Bug 1316820:
    2265             :         //
    2266             :         // TODO / OPTIMIZE: on x64, at least, scratch will be a 64-bit
    2267             :         // register and we can move 64 bits at a time.
    2268             :         //
    2269             :         // TODO / OPTIMIZE: On SSE2 or better SIMD systems we may be
    2270             :         // able to store 128 bits at a time.  (I suppose on some
    2271             :         // systems we have 512-bit SIMD for that matter.)
    2272             :         //
    2273             :         // TODO / OPTIMIZE: if we have only one initializing store
    2274             :         // then it's better to store a zero literal, probably.
    2275             : 
    2276           0 :         if (varLow_ < varHigh_) {
    2277           0 :             ScratchI32 scratch(*this);
    2278           0 :             masm.mov(ImmWord(0), scratch);
    2279           0 :             for (int32_t i = varLow_ ; i < varHigh_ ; i += 4)
    2280           0 :                 storeToFrameI32(scratch, i + 4);
    2281             :         }
    2282             : 
    2283           0 :         if (debugEnabled_)
    2284           0 :             insertBreakablePoint(CallSiteDesc::EnterFrame);
    2285           0 :     }
    2286             : 
    2287           0 :     void saveResult() {
    2288           0 :         MOZ_ASSERT(debugEnabled_);
    2289           0 :         size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
    2290           0 :         Address resultsAddress(StackPointer, debugFrameOffset + DebugFrame::offsetOfResults());
    2291           0 :         switch (func_.sig().ret()) {
    2292             :           case ExprType::Void:
    2293           0 :             break;
    2294             :           case ExprType::I32:
    2295           0 :             masm.store32(RegI32(ReturnReg), resultsAddress);
    2296           0 :             break;
    2297             : 
    2298             :           case ExprType::I64:
    2299           0 :             masm.store64(RegI64(ReturnReg64), resultsAddress);
    2300           0 :             break;
    2301             :           case ExprType::F64:
    2302           0 :             masm.storeDouble(RegF64(ReturnDoubleReg), resultsAddress);
    2303           0 :             break;
    2304             :           case ExprType::F32:
    2305           0 :             masm.storeFloat32(RegF32(ReturnFloat32Reg), resultsAddress);
    2306           0 :             break;
    2307             :           default:
    2308           0 :             MOZ_CRASH("Function return type");
    2309             :         }
    2310           0 :     }
    2311             : 
    2312           0 :     void restoreResult() {
    2313           0 :         MOZ_ASSERT(debugEnabled_);
    2314           0 :         size_t debugFrameOffset = masm.framePushed() - DebugFrame::offsetOfFrame();
    2315           0 :         Address resultsAddress(StackPointer, debugFrameOffset + DebugFrame::offsetOfResults());
    2316           0 :         switch (func_.sig().ret()) {
    2317             :           case ExprType::Void:
    2318           0 :             break;
    2319             :           case ExprType::I32:
    2320           0 :             masm.load32(resultsAddress, RegI32(ReturnReg));
    2321           0 :             break;
    2322             :           case ExprType::I64:
    2323           0 :             masm.load64(resultsAddress, RegI64(ReturnReg64));
    2324           0 :             break;
    2325             :           case ExprType::F64:
    2326           0 :             masm.loadDouble(resultsAddress, RegF64(ReturnDoubleReg));
    2327           0 :             break;
    2328             :           case ExprType::F32:
    2329           0 :             masm.loadFloat32(resultsAddress, RegF32(ReturnFloat32Reg));
    2330           0 :             break;
    2331             :           default:
    2332           0 :             MOZ_CRASH("Function return type");
    2333             :         }
    2334           0 :     }
    2335             : 
    2336           0 :     bool endFunction() {
    2337             :         // Always branch to stackOverflowLabel_ or returnLabel_.
    2338           0 :         masm.breakpoint();
    2339             : 
    2340             :         // Patch the add in the prologue so that it checks against the correct
    2341             :         // frame size. Flush the constant pool in case it needs to be patched.
    2342           0 :         MOZ_ASSERT(maxFramePushed_ >= localSize_);
    2343           0 :         masm.flush();
    2344             : 
    2345             :         // Precondition for patching.
    2346           0 :         if (masm.oom())
    2347           0 :             return false;
    2348           0 :         masm.patchAdd32ToPtr(stackAddOffset_, Imm32(-int32_t(maxFramePushed_ - localSize_)));
    2349             : 
    2350             :         // Since we just overflowed the stack, to be on the safe side, pop the
    2351             :         // stack so that, when the trap exit stub executes, it is a safe
    2352             :         // distance away from the end of the native stack. If debugEnabled_ is
    2353             :         // set, we pop all locals space except allocated for DebugFrame to
    2354             :         // maintain the invariant that, when debugEnabled_, all wasm::Frames
    2355             :         // are valid wasm::DebugFrames which is observable by WasmHandleThrow.
    2356           0 :         masm.bind(&stackOverflowLabel_);
    2357           0 :         int32_t debugFrameReserved = debugEnabled_ ? DebugFrame::offsetOfFrame() : 0;
    2358           0 :         MOZ_ASSERT(localSize_ >= debugFrameReserved);
    2359           0 :         if (localSize_ > debugFrameReserved)
    2360           0 :             masm.addToStackPtr(Imm32(localSize_ - debugFrameReserved));
    2361           0 :         BytecodeOffset prologueTrapOffset(func_.lineOrBytecode());
    2362           0 :         masm.jump(TrapDesc(prologueTrapOffset, Trap::StackOverflow, debugFrameReserved));
    2363             : 
    2364           0 :         masm.bind(&returnLabel_);
    2365             : 
    2366           0 :         if (debugEnabled_) {
    2367             :             // Store and reload the return value from DebugFrame::return so that
    2368             :             // it can be clobbered, and/or modified by the debug trap.
    2369           0 :             saveResult();
    2370           0 :             insertBreakablePoint(CallSiteDesc::Breakpoint);
    2371           0 :             insertBreakablePoint(CallSiteDesc::LeaveFrame);
    2372           0 :             restoreResult();
    2373             :         }
    2374             : 
    2375           0 :         GenerateFunctionEpilogue(masm, localSize_, &offsets_);
    2376             : 
    2377             : #if defined(JS_ION_PERF)
    2378             :         // FIXME - profiling code missing.  No bug for this.
    2379             : 
    2380             :         // Note the end of the inline code and start of the OOL code.
    2381             :         //gen->perfSpewer().noteEndInlineCode(masm);
    2382             : #endif
    2383             : 
    2384           0 :         if (!generateOutOfLineCode())
    2385           0 :             return false;
    2386             : 
    2387           0 :         masm.wasmEmitTrapOutOfLineCode();
    2388             : 
    2389           0 :         offsets_.end = masm.currentOffset();
    2390             : 
    2391             :         // A frame greater than 256KB is implausible, probably an attack,
    2392             :         // so fail the compilation.
    2393             : 
    2394           0 :         if (maxFramePushed_ > 256 * 1024)
    2395           0 :             return false;
    2396             : 
    2397           0 :         return !masm.oom();
    2398             :     }
    2399             : 
    2400             :     //////////////////////////////////////////////////////////////////////
    2401             :     //
    2402             :     // Calls.
    2403             : 
    2404             :     struct FunctionCall
    2405             :     {
    2406           0 :         explicit FunctionCall(uint32_t lineOrBytecode)
    2407           0 :           : lineOrBytecode(lineOrBytecode),
    2408             :             reloadMachineStateAfter(false),
    2409             :             usesSystemAbi(false),
    2410             : #ifdef JS_CODEGEN_ARM
    2411             :             hardFP(true),
    2412             : #endif
    2413             :             frameAlignAdjustment(0),
    2414           0 :             stackArgAreaSize(0)
    2415           0 :         {}
    2416             : 
    2417             :         uint32_t lineOrBytecode;
    2418             :         ABIArgGenerator abi;
    2419             :         bool reloadMachineStateAfter;
    2420             :         bool usesSystemAbi;
    2421             : #ifdef JS_CODEGEN_ARM
    2422             :         bool hardFP;
    2423             : #endif
    2424             :         size_t frameAlignAdjustment;
    2425             :         size_t stackArgAreaSize;
    2426             :     };
    2427             : 
    2428           0 :     void beginCall(FunctionCall& call, UseABI useABI, InterModule interModule)
    2429             :     {
    2430           0 :         call.reloadMachineStateAfter = interModule == InterModule::True || useABI == UseABI::System;
    2431           0 :         call.usesSystemAbi = useABI == UseABI::System;
    2432             : 
    2433           0 :         if (call.usesSystemAbi) {
    2434             :             // Call-outs need to use the appropriate system ABI.
    2435             : #if defined(JS_CODEGEN_ARM)
    2436             : # if defined(JS_SIMULATOR_ARM)
    2437             :             call.hardFP = UseHardFpABI();
    2438             : # elif defined(JS_CODEGEN_ARM_HARDFP)
    2439             :             call.hardFP = true;
    2440             : # else
    2441             :             call.hardFP = false;
    2442             : # endif
    2443             :             call.abi.setUseHardFp(call.hardFP);
    2444             : #endif
    2445             :         }
    2446             : 
    2447           0 :         call.frameAlignAdjustment = ComputeByteAlignment(masm.framePushed() + sizeof(Frame),
    2448             :                                                          JitStackAlignment);
    2449           0 :     }
    2450             : 
    2451           0 :     void endCall(FunctionCall& call, size_t stackSpace)
    2452             :     {
    2453           0 :         size_t adjustment = call.stackArgAreaSize + call.frameAlignAdjustment;
    2454           0 :         masm.freeStack(stackSpace + adjustment);
    2455             : 
    2456           0 :         if (call.reloadMachineStateAfter) {
    2457             :             // On x86 there are no pinned registers, so don't waste time
    2458             :             // reloading the Tls.
    2459             : #ifndef JS_CODEGEN_X86
    2460           0 :             masm.loadWasmTlsRegFromFrame();
    2461           0 :             masm.loadWasmPinnedRegsFromTls();
    2462             : #endif
    2463             :         }
    2464           0 :     }
    2465             : 
    2466             :     // TODO / OPTIMIZE (Bug 1316821): This is expensive; let's roll the iterator
    2467             :     // walking into the walking done for passArg.  See comments in passArg.
    2468             : 
    2469             :     // Note, stackArgAreaSize() must process all the arguments to get the
    2470             :     // alignment right; the signature must therefore be the complete call
    2471             :     // signature.
    2472             : 
    2473             :     template<class T>
    2474           0 :     size_t stackArgAreaSize(const T& args) {
    2475           0 :         ABIArgIter<const T> i(args);
    2476           0 :         while (!i.done())
    2477           0 :             i++;
    2478           0 :         return AlignBytes(i.stackBytesConsumedSoFar(), 16u);
    2479             :     }
    2480             : 
    2481           0 :     void startCallArgs(FunctionCall& call, size_t stackArgAreaSize)
    2482             :     {
    2483           0 :         call.stackArgAreaSize = stackArgAreaSize;
    2484             : 
    2485           0 :         size_t adjustment = call.stackArgAreaSize + call.frameAlignAdjustment;
    2486           0 :         if (adjustment)
    2487           0 :             masm.reserveStack(adjustment);
    2488           0 :     }
    2489             : 
    2490           0 :     const ABIArg reservePointerArgument(FunctionCall& call) {
    2491           0 :         return call.abi.next(MIRType::Pointer);
    2492             :     }
    2493             : 
    2494             :     // TODO / OPTIMIZE (Bug 1316821): Note passArg is used only in one place.
    2495             :     // (Or it was, until Luke wandered through, but that can be fixed again.)
    2496             :     // I'm not saying we should manually inline it, but we could hoist the
    2497             :     // dispatch into the caller and have type-specific implementations of
    2498             :     // passArg: passArgI32(), etc.  Then those might be inlined, at least in PGO
    2499             :     // builds.
    2500             :     //
    2501             :     // The bulk of the work here (60%) is in the next() call, though.
    2502             :     //
    2503             :     // Notably, since next() is so expensive, stackArgAreaSize() becomes
    2504             :     // expensive too.
    2505             :     //
    2506             :     // Somehow there could be a trick here where the sequence of
    2507             :     // argument types (read from the input stream) leads to a cached
    2508             :     // entry for stackArgAreaSize() and for how to pass arguments...
    2509             :     //
    2510             :     // But at least we could reduce the cost of stackArgAreaSize() by
    2511             :     // first reading the argument types into a (reusable) vector, then
    2512             :     // we have the outgoing size at low cost, and then we can pass
    2513             :     // args based on the info we read.
    2514             : 
    2515           0 :     void passArg(FunctionCall& call, ValType type, Stk& arg) {
    2516           0 :         switch (type) {
    2517             :           case ValType::I32: {
    2518           0 :             ABIArg argLoc = call.abi.next(MIRType::Int32);
    2519           0 :             if (argLoc.kind() == ABIArg::Stack) {
    2520           0 :                 ScratchI32 scratch(*this);
    2521           0 :                 loadI32(scratch, arg);
    2522           0 :                 masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase()));
    2523             :             } else {
    2524           0 :                 loadI32(argLoc.gpr(), arg);
    2525             :             }
    2526           0 :             break;
    2527             :           }
    2528             :           case ValType::I64: {
    2529           0 :             ABIArg argLoc = call.abi.next(MIRType::Int64);
    2530           0 :             if (argLoc.kind() == ABIArg::Stack) {
    2531           0 :                 ScratchI32 scratch(*this);
    2532             : #if defined(JS_CODEGEN_X64)
    2533           0 :                 loadI64(Register64(scratch), arg);
    2534           0 :                 masm.movq(scratch, Operand(StackPointer, argLoc.offsetFromArgBase()));
    2535             : #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    2536             :                 loadI64Low(scratch, arg);
    2537             :                 masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64LOW_OFFSET));
    2538             :                 loadI64High(scratch, arg);
    2539             :                 masm.store32(scratch, Address(StackPointer, argLoc.offsetFromArgBase() + INT64HIGH_OFFSET));
    2540             : #else
    2541             :                 MOZ_CRASH("BaseCompiler platform hook: passArg I64");
    2542             : #endif
    2543             :             } else {
    2544           0 :                 loadI64(argLoc.gpr64(), arg);
    2545             :             }
    2546           0 :             break;
    2547             :           }
    2548             :           case ValType::F64: {
    2549           0 :             ABIArg argLoc = call.abi.next(MIRType::Double);
    2550           0 :             switch (argLoc.kind()) {
    2551             :               case ABIArg::Stack: {
    2552           0 :                 ScratchF64 scratch(*this);
    2553           0 :                 loadF64(scratch, arg);
    2554           0 :                 masm.storeDouble(scratch, Address(StackPointer, argLoc.offsetFromArgBase()));
    2555           0 :                 break;
    2556             :               }
    2557             : #if defined(JS_CODEGEN_REGISTER_PAIR)
    2558             :               case ABIArg::GPR_PAIR: {
    2559             : # ifdef JS_CODEGEN_ARM
    2560             :                 ScratchF64 scratch(*this);
    2561             :                 loadF64(scratch, arg);
    2562             :                 masm.ma_vxfer(scratch, argLoc.evenGpr(), argLoc.oddGpr());
    2563             :                 break;
    2564             : # else
    2565             :                 MOZ_CRASH("BaseCompiler platform hook: passArg F64 pair");
    2566             : # endif
    2567             :               }
    2568             : #endif
    2569             :               case ABIArg::FPU: {
    2570           0 :                 loadF64(argLoc.fpu(), arg);
    2571           0 :                 break;
    2572             :               }
    2573             :               case ABIArg::GPR: {
    2574           0 :                 MOZ_CRASH("Unexpected parameter passing discipline");
    2575             :               }
    2576             :             }
    2577           0 :             break;
    2578             :           }
    2579             :           case ValType::F32: {
    2580           0 :             ABIArg argLoc = call.abi.next(MIRType::Float32);
    2581           0 :             switch (argLoc.kind()) {
    2582             :               case ABIArg::Stack: {
    2583           0 :                 ScratchF32 scratch(*this);
    2584           0 :                 loadF32(scratch, arg);
    2585           0 :                 masm.storeFloat32(scratch, Address(StackPointer, argLoc.offsetFromArgBase()));
    2586           0 :                 break;
    2587             :               }
    2588             :               case ABIArg::GPR: {
    2589           0 :                 ScratchF32 scratch(*this);
    2590           0 :                 loadF32(scratch, arg);
    2591           0 :                 masm.moveFloat32ToGPR(scratch, argLoc.gpr());
    2592           0 :                 break;
    2593             :               }
    2594             :               case ABIArg::FPU: {
    2595           0 :                 loadF32(argLoc.fpu(), arg);
    2596           0 :                 break;
    2597             :               }
    2598             : #if defined(JS_CODEGEN_REGISTER_PAIR)
    2599             :               case ABIArg::GPR_PAIR: {
    2600             :                 MOZ_CRASH("Unexpected parameter passing discipline");
    2601             :               }
    2602             : #endif
    2603             :             }
    2604           0 :             break;
    2605             :           }
    2606             :           default:
    2607           0 :             MOZ_CRASH("Function argument type");
    2608             :         }
    2609           0 :     }
    2610             : 
    2611           0 :     void callDefinition(uint32_t funcIndex, const FunctionCall& call)
    2612             :     {
    2613           0 :         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Func);
    2614           0 :         masm.call(desc, funcIndex);
    2615           0 :     }
    2616             : 
    2617           0 :     void callSymbolic(SymbolicAddress callee, const FunctionCall& call) {
    2618           0 :         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic);
    2619           0 :         masm.call(desc, callee);
    2620           0 :     }
    2621             : 
    2622             :     // Precondition: sync()
    2623             : 
    2624           0 :     void callIndirect(uint32_t sigIndex, Stk& indexVal, const FunctionCall& call)
    2625             :     {
    2626           0 :         const SigWithId& sig = env_.sigs[sigIndex];
    2627           0 :         MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
    2628             : 
    2629           0 :         MOZ_ASSERT(env_.tables.length() == 1);
    2630           0 :         const TableDesc& table = env_.tables[0];
    2631             : 
    2632           0 :         loadI32(WasmTableCallIndexReg, indexVal);
    2633             : 
    2634           0 :         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Dynamic);
    2635           0 :         CalleeDesc callee = CalleeDesc::wasmTable(table, sig.id);
    2636           0 :         masm.wasmCallIndirect(desc, callee, NeedsBoundsCheck(true));
    2637           0 :     }
    2638             : 
    2639             :     // Precondition: sync()
    2640             : 
    2641           0 :     void callImport(unsigned globalDataOffset, const FunctionCall& call)
    2642             :     {
    2643           0 :         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Dynamic);
    2644           0 :         CalleeDesc callee = CalleeDesc::import(globalDataOffset);
    2645           0 :         masm.wasmCallImport(desc, callee);
    2646           0 :     }
    2647             : 
    2648           0 :     void builtinCall(SymbolicAddress builtin, const FunctionCall& call)
    2649             :     {
    2650           0 :         callSymbolic(builtin, call);
    2651           0 :     }
    2652             : 
    2653           0 :     void builtinInstanceMethodCall(SymbolicAddress builtin, const ABIArg& instanceArg,
    2654             :                                    const FunctionCall& call)
    2655             :     {
    2656             :         // Builtin method calls assume the TLS register has been set.
    2657           0 :         masm.loadWasmTlsRegFromFrame();
    2658             : 
    2659           0 :         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic);
    2660           0 :         masm.wasmCallBuiltinInstanceMethod(desc, instanceArg, builtin);
    2661           0 :     }
    2662             : 
    2663             :     //////////////////////////////////////////////////////////////////////
    2664             :     //
    2665             :     // Sundry low-level code generators.
    2666             : 
    2667           0 :     void addInterruptCheck()
    2668             :     {
    2669             :         // Always use signals for interrupts with Asm.JS/Wasm
    2670           0 :         MOZ_RELEASE_ASSERT(HaveSignalHandlers());
    2671           0 :     }
    2672             : 
    2673           0 :     void jumpTable(LabelVector& labels, Label* theTable) {
    2674             :         // Flush constant pools to ensure that the table is never interrupted by
    2675             :         // constant pool entries.
    2676           0 :         masm.flush();
    2677             : 
    2678           0 :         masm.bind(theTable);
    2679             : 
    2680             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    2681           0 :         for (uint32_t i = 0; i < labels.length(); i++) {
    2682           0 :             CodeLabel cl;
    2683           0 :             masm.writeCodePointer(cl.patchAt());
    2684           0 :             cl.target()->bind(labels[i].offset());
    2685           0 :             masm.addCodeLabel(cl);
    2686             :         }
    2687             : #else
    2688             :         MOZ_CRASH("BaseCompiler platform hook: jumpTable");
    2689             : #endif
    2690           0 :     }
    2691             : 
    2692           0 :     void tableSwitch(Label* theTable, RegI32 switchValue, Label* dispatchCode) {
    2693           0 :         masm.bind(dispatchCode);
    2694             : 
    2695             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    2696           0 :         ScratchI32 scratch(*this);
    2697           0 :         CodeLabel tableCl;
    2698             : 
    2699           0 :         masm.mov(tableCl.patchAt(), scratch);
    2700             : 
    2701           0 :         tableCl.target()->bind(theTable->offset());
    2702           0 :         masm.addCodeLabel(tableCl);
    2703             : 
    2704           0 :         masm.jmp(Operand(scratch, switchValue, ScalePointer));
    2705             : #elif defined(JS_CODEGEN_ARM)
    2706             :         // Flush constant pools: offset must reflect the distance from the MOV
    2707             :         // to the start of the table; as the address of the MOV is given by the
    2708             :         // label, nothing must come between the bind() and the ma_mov().
    2709             :         masm.flush();
    2710             : 
    2711             :         ScratchI32 scratch(*this);
    2712             : 
    2713             :         // Compute the offset from the ma_mov instruction to the jump table.
    2714             :         Label here;
    2715             :         masm.bind(&here);
    2716             :         uint32_t offset = here.offset() - theTable->offset();
    2717             : 
    2718             :         // Read PC+8
    2719             :         masm.ma_mov(pc, scratch);
    2720             : 
    2721             :         // ARM scratch register is required by ma_sub.
    2722             :         ScratchRegisterScope arm_scratch(*this);
    2723             : 
    2724             :         // Compute the absolute table base pointer into `scratch`, offset by 8
    2725             :         // to account for the fact that ma_mov read PC+8.
    2726             :         masm.ma_sub(Imm32(offset + 8), scratch, arm_scratch);
    2727             : 
    2728             :         // Jump indirect via table element.
    2729             :         masm.ma_ldr(DTRAddr(scratch, DtrRegImmShift(switchValue, LSL, 2)), pc, Offset,
    2730             :                     Assembler::Always);
    2731             : #else
    2732             :         MOZ_CRASH("BaseCompiler platform hook: tableSwitch");
    2733             : #endif
    2734           0 :     }
    2735             : 
    2736           0 :     RegI32 captureReturnedI32() {
    2737           0 :         RegI32 rv = RegI32(ReturnReg);
    2738           0 :         MOZ_ASSERT(isAvailable(rv));
    2739           0 :         needI32(rv);
    2740           0 :         return rv;
    2741             :     }
    2742             : 
    2743           0 :     RegI64 captureReturnedI64() {
    2744           0 :         RegI64 rv = RegI64(ReturnReg64);
    2745           0 :         MOZ_ASSERT(isAvailable(rv));
    2746           0 :         needI64(rv);
    2747           0 :         return rv;
    2748             :     }
    2749             : 
    2750           0 :     RegF32 captureReturnedF32(const FunctionCall& call) {
    2751           0 :         RegF32 rv = RegF32(ReturnFloat32Reg);
    2752           0 :         MOZ_ASSERT(isAvailable(rv));
    2753           0 :         needF32(rv);
    2754             : #if defined(JS_CODEGEN_ARM)
    2755             :         if (call.usesSystemAbi && !call.hardFP)
    2756             :             masm.ma_vxfer(r0, rv);
    2757             : #endif
    2758           0 :         return rv;
    2759             :     }
    2760             : 
    2761           0 :     RegF64 captureReturnedF64(const FunctionCall& call) {
    2762           0 :         RegF64 rv = RegF64(ReturnDoubleReg);
    2763           0 :         MOZ_ASSERT(isAvailable(rv));
    2764           0 :         needF64(rv);
    2765             : #if defined(JS_CODEGEN_ARM)
    2766             :         if (call.usesSystemAbi && !call.hardFP)
    2767             :             masm.ma_vxfer(r0, r1, rv);
    2768             : #endif
    2769           0 :         return rv;
    2770             :     }
    2771             : 
    2772           0 :     void returnCleanup(bool popStack) {
    2773           0 :         if (popStack)
    2774           0 :             popStackBeforeBranch(controlOutermost().framePushed);
    2775           0 :         masm.jump(&returnLabel_);
    2776           0 :     }
    2777             : 
    2778           0 :     void pop2xI32ForIntMulDiv(RegI32* r0, RegI32* r1) {
    2779             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    2780             :         // srcDest must be eax, and edx will be clobbered.
    2781           0 :         need2xI32(specific_eax, specific_edx);
    2782           0 :         *r1 = popI32();
    2783           0 :         *r0 = popI32ToSpecific(specific_eax);
    2784           0 :         freeI32(specific_edx);
    2785             : #else
    2786             :         pop2xI32(r0, r1);
    2787             : #endif
    2788           0 :     }
    2789             : 
    2790           0 :     void pop2xI64ForIntDiv(RegI64* r0, RegI64* r1) {
    2791             : #ifdef JS_CODEGEN_X64
    2792             :         // srcDest must be rax, and rdx will be clobbered.
    2793           0 :         need2xI64(specific_rax, specific_rdx);
    2794           0 :         *r1 = popI64();
    2795           0 :         *r0 = popI64ToSpecific(specific_rax);
    2796           0 :         freeI64(specific_rdx);
    2797             : #else
    2798             :         pop2xI64(r0, r1);
    2799             : #endif
    2800           0 :     }
    2801             : 
    2802           0 :     void checkDivideByZeroI32(RegI32 rhs, RegI32 srcDest, Label* done) {
    2803           0 :         masm.branchTest32(Assembler::Zero, rhs, rhs, trap(Trap::IntegerDivideByZero));
    2804           0 :     }
    2805             : 
    2806           0 :     void checkDivideByZeroI64(RegI64 r) {
    2807           0 :         ScratchI32 scratch(*this);
    2808           0 :         masm.branchTest64(Assembler::Zero, r, r, scratch, trap(Trap::IntegerDivideByZero));
    2809           0 :     }
    2810             : 
    2811           0 :     void checkDivideSignedOverflowI32(RegI32 rhs, RegI32 srcDest, Label* done, bool zeroOnOverflow) {
    2812           0 :         Label notMin;
    2813           0 :         masm.branch32(Assembler::NotEqual, srcDest, Imm32(INT32_MIN), &notMin);
    2814           0 :         if (zeroOnOverflow) {
    2815           0 :             masm.branch32(Assembler::NotEqual, rhs, Imm32(-1), &notMin);
    2816           0 :             masm.move32(Imm32(0), srcDest);
    2817           0 :             masm.jump(done);
    2818             :         } else {
    2819           0 :             masm.branch32(Assembler::Equal, rhs, Imm32(-1), trap(Trap::IntegerOverflow));
    2820             :         }
    2821           0 :         masm.bind(&notMin);
    2822           0 :     }
    2823             : 
    2824           0 :     void checkDivideSignedOverflowI64(RegI64 rhs, RegI64 srcDest, Label* done, bool zeroOnOverflow) {
    2825           0 :         Label notmin;
    2826           0 :         masm.branch64(Assembler::NotEqual, srcDest, Imm64(INT64_MIN), &notmin);
    2827           0 :         masm.branch64(Assembler::NotEqual, rhs, Imm64(-1), &notmin);
    2828           0 :         if (zeroOnOverflow) {
    2829           0 :             masm.xor64(srcDest, srcDest);
    2830           0 :             masm.jump(done);
    2831             :         } else {
    2832           0 :             masm.jump(trap(Trap::IntegerOverflow));
    2833             :         }
    2834           0 :         masm.bind(&notmin);
    2835           0 :     }
    2836             : 
    2837             : #ifndef INT_DIV_I64_CALLOUT
    2838           0 :     void quotientI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned,
    2839             :                      bool isConst, int64_t c)
    2840             :     {
    2841           0 :         Label done;
    2842             : 
    2843           0 :         if (!isConst || c == 0)
    2844           0 :             checkDivideByZeroI64(rhs);
    2845             : 
    2846           0 :         if (!isUnsigned && (!isConst || c == -1))
    2847           0 :             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
    2848             : 
    2849             : # if defined(JS_CODEGEN_X64)
    2850             :         // The caller must set up the following situation.
    2851           0 :         MOZ_ASSERT(srcDest.reg == rax);
    2852           0 :         MOZ_ASSERT(isAvailable(rdx));
    2853           0 :         if (isUnsigned) {
    2854           0 :             masm.xorq(rdx, rdx);
    2855           0 :             masm.udivq(rhs.reg);
    2856             :         } else {
    2857           0 :             masm.cqo();
    2858           0 :             masm.idivq(rhs.reg);
    2859             :         }
    2860             : # else
    2861             :         MOZ_CRASH("BaseCompiler platform hook: quotientI64");
    2862             : # endif
    2863           0 :         masm.bind(&done);
    2864           0 :     }
    2865             : 
    2866           0 :     void remainderI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned,
    2867             :                       bool isConst, int64_t c)
    2868             :     {
    2869           0 :         Label done;
    2870             : 
    2871           0 :         if (!isConst || c == 0)
    2872           0 :             checkDivideByZeroI64(rhs);
    2873             : 
    2874           0 :         if (!isUnsigned && (!isConst || c == -1))
    2875           0 :             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
    2876             : 
    2877             : # if defined(JS_CODEGEN_X64)
    2878             :         // The caller must set up the following situation.
    2879           0 :         MOZ_ASSERT(srcDest.reg == rax);
    2880           0 :         MOZ_ASSERT(isAvailable(rdx));
    2881             : 
    2882           0 :         if (isUnsigned) {
    2883           0 :             masm.xorq(rdx, rdx);
    2884           0 :             masm.udivq(rhs.reg);
    2885             :         } else {
    2886           0 :             masm.cqo();
    2887           0 :             masm.idivq(rhs.reg);
    2888             :         }
    2889           0 :         masm.movq(rdx, rax);
    2890             : # else
    2891             :         MOZ_CRASH("BaseCompiler platform hook: remainderI64");
    2892             : # endif
    2893           0 :         masm.bind(&done);
    2894           0 :     }
    2895             : #endif // INT_DIV_I64_CALLOUT
    2896             : 
    2897           0 :     void pop2xI32ForShiftOrRotate(RegI32* r0, RegI32* r1) {
    2898             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    2899           0 :         *r1 = popI32(specific_ecx);
    2900           0 :         *r0 = popI32();
    2901             : #else
    2902             :         pop2xI32(r0, r1);
    2903             : #endif
    2904           0 :     }
    2905             : 
    2906           0 :     void pop2xI64ForShiftOrRotate(RegI64* r0, RegI64* r1) {
    2907             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    2908           0 :         needI32(specific_ecx);
    2909           0 :         *r1 = widenI32(specific_ecx);
    2910           0 :         *r1 = popI64ToSpecific(*r1);
    2911           0 :         *r0 = popI64();
    2912             : #else
    2913             :         pop2xI64(r0, r1);
    2914             : #endif
    2915           0 :     }
    2916             : 
    2917           0 :     bool rotate64NeedsTemp() const {
    2918             : #if defined(JS_CODEGEN_X86)
    2919             :         return true;
    2920             : #else
    2921           0 :         return false;
    2922             : #endif
    2923             :     }
    2924             : 
    2925           0 :     void maskShiftCount32(RegI32 r) {
    2926             : #if defined(JS_CODEGEN_ARM)
    2927             :         masm.and32(Imm32(31), r);
    2928             : #endif
    2929           0 :     }
    2930             : 
    2931           0 :     bool popcnt32NeedsTemp() const {
    2932             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    2933           0 :         return !AssemblerX86Shared::HasPOPCNT();
    2934             : #elif defined(JS_CODEGEN_ARM)
    2935             :         return true;
    2936             : #else
    2937             :         MOZ_CRASH("BaseCompiler platform hook: popcnt32NeedsTemp");
    2938             : #endif
    2939             :     }
    2940             : 
    2941           0 :     bool popcnt64NeedsTemp() const {
    2942             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    2943           0 :         return !AssemblerX86Shared::HasPOPCNT();
    2944             : #elif defined(JS_CODEGEN_ARM)
    2945             :         return true;
    2946             : #else
    2947             :         MOZ_CRASH("BaseCompiler platform hook: popcnt64NeedsTemp");
    2948             : #endif
    2949             :     }
    2950             : 
    2951           0 :     void reinterpretI64AsF64(RegI64 src, RegF64 dest) {
    2952             : #if defined(JS_CODEGEN_X64)
    2953           0 :         masm.vmovq(src.reg, dest);
    2954             : #elif defined(JS_CODEGEN_X86)
    2955             :         masm.Push(src.high);
    2956             :         masm.Push(src.low);
    2957             :         masm.vmovq(Operand(esp, 0), dest);
    2958             :         masm.freeStack(sizeof(uint64_t));
    2959             : #elif defined(JS_CODEGEN_ARM)
    2960             :         masm.ma_vxfer(src.low, src.high, dest);
    2961             : #else
    2962             :         MOZ_CRASH("BaseCompiler platform hook: reinterpretI64AsF64");
    2963             : #endif
    2964           0 :     }
    2965             : 
    2966           0 :     void reinterpretF64AsI64(RegF64 src, RegI64 dest) {
    2967             : #if defined(JS_CODEGEN_X64)
    2968           0 :         masm.vmovq(src, dest.reg);
    2969             : #elif defined(JS_CODEGEN_X86)
    2970             :         masm.reserveStack(sizeof(uint64_t));
    2971             :         masm.vmovq(src, Operand(esp, 0));
    2972             :         masm.Pop(dest.low);
    2973             :         masm.Pop(dest.high);
    2974             : #elif defined(JS_CODEGEN_ARM)
    2975             :         masm.ma_vxfer(src, dest.low, dest.high);
    2976             : #else
    2977             :         MOZ_CRASH("BaseCompiler platform hook: reinterpretF64AsI64");
    2978             : #endif
    2979           0 :     }
    2980             : 
    2981           0 :     void wrapI64ToI32(RegI64 src, RegI32 dest) {
    2982             : #if defined(JS_CODEGEN_X64)
    2983             :         // movl clears the high bits if the two registers are the same.
    2984           0 :         masm.movl(src.reg, dest);
    2985             : #elif defined(JS_NUNBOX32)
    2986             :         if (src.low != dest)
    2987             :             masm.move32(src.low, dest);
    2988             : #else
    2989             :         MOZ_CRASH("BaseCompiler platform hook: wrapI64ToI32");
    2990             : #endif
    2991           0 :     }
    2992             : 
    2993           0 :     RegI64 popI32ForSignExtendI64() {
    2994             : #if defined(JS_CODEGEN_X86)
    2995             :         need2xI32(specific_edx, specific_eax);
    2996             :         RegI32 r0 = popI32ToSpecific(specific_eax);
    2997             :         RegI64 x0 = RegI64(Register64(specific_edx, specific_eax));
    2998             :         (void)r0;               // x0 is the widening of r0
    2999             : #else
    3000           0 :         RegI32 r0 = popI32();
    3001           0 :         RegI64 x0 = widenI32(r0);
    3002             : #endif
    3003           0 :         return x0;
    3004             :     }
    3005             : 
    3006           0 :     void signExtendI32ToI64(RegI32 src, RegI64 dest) {
    3007             : #if defined(JS_CODEGEN_X64)
    3008           0 :         masm.movslq(src, dest.reg);
    3009             : #elif defined(JS_CODEGEN_X86)
    3010             :         MOZ_ASSERT(dest.low == src);
    3011             :         MOZ_ASSERT(dest.low == eax);
    3012             :         MOZ_ASSERT(dest.high == edx);
    3013             :         masm.cdq();
    3014             : #elif defined(JS_CODEGEN_ARM)
    3015             :         masm.ma_mov(src, dest.low);
    3016             :         masm.ma_asr(Imm32(31), src, dest.high);
    3017             : #else
    3018             :         MOZ_CRASH("BaseCompiler platform hook: signExtendI32ToI64");
    3019             : #endif
    3020           0 :     }
    3021             : 
    3022           0 :     void extendU32ToI64(RegI32 src, RegI64 dest) {
    3023             : #if defined(JS_CODEGEN_X64)
    3024           0 :         masm.movl(src, dest.reg);
    3025             : #elif defined(JS_NUNBOX32)
    3026             :         if (src != dest.low)
    3027             :             masm.move32(src, dest.low);
    3028             :         masm.move32(Imm32(0), dest.high);
    3029             : #else
    3030             :         MOZ_CRASH("BaseCompiler platform hook: extendU32ToI64");
    3031             : #endif
    3032           0 :     }
    3033             : 
    3034             :     class OutOfLineTruncateF32OrF64ToI32 : public OutOfLineCode
    3035             :     {
    3036             :         AnyReg src;
    3037             :         RegI32 dest;
    3038             :         bool isUnsigned;
    3039             :         BytecodeOffset off;
    3040             : 
    3041             :       public:
    3042           0 :         OutOfLineTruncateF32OrF64ToI32(AnyReg src, RegI32 dest, bool isUnsigned, BytecodeOffset off)
    3043           0 :           : src(src),
    3044             :             dest(dest),
    3045             :             isUnsigned(isUnsigned),
    3046           0 :             off(off)
    3047           0 :         {}
    3048             : 
    3049           0 :         virtual void generate(MacroAssembler& masm) {
    3050           0 :             bool isFloat = src.tag == AnyReg::F32;
    3051           0 :             FloatRegister fsrc = isFloat ? static_cast<FloatRegister>(src.f32())
    3052           0 :                                          : static_cast<FloatRegister>(src.f64());
    3053             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    3054           0 :             if (isFloat)
    3055           0 :                 masm.outOfLineWasmTruncateFloat32ToInt32(fsrc, isUnsigned, off, rejoin());
    3056             :             else
    3057           0 :                 masm.outOfLineWasmTruncateDoubleToInt32(fsrc, isUnsigned, off, rejoin());
    3058             : #elif defined(JS_CODEGEN_ARM)
    3059             :             masm.outOfLineWasmTruncateToIntCheck(fsrc,
    3060             :                                                  isFloat ? MIRType::Float32 : MIRType::Double,
    3061             :                                                  MIRType::Int32, isUnsigned, rejoin(), off);
    3062             : #else
    3063             :             (void)isUnsigned;
    3064             :             (void)off;
    3065             :             (void)isFloat;
    3066             :             (void)fsrc;
    3067             :             MOZ_CRASH("BaseCompiler platform hook: OutOfLineTruncateF32OrF64ToI32 wasm");
    3068             : #endif
    3069           0 :         }
    3070             :     };
    3071             : 
    3072           0 :     MOZ_MUST_USE bool truncateF32ToI32(RegF32 src, RegI32 dest, bool isUnsigned) {
    3073           0 :         BytecodeOffset off = bytecodeOffset();
    3074             :         OutOfLineCode* ool;
    3075             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
    3076           0 :         ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, isUnsigned, off);
    3077           0 :         ool = addOutOfLineCode(ool);
    3078           0 :         if (!ool)
    3079           0 :             return false;
    3080           0 :         if (isUnsigned)
    3081           0 :             masm.wasmTruncateFloat32ToUInt32(src, dest, ool->entry());
    3082             :         else
    3083           0 :             masm.wasmTruncateFloat32ToInt32(src, dest, ool->entry());
    3084             : #else
    3085             :         (void)off;
    3086             :         MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI32 wasm");
    3087             : #endif
    3088           0 :         masm.bind(ool->rejoin());
    3089           0 :         return true;
    3090             :     }
    3091             : 
    3092           0 :     MOZ_MUST_USE bool truncateF64ToI32(RegF64 src, RegI32 dest, bool isUnsigned) {
    3093           0 :         BytecodeOffset off = bytecodeOffset();
    3094             :         OutOfLineCode* ool;
    3095             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
    3096           0 :         ool = new(alloc_) OutOfLineTruncateF32OrF64ToI32(AnyReg(src), dest, isUnsigned, off);
    3097           0 :         ool = addOutOfLineCode(ool);
    3098           0 :         if (!ool)
    3099           0 :             return false;
    3100           0 :         if (isUnsigned)
    3101           0 :             masm.wasmTruncateDoubleToUInt32(src, dest, ool->entry());
    3102             :         else
    3103           0 :             masm.wasmTruncateDoubleToInt32(src, dest, ool->entry());
    3104             : #else
    3105             :         (void)off;
    3106             :         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI32 wasm");
    3107             : #endif
    3108           0 :         masm.bind(ool->rejoin());
    3109           0 :         return true;
    3110             :     }
    3111             : 
    3112             :     // This does not generate a value; if the truncation failed then it traps.
    3113             : 
    3114             :     class OutOfLineTruncateCheckF32OrF64ToI64 : public OutOfLineCode
    3115             :     {
    3116             :         AnyReg src;
    3117             :         bool isUnsigned;
    3118             :         BytecodeOffset off;
    3119             : 
    3120             :       public:
    3121           0 :         OutOfLineTruncateCheckF32OrF64ToI64(AnyReg src, bool isUnsigned, BytecodeOffset off)
    3122           0 :           : src(src),
    3123             :             isUnsigned(isUnsigned),
    3124           0 :             off(off)
    3125           0 :         {}
    3126             : 
    3127           0 :         virtual void generate(MacroAssembler& masm) {
    3128             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    3129           0 :             if (src.tag == AnyReg::F32)
    3130           0 :                 masm.outOfLineWasmTruncateFloat32ToInt64(src.f32(), isUnsigned, off, rejoin());
    3131           0 :             else if (src.tag == AnyReg::F64)
    3132           0 :                 masm.outOfLineWasmTruncateDoubleToInt64(src.f64(), isUnsigned, off, rejoin());
    3133             :             else
    3134           0 :                 MOZ_CRASH("unexpected type");
    3135             : #elif defined(JS_CODEGEN_ARM)
    3136             :             if (src.tag == AnyReg::F32)
    3137             :                 masm.outOfLineWasmTruncateToIntCheck(src.f32(), MIRType::Float32,
    3138             :                                                      MIRType::Int64, isUnsigned, rejoin(), off);
    3139             :             else if (src.tag == AnyReg::F64)
    3140             :                 masm.outOfLineWasmTruncateToIntCheck(src.f64(), MIRType::Double, MIRType::Int64,
    3141             :                                                      isUnsigned, rejoin(), off);
    3142             :             else
    3143             :                 MOZ_CRASH("unexpected type");
    3144             : #else
    3145             :             (void)src;
    3146             :             (void)isUnsigned;
    3147             :             (void)off;
    3148             :             MOZ_CRASH("BaseCompiler platform hook: OutOfLineTruncateCheckF32OrF64ToI64");
    3149             : #endif
    3150           0 :         }
    3151             :     };
    3152             : 
    3153             : #ifndef FLOAT_TO_I64_CALLOUT
    3154           0 :     MOZ_MUST_USE bool truncateF32ToI64(RegF32 src, RegI64 dest, bool isUnsigned, RegF64 temp) {
    3155             : # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3156             :         OutOfLineCode* ool =
    3157           0 :             addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(AnyReg(src),
    3158             :                                                                               isUnsigned,
    3159           0 :                                                                               bytecodeOffset()));
    3160           0 :         if (!ool)
    3161           0 :             return false;
    3162           0 :         if (isUnsigned)
    3163           0 :             masm.wasmTruncateFloat32ToUInt64(src, dest, ool->entry(),
    3164           0 :                                              ool->rejoin(), temp);
    3165             :         else
    3166           0 :             masm.wasmTruncateFloat32ToInt64(src, dest, ool->entry(),
    3167           0 :                                             ool->rejoin(), temp);
    3168             : # else
    3169             :         MOZ_CRASH("BaseCompiler platform hook: truncateF32ToI64");
    3170             : # endif
    3171           0 :         return true;
    3172             :     }
    3173             : 
    3174           0 :     MOZ_MUST_USE bool truncateF64ToI64(RegF64 src, RegI64 dest, bool isUnsigned, RegF64 temp) {
    3175             : # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3176             :         OutOfLineCode* ool =
    3177           0 :             addOutOfLineCode(new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(AnyReg(src),
    3178             :                                                                               isUnsigned,
    3179           0 :                                                                               bytecodeOffset()));
    3180           0 :         if (!ool)
    3181           0 :             return false;
    3182           0 :         if (isUnsigned)
    3183           0 :             masm.wasmTruncateDoubleToUInt64(src, dest, ool->entry(),
    3184           0 :                                             ool->rejoin(), temp);
    3185             :         else
    3186           0 :             masm.wasmTruncateDoubleToInt64(src, dest, ool->entry(),
    3187           0 :                                            ool->rejoin(), temp);
    3188             : # else
    3189             :         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
    3190             : # endif
    3191           0 :         return true;
    3192             :     }
    3193             : #endif // FLOAT_TO_I64_CALLOUT
    3194             : 
    3195             : #ifndef I64_TO_FLOAT_CALLOUT
    3196           0 :     bool convertI64ToFloatNeedsTemp(ValType to, bool isUnsigned) const {
    3197             : # if defined(JS_CODEGEN_X86)
    3198             :         return isUnsigned &&
    3199             :                ((to == ValType::F64 && AssemblerX86Shared::HasSSE3()) ||
    3200             :                to == ValType::F32);
    3201             : # else
    3202           0 :         return isUnsigned;
    3203             : # endif
    3204             :     }
    3205             : 
    3206           0 :     void convertI64ToF32(RegI64 src, bool isUnsigned, RegF32 dest, RegI32 temp) {
    3207             : # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3208           0 :         if (isUnsigned)
    3209           0 :             masm.convertUInt64ToFloat32(src, dest, temp);
    3210             :         else
    3211           0 :             masm.convertInt64ToFloat32(src, dest);
    3212             : # else
    3213             :         MOZ_CRASH("BaseCompiler platform hook: convertI64ToF32");
    3214             : # endif
    3215           0 :     }
    3216             : 
    3217           0 :     void convertI64ToF64(RegI64 src, bool isUnsigned, RegF64 dest, RegI32 temp) {
    3218             : # if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3219           0 :         if (isUnsigned)
    3220           0 :             masm.convertUInt64ToDouble(src, dest, temp);
    3221             :         else
    3222           0 :             masm.convertInt64ToDouble(src, dest);
    3223             : # else
    3224             :         MOZ_CRASH("BaseCompiler platform hook: convertI64ToF64");
    3225             : # endif
    3226           0 :     }
    3227             : #endif // I64_TO_FLOAT_CALLOUT
    3228             : 
    3229           0 :     void cmp64Set(Assembler::Condition cond, RegI64 lhs, RegI64 rhs, RegI32 dest) {
    3230             : #if defined(JS_CODEGEN_X64)
    3231           0 :         masm.cmpq(rhs.reg, lhs.reg);
    3232           0 :         masm.emitSet(cond, dest);
    3233             : #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    3234             :         // TODO / OPTIMIZE (Bug 1316822): This is pretty branchy, we should be
    3235             :         // able to do better.
    3236             :         Label done, condTrue;
    3237             :         masm.branch64(cond, lhs, rhs, &condTrue);
    3238             :         masm.move32(Imm32(0), dest);
    3239             :         masm.jump(&done);
    3240             :         masm.bind(&condTrue);
    3241             :         masm.move32(Imm32(1), dest);
    3242             :         masm.bind(&done);
    3243             : #else
    3244             :         MOZ_CRASH("BaseCompiler platform hook: cmp64Set");
    3245             : #endif
    3246           0 :     }
    3247             : 
    3248           0 :     void eqz64(RegI64 src, RegI32 dest) {
    3249             : #if defined(JS_CODEGEN_X64)
    3250           0 :         masm.cmpq(Imm32(0), src.reg);
    3251           0 :         masm.emitSet(Assembler::Equal, dest);
    3252             : #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    3253             :         masm.or32(src.high, src.low);
    3254             :         masm.cmp32(src.low, Imm32(0));
    3255             :         masm.emitSet(Assembler::Equal, dest);
    3256             : #else
    3257             :         MOZ_CRASH("BaseCompiler platform hook: eqz64");
    3258             : #endif
    3259           0 :     }
    3260             : 
    3261           0 :     void unreachableTrap()
    3262             :     {
    3263           0 :         masm.jump(trap(Trap::Unreachable));
    3264             : #ifdef DEBUG
    3265           0 :         masm.breakpoint();
    3266             : #endif
    3267           0 :     }
    3268             : 
    3269             :     //////////////////////////////////////////////////////////////////////
    3270             :     //
    3271             :     // Global variable access.
    3272             : 
    3273           0 :     uint32_t globalToTlsOffset(uint32_t globalOffset) {
    3274           0 :         return offsetof(TlsData, globalArea) + globalOffset;
    3275             :     }
    3276             : 
    3277           0 :     void loadGlobalVarI32(unsigned globalDataOffset, RegI32 r)
    3278             :     {
    3279           0 :         ScratchI32 tmp(*this);
    3280           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3281           0 :         masm.load32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
    3282           0 :     }
    3283             : 
    3284           0 :     void loadGlobalVarI64(unsigned globalDataOffset, RegI64 r)
    3285             :     {
    3286           0 :         ScratchI32 tmp(*this);
    3287           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3288           0 :         masm.load64(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
    3289           0 :     }
    3290             : 
    3291           0 :     void loadGlobalVarF32(unsigned globalDataOffset, RegF32 r)
    3292             :     {
    3293           0 :         ScratchI32 tmp(*this);
    3294           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3295           0 :         masm.loadFloat32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
    3296           0 :     }
    3297             : 
    3298           0 :     void loadGlobalVarF64(unsigned globalDataOffset, RegF64 r)
    3299             :     {
    3300           0 :         ScratchI32 tmp(*this);
    3301           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3302           0 :         masm.loadDouble(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
    3303           0 :     }
    3304             : 
    3305           0 :     void storeGlobalVarI32(unsigned globalDataOffset, RegI32 r)
    3306             :     {
    3307           0 :         ScratchI32 tmp(*this);
    3308           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3309           0 :         masm.store32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
    3310           0 :     }
    3311             : 
    3312           0 :     void storeGlobalVarI64(unsigned globalDataOffset, RegI64 r)
    3313             :     {
    3314           0 :         ScratchI32 tmp(*this);
    3315           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3316           0 :         masm.store64(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
    3317           0 :     }
    3318             : 
    3319           0 :     void storeGlobalVarF32(unsigned globalDataOffset, RegF32 r)
    3320             :     {
    3321           0 :         ScratchI32 tmp(*this);
    3322           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3323           0 :         masm.storeFloat32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
    3324           0 :     }
    3325             : 
    3326           0 :     void storeGlobalVarF64(unsigned globalDataOffset, RegF64 r)
    3327             :     {
    3328           0 :         ScratchI32 tmp(*this);
    3329           0 :         masm.loadWasmTlsRegFromFrame(tmp);
    3330           0 :         masm.storeDouble(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
    3331           0 :     }
    3332             : 
    3333             :     //////////////////////////////////////////////////////////////////////
    3334             :     //
    3335             :     // Heap access.
    3336             : 
    3337           0 :     void bceCheckLocal(MemoryAccessDesc* access, uint32_t local, bool* omitBoundsCheck) {
    3338           0 :         if (local >= sizeof(BCESet)*8)
    3339           0 :             return;
    3340             : 
    3341           0 :         if ((bceSafe_ & (BCESet(1) << local)) && access->offset() < wasm::OffsetGuardLimit)
    3342           0 :             *omitBoundsCheck = true;
    3343             : 
    3344             :         // The local becomes safe even if the offset is beyond the guard limit.
    3345           0 :         bceSafe_ |= (BCESet(1) << local);
    3346             :     }
    3347             : 
    3348           0 :     void bceLocalIsUpdated(uint32_t local) {
    3349           0 :         if (local >= sizeof(BCESet)*8)
    3350           0 :             return;
    3351             : 
    3352           0 :         bceSafe_ &= ~(BCESet(1) << local);
    3353             :     }
    3354             : 
    3355           0 :     void checkOffset(MemoryAccessDesc* access, RegI32 ptr) {
    3356           0 :         if (access->offset() >= OffsetGuardLimit) {
    3357           0 :             masm.branchAdd32(Assembler::CarrySet, Imm32(access->offset()), ptr,
    3358           0 :                              trap(Trap::OutOfBounds));
    3359           0 :             access->clearOffset();
    3360             :         }
    3361           0 :     }
    3362             : 
    3363             :     // This is the temp register passed as the last argument to load()
    3364           0 :     MOZ_MUST_USE size_t loadTemps(MemoryAccessDesc& access) {
    3365             : #if defined(JS_CODEGEN_ARM)
    3366             :         if (IsUnaligned(access)) {
    3367             :             switch (access.type()) {
    3368             :               case Scalar::Float32:
    3369             :                 return 2;
    3370             :               case Scalar::Float64:
    3371             :                 return 3;
    3372             :               default:
    3373             :                 return 1;
    3374             :             }
    3375             :         }
    3376             :         return 0;
    3377             : #else
    3378           0 :         return 0;
    3379             : #endif
    3380             :     }
    3381             : 
    3382           0 :     MOZ_MUST_USE bool needTlsForAccess(bool omitBoundsCheck) {
    3383             : #if defined(JS_CODEGEN_ARM)
    3384             :         return !omitBoundsCheck;
    3385             : #elif defined(JS_CODEGEN_X86)
    3386             :         return true;
    3387             : #else
    3388           0 :         return false;
    3389             : #endif
    3390             :     }
    3391             : 
    3392             :     // ptr and dest may be the same iff dest is I32.
    3393             :     // This may destroy ptr even if ptr and dest are not the same.
    3394           0 :     MOZ_MUST_USE bool load(MemoryAccessDesc* access, RegI32 tls, RegI32 ptr, bool omitBoundsCheck,
    3395             :                            AnyReg dest, RegI32 tmp1, RegI32 tmp2, RegI32 tmp3)
    3396             :     {
    3397           0 :         checkOffset(access, ptr);
    3398             : 
    3399             : #ifdef WASM_HUGE_MEMORY
    3400             :         // We have HeapReg and no bounds checking and need load neither
    3401             :         // memoryBase nor boundsCheckLimit from tls.
    3402           0 :         MOZ_ASSERT(tls == invalidI32());
    3403             : #endif
    3404             : #ifdef JS_CODEGEN_ARM
    3405             :         // We have HeapReg on ARM and don't need to load the memoryBase from tls.
    3406             :         MOZ_ASSERT_IF(omitBoundsCheck, tls == invalidI32());
    3407             : #endif
    3408             : 
    3409             : #ifndef WASM_HUGE_MEMORY
    3410             :         if (!omitBoundsCheck) {
    3411             :             masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr,
    3412             :                                  Address(tls, offsetof(TlsData, boundsCheckLimit)),
    3413             :                                  trap(Trap::OutOfBounds));
    3414             :         }
    3415             : #endif
    3416             : 
    3417             : #if defined(JS_CODEGEN_X64)
    3418           0 :         Operand srcAddr(HeapReg, ptr, TimesOne, access->offset());
    3419             : 
    3420           0 :         if (dest.tag == AnyReg::I64)
    3421           0 :             masm.wasmLoadI64(*access, srcAddr, dest.i64());
    3422             :         else
    3423           0 :             masm.wasmLoad(*access, srcAddr, dest.any());
    3424             : #elif defined(JS_CODEGEN_X86)
    3425             :         masm.addPtr(Address(tls, offsetof(TlsData, memoryBase)), ptr);
    3426             :         Operand srcAddr(ptr, access->offset());
    3427             : 
    3428             :         if (dest.tag == AnyReg::I64) {
    3429             :             MOZ_ASSERT(dest.i64() == abiReturnRegI64);
    3430             :             masm.wasmLoadI64(*access, srcAddr, dest.i64());
    3431             :         } else {
    3432             :             bool byteRegConflict = access->byteSize() == 1 && !singleByteRegs_.has(dest.i32());
    3433             :             AnyRegister out = byteRegConflict ? AnyRegister(ScratchRegX86) : dest.any();
    3434             : 
    3435             :             masm.wasmLoad(*access, srcAddr, out);
    3436             : 
    3437             :             if (byteRegConflict)
    3438             :                 masm.mov(ScratchRegX86, dest.i32());
    3439             :         }
    3440             : #elif defined(JS_CODEGEN_ARM)
    3441             :         if (IsUnaligned(*access)) {
    3442             :             switch (dest.tag) {
    3443             :               case AnyReg::I64:
    3444             :                 masm.wasmUnalignedLoadI64(*access, HeapReg, ptr, ptr, dest.i64(), tmp1);
    3445             :                 break;
    3446             :               case AnyReg::F32:
    3447             :                 masm.wasmUnalignedLoadFP(*access, HeapReg, ptr, ptr, dest.f32(), tmp1, tmp2,
    3448             :                                          Register::Invalid());
    3449             :                 break;
    3450             :               case AnyReg::F64:
    3451             :                 masm.wasmUnalignedLoadFP(*access, HeapReg, ptr, ptr, dest.f64(), tmp1, tmp2, tmp3);
    3452             :                 break;
    3453             :               default:
    3454             :                 masm.wasmUnalignedLoad(*access, HeapReg, ptr, ptr, dest.i32(), tmp1);
    3455             :                 break;
    3456             :             }
    3457             :         } else {
    3458             :             if (dest.tag == AnyReg::I64)
    3459             :                 masm.wasmLoadI64(*access, HeapReg, ptr, ptr, dest.i64());
    3460             :             else
    3461             :                 masm.wasmLoad(*access, HeapReg, ptr, ptr, dest.any());
    3462             :         }
    3463             : #else
    3464             :         MOZ_CRASH("BaseCompiler platform hook: load");
    3465             : #endif
    3466             : 
    3467           0 :         return true;
    3468             :     }
    3469             : 
    3470           0 :     MOZ_MUST_USE size_t storeTemps(const MemoryAccessDesc& access, ValType srcType) {
    3471             : #if defined(JS_CODEGEN_ARM)
    3472             :         if (IsUnaligned(access) && srcType != ValType::I32)
    3473             :             return 1;
    3474             : #endif
    3475           0 :         return 0;
    3476             :     }
    3477             : 
    3478             :     // ptr and src must not be the same register.
    3479             :     // This may destroy ptr and src.
    3480           0 :     MOZ_MUST_USE bool store(MemoryAccessDesc* access, RegI32 tls, RegI32 ptr, bool omitBoundsCheck,
    3481             :                             AnyReg src, RegI32 tmp)
    3482             :     {
    3483           0 :         checkOffset(access, ptr);
    3484             : 
    3485             : #ifdef WASM_HUGE_MEMORY
    3486             :         // We have HeapReg and no bounds checking and need load neither
    3487             :         // memoryBase nor boundsCheckLimit from tls.
    3488           0 :         MOZ_ASSERT(tls == invalidI32());
    3489             : #endif
    3490             : #ifdef JS_CODEGEN_ARM
    3491             :         // We have HeapReg on ARM and don't need to load the memoryBase from tls.
    3492             :         MOZ_ASSERT_IF(omitBoundsCheck, tls == invalidI32());
    3493             : #endif
    3494             : 
    3495             : #ifndef WASM_HUGE_MEMORY
    3496             :         if (!omitBoundsCheck) {
    3497             :             masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr,
    3498             :                                  Address(tls, offsetof(TlsData, boundsCheckLimit)),
    3499             :                                  trap(Trap::OutOfBounds));
    3500             :         }
    3501             : #endif
    3502             : 
    3503             :         // Emit the store
    3504             : #if defined(JS_CODEGEN_X64)
    3505           0 :         MOZ_ASSERT(tmp == Register::Invalid());
    3506           0 :         Operand dstAddr(HeapReg, ptr, TimesOne, access->offset());
    3507             : 
    3508           0 :         masm.wasmStore(*access, src.any(), dstAddr);
    3509             : #elif defined(JS_CODEGEN_X86)
    3510             :         MOZ_ASSERT(tmp == Register::Invalid());
    3511             :         masm.addPtr(Address(tls, offsetof(TlsData, memoryBase)), ptr);
    3512             :         Operand dstAddr(ptr, access->offset());
    3513             : 
    3514             :         if (access->type() == Scalar::Int64) {
    3515             :             masm.wasmStoreI64(*access, src.i64(), dstAddr);
    3516             :         } else {
    3517             :             AnyRegister value;
    3518             :             if (src.tag == AnyReg::I64) {
    3519             :                 if (access->byteSize() == 1 && !singleByteRegs_.has(src.i64().low)) {
    3520             :                     masm.mov(src.i64().low, ScratchRegX86);
    3521             :                     value = AnyRegister(ScratchRegX86);
    3522             :                 } else {
    3523             :                     value = AnyRegister(src.i64().low);
    3524             :                 }
    3525             :             } else if (access->byteSize() == 1 && !singleByteRegs_.has(src.i32())) {
    3526             :                 masm.mov(src.i32(), ScratchRegX86);
    3527             :                 value = AnyRegister(ScratchRegX86);
    3528             :             } else {
    3529             :                 value = src.any();
    3530             :             }
    3531             : 
    3532             :             masm.wasmStore(*access, value, dstAddr);
    3533             :         }
    3534             : #elif defined(JS_CODEGEN_ARM)
    3535             :         if (IsUnaligned(*access)) {
    3536             :             switch (src.tag) {
    3537             :               case AnyReg::I64:
    3538             :                 masm.wasmUnalignedStoreI64(*access, src.i64(), HeapReg, ptr, ptr, tmp);
    3539             :                 break;
    3540             :               case AnyReg::F32:
    3541             :                 masm.wasmUnalignedStoreFP(*access, src.f32(), HeapReg, ptr, ptr, tmp);
    3542             :                 break;
    3543             :               case AnyReg::F64:
    3544             :                 masm.wasmUnalignedStoreFP(*access, src.f64(), HeapReg, ptr, ptr, tmp);
    3545             :                 break;
    3546             :               default:
    3547             :                 MOZ_ASSERT(tmp == Register::Invalid());
    3548             :                 masm.wasmUnalignedStore(*access, src.i32(), HeapReg, ptr, ptr);
    3549             :                 break;
    3550             :             }
    3551             :         } else {
    3552             :             MOZ_ASSERT(tmp == Register::Invalid());
    3553             :             if (access->type() == Scalar::Int64)
    3554             :                 masm.wasmStoreI64(*access, src.i64(), HeapReg, ptr, ptr);
    3555             :             else if (src.tag == AnyReg::I64)
    3556             :                 masm.wasmStore(*access, AnyRegister(src.i64().low), HeapReg, ptr, ptr);
    3557             :             else
    3558             :                 masm.wasmStore(*access, src.any(), HeapReg, ptr, ptr);
    3559             :         }
    3560             : #else
    3561             :         MOZ_CRASH("BaseCompiler platform hook: store");
    3562             : #endif
    3563             : 
    3564           0 :         return true;
    3565             :     }
    3566             : 
    3567             :     MOZ_MUST_USE bool
    3568           0 :     supportsRoundInstruction(RoundingMode mode)
    3569             :     {
    3570             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3571           0 :         return Assembler::HasRoundInstruction(mode);
    3572             : #else
    3573             :         return false;
    3574             : #endif
    3575             :     }
    3576             : 
    3577             :     void
    3578           0 :     roundF32(RoundingMode roundingMode, RegF32 f0)
    3579             :     {
    3580             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3581           0 :         masm.vroundss(Assembler::ToX86RoundingMode(roundingMode), f0, f0, f0);
    3582             : #else
    3583             :         MOZ_CRASH("NYI");
    3584             : #endif
    3585           0 :     }
    3586             : 
    3587             :     void
    3588           0 :     roundF64(RoundingMode roundingMode, RegF64 f0)
    3589             :     {
    3590             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    3591           0 :         masm.vroundsd(Assembler::ToX86RoundingMode(roundingMode), f0, f0, f0);
    3592             : #else
    3593             :         MOZ_CRASH("NYI");
    3594             : #endif
    3595           0 :     }
    3596             : 
    3597             :     ////////////////////////////////////////////////////////////
    3598             : 
    3599             :     // Generally speaking, ABOVE this point there should be no value
    3600             :     // stack manipulation (calls to popI32 etc).
    3601             : 
    3602             :     // Generally speaking, BELOW this point there should be no
    3603             :     // platform dependencies.  We make an exception for x86 register
    3604             :     // targeting, which is not too hard to keep clean.
    3605             : 
    3606             :     ////////////////////////////////////////////////////////////
    3607             :     //
    3608             :     // Sundry wrappers.
    3609             : 
    3610           0 :     void pop2xI32(RegI32* r0, RegI32* r1) {
    3611           0 :         *r1 = popI32();
    3612           0 :         *r0 = popI32();
    3613           0 :     }
    3614             : 
    3615           0 :     RegI32 popI32ToSpecific(RegI32 specific) {
    3616           0 :         freeI32(specific);
    3617           0 :         return popI32(specific);
    3618             :     }
    3619             : 
    3620           0 :     void pop2xI64(RegI64* r0, RegI64* r1) {
    3621           0 :         *r1 = popI64();
    3622           0 :         *r0 = popI64();
    3623           0 :     }
    3624             : 
    3625           0 :     RegI64 popI64ToSpecific(RegI64 specific) {
    3626           0 :         freeI64(specific);
    3627           0 :         return popI64(specific);
    3628             :     }
    3629             : 
    3630           0 :     void pop2xF32(RegF32* r0, RegF32* r1) {
    3631           0 :         *r1 = popF32();
    3632           0 :         *r0 = popF32();
    3633           0 :     }
    3634             : 
    3635           0 :     void pop2xF64(RegF64* r0, RegF64* r1) {
    3636           0 :         *r1 = popF64();
    3637           0 :         *r0 = popF64();
    3638           0 :     }
    3639             : 
    3640             :     RegI32 popMemoryAccess(MemoryAccessDesc* access, bool* omitBoundsCheck);
    3641             : 
    3642             :     ////////////////////////////////////////////////////////////
    3643             :     //
    3644             :     // Sundry helpers.
    3645             : 
    3646           0 :     uint32_t readCallSiteLineOrBytecode() {
    3647           0 :         if (!func_.callSiteLineNums().empty())
    3648           0 :             return func_.callSiteLineNums()[lastReadCallSite_++];
    3649           0 :         return iter_.lastOpcodeOffset();
    3650             :     }
    3651             : 
    3652           0 :     bool done() const {
    3653           0 :         return iter_.done();
    3654             :     }
    3655             : 
    3656           0 :     BytecodeOffset bytecodeOffset() const {
    3657           0 :         return iter_.bytecodeOffset();
    3658             :     }
    3659             : 
    3660           0 :     TrapDesc trap(Trap t) const {
    3661           0 :         return TrapDesc(bytecodeOffset(), t, masm.framePushed());
    3662             :     }
    3663             : 
    3664             :     ////////////////////////////////////////////////////////////
    3665             :     //
    3666             :     // Machinery for optimized conditional branches.
    3667             :     //
    3668             :     // To disable this optimization it is enough always to return false from
    3669             :     // sniffConditionalControl{Cmp,Eqz}.
    3670             : 
    3671             :     struct BranchState {
    3672             :         static const int32_t NoPop = ~0;
    3673             : 
    3674             :         union {
    3675             :             struct {
    3676             :                 RegI32 lhs;
    3677             :                 RegI32 rhs;
    3678             :                 int32_t imm;
    3679             :                 bool rhsImm;
    3680             :             } i32;
    3681             :             struct {
    3682             :                 RegI64 lhs;
    3683             :                 RegI64 rhs;
    3684             :                 int64_t imm;
    3685             :                 bool rhsImm;
    3686             :             } i64;
    3687             :             struct {
    3688             :                 RegF32 lhs;
    3689             :                 RegF32 rhs;
    3690             :             } f32;
    3691             :             struct {
    3692             :                 RegF64 lhs;
    3693             :                 RegF64 rhs;
    3694             :             } f64;
    3695             :         };
    3696             : 
    3697             :         Label* const label;        // The target of the branch, never NULL
    3698             :         const int32_t framePushed; // Either NoPop, or the value to pop to along the taken edge
    3699             :         const bool invertBranch;   // If true, invert the sense of the branch
    3700             :         const ExprType resultType; // The result propagated along the edges, or Void
    3701             : 
    3702           0 :         explicit BranchState(Label* label, int32_t framePushed = NoPop,
    3703             :                              uint32_t invertBranch = false, ExprType resultType = ExprType::Void)
    3704           0 :           : label(label),
    3705             :             framePushed(framePushed),
    3706             :             invertBranch(invertBranch),
    3707           0 :             resultType(resultType)
    3708           0 :         {}
    3709             :     };
    3710             : 
    3711           0 :     void setLatentCompare(Assembler::Condition compareOp, ValType operandType) {
    3712           0 :         latentOp_ = LatentOp::Compare;
    3713           0 :         latentType_ = operandType;
    3714           0 :         latentIntCmp_ = compareOp;
    3715           0 :     }
    3716             : 
    3717           0 :     void setLatentCompare(Assembler::DoubleCondition compareOp, ValType operandType) {
    3718           0 :         latentOp_ = LatentOp::Compare;
    3719           0 :         latentType_ = operandType;
    3720           0 :         latentDoubleCmp_ = compareOp;
    3721           0 :     }
    3722             : 
    3723           0 :     void setLatentEqz(ValType operandType) {
    3724           0 :         latentOp_ = LatentOp::Eqz;
    3725           0 :         latentType_ = operandType;
    3726           0 :     }
    3727             : 
    3728           0 :     void resetLatentOp() {
    3729           0 :         latentOp_ = LatentOp::None;
    3730           0 :     }
    3731             : 
    3732           0 :     void branchTo(Assembler::DoubleCondition c, RegF64 lhs, RegF64 rhs, Label* l) {
    3733           0 :         masm.branchDouble(c, lhs, rhs, l);
    3734           0 :     }
    3735             : 
    3736           0 :     void branchTo(Assembler::DoubleCondition c, RegF32 lhs, RegF32 rhs, Label* l) {
    3737           0 :         masm.branchFloat(c, lhs, rhs, l);
    3738           0 :     }
    3739             : 
    3740           0 :     void branchTo(Assembler::Condition c, RegI32 lhs, RegI32 rhs, Label* l) {
    3741           0 :         masm.branch32(c, lhs, rhs, l);
    3742           0 :     }
    3743             : 
    3744           0 :     void branchTo(Assembler::Condition c, RegI32 lhs, Imm32 rhs, Label* l) {
    3745           0 :         masm.branch32(c, lhs, rhs, l);
    3746           0 :     }
    3747             : 
    3748           0 :     void branchTo(Assembler::Condition c, RegI64 lhs, RegI64 rhs, Label* l) {
    3749           0 :         masm.branch64(c, lhs, rhs, l);
    3750           0 :     }
    3751             : 
    3752           0 :     void branchTo(Assembler::Condition c, RegI64 lhs, Imm64 rhs, Label* l) {
    3753           0 :         masm.branch64(c, lhs, rhs, l);
    3754           0 :     }
    3755             : 
    3756             :     // Emit a conditional branch that optionally and optimally cleans up the CPU
    3757             :     // stack before we branch.
    3758             :     //
    3759             :     // Cond is either Assembler::Condition or Assembler::DoubleCondition.
    3760             :     //
    3761             :     // Lhs is Register, Register64, or FloatRegister.
    3762             :     //
    3763             :     // Rhs is either the same as Lhs, or an immediate expression compatible with
    3764             :     // Lhs "when applicable".
    3765             : 
    3766             :     template<typename Cond, typename Lhs, typename Rhs>
    3767           0 :     void jumpConditionalWithJoinReg(BranchState* b, Cond cond, Lhs lhs, Rhs rhs)
    3768             :     {
    3769           0 :         AnyReg r = popJoinRegUnlessVoid(b->resultType);
    3770             : 
    3771           0 :         if (b->framePushed != BranchState::NoPop && willPopStackBeforeBranch(b->framePushed)) {
    3772           0 :             Label notTaken;
    3773           0 :             branchTo(b->invertBranch ? cond : Assembler::InvertCondition(cond), lhs, rhs, &notTaken);
    3774           0 :             popStackBeforeBranch(b->framePushed);
    3775           0 :             masm.jump(b->label);
    3776           0 :             masm.bind(&notTaken);
    3777             :         } else {
    3778           0 :             branchTo(b->invertBranch ? Assembler::InvertCondition(cond) : cond, lhs, rhs, b->label);
    3779             :         }
    3780             : 
    3781           0 :         pushJoinRegUnlessVoid(r);
    3782           0 :     }
    3783             : 
    3784             :     // sniffConditionalControl{Cmp,Eqz} may modify the latentWhatever_ state in
    3785             :     // the BaseCompiler so that a subsequent conditional branch can be compiled
    3786             :     // optimally.  emitBranchSetup() and emitBranchPerform() will consume that
    3787             :     // state.  If the latter methods are not called because deadCode_ is true
    3788             :     // then the compiler MUST instead call resetLatentOp() to reset the state.
    3789             : 
    3790             :     template<typename Cond> bool sniffConditionalControlCmp(Cond compareOp, ValType operandType);
    3791             :     bool sniffConditionalControlEqz(ValType operandType);
    3792             :     void emitBranchSetup(BranchState* b);
    3793             :     void emitBranchPerform(BranchState* b);
    3794             : 
    3795             :     //////////////////////////////////////////////////////////////////////
    3796             : 
    3797             :     MOZ_MUST_USE bool emitBody();
    3798             :     MOZ_MUST_USE bool emitBlock();
    3799             :     MOZ_MUST_USE bool emitLoop();
    3800             :     MOZ_MUST_USE bool emitIf();
    3801             :     MOZ_MUST_USE bool emitElse();
    3802             :     MOZ_MUST_USE bool emitEnd();
    3803             :     MOZ_MUST_USE bool emitBr();
    3804             :     MOZ_MUST_USE bool emitBrIf();
    3805             :     MOZ_MUST_USE bool emitBrTable();
    3806             :     MOZ_MUST_USE bool emitDrop();
    3807             :     MOZ_MUST_USE bool emitReturn();
    3808             :     MOZ_MUST_USE bool emitCallArgs(const ValTypeVector& args, FunctionCall& baselineCall);
    3809             :     MOZ_MUST_USE bool emitCall();
    3810             :     MOZ_MUST_USE bool emitCallIndirect();
    3811             :     MOZ_MUST_USE bool emitUnaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
    3812             :     MOZ_MUST_USE bool emitGetLocal();
    3813             :     MOZ_MUST_USE bool emitSetLocal();
    3814             :     MOZ_MUST_USE bool emitTeeLocal();
    3815             :     MOZ_MUST_USE bool emitGetGlobal();
    3816             :     MOZ_MUST_USE bool emitSetGlobal();
    3817             :     MOZ_MUST_USE RegI32 maybeLoadTlsForAccess(bool omitBoundsCheck);
    3818             :     MOZ_MUST_USE bool emitLoad(ValType type, Scalar::Type viewType);
    3819             :     MOZ_MUST_USE bool emitStore(ValType resultType, Scalar::Type viewType);
    3820             :     MOZ_MUST_USE bool emitSelect();
    3821             : 
    3822             :     // Mark these templates as inline to work around a compiler crash in
    3823             :     // gcc 4.8.5 when compiling for linux64-opt.
    3824             : 
    3825             :     template<bool isSetLocal> MOZ_MUST_USE inline bool emitSetOrTeeLocal(uint32_t slot);
    3826             : 
    3827             :     void endBlock(ExprType type);
    3828             :     void endLoop(ExprType type);
    3829             :     void endIfThen();
    3830             :     void endIfThenElse(ExprType type);
    3831             : 
    3832             :     void doReturn(ExprType returnType, bool popStack);
    3833             :     void pushReturned(const FunctionCall& call, ExprType type);
    3834             : 
    3835             :     void emitCompareI32(Assembler::Condition compareOp, ValType compareType);
    3836             :     void emitCompareI64(Assembler::Condition compareOp, ValType compareType);
    3837             :     void emitCompareF32(Assembler::DoubleCondition compareOp, ValType compareType);
    3838             :     void emitCompareF64(Assembler::DoubleCondition compareOp, ValType compareType);
    3839             : 
    3840             :     void emitAddI32();
    3841             :     void emitAddI64();
    3842             :     void emitAddF64();
    3843             :     void emitAddF32();
    3844             :     void emitSubtractI32();
    3845             :     void emitSubtractI64();
    3846             :     void emitSubtractF32();
    3847             :     void emitSubtractF64();
    3848             :     void emitMultiplyI32();
    3849             :     void emitMultiplyI64();
    3850             :     void emitMultiplyF32();
    3851             :     void emitMultiplyF64();
    3852             :     void emitQuotientI32();
    3853             :     void emitQuotientU32();
    3854             :     void emitRemainderI32();
    3855             :     void emitRemainderU32();
    3856             : #ifdef INT_DIV_I64_CALLOUT
    3857             :     void emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType);
    3858             : #else
    3859             :     void emitQuotientI64();
    3860             :     void emitQuotientU64();
    3861             :     void emitRemainderI64();
    3862             :     void emitRemainderU64();
    3863             : #endif
    3864             :     void emitDivideF32();
    3865             :     void emitDivideF64();
    3866             :     void emitMinF32();
    3867             :     void emitMaxF32();
    3868             :     void emitMinF64();
    3869             :     void emitMaxF64();
    3870             :     void emitCopysignF32();
    3871             :     void emitCopysignF64();
    3872             :     void emitOrI32();
    3873             :     void emitOrI64();
    3874             :     void emitAndI32();
    3875             :     void emitAndI64();
    3876             :     void emitXorI32();
    3877             :     void emitXorI64();
    3878             :     void emitShlI32();
    3879             :     void emitShlI64();
    3880             :     void emitShrI32();
    3881             :     void emitShrI64();
    3882             :     void emitShrU32();
    3883             :     void emitShrU64();
    3884             :     void emitRotrI32();
    3885             :     void emitRotrI64();
    3886             :     void emitRotlI32();
    3887             :     void emitRotlI64();
    3888             :     void emitEqzI32();
    3889             :     void emitEqzI64();
    3890             :     void emitClzI32();
    3891             :     void emitClzI64();
    3892             :     void emitCtzI32();
    3893             :     void emitCtzI64();
    3894             :     void emitPopcntI32();
    3895             :     void emitPopcntI64();
    3896             :     void emitAbsF32();
    3897             :     void emitAbsF64();
    3898             :     void emitNegateF32();
    3899             :     void emitNegateF64();
    3900             :     void emitSqrtF32();
    3901             :     void emitSqrtF64();
    3902             :     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF32ToI32();
    3903             :     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI32();
    3904             : #ifdef FLOAT_TO_I64_CALLOUT
    3905             :     MOZ_MUST_USE bool emitConvertFloatingToInt64Callout(SymbolicAddress callee, ValType operandType,
    3906             :                                                         ValType resultType);
    3907             : #else
    3908             :     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF32ToI64();
    3909             :     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI64();
    3910             : #endif
    3911             :     void emitWrapI64ToI32();
    3912             :     void emitExtendI32ToI64();
    3913             :     void emitExtendU32ToI64();
    3914             :     void emitReinterpretF32AsI32();
    3915             :     void emitReinterpretF64AsI64();
    3916             :     void emitConvertF64ToF32();
    3917             :     void emitConvertI32ToF32();
    3918             :     void emitConvertU32ToF32();
    3919             :     void emitConvertF32ToF64();
    3920             :     void emitConvertI32ToF64();
    3921             :     void emitConvertU32ToF64();
    3922             : #ifdef I64_TO_FLOAT_CALLOUT
    3923             :     MOZ_MUST_USE bool emitConvertInt64ToFloatingCallout(SymbolicAddress callee, ValType operandType,
    3924             :                                                         ValType resultType);
    3925             : #else
    3926             :     void emitConvertI64ToF32();
    3927             :     void emitConvertU64ToF32();
    3928             :     void emitConvertI64ToF64();
    3929             :     void emitConvertU64ToF64();
    3930             : #endif
    3931             :     void emitReinterpretI32AsF32();
    3932             :     void emitReinterpretI64AsF64();
    3933             :     void emitRound(RoundingMode roundingMode, ValType operandType);
    3934             :     MOZ_MUST_USE bool emitGrowMemory();
    3935             :     MOZ_MUST_USE bool emitCurrentMemory();
    3936             : };
    3937             : 
    3938             : void
    3939           0 : BaseCompiler::emitAddI32()
    3940             : {
    3941             :     int32_t c;
    3942           0 :     if (popConstI32(&c)) {
    3943           0 :         RegI32 r = popI32();
    3944           0 :         masm.add32(Imm32(c), r);
    3945           0 :         pushI32(r);
    3946             :     } else {
    3947           0 :         RegI32 r0, r1;
    3948           0 :         pop2xI32(&r0, &r1);
    3949           0 :         masm.add32(r1, r0);
    3950           0 :         freeI32(r1);
    3951           0 :         pushI32(r0);
    3952             :     }
    3953           0 : }
    3954             : 
    3955             : void
    3956           0 : BaseCompiler::emitAddI64()
    3957             : {
    3958             :     int64_t c;
    3959           0 :     if (popConstI64(&c)) {
    3960           0 :         RegI64 r = popI64();
    3961           0 :         masm.add64(Imm64(c), r);
    3962           0 :         pushI64(r);
    3963             :     } else {
    3964           0 :         RegI64 r0, r1;
    3965           0 :         pop2xI64(&r0, &r1);
    3966           0 :         masm.add64(r1, r0);
    3967           0 :         freeI64(r1);
    3968           0 :         pushI64(r0);
    3969             :     }
    3970           0 : }
    3971             : 
    3972             : void
    3973           0 : BaseCompiler::emitAddF64()
    3974             : {
    3975           0 :     RegF64 r0, r1;
    3976           0 :     pop2xF64(&r0, &r1);
    3977           0 :     masm.addDouble(r1, r0);
    3978           0 :     freeF64(r1);
    3979           0 :     pushF64(r0);
    3980           0 : }
    3981             : 
    3982             : void
    3983           0 : BaseCompiler::emitAddF32()
    3984             : {
    3985           0 :     RegF32 r0, r1;
    3986           0 :     pop2xF32(&r0, &r1);
    3987           0 :     masm.addFloat32(r1, r0);
    3988           0 :     freeF32(r1);
    3989           0 :     pushF32(r0);
    3990           0 : }
    3991             : 
    3992             : void
    3993           0 : BaseCompiler::emitSubtractI32()
    3994             : {
    3995             :     int32_t c;
    3996           0 :     if (popConstI32(&c)) {
    3997           0 :         RegI32 r = popI32();
    3998           0 :         masm.sub32(Imm32(c), r);
    3999           0 :         pushI32(r);
    4000             :     } else {
    4001           0 :         RegI32 r0, r1;
    4002           0 :         pop2xI32(&r0, &r1);
    4003           0 :         masm.sub32(r1, r0);
    4004           0 :         freeI32(r1);
    4005           0 :         pushI32(r0);
    4006             :     }
    4007           0 : }
    4008             : 
    4009             : void
    4010           0 : BaseCompiler::emitSubtractI64()
    4011             : {
    4012             :     int64_t c;
    4013           0 :     if (popConstI64(&c)) {
    4014           0 :         RegI64 r = popI64();
    4015           0 :         masm.sub64(Imm64(c), r);
    4016           0 :         pushI64(r);
    4017             :     } else {
    4018           0 :         RegI64 r0, r1;
    4019           0 :         pop2xI64(&r0, &r1);
    4020           0 :         masm.sub64(r1, r0);
    4021           0 :         freeI64(r1);
    4022           0 :         pushI64(r0);
    4023             :     }
    4024           0 : }
    4025             : 
    4026             : void
    4027           0 : BaseCompiler::emitSubtractF32()
    4028             : {
    4029           0 :     RegF32 r0, r1;
    4030           0 :     pop2xF32(&r0, &r1);
    4031           0 :     masm.subFloat32(r1, r0);
    4032           0 :     freeF32(r1);
    4033           0 :     pushF32(r0);
    4034           0 : }
    4035             : 
    4036             : void
    4037           0 : BaseCompiler::emitSubtractF64()
    4038             : {
    4039           0 :     RegF64 r0, r1;
    4040           0 :     pop2xF64(&r0, &r1);
    4041           0 :     masm.subDouble(r1, r0);
    4042           0 :     freeF64(r1);
    4043           0 :     pushF64(r0);
    4044           0 : }
    4045             : 
    4046             : void
    4047           0 : BaseCompiler::emitMultiplyI32()
    4048             : {
    4049           0 :     RegI32 r0, r1;
    4050           0 :     pop2xI32ForIntMulDiv(&r0, &r1);
    4051           0 :     masm.mul32(r1, r0);
    4052           0 :     freeI32(r1);
    4053           0 :     pushI32(r0);
    4054           0 : }
    4055             : 
    4056             : void
    4057           0 : BaseCompiler::emitMultiplyI64()
    4058             : {
    4059           0 :     RegI64 r0, r1;
    4060           0 :     RegI32 temp;
    4061             : #if defined(JS_CODEGEN_X64)
    4062             :     // srcDest must be rax, and rdx will be clobbered.
    4063           0 :     need2xI64(specific_rax, specific_rdx);
    4064           0 :     r1 = popI64();
    4065           0 :     r0 = popI64ToSpecific(specific_rax);
    4066           0 :     freeI64(specific_rdx);
    4067             : #elif defined(JS_CODEGEN_X86)
    4068             :     need2xI32(specific_eax, specific_edx);
    4069             :     r1 = popI64();
    4070             :     r0 = popI64ToSpecific(RegI64(Register64(specific_edx, specific_eax)));
    4071             :     temp = needI32();
    4072             : #else
    4073             :     pop2xI64(&r0, &r1);
    4074             :     temp = needI32();
    4075             : #endif
    4076           0 :     masm.mul64(r1, r0, temp);
    4077           0 :     if (temp != Register::Invalid())
    4078           0 :         freeI32(temp);
    4079           0 :     freeI64(r1);
    4080           0 :     pushI64(r0);
    4081           0 : }
    4082             : 
    4083             : void
    4084           0 : BaseCompiler::emitMultiplyF32()
    4085             : {
    4086           0 :     RegF32 r0, r1;
    4087           0 :     pop2xF32(&r0, &r1);
    4088           0 :     masm.mulFloat32(r1, r0);
    4089           0 :     freeF32(r1);
    4090           0 :     pushF32(r0);
    4091           0 : }
    4092             : 
    4093             : void
    4094           0 : BaseCompiler::emitMultiplyF64()
    4095             : {
    4096           0 :     RegF64 r0, r1;
    4097           0 :     pop2xF64(&r0, &r1);
    4098           0 :     masm.mulDouble(r1, r0);
    4099           0 :     freeF64(r1);
    4100           0 :     pushF64(r0);
    4101           0 : }
    4102             : 
    4103             : void
    4104           0 : BaseCompiler::emitQuotientI32()
    4105             : {
    4106             :     int32_t c;
    4107             :     uint_fast8_t power;
    4108           0 :     if (popConstPositivePowerOfTwoI32(&c, &power, 0)) {
    4109           0 :         if (power != 0) {
    4110           0 :             RegI32 r = popI32();
    4111           0 :             Label positive;
    4112           0 :             masm.branchTest32(Assembler::NotSigned, r, r, &positive);
    4113           0 :             masm.add32(Imm32(c-1), r);
    4114           0 :             masm.bind(&positive);
    4115             : 
    4116           0 :             masm.rshift32Arithmetic(Imm32(power & 31), r);
    4117           0 :             pushI32(r);
    4118             :         }
    4119             :     } else {
    4120           0 :         bool isConst = peekConstI32(&c);
    4121           0 :         RegI32 r0, r1;
    4122           0 :         pop2xI32ForIntMulDiv(&r0, &r1);
    4123             : 
    4124           0 :         Label done;
    4125           0 :         if (!isConst || c == 0)
    4126           0 :             checkDivideByZeroI32(r1, r0, &done);
    4127           0 :         if (!isConst || c == -1)
    4128           0 :             checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(false));
    4129           0 :         masm.quotient32(r1, r0, IsUnsigned(false));
    4130           0 :         masm.bind(&done);
    4131             : 
    4132           0 :         freeI32(r1);
    4133           0 :         pushI32(r0);
    4134             :     }
    4135           0 : }
    4136             : 
    4137             : void
    4138           0 : BaseCompiler::emitQuotientU32()
    4139             : {
    4140             :     int32_t c;
    4141             :     uint_fast8_t power;
    4142           0 :     if (popConstPositivePowerOfTwoI32(&c, &power, 0)) {
    4143           0 :         if (power != 0) {
    4144           0 :             RegI32 r = popI32();
    4145           0 :             masm.rshift32(Imm32(power & 31), r);
    4146           0 :             pushI32(r);
    4147             :         }
    4148             :     } else {
    4149           0 :         bool isConst = peekConstI32(&c);
    4150           0 :         RegI32 r0, r1;
    4151           0 :         pop2xI32ForIntMulDiv(&r0, &r1);
    4152             : 
    4153           0 :         Label done;
    4154           0 :         if (!isConst || c == 0)
    4155           0 :             checkDivideByZeroI32(r1, r0, &done);
    4156           0 :         masm.quotient32(r1, r0, IsUnsigned(true));
    4157           0 :         masm.bind(&done);
    4158             : 
    4159           0 :         freeI32(r1);
    4160           0 :         pushI32(r0);
    4161             :     }
    4162           0 : }
    4163             : 
    4164             : void
    4165           0 : BaseCompiler::emitRemainderI32()
    4166             : {
    4167             :     int32_t c;
    4168             :     uint_fast8_t power;
    4169           0 :     if (popConstPositivePowerOfTwoI32(&c, &power, 1)) {
    4170           0 :         RegI32 r = popI32();
    4171           0 :         RegI32 temp = needI32();
    4172           0 :         moveI32(r, temp);
    4173             : 
    4174           0 :         Label positive;
    4175           0 :         masm.branchTest32(Assembler::NotSigned, temp, temp, &positive);
    4176           0 :         masm.add32(Imm32(c-1), temp);
    4177           0 :         masm.bind(&positive);
    4178             : 
    4179           0 :         masm.rshift32Arithmetic(Imm32(power & 31), temp);
    4180           0 :         masm.lshift32(Imm32(power & 31), temp);
    4181           0 :         masm.sub32(temp, r);
    4182           0 :         freeI32(temp);
    4183             : 
    4184           0 :         pushI32(r);
    4185             :     } else {
    4186           0 :         bool isConst = peekConstI32(&c);
    4187           0 :         RegI32 r0, r1;
    4188           0 :         pop2xI32ForIntMulDiv(&r0, &r1);
    4189             : 
    4190           0 :         Label done;
    4191           0 :         if (!isConst || c == 0)
    4192           0 :             checkDivideByZeroI32(r1, r0, &done);
    4193           0 :         if (!isConst || c == -1)
    4194           0 :             checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(true));
    4195           0 :         masm.remainder32(r1, r0, IsUnsigned(false));
    4196           0 :         masm.bind(&done);
    4197             : 
    4198           0 :         freeI32(r1);
    4199           0 :         pushI32(r0);
    4200             :     }
    4201           0 : }
    4202             : 
    4203             : void
    4204           0 : BaseCompiler::emitRemainderU32()
    4205             : {
    4206             :     int32_t c;
    4207             :     uint_fast8_t power;
    4208           0 :     if (popConstPositivePowerOfTwoI32(&c, &power, 1)) {
    4209           0 :         RegI32 r = popI32();
    4210           0 :         masm.and32(Imm32(c-1), r);
    4211           0 :         pushI32(r);
    4212             :     } else {
    4213           0 :         bool isConst = peekConstI32(&c);
    4214           0 :         RegI32 r0, r1;
    4215           0 :         pop2xI32ForIntMulDiv(&r0, &r1);
    4216             : 
    4217           0 :         Label done;
    4218           0 :         if (!isConst || c == 0)
    4219           0 :             checkDivideByZeroI32(r1, r0, &done);
    4220           0 :         masm.remainder32(r1, r0, IsUnsigned(true));
    4221           0 :         masm.bind(&done);
    4222             : 
    4223           0 :         freeI32(r1);
    4224           0 :         pushI32(r0);
    4225             :     }
    4226           0 : }
    4227             : 
    4228             : #ifndef INT_DIV_I64_CALLOUT
    4229             : void
    4230           0 : BaseCompiler::emitQuotientI64()
    4231             : {
    4232             : # ifdef JS_PUNBOX64
    4233             :     int64_t c;
    4234             :     uint_fast8_t power;
    4235           0 :     if (popConstPositivePowerOfTwoI64(&c, &power, 0)) {
    4236           0 :         if (power != 0) {
    4237           0 :             RegI64 r = popI64();
    4238           0 :             Label positive;
    4239           0 :             masm.branchTest64(Assembler::NotSigned, r, r, Register::Invalid(),
    4240           0 :                               &positive);
    4241           0 :             masm.add64(Imm32(c-1), r);
    4242           0 :             masm.bind(&positive);
    4243             : 
    4244           0 :             masm.rshift64Arithmetic(Imm32(power & 63), r);
    4245           0 :             pushI64(r);
    4246             :         }
    4247             :     } else {
    4248           0 :         bool isConst = peekConstI64(&c);
    4249           0 :         RegI64 r0, r1;
    4250           0 :         pop2xI64ForIntDiv(&r0, &r1);
    4251           0 :         quotientI64(r1, r0, IsUnsigned(false), isConst, c);
    4252           0 :         freeI64(r1);
    4253           0 :         pushI64(r0);
    4254             :     }
    4255             : # else
    4256             :     MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
    4257             : # endif
    4258           0 : }
    4259             : 
    4260             : void
    4261           0 : BaseCompiler::emitQuotientU64()
    4262             : {
    4263             : # ifdef JS_PUNBOX64
    4264             :     int64_t c;
    4265             :     uint_fast8_t power;
    4266           0 :     if (popConstPositivePowerOfTwoI64(&c, &power, 0)) {
    4267           0 :         if (power != 0) {
    4268           0 :             RegI64 r = popI64();
    4269           0 :             masm.rshift64(Imm32(power & 63), r);
    4270           0 :             pushI64(r);
    4271             :         }
    4272             :     } else {
    4273           0 :         bool isConst = peekConstI64(&c);
    4274           0 :         RegI64 r0, r1;
    4275           0 :         pop2xI64ForIntDiv(&r0, &r1);
    4276           0 :         quotientI64(r1, r0, IsUnsigned(true), isConst, c);
    4277           0 :         freeI64(r1);
    4278           0 :         pushI64(r0);
    4279             :     }
    4280             : # else
    4281             :     MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
    4282             : # endif
    4283           0 : }
    4284             : 
    4285             : void
    4286           0 : BaseCompiler::emitRemainderI64()
    4287             : {
    4288             : # ifdef JS_PUNBOX64
    4289             :     int64_t c;
    4290             :     uint_fast8_t power;
    4291           0 :     if (popConstPositivePowerOfTwoI64(&c, &power, 1)) {
    4292           0 :         RegI64 r = popI64();
    4293           0 :         RegI64 temp = needI64();
    4294           0 :         moveI64(r, temp);
    4295             : 
    4296           0 :         Label positive;
    4297           0 :         masm.branchTest64(Assembler::NotSigned, temp, temp,
    4298           0 :                           Register::Invalid(), &positive);
    4299           0 :         masm.add64(Imm64(c-1), temp);
    4300           0 :         masm.bind(&positive);
    4301             : 
    4302           0 :         masm.rshift64Arithmetic(Imm32(power & 63), temp);
    4303           0 :         masm.lshift64(Imm32(power & 63), temp);
    4304           0 :         masm.sub64(temp, r);
    4305           0 :         freeI64(temp);
    4306             : 
    4307           0 :         pushI64(r);
    4308             :     } else {
    4309           0 :         bool isConst = peekConstI64(&c);
    4310           0 :         RegI64 r0, r1;
    4311           0 :         pop2xI64ForIntDiv(&r0, &r1);
    4312           0 :         remainderI64(r1, r0, IsUnsigned(false), isConst, c);
    4313           0 :         freeI64(r1);
    4314           0 :         pushI64(r0);
    4315             :     }
    4316             : # else
    4317             :     MOZ_CRASH("BaseCompiler platform hook: emitRemainderI64");
    4318             : # endif
    4319           0 : }
    4320             : 
    4321             : void
    4322           0 : BaseCompiler::emitRemainderU64()
    4323             : {
    4324             : # ifdef JS_PUNBOX64
    4325             :     int64_t c;
    4326             :     uint_fast8_t power;
    4327           0 :     if (popConstPositivePowerOfTwoI64(&c, &power, 1)) {
    4328           0 :         RegI64 r = popI64();
    4329           0 :         masm.and64(Imm64(c-1), r);
    4330           0 :         pushI64(r);
    4331             :     } else {
    4332           0 :         bool isConst = peekConstI64(&c);
    4333           0 :         RegI64 r0, r1;
    4334           0 :         pop2xI64ForIntDiv(&r0, &r1);
    4335           0 :         remainderI64(r1, r0, IsUnsigned(true), isConst, c);
    4336           0 :         freeI64(r1);
    4337           0 :         pushI64(r0);
    4338             :     }
    4339             : # else
    4340             :     MOZ_CRASH("BaseCompiler platform hook: emitRemainderU64");
    4341             : # endif
    4342           0 : }
    4343             : #endif // INT_DIV_I64_CALLOUT
    4344             : 
    4345             : void
    4346           0 : BaseCompiler::emitDivideF32()
    4347             : {
    4348           0 :     RegF32 r0, r1;
    4349           0 :     pop2xF32(&r0, &r1);
    4350           0 :     masm.divFloat32(r1, r0);
    4351           0 :     freeF32(r1);
    4352           0 :     pushF32(r0);
    4353           0 : }
    4354             : 
    4355             : void
    4356           0 : BaseCompiler::emitDivideF64()
    4357             : {
    4358           0 :     RegF64 r0, r1;
    4359           0 :     pop2xF64(&r0, &r1);
    4360           0 :     masm.divDouble(r1, r0);
    4361           0 :     freeF64(r1);
    4362           0 :     pushF64(r0);
    4363           0 : }
    4364             : 
    4365             : void
    4366           0 : BaseCompiler::emitMinF32()
    4367             : {
    4368           0 :     RegF32 r0, r1;
    4369           0 :     pop2xF32(&r0, &r1);
    4370             :     // Convert signaling NaN to quiet NaNs.
    4371             :     //
    4372             :     // TODO / OPTIMIZE (bug 1316824): Don't do this if one of the operands
    4373             :     // is known to be a constant.
    4374           0 :     ScratchF32 zero(*this);
    4375           0 :     masm.loadConstantFloat32(0.f, zero);
    4376           0 :     masm.subFloat32(zero, r0);
    4377           0 :     masm.subFloat32(zero, r1);
    4378           0 :     masm.minFloat32(r1, r0, HandleNaNSpecially(true));
    4379           0 :     freeF32(r1);
    4380           0 :     pushF32(r0);
    4381           0 : }
    4382             : 
    4383             : void
    4384           0 : BaseCompiler::emitMaxF32()
    4385             : {
    4386           0 :     RegF32 r0, r1;
    4387           0 :     pop2xF32(&r0, &r1);
    4388             :     // Convert signaling NaN to quiet NaNs.
    4389             :     //
    4390             :     // TODO / OPTIMIZE (bug 1316824): see comment in emitMinF32.
    4391           0 :     ScratchF32 zero(*this);
    4392           0 :     masm.loadConstantFloat32(0.f, zero);
    4393           0 :     masm.subFloat32(zero, r0);
    4394           0 :     masm.subFloat32(zero, r1);
    4395           0 :     masm.maxFloat32(r1, r0, HandleNaNSpecially(true));
    4396           0 :     freeF32(r1);
    4397           0 :     pushF32(r0);
    4398           0 : }
    4399             : 
    4400             : void
    4401           0 : BaseCompiler::emitMinF64()
    4402             : {
    4403           0 :     RegF64 r0, r1;
    4404           0 :     pop2xF64(&r0, &r1);
    4405             :     // Convert signaling NaN to quiet NaNs.
    4406             :     //
    4407             :     // TODO / OPTIMIZE (bug 1316824): see comment in emitMinF32.
    4408           0 :     ScratchF64 zero(*this);
    4409           0 :     masm.loadConstantDouble(0, zero);
    4410           0 :     masm.subDouble(zero, r0);
    4411           0 :     masm.subDouble(zero, r1);
    4412           0 :     masm.minDouble(r1, r0, HandleNaNSpecially(true));
    4413           0 :     freeF64(r1);
    4414           0 :     pushF64(r0);
    4415           0 : }
    4416             : 
    4417             : void
    4418           0 : BaseCompiler::emitMaxF64()
    4419             : {
    4420           0 :     RegF64 r0, r1;
    4421           0 :     pop2xF64(&r0, &r1);
    4422             :     // Convert signaling NaN to quiet NaNs.
    4423             :     //
    4424             :     // TODO / OPTIMIZE (bug 1316824): see comment in emitMinF32.
    4425           0 :     ScratchF64 zero(*this);
    4426           0 :     masm.loadConstantDouble(0, zero);
    4427           0 :     masm.subDouble(zero, r0);
    4428           0 :     masm.subDouble(zero, r1);
    4429           0 :     masm.maxDouble(r1, r0, HandleNaNSpecially(true));
    4430           0 :     freeF64(r1);
    4431           0 :     pushF64(r0);
    4432           0 : }
    4433             : 
    4434             : void
    4435           0 : BaseCompiler::emitCopysignF32()
    4436             : {
    4437           0 :     RegF32 r0, r1;
    4438           0 :     pop2xF32(&r0, &r1);
    4439           0 :     RegI32 i0 = needI32();
    4440           0 :     RegI32 i1 = needI32();
    4441           0 :     masm.moveFloat32ToGPR(r0, i0);
    4442           0 :     masm.moveFloat32ToGPR(r1, i1);
    4443           0 :     masm.and32(Imm32(INT32_MAX), i0);
    4444           0 :     masm.and32(Imm32(INT32_MIN), i1);
    4445           0 :     masm.or32(i1, i0);
    4446           0 :     masm.moveGPRToFloat32(i0, r0);
    4447           0 :     freeI32(i0);
    4448           0 :     freeI32(i1);
    4449           0 :     freeF32(r1);
    4450           0 :     pushF32(r0);
    4451           0 : }
    4452             : 
    4453             : void
    4454           0 : BaseCompiler::emitCopysignF64()
    4455             : {
    4456           0 :     RegF64 r0, r1;
    4457           0 :     pop2xF64(&r0, &r1);
    4458           0 :     RegI64 x0 = needI64();
    4459           0 :     RegI64 x1 = needI64();
    4460           0 :     reinterpretF64AsI64(r0, x0);
    4461           0 :     reinterpretF64AsI64(r1, x1);
    4462           0 :     masm.and64(Imm64(INT64_MAX), x0);
    4463           0 :     masm.and64(Imm64(INT64_MIN), x1);
    4464           0 :     masm.or64(x1, x0);
    4465           0 :     reinterpretI64AsF64(x0, r0);
    4466           0 :     freeI64(x0);
    4467           0 :     freeI64(x1);
    4468           0 :     freeF64(r1);
    4469           0 :     pushF64(r0);
    4470           0 : }
    4471             : 
    4472             : void
    4473           0 : BaseCompiler::emitOrI32()
    4474             : {
    4475             :     int32_t c;
    4476           0 :     if (popConstI32(&c)) {
    4477           0 :         RegI32 r = popI32();
    4478           0 :         masm.or32(Imm32(c), r);
    4479           0 :         pushI32(r);
    4480             :     } else {
    4481           0 :         RegI32 r0, r1;
    4482           0 :         pop2xI32(&r0, &r1);
    4483           0 :         masm.or32(r1, r0);
    4484           0 :         freeI32(r1);
    4485           0 :         pushI32(r0);
    4486             :     }
    4487           0 : }
    4488             : 
    4489             : void
    4490           0 : BaseCompiler::emitOrI64()
    4491             : {
    4492             :     int64_t c;
    4493           0 :     if (popConstI64(&c)) {
    4494           0 :         RegI64 r = popI64();
    4495           0 :         masm.or64(Imm64(c), r);
    4496           0 :         pushI64(r);
    4497             :     } else {
    4498           0 :         RegI64 r0, r1;
    4499           0 :         pop2xI64(&r0, &r1);
    4500           0 :         masm.or64(r1, r0);
    4501           0 :         freeI64(r1);
    4502           0 :         pushI64(r0);
    4503             :     }
    4504           0 : }
    4505             : 
    4506             : void
    4507           0 : BaseCompiler::emitAndI32()
    4508             : {
    4509             :     int32_t c;
    4510           0 :     if (popConstI32(&c)) {
    4511           0 :         RegI32 r = popI32();
    4512           0 :         masm.and32(Imm32(c), r);
    4513           0 :         pushI32(r);
    4514             :     } else {
    4515           0 :         RegI32 r0, r1;
    4516           0 :         pop2xI32(&r0, &r1);
    4517           0 :         masm.and32(r1, r0);
    4518           0 :         freeI32(r1);
    4519           0 :         pushI32(r0);
    4520             :     }
    4521           0 : }
    4522             : 
    4523             : void
    4524           0 : BaseCompiler::emitAndI64()
    4525             : {
    4526             :     int64_t c;
    4527           0 :     if (popConstI64(&c)) {
    4528           0 :         RegI64 r = popI64();
    4529           0 :         masm.and64(Imm64(c), r);
    4530           0 :         pushI64(r);
    4531             :     } else {
    4532           0 :         RegI64 r0, r1;
    4533           0 :         pop2xI64(&r0, &r1);
    4534           0 :         masm.and64(r1, r0);
    4535           0 :         freeI64(r1);
    4536           0 :         pushI64(r0);
    4537             :     }
    4538           0 : }
    4539             : 
    4540             : void
    4541           0 : BaseCompiler::emitXorI32()
    4542             : {
    4543             :     int32_t c;
    4544           0 :     if (popConstI32(&c)) {
    4545           0 :         RegI32 r = popI32();
    4546           0 :         masm.xor32(Imm32(c), r);
    4547           0 :         pushI32(r);
    4548             :     } else {
    4549           0 :         RegI32 r0, r1;
    4550           0 :         pop2xI32(&r0, &r1);
    4551           0 :         masm.xor32(r1, r0);
    4552           0 :         freeI32(r1);
    4553           0 :         pushI32(r0);
    4554             :     }
    4555           0 : }
    4556             : 
    4557             : void
    4558           0 : BaseCompiler::emitXorI64()
    4559             : {
    4560             :     int64_t c;
    4561           0 :     if (popConstI64(&c)) {
    4562           0 :         RegI64 r = popI64();
    4563           0 :         masm.xor64(Imm64(c), r);
    4564           0 :         pushI64(r);
    4565             :     } else {
    4566           0 :         RegI64 r0, r1;
    4567           0 :         pop2xI64(&r0, &r1);
    4568           0 :         masm.xor64(r1, r0);
    4569           0 :         freeI64(r1);
    4570           0 :         pushI64(r0);
    4571             :     }
    4572           0 : }
    4573             : 
    4574             : void
    4575           0 : BaseCompiler::emitShlI32()
    4576             : {
    4577             :     int32_t c;
    4578           0 :     if (popConstI32(&c)) {
    4579           0 :         RegI32 r = popI32();
    4580           0 :         masm.lshift32(Imm32(c & 31), r);
    4581           0 :         pushI32(r);
    4582             :     } else {
    4583           0 :         RegI32 r0, r1;
    4584           0 :         pop2xI32ForShiftOrRotate(&r0, &r1);
    4585           0 :         maskShiftCount32(r1);
    4586           0 :         masm.lshift32(r1, r0);
    4587           0 :         freeI32(r1);
    4588           0 :         pushI32(r0);
    4589             :     }
    4590           0 : }
    4591             : 
    4592             : void
    4593           0 : BaseCompiler::emitShlI64()
    4594             : {
    4595             :     int64_t c;
    4596           0 :     if (popConstI64(&c)) {
    4597           0 :         RegI64 r = popI64();
    4598           0 :         masm.lshift64(Imm32(c & 63), r);
    4599           0 :         pushI64(r);
    4600             :     } else {
    4601           0 :         RegI64 r0, r1;
    4602           0 :         pop2xI64ForShiftOrRotate(&r0, &r1);
    4603           0 :         masm.lshift64(lowPart(r1), r0);
    4604           0 :         freeI64(r1);
    4605           0 :         pushI64(r0);
    4606             :     }
    4607           0 : }
    4608             : 
    4609             : void
    4610           0 : BaseCompiler::emitShrI32()
    4611             : {
    4612             :     int32_t c;
    4613           0 :     if (popConstI32(&c)) {
    4614           0 :         RegI32 r = popI32();
    4615           0 :         masm.rshift32Arithmetic(Imm32(c & 31), r);
    4616           0 :         pushI32(r);
    4617             :     } else {
    4618           0 :         RegI32 r0, r1;
    4619           0 :         pop2xI32ForShiftOrRotate(&r0, &r1);
    4620           0 :         maskShiftCount32(r1);
    4621           0 :         masm.rshift32Arithmetic(r1, r0);
    4622           0 :         freeI32(r1);
    4623           0 :         pushI32(r0);
    4624             :     }
    4625           0 : }
    4626             : 
    4627             : void
    4628           0 : BaseCompiler::emitShrI64()
    4629             : {
    4630             :     int64_t c;
    4631           0 :     if (popConstI64(&c)) {
    4632           0 :         RegI64 r = popI64();
    4633           0 :         masm.rshift64Arithmetic(Imm32(c & 63), r);
    4634           0 :         pushI64(r);
    4635             :     } else {
    4636           0 :         RegI64 r0, r1;
    4637           0 :         pop2xI64ForShiftOrRotate(&r0, &r1);
    4638           0 :         masm.rshift64Arithmetic(lowPart(r1), r0);
    4639           0 :         freeI64(r1);
    4640           0 :         pushI64(r0);
    4641             :     }
    4642           0 : }
    4643             : 
    4644             : void
    4645           0 : BaseCompiler::emitShrU32()
    4646             : {
    4647             :     int32_t c;
    4648           0 :     if (popConstI32(&c)) {
    4649           0 :         RegI32 r = popI32();
    4650           0 :         masm.rshift32(Imm32(c & 31), r);
    4651           0 :         pushI32(r);
    4652             :     } else {
    4653           0 :         RegI32 r0, r1;
    4654           0 :         pop2xI32ForShiftOrRotate(&r0, &r1);
    4655           0 :         maskShiftCount32(r1);
    4656           0 :         masm.rshift32(r1, r0);
    4657           0 :         freeI32(r1);
    4658           0 :         pushI32(r0);
    4659             :     }
    4660           0 : }
    4661             : 
    4662             : void
    4663           0 : BaseCompiler::emitShrU64()
    4664             : {
    4665             :     int64_t c;
    4666           0 :     if (popConstI64(&c)) {
    4667           0 :         RegI64 r = popI64();
    4668           0 :         masm.rshift64(Imm32(c & 63), r);
    4669           0 :         pushI64(r);
    4670             :     } else {
    4671           0 :         RegI64 r0, r1;
    4672           0 :         pop2xI64ForShiftOrRotate(&r0, &r1);
    4673           0 :         masm.rshift64(lowPart(r1), r0);
    4674           0 :         freeI64(r1);
    4675           0 :         pushI64(r0);
    4676             :     }
    4677           0 : }
    4678             : 
    4679             : void
    4680           0 : BaseCompiler::emitRotrI32()
    4681             : {
    4682             :     int32_t c;
    4683           0 :     if (popConstI32(&c)) {
    4684           0 :         RegI32 r = popI32();
    4685           0 :         masm.rotateRight(Imm32(c & 31), r, r);
    4686           0 :         pushI32(r);
    4687             :     } else {
    4688           0 :         RegI32 r0, r1;
    4689           0 :         pop2xI32ForShiftOrRotate(&r0, &r1);
    4690           0 :         masm.rotateRight(r1, r0, r0);
    4691           0 :         freeI32(r1);
    4692           0 :         pushI32(r0);
    4693             :     }
    4694           0 : }
    4695             : 
    4696             : void
    4697           0 : BaseCompiler::emitRotrI64()
    4698             : {
    4699             :     int64_t c;
    4700           0 :     if (popConstI64(&c)) {
    4701           0 :         RegI64 r = popI64();
    4702           0 :         RegI32 temp;
    4703           0 :         if (rotate64NeedsTemp())
    4704           0 :             temp = needI32();
    4705           0 :         masm.rotateRight64(Imm32(c & 63), r, r, temp);
    4706           0 :         if (temp != Register::Invalid())
    4707           0 :             freeI32(temp);
    4708           0 :         pushI64(r);
    4709             :     } else {
    4710           0 :         RegI64 r0, r1;
    4711           0 :         pop2xI64ForShiftOrRotate(&r0, &r1);
    4712           0 :         masm.rotateRight64(lowPart(r1), r0, r0, maybeHighPart(r1));
    4713           0 :         freeI64(r1);
    4714           0 :         pushI64(r0);
    4715             :     }
    4716           0 : }
    4717             : 
    4718             : void
    4719           0 : BaseCompiler::emitRotlI32()
    4720             : {
    4721             :     int32_t c;
    4722           0 :     if (popConstI32(&c)) {
    4723           0 :         RegI32 r = popI32();
    4724           0 :         masm.rotateLeft(Imm32(c & 31), r, r);
    4725           0 :         pushI32(r);
    4726             :     } else {
    4727           0 :         RegI32 r0, r1;
    4728           0 :         pop2xI32ForShiftOrRotate(&r0, &r1);
    4729           0 :         masm.rotateLeft(r1, r0, r0);
    4730           0 :         freeI32(r1);
    4731           0 :         pushI32(r0);
    4732             :     }
    4733           0 : }
    4734             : 
    4735             : void
    4736           0 : BaseCompiler::emitRotlI64()
    4737             : {
    4738             :     int64_t c;
    4739           0 :     if (popConstI64(&c)) {
    4740           0 :         RegI64 r = popI64();
    4741           0 :         RegI32 temp;
    4742           0 :         if (rotate64NeedsTemp())
    4743           0 :             temp = needI32();
    4744           0 :         masm.rotateLeft64(Imm32(c & 63), r, r, temp);
    4745           0 :         if (temp != Register::Invalid())
    4746           0 :             freeI32(temp);
    4747           0 :         pushI64(r);
    4748             :     } else {
    4749           0 :         RegI64 r0, r1;
    4750           0 :         pop2xI64ForShiftOrRotate(&r0, &r1);
    4751           0 :         masm.rotateLeft64(lowPart(r1), r0, r0, maybeHighPart(r1));
    4752           0 :         freeI64(r1);
    4753           0 :         pushI64(r0);
    4754             :     }
    4755           0 : }
    4756             : 
    4757             : void
    4758           0 : BaseCompiler::emitEqzI32()
    4759             : {
    4760           0 :     if (sniffConditionalControlEqz(ValType::I32))
    4761           0 :         return;
    4762             : 
    4763           0 :     RegI32 r0 = popI32();
    4764           0 :     masm.cmp32Set(Assembler::Equal, r0, Imm32(0), r0);
    4765           0 :     pushI32(r0);
    4766             : }
    4767             : 
    4768             : void
    4769           0 : BaseCompiler::emitEqzI64()
    4770             : {
    4771           0 :     if (sniffConditionalControlEqz(ValType::I64))
    4772           0 :         return;
    4773             : 
    4774           0 :     RegI64 r0 = popI64();
    4775           0 :     RegI32 i0 = fromI64(r0);
    4776           0 :     eqz64(r0, i0);
    4777           0 :     freeI64Except(r0, i0);
    4778           0 :     pushI32(i0);
    4779             : }
    4780             : 
    4781             : void
    4782           0 : BaseCompiler::emitClzI32()
    4783             : {
    4784           0 :     RegI32 r0 = popI32();
    4785           0 :     masm.clz32(r0, r0, IsKnownNotZero(false));
    4786           0 :     pushI32(r0);
    4787           0 : }
    4788             : 
    4789             : void
    4790           0 : BaseCompiler::emitClzI64()
    4791             : {
    4792           0 :     RegI64 r0 = popI64();
    4793           0 :     masm.clz64(r0, lowPart(r0));
    4794           0 :     maybeClearHighPart(r0);
    4795           0 :     pushI64(r0);
    4796           0 : }
    4797             : 
    4798             : void
    4799           0 : BaseCompiler::emitCtzI32()
    4800             : {
    4801           0 :     RegI32 r0 = popI32();
    4802           0 :     masm.ctz32(r0, r0, IsKnownNotZero(false));
    4803           0 :     pushI32(r0);
    4804           0 : }
    4805             : 
    4806             : void
    4807           0 : BaseCompiler::emitCtzI64()
    4808             : {
    4809           0 :     RegI64 r0 = popI64();
    4810           0 :     masm.ctz64(r0, lowPart(r0));
    4811           0 :     maybeClearHighPart(r0);
    4812           0 :     pushI64(r0);
    4813           0 : }
    4814             : 
    4815             : void
    4816           0 : BaseCompiler::emitPopcntI32()
    4817             : {
    4818           0 :     RegI32 r0 = popI32();
    4819           0 :     if (popcnt32NeedsTemp()) {
    4820           0 :         RegI32 tmp = needI32();
    4821           0 :         masm.popcnt32(r0, r0, tmp);
    4822           0 :         freeI32(tmp);
    4823             :     } else {
    4824           0 :         masm.popcnt32(r0, r0, invalidI32());
    4825             :     }
    4826           0 :     pushI32(r0);
    4827           0 : }
    4828             : 
    4829             : void
    4830           0 : BaseCompiler::emitPopcntI64()
    4831             : {
    4832           0 :     RegI64 r0 = popI64();
    4833           0 :     if (popcnt64NeedsTemp()) {
    4834           0 :         RegI32 tmp = needI32();
    4835           0 :         masm.popcnt64(r0, r0, tmp);
    4836           0 :         freeI32(tmp);
    4837             :     } else {
    4838           0 :         masm.popcnt64(r0, r0, invalidI32());
    4839             :     }
    4840           0 :     pushI64(r0);
    4841           0 : }
    4842             : 
    4843             : void
    4844           0 : BaseCompiler::emitAbsF32()
    4845             : {
    4846           0 :     RegF32 r0 = popF32();
    4847           0 :     masm.absFloat32(r0, r0);
    4848           0 :     pushF32(r0);
    4849           0 : }
    4850             : 
    4851             : void
    4852           0 : BaseCompiler::emitAbsF64()
    4853             : {
    4854           0 :     RegF64 r0 = popF64();
    4855           0 :     masm.absDouble(r0, r0);
    4856           0 :     pushF64(r0);
    4857           0 : }
    4858             : 
    4859             : void
    4860           0 : BaseCompiler::emitNegateF32()
    4861             : {
    4862           0 :     RegF32 r0 = popF32();
    4863           0 :     masm.negateFloat(r0);
    4864           0 :     pushF32(r0);
    4865           0 : }
    4866             : 
    4867             : void
    4868           0 : BaseCompiler::emitNegateF64()
    4869             : {
    4870           0 :     RegF64 r0 = popF64();
    4871           0 :     masm.negateDouble(r0);
    4872           0 :     pushF64(r0);
    4873           0 : }
    4874             : 
    4875             : void
    4876           0 : BaseCompiler::emitSqrtF32()
    4877             : {
    4878           0 :     RegF32 r0 = popF32();
    4879           0 :     masm.sqrtFloat32(r0, r0);
    4880           0 :     pushF32(r0);
    4881           0 : }
    4882             : 
    4883             : void
    4884           0 : BaseCompiler::emitSqrtF64()
    4885             : {
    4886           0 :     RegF64 r0 = popF64();
    4887           0 :     masm.sqrtDouble(r0, r0);
    4888           0 :     pushF64(r0);
    4889           0 : }
    4890             : 
    4891             : template<bool isUnsigned>
    4892             : bool
    4893           0 : BaseCompiler::emitTruncateF32ToI32()
    4894             : {
    4895           0 :     RegF32 r0 = popF32();
    4896           0 :     RegI32 i0 = needI32();
    4897           0 :     if (!truncateF32ToI32(r0, i0, isUnsigned))
    4898           0 :         return false;
    4899           0 :     freeF32(r0);
    4900           0 :     pushI32(i0);
    4901           0 :     return true;
    4902             : }
    4903             : 
    4904             : template<bool isUnsigned>
    4905             : bool
    4906           0 : BaseCompiler::emitTruncateF64ToI32()
    4907             : {
    4908           0 :     RegF64 r0 = popF64();
    4909           0 :     RegI32 i0 = needI32();
    4910           0 :     if (!truncateF64ToI32(r0, i0, isUnsigned))
    4911           0 :         return false;
    4912           0 :     freeF64(r0);
    4913           0 :     pushI32(i0);
    4914           0 :     return true;
    4915             : }
    4916             : 
    4917             : #ifndef FLOAT_TO_I64_CALLOUT
    4918             : template<bool isUnsigned>
    4919             : bool
    4920           0 : BaseCompiler::emitTruncateF32ToI64()
    4921             : {
    4922           0 :     RegF32 r0 = popF32();
    4923           0 :     RegI64 x0 = needI64();
    4924             :     if (isUnsigned) {
    4925           0 :         RegF64 tmp = needF64();
    4926           0 :         if (!truncateF32ToI64(r0, x0, isUnsigned, tmp))
    4927           0 :             return false;
    4928           0 :         freeF64(tmp);
    4929             :     } else {
    4930           0 :         if (!truncateF32ToI64(r0, x0, isUnsigned, invalidF64()))
    4931           0 :             return false;
    4932             :     }
    4933           0 :     freeF32(r0);
    4934           0 :     pushI64(x0);
    4935           0 :     return true;
    4936             : }
    4937             : 
    4938             : template<bool isUnsigned>
    4939             : bool
    4940           0 : BaseCompiler::emitTruncateF64ToI64()
    4941             : {
    4942           0 :     RegF64 r0 = popF64();
    4943           0 :     RegI64 x0 = needI64();
    4944             :     if (isUnsigned) {
    4945           0 :         RegF64 tmp = needF64();
    4946           0 :         if (!truncateF64ToI64(r0, x0, isUnsigned, tmp))
    4947           0 :             return false;
    4948           0 :         freeF64(tmp);
    4949             :     } else {
    4950           0 :         if (!truncateF64ToI64(r0, x0, isUnsigned, invalidF64()))
    4951           0 :             return false;
    4952             :     }
    4953           0 :     freeF64(r0);
    4954           0 :     pushI64(x0);
    4955           0 :     return true;
    4956             : }
    4957             : #endif // FLOAT_TO_I64_CALLOUT
    4958             : 
    4959             : void
    4960           0 : BaseCompiler::emitWrapI64ToI32()
    4961             : {
    4962           0 :     RegI64 r0 = popI64();
    4963           0 :     RegI32 i0 = fromI64(r0);
    4964           0 :     wrapI64ToI32(r0, i0);
    4965           0 :     freeI64Except(r0, i0);
    4966           0 :     pushI32(i0);
    4967           0 : }
    4968             : 
    4969             : void
    4970           0 : BaseCompiler::emitExtendI32ToI64()
    4971             : {
    4972           0 :     RegI64 x0 = popI32ForSignExtendI64();
    4973           0 :     RegI32 r0 = RegI32(lowPart(x0));
    4974           0 :     signExtendI32ToI64(r0, x0);
    4975           0 :     pushI64(x0);
    4976             :     // Note: no need to free r0, since it is part of x0
    4977           0 : }
    4978             : 
    4979             : void
    4980           0 : BaseCompiler::emitExtendU32ToI64()
    4981             : {
    4982           0 :     RegI32 r0 = popI32();
    4983           0 :     RegI64 x0 = widenI32(r0);
    4984           0 :     extendU32ToI64(r0, x0);
    4985           0 :     pushI64(x0);
    4986             :     // Note: no need to free r0, since it is part of x0
    4987           0 : }
    4988             : 
    4989             : void
    4990           0 : BaseCompiler::emitReinterpretF32AsI32()
    4991             : {
    4992           0 :     RegF32 r0 = popF32();
    4993           0 :     RegI32 i0 = needI32();
    4994           0 :     masm.moveFloat32ToGPR(r0, i0);
    4995           0 :     freeF32(r0);
    4996           0 :     pushI32(i0);
    4997           0 : }
    4998             : 
    4999             : void
    5000           0 : BaseCompiler::emitReinterpretF64AsI64()
    5001             : {
    5002           0 :     RegF64 r0 = popF64();
    5003           0 :     RegI64 x0 = needI64();
    5004           0 :     reinterpretF64AsI64(r0, x0);
    5005           0 :     freeF64(r0);
    5006           0 :     pushI64(x0);
    5007           0 : }
    5008             : 
    5009             : void
    5010           0 : BaseCompiler::emitConvertF64ToF32()
    5011             : {
    5012           0 :     RegF64 r0 = popF64();
    5013           0 :     RegF32 f0 = needF32();
    5014           0 :     masm.convertDoubleToFloat32(r0, f0);
    5015           0 :     freeF64(r0);
    5016           0 :     pushF32(f0);
    5017           0 : }
    5018             : 
    5019             : void
    5020           0 : BaseCompiler::emitConvertI32ToF32()
    5021             : {
    5022           0 :     RegI32 r0 = popI32();
    5023           0 :     RegF32 f0 = needF32();
    5024           0 :     masm.convertInt32ToFloat32(r0, f0);
    5025           0 :     freeI32(r0);
    5026           0 :     pushF32(f0);
    5027           0 : }
    5028             : 
    5029             : void
    5030           0 : BaseCompiler::emitConvertU32ToF32()
    5031             : {
    5032           0 :     RegI32 r0 = popI32();
    5033           0 :     RegF32 f0 = needF32();
    5034           0 :     masm.convertUInt32ToFloat32(r0, f0);
    5035           0 :     freeI32(r0);
    5036           0 :     pushF32(f0);
    5037           0 : }
    5038             : 
    5039             : #ifndef I64_TO_FLOAT_CALLOUT
    5040             : void
    5041           0 : BaseCompiler::emitConvertI64ToF32()
    5042             : {
    5043           0 :     RegI64 r0 = popI64();
    5044           0 :     RegF32 f0 = needF32();
    5045           0 :     convertI64ToF32(r0, IsUnsigned(false), f0, RegI32());
    5046           0 :     freeI64(r0);
    5047           0 :     pushF32(f0);
    5048           0 : }
    5049             : 
    5050             : void
    5051           0 : BaseCompiler::emitConvertU64ToF32()
    5052             : {
    5053           0 :     RegI64 r0 = popI64();
    5054           0 :     RegF32 f0 = needF32();
    5055           0 :     RegI32 temp;
    5056           0 :     if (convertI64ToFloatNeedsTemp(ValType::F32, IsUnsigned(true)))
    5057           0 :         temp = needI32();
    5058           0 :     convertI64ToF32(r0, IsUnsigned(true), f0, temp);
    5059           0 :     if (temp != Register::Invalid())
    5060           0 :         freeI32(temp);
    5061           0 :     freeI64(r0);
    5062           0 :     pushF32(f0);
    5063           0 : }
    5064             : #endif
    5065             : 
    5066             : void
    5067           0 : BaseCompiler::emitConvertF32ToF64()
    5068             : {
    5069           0 :     RegF32 r0 = popF32();
    5070           0 :     RegF64 d0 = needF64();
    5071           0 :     masm.convertFloat32ToDouble(r0, d0);
    5072           0 :     freeF32(r0);
    5073           0 :     pushF64(d0);
    5074           0 : }
    5075             : 
    5076             : void
    5077           0 : BaseCompiler::emitConvertI32ToF64()
    5078             : {
    5079           0 :     RegI32 r0 = popI32();
    5080           0 :     RegF64 d0 = needF64();
    5081           0 :     masm.convertInt32ToDouble(r0, d0);
    5082           0 :     freeI32(r0);
    5083           0 :     pushF64(d0);
    5084           0 : }
    5085             : 
    5086             : void
    5087           0 : BaseCompiler::emitConvertU32ToF64()
    5088             : {
    5089           0 :     RegI32 r0 = popI32();
    5090           0 :     RegF64 d0 = needF64();
    5091           0 :     masm.convertUInt32ToDouble(r0, d0);
    5092           0 :     freeI32(r0);
    5093           0 :     pushF64(d0);
    5094           0 : }
    5095             : 
    5096             : #ifndef I64_TO_FLOAT_CALLOUT
    5097             : void
    5098           0 : BaseCompiler::emitConvertI64ToF64()
    5099             : {
    5100           0 :     RegI64 r0 = popI64();
    5101           0 :     RegF64 d0 = needF64();
    5102           0 :     convertI64ToF64(r0, IsUnsigned(false), d0, RegI32());
    5103           0 :     freeI64(r0);
    5104           0 :     pushF64(d0);
    5105           0 : }
    5106             : 
    5107             : void
    5108           0 : BaseCompiler::emitConvertU64ToF64()
    5109             : {
    5110           0 :     RegI64 r0 = popI64();
    5111           0 :     RegF64 d0 = needF64();
    5112           0 :     RegI32 temp;
    5113           0 :     if (convertI64ToFloatNeedsTemp(ValType::F64, IsUnsigned(true)))
    5114           0 :         temp = needI32();
    5115           0 :     convertI64ToF64(r0, IsUnsigned(true), d0, temp);
    5116           0 :     if (temp != Register::Invalid())
    5117           0 :         freeI32(temp);
    5118           0 :     freeI64(r0);
    5119           0 :     pushF64(d0);
    5120           0 : }
    5121             : #endif // I64_TO_FLOAT_CALLOUT
    5122             : 
    5123             : void
    5124           0 : BaseCompiler::emitReinterpretI32AsF32()
    5125             : {
    5126           0 :     RegI32 r0 = popI32();
    5127           0 :     RegF32 f0 = needF32();
    5128           0 :     masm.moveGPRToFloat32(r0, f0);
    5129           0 :     freeI32(r0);
    5130           0 :     pushF32(f0);
    5131           0 : }
    5132             : 
    5133             : void
    5134           0 : BaseCompiler::emitReinterpretI64AsF64()
    5135             : {
    5136           0 :     RegI64 r0 = popI64();
    5137           0 :     RegF64 d0 = needF64();
    5138           0 :     reinterpretI64AsF64(r0, d0);
    5139           0 :     freeI64(r0);
    5140           0 :     pushF64(d0);
    5141           0 : }
    5142             : 
    5143             : template<typename Cond>
    5144             : bool
    5145           0 : BaseCompiler::sniffConditionalControlCmp(Cond compareOp, ValType operandType)
    5146             : {
    5147           0 :     MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset");
    5148             : 
    5149           0 :     OpBytes op;
    5150           0 :     iter_.peekOp(&op);
    5151           0 :     switch (op.b0) {
    5152             :       case uint16_t(Op::Select):
    5153             : #ifdef JS_CODEGEN_X86
    5154             :         // On x86, with only 5 available registers, a latent i64 binary
    5155             :         // comparison takes 4 leaving only 1 which is not enough for select.
    5156             :         if (operandType == ValType::I64)
    5157             :             return false;
    5158             : #endif
    5159             :         MOZ_FALLTHROUGH;
    5160             :       case uint16_t(Op::BrIf):
    5161             :       case uint16_t(Op::If):
    5162           0 :         setLatentCompare(compareOp, operandType);
    5163           0 :         return true;
    5164             :       default:
    5165           0 :         return false;
    5166             :     }
    5167             : }
    5168             : 
    5169             : bool
    5170           0 : BaseCompiler::sniffConditionalControlEqz(ValType operandType)
    5171             : {
    5172           0 :     MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset");
    5173             : 
    5174           0 :     OpBytes op;
    5175           0 :     iter_.peekOp(&op);
    5176           0 :     switch (op.b0) {
    5177             :       case uint16_t(Op::BrIf):
    5178             :       case uint16_t(Op::Select):
    5179             :       case uint16_t(Op::If):
    5180           0 :         setLatentEqz(operandType);
    5181           0 :         return true;
    5182             :       default:
    5183           0 :         return false;
    5184             :     }
    5185             : }
    5186             : 
    5187             : void
    5188           0 : BaseCompiler::emitBranchSetup(BranchState* b)
    5189             : {
    5190           0 :     maybeReserveJoinReg(b->resultType);
    5191             : 
    5192             :     // Set up fields so that emitBranchPerform() need not switch on latentOp_.
    5193           0 :     switch (latentOp_) {
    5194             :       case LatentOp::None: {
    5195           0 :         latentIntCmp_ = Assembler::NotEqual;
    5196           0 :         latentType_ = ValType::I32;
    5197           0 :         b->i32.lhs = popI32();
    5198           0 :         b->i32.rhsImm = true;
    5199           0 :         b->i32.imm = 0;
    5200           0 :         break;
    5201             :       }
    5202             :       case LatentOp::Compare: {
    5203           0 :         switch (latentType_) {
    5204             :           case ValType::I32: {
    5205           0 :             if (popConstI32(&b->i32.imm)) {
    5206           0 :                 b->i32.lhs = popI32();
    5207           0 :                 b->i32.rhsImm = true;
    5208             :             } else {
    5209           0 :                 pop2xI32(&b->i32.lhs, &b->i32.rhs);
    5210           0 :                 b->i32.rhsImm = false;
    5211             :             }
    5212           0 :             break;
    5213             :           }
    5214             :           case ValType::I64: {
    5215           0 :             pop2xI64(&b->i64.lhs, &b->i64.rhs);
    5216           0 :             b->i64.rhsImm = false;
    5217           0 :             break;
    5218             :           }
    5219             :           case ValType::F32: {
    5220           0 :             pop2xF32(&b->f32.lhs, &b->f32.rhs);
    5221           0 :             break;
    5222             :           }
    5223             :           case ValType::F64: {
    5224           0 :             pop2xF64(&b->f64.lhs, &b->f64.rhs);
    5225           0 :             break;
    5226             :           }
    5227             :           default: {
    5228           0 :             MOZ_CRASH("Unexpected type for LatentOp::Compare");
    5229             :           }
    5230             :         }
    5231           0 :         break;
    5232             :       }
    5233             :       case LatentOp::Eqz: {
    5234           0 :         switch (latentType_) {
    5235             :           case ValType::I32: {
    5236           0 :             latentIntCmp_ = Assembler::Equal;
    5237           0 :             b->i32.lhs = popI32();
    5238           0 :             b->i32.rhsImm = true;
    5239           0 :             b->i32.imm = 0;
    5240           0 :             break;
    5241             :           }
    5242             :           case ValType::I64: {
    5243           0 :             latentIntCmp_ = Assembler::Equal;
    5244           0 :             b->i64.lhs = popI64();
    5245           0 :             b->i64.rhsImm = true;
    5246           0 :             b->i64.imm = 0;
    5247           0 :             break;
    5248             :           }
    5249             :           default: {
    5250           0 :             MOZ_CRASH("Unexpected type for LatentOp::Eqz");
    5251             :           }
    5252             :         }
    5253           0 :         break;
    5254             :       }
    5255             :     }
    5256             : 
    5257           0 :     maybeUnreserveJoinReg(b->resultType);
    5258           0 : }
    5259             : 
    5260             : void
    5261           0 : BaseCompiler::emitBranchPerform(BranchState* b)
    5262             : {
    5263           0 :     switch (latentType_) {
    5264             :       case ValType::I32: {
    5265           0 :         if (b->i32.rhsImm) {
    5266           0 :             jumpConditionalWithJoinReg(b, latentIntCmp_, b->i32.lhs, Imm32(b->i32.imm));
    5267             :         } else {
    5268           0 :             jumpConditionalWithJoinReg(b, latentIntCmp_, b->i32.lhs, b->i32.rhs);
    5269           0 :             freeI32(b->i32.rhs);
    5270             :         }
    5271           0 :         freeI32(b->i32.lhs);
    5272           0 :         break;
    5273             :       }
    5274             :       case ValType::I64: {
    5275           0 :         if (b->i64.rhsImm) {
    5276           0 :             jumpConditionalWithJoinReg(b, latentIntCmp_, b->i64.lhs, Imm64(b->i64.imm));
    5277             :         } else {
    5278           0 :             jumpConditionalWithJoinReg(b, latentIntCmp_, b->i64.lhs, b->i64.rhs);
    5279           0 :             freeI64(b->i64.rhs);
    5280             :         }
    5281           0 :         freeI64(b->i64.lhs);
    5282           0 :         break;
    5283             :       }
    5284             :       case ValType::F32: {
    5285           0 :         jumpConditionalWithJoinReg(b, latentDoubleCmp_, b->f32.lhs, b->f32.rhs);
    5286           0 :         freeF32(b->f32.lhs);
    5287           0 :         freeF32(b->f32.rhs);
    5288           0 :         break;
    5289             :       }
    5290             :       case ValType::F64: {
    5291           0 :         jumpConditionalWithJoinReg(b, latentDoubleCmp_, b->f64.lhs, b->f64.rhs);
    5292           0 :         freeF64(b->f64.lhs);
    5293           0 :         freeF64(b->f64.rhs);
    5294           0 :         break;
    5295             :       }
    5296             :       default: {
    5297           0 :         MOZ_CRASH("Unexpected type for LatentOp::Compare");
    5298             :       }
    5299             :     }
    5300           0 :     resetLatentOp();
    5301           0 : }
    5302             : 
    5303             : // For blocks and loops and ifs:
    5304             : //
    5305             : //  - Sync the value stack before going into the block in order to simplify exit
    5306             : //    from the block: all exits from the block can assume that there are no
    5307             : //    live registers except the one carrying the exit value.
    5308             : //  - The block can accumulate a number of dead values on the stacks, so when
    5309             : //    branching out of the block or falling out at the end be sure to
    5310             : //    pop the appropriate stacks back to where they were on entry, while
    5311             : //    preserving the exit value.
    5312             : //  - A continue branch in a loop is much like an exit branch, but the branch
    5313             : //    value must not be preserved.
    5314             : //  - The exit value is always in a designated join register (type dependent).
    5315             : 
    5316             : bool
    5317           0 : BaseCompiler::emitBlock()
    5318             : {
    5319           0 :     if (!iter_.readBlock())
    5320           0 :         return false;
    5321             : 
    5322           0 :     if (!deadCode_)
    5323           0 :         sync();                    // Simplifies branching out from block
    5324             : 
    5325           0 :     initControl(controlItem());
    5326             : 
    5327           0 :     return true;
    5328             : }
    5329             : 
    5330             : void
    5331           0 : BaseCompiler::endBlock(ExprType type)
    5332             : {
    5333           0 :     Control& block = controlItem();
    5334             : 
    5335             :     // Save the value.
    5336           0 :     AnyReg r;
    5337           0 :     if (!deadCode_) {
    5338           0 :         r = popJoinRegUnlessVoid(type);
    5339           0 :         block.bceSafeOnExit &= bceSafe_;
    5340             :     }
    5341             : 
    5342             :     // Leave the block.
    5343           0 :     popStackOnBlockExit(block.framePushed);
    5344           0 :     popValueStackTo(block.stackSize);
    5345             : 
    5346             :     // Bind after cleanup: branches out will have popped the stack.
    5347           0 :     if (block.label.used()) {
    5348           0 :         masm.bind(&block.label);
    5349             :         // No value was provided by the fallthrough but the branch out will
    5350             :         // have stored one in joinReg, so capture that.
    5351           0 :         if (deadCode_)
    5352           0 :             r = captureJoinRegUnlessVoid(type);
    5353           0 :         deadCode_ = false;
    5354             :     }
    5355             : 
    5356           0 :     bceSafe_ = block.bceSafeOnExit;
    5357             : 
    5358             :     // Retain the value stored in joinReg by all paths, if there are any.
    5359           0 :     if (!deadCode_)
    5360           0 :         pushJoinRegUnlessVoid(r);
    5361           0 : }
    5362             : 
    5363             : bool
    5364           0 : BaseCompiler::emitLoop()
    5365             : {
    5366           0 :     if (!iter_.readLoop())
    5367           0 :         return false;
    5368             : 
    5369           0 :     if (!deadCode_)
    5370           0 :         sync();                    // Simplifies branching out from block
    5371             : 
    5372           0 :     initControl(controlItem());
    5373           0 :     bceSafe_ = 0;
    5374             : 
    5375           0 :     if (!deadCode_) {
    5376           0 :         masm.nopAlign(CodeAlignment);
    5377           0 :         masm.bind(&controlItem(0).label);
    5378           0 :         addInterruptCheck();
    5379             :     }
    5380             : 
    5381           0 :     return true;
    5382             : }
    5383             : 
    5384             : void
    5385           0 : BaseCompiler::endLoop(ExprType type)
    5386             : {
    5387           0 :     Control& block = controlItem();
    5388             : 
    5389           0 :     AnyReg r;
    5390           0 :     if (!deadCode_) {
    5391           0 :         r = popJoinRegUnlessVoid(type);
    5392             :         // block.bceSafeOnExit need not be updated because it won't be used for
    5393             :         // the fallthrough path.
    5394             :     }
    5395             : 
    5396           0 :     popStackOnBlockExit(block.framePushed);
    5397           0 :     popValueStackTo(block.stackSize);
    5398             : 
    5399             :     // bceSafe_ stays the same along the fallthrough path because branches to
    5400             :     // loops branch to the top.
    5401             : 
    5402             :     // Retain the value stored in joinReg by all paths.
    5403           0 :     if (!deadCode_)
    5404           0 :         pushJoinRegUnlessVoid(r);
    5405           0 : }
    5406             : 
    5407             : // The bodies of the "then" and "else" arms can be arbitrary sequences
    5408             : // of expressions, they push control and increment the nesting and can
    5409             : // even be targeted by jumps.  A branch to the "if" block branches to
    5410             : // the exit of the if, ie, it's like "break".  Consider:
    5411             : //
    5412             : //      (func (result i32)
    5413             : //       (if (i32.const 1)
    5414             : //           (begin (br 1) (unreachable))
    5415             : //           (begin (unreachable)))
    5416             : //       (i32.const 1))
    5417             : //
    5418             : // The branch causes neither of the unreachable expressions to be
    5419             : // evaluated.
    5420             : 
    5421             : bool
    5422           0 : BaseCompiler::emitIf()
    5423             : {
    5424             :     Nothing unused_cond;
    5425           0 :     if (!iter_.readIf(&unused_cond))
    5426           0 :         return false;
    5427             : 
    5428           0 :     BranchState b(&controlItem().otherLabel, BranchState::NoPop, InvertBranch(true));
    5429           0 :     if (!deadCode_) {
    5430           0 :         emitBranchSetup(&b);
    5431           0 :         sync();
    5432             :     } else {
    5433           0 :         resetLatentOp();
    5434             :     }
    5435             : 
    5436           0 :     initControl(controlItem());
    5437             : 
    5438           0 :     if (!deadCode_)
    5439           0 :         emitBranchPerform(&b);
    5440             : 
    5441           0 :     return true;
    5442             : }
    5443             : 
    5444             : void
    5445           0 : BaseCompiler::endIfThen()
    5446             : {
    5447           0 :     Control& ifThen = controlItem();
    5448             : 
    5449           0 :     popStackOnBlockExit(ifThen.framePushed);
    5450           0 :     popValueStackTo(ifThen.stackSize);
    5451             : 
    5452           0 :     if (ifThen.otherLabel.used())
    5453           0 :         masm.bind(&ifThen.otherLabel);
    5454             : 
    5455           0 :     if (ifThen.label.used())
    5456           0 :         masm.bind(&ifThen.label);
    5457             : 
    5458           0 :     if (!deadCode_)
    5459           0 :         ifThen.bceSafeOnExit &= bceSafe_;
    5460             : 
    5461           0 :     deadCode_ = ifThen.deadOnArrival;
    5462             : 
    5463           0 :     bceSafe_ = ifThen.bceSafeOnExit & ifThen.bceSafeOnEntry;
    5464           0 : }
    5465             : 
    5466             : bool
    5467           0 : BaseCompiler::emitElse()
    5468             : {
    5469             :     ExprType thenType;
    5470             :     Nothing unused_thenValue;
    5471             : 
    5472           0 :     if (!iter_.readElse(&thenType, &unused_thenValue))
    5473           0 :         return false;
    5474             : 
    5475           0 :     Control& ifThenElse = controlItem(0);
    5476             : 
    5477             :     // See comment in endIfThenElse, below.
    5478             : 
    5479             :     // Exit the "then" branch.
    5480             : 
    5481           0 :     ifThenElse.deadThenBranch = deadCode_;
    5482             : 
    5483           0 :     AnyReg r;
    5484           0 :     if (!deadCode_)
    5485           0 :         r = popJoinRegUnlessVoid(thenType);
    5486             : 
    5487           0 :     popStackOnBlockExit(ifThenElse.framePushed);
    5488           0 :     popValueStackTo(ifThenElse.stackSize);
    5489             : 
    5490           0 :     if (!deadCode_)
    5491           0 :         masm.jump(&ifThenElse.label);
    5492             : 
    5493           0 :     if (ifThenElse.otherLabel.used())
    5494           0 :         masm.bind(&ifThenElse.otherLabel);
    5495             : 
    5496             :     // Reset to the "else" branch.
    5497             : 
    5498           0 :     if (!deadCode_) {
    5499           0 :         freeJoinRegUnlessVoid(r);
    5500           0 :         ifThenElse.bceSafeOnExit &= bceSafe_;
    5501             :     }
    5502             : 
    5503           0 :     deadCode_ = ifThenElse.deadOnArrival;
    5504           0 :     bceSafe_ = ifThenElse.bceSafeOnEntry;
    5505             : 
    5506           0 :     return true;
    5507             : }
    5508             : 
    5509             : void
    5510           0 : BaseCompiler::endIfThenElse(ExprType type)
    5511             : {
    5512           0 :     Control& ifThenElse = controlItem();
    5513             : 
    5514             :     // The expression type is not a reliable guide to what we'll find
    5515             :     // on the stack, we could have (if E (i32.const 1) (unreachable))
    5516             :     // in which case the "else" arm is AnyType but the type of the
    5517             :     // full expression is I32.  So restore whatever's there, not what
    5518             :     // we want to find there.  The "then" arm has the same constraint.
    5519             : 
    5520           0 :     AnyReg r;
    5521             : 
    5522           0 :     if (!deadCode_) {
    5523           0 :         r = popJoinRegUnlessVoid(type);
    5524           0 :         ifThenElse.bceSafeOnExit &= bceSafe_;
    5525             :     }
    5526             : 
    5527           0 :     popStackOnBlockExit(ifThenElse.framePushed);
    5528           0 :     popValueStackTo(ifThenElse.stackSize);
    5529             : 
    5530           0 :     if (ifThenElse.label.used())
    5531           0 :         masm.bind(&ifThenElse.label);
    5532             : 
    5533           0 :     bool joinLive = !ifThenElse.deadOnArrival &&
    5534           0 :                     (!ifThenElse.deadThenBranch || !deadCode_ || ifThenElse.label.bound());
    5535             : 
    5536           0 :     if (joinLive) {
    5537             :         // No value was provided by the "then" path but capture the one
    5538             :         // provided by the "else" path.
    5539           0 :         if (deadCode_)
    5540           0 :             r = captureJoinRegUnlessVoid(type);
    5541           0 :         deadCode_ = false;
    5542             :     }
    5543             : 
    5544           0 :     bceSafe_ = ifThenElse.bceSafeOnExit;
    5545             : 
    5546           0 :     if (!deadCode_)
    5547           0 :         pushJoinRegUnlessVoid(r);
    5548           0 : }
    5549             : 
    5550             : bool
    5551           0 : BaseCompiler::emitEnd()
    5552             : {
    5553             :     LabelKind kind;
    5554             :     ExprType type;
    5555             :     Nothing unused_value;
    5556           0 :     if (!iter_.readEnd(&kind, &type, &unused_value))
    5557           0 :         return false;
    5558             : 
    5559           0 :     switch (kind) {
    5560           0 :       case LabelKind::Block: endBlock(type); break;
    5561           0 :       case LabelKind::Loop:  endLoop(type); break;
    5562           0 :       case LabelKind::Then:  endIfThen(); break;
    5563           0 :       case LabelKind::Else:  endIfThenElse(type); break;
    5564             :     }
    5565             : 
    5566           0 :     iter_.popEnd();
    5567             : 
    5568           0 :     return true;
    5569             : }
    5570             : 
    5571             : bool
    5572           0 : BaseCompiler::emitBr()
    5573             : {
    5574             :     uint32_t relativeDepth;
    5575             :     ExprType type;
    5576             :     Nothing unused_value;
    5577           0 :     if (!iter_.readBr(&relativeDepth, &type, &unused_value))
    5578           0 :         return false;
    5579             : 
    5580           0 :     if (deadCode_)
    5581           0 :         return true;
    5582             : 
    5583           0 :     Control& target = controlItem(relativeDepth);
    5584           0 :     target.bceSafeOnExit &= bceSafe_;
    5585             : 
    5586             :     // Save any value in the designated join register, where the
    5587             :     // normal block exit code will also leave it.
    5588             : 
    5589           0 :     AnyReg r = popJoinRegUnlessVoid(type);
    5590             : 
    5591           0 :     popStackBeforeBranch(target.framePushed);
    5592           0 :     masm.jump(&target.label);
    5593             : 
    5594             :     // The register holding the join value is free for the remainder
    5595             :     // of this block.
    5596             : 
    5597           0 :     freeJoinRegUnlessVoid(r);
    5598             : 
    5599           0 :     deadCode_ = true;
    5600             : 
    5601           0 :     return true;
    5602             : }
    5603             : 
    5604             : bool
    5605           0 : BaseCompiler::emitBrIf()
    5606             : {
    5607             :     uint32_t relativeDepth;
    5608             :     ExprType type;
    5609             :     Nothing unused_value, unused_condition;
    5610           0 :     if (!iter_.readBrIf(&relativeDepth, &type, &unused_value, &unused_condition))
    5611           0 :         return false;
    5612             : 
    5613           0 :     if (deadCode_) {
    5614           0 :         resetLatentOp();
    5615           0 :         return true;
    5616             :     }
    5617             : 
    5618           0 :     Control& target = controlItem(relativeDepth);
    5619           0 :     target.bceSafeOnExit &= bceSafe_;
    5620             : 
    5621           0 :     BranchState b(&target.label, target.framePushed, InvertBranch(false), type);
    5622           0 :     emitBranchSetup(&b);
    5623           0 :     emitBranchPerform(&b);
    5624             : 
    5625           0 :     return true;
    5626             : }
    5627             : 
    5628             : bool
    5629           0 : BaseCompiler::emitBrTable()
    5630             : {
    5631           0 :     Uint32Vector depths;
    5632             :     uint32_t defaultDepth;
    5633             :     ExprType branchValueType;
    5634             :     Nothing unused_value, unused_index;
    5635           0 :     if (!iter_.readBrTable(&depths, &defaultDepth, &branchValueType, &unused_value, &unused_index))
    5636           0 :         return false;
    5637             : 
    5638           0 :     if (deadCode_)
    5639           0 :         return true;
    5640             : 
    5641             :     // Don't use joinReg for rc
    5642           0 :     maybeReserveJoinRegI(branchValueType);
    5643             : 
    5644             :     // Table switch value always on top.
    5645           0 :     RegI32 rc = popI32();
    5646             : 
    5647           0 :     maybeUnreserveJoinRegI(branchValueType);
    5648             : 
    5649           0 :     AnyReg r = popJoinRegUnlessVoid(branchValueType);
    5650             : 
    5651           0 :     Label dispatchCode;
    5652           0 :     masm.branch32(Assembler::Below, rc, Imm32(depths.length()), &dispatchCode);
    5653             : 
    5654             :     // This is the out-of-range stub.  rc is dead here but we don't need it.
    5655             : 
    5656           0 :     popStackBeforeBranch(controlItem(defaultDepth).framePushed);
    5657           0 :     controlItem(defaultDepth).bceSafeOnExit &= bceSafe_;
    5658           0 :     masm.jump(&controlItem(defaultDepth).label);
    5659             : 
    5660             :     // Emit stubs.  rc is dead in all of these but we don't need it.
    5661             :     //
    5662             :     // The labels in the vector are in the TempAllocator and will
    5663             :     // be freed by and by.
    5664             :     //
    5665             :     // TODO / OPTIMIZE (Bug 1316804): Branch directly to the case code if we
    5666             :     // can, don't emit an intermediate stub.
    5667             : 
    5668           0 :     LabelVector stubs;
    5669           0 :     if (!stubs.reserve(depths.length()))
    5670           0 :         return false;
    5671             : 
    5672           0 :     for (uint32_t depth : depths) {
    5673           0 :         stubs.infallibleEmplaceBack(NonAssertingLabel());
    5674           0 :         masm.bind(&stubs.back());
    5675           0 :         popStackBeforeBranch(controlItem(depth).framePushed);
    5676           0 :         controlItem(depth).bceSafeOnExit &= bceSafe_;
    5677           0 :         masm.jump(&controlItem(depth).label);
    5678             :     }
    5679             : 
    5680             :     // Emit table.
    5681             : 
    5682           0 :     Label theTable;
    5683           0 :     jumpTable(stubs, &theTable);
    5684             : 
    5685             :     // Emit indirect jump.  rc is live here.
    5686             : 
    5687           0 :     tableSwitch(&theTable, rc, &dispatchCode);
    5688             : 
    5689           0 :     deadCode_ = true;
    5690             : 
    5691             :     // Clean up.
    5692             : 
    5693           0 :     freeI32(rc);
    5694           0 :     freeJoinRegUnlessVoid(r);
    5695             : 
    5696           0 :     return true;
    5697             : }
    5698             : 
    5699             : bool
    5700           0 : BaseCompiler::emitDrop()
    5701             : {
    5702           0 :     if (!iter_.readDrop())
    5703           0 :         return false;
    5704             : 
    5705           0 :     if (deadCode_)
    5706           0 :         return true;
    5707             : 
    5708           0 :     popStackIfMemory();
    5709           0 :     popValueStackBy(1);
    5710           0 :     return true;
    5711             : }
    5712             : 
    5713             : void
    5714           0 : BaseCompiler::doReturn(ExprType type, bool popStack)
    5715             : {
    5716           0 :     switch (type) {
    5717             :       case ExprType::Void: {
    5718           0 :         returnCleanup(popStack);
    5719           0 :         break;
    5720             :       }
    5721             :       case ExprType::I32: {
    5722           0 :         RegI32 rv = popI32(RegI32(ReturnReg));
    5723           0 :         returnCleanup(popStack);
    5724           0 :         freeI32(rv);
    5725           0 :         break;
    5726             :       }
    5727             :       case ExprType::I64: {
    5728           0 :         RegI64 rv = popI64(RegI64(ReturnReg64));
    5729           0 :         returnCleanup(popStack);
    5730           0 :         freeI64(rv);
    5731           0 :         break;
    5732             :       }
    5733             :       case ExprType::F64: {
    5734           0 :         RegF64 rv = popF64(RegF64(ReturnDoubleReg));
    5735           0 :         returnCleanup(popStack);
    5736           0 :         freeF64(rv);
    5737           0 :         break;
    5738             :       }
    5739             :       case ExprType::F32: {
    5740           0 :         RegF32 rv = popF32(RegF32(ReturnFloat32Reg));
    5741           0 :         returnCleanup(popStack);
    5742           0 :         freeF32(rv);
    5743           0 :         break;
    5744             :       }
    5745             :       default: {
    5746           0 :         MOZ_CRASH("Function return type");
    5747             :       }
    5748             :     }
    5749           0 : }
    5750             : 
    5751             : bool
    5752           0 : BaseCompiler::emitReturn()
    5753             : {
    5754             :     Nothing unused_value;
    5755           0 :     if (!iter_.readReturn(&unused_value))
    5756           0 :         return false;
    5757             : 
    5758           0 :     if (deadCode_)
    5759           0 :         return true;
    5760             : 
    5761           0 :     doReturn(func_.sig().ret(), PopStack(true));
    5762           0 :     deadCode_ = true;
    5763             : 
    5764           0 :     return true;
    5765             : }
    5766             : 
    5767             : bool
    5768           0 : BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baselineCall)
    5769             : {
    5770           0 :     MOZ_ASSERT(!deadCode_);
    5771             : 
    5772           0 :     startCallArgs(baselineCall, stackArgAreaSize(argTypes));
    5773             : 
    5774           0 :     uint32_t numArgs = argTypes.length();
    5775           0 :     for (size_t i = 0; i < numArgs; ++i)
    5776           0 :         passArg(baselineCall, argTypes[i], peek(numArgs - 1 - i));
    5777             : 
    5778           0 :     masm.loadWasmTlsRegFromFrame();
    5779           0 :     return true;
    5780             : }
    5781             : 
    5782             : void
    5783           0 : BaseCompiler::pushReturned(const FunctionCall& call, ExprType type)
    5784             : {
    5785           0 :     switch (type) {
    5786             :       case ExprType::Void:
    5787           0 :         MOZ_CRASH("Compiler bug: attempt to push void return");
    5788             :         break;
    5789             :       case ExprType::I32: {
    5790           0 :         RegI32 rv = captureReturnedI32();
    5791           0 :         pushI32(rv);
    5792           0 :         break;
    5793             :       }
    5794             :       case ExprType::I64: {
    5795           0 :         RegI64 rv = captureReturnedI64();
    5796           0 :         pushI64(rv);
    5797           0 :         break;
    5798             :       }
    5799             :       case ExprType::F32: {
    5800           0 :         RegF32 rv = captureReturnedF32(call);
    5801           0 :         pushF32(rv);
    5802           0 :         break;
    5803             :       }
    5804             :       case ExprType::F64: {
    5805           0 :         RegF64 rv = captureReturnedF64(call);
    5806           0 :         pushF64(rv);
    5807           0 :         break;
    5808             :       }
    5809             :       default:
    5810           0 :         MOZ_CRASH("Function return type");
    5811             :     }
    5812           0 : }
    5813             : 
    5814             : // For now, always sync() at the beginning of the call to easily save live
    5815             : // values.
    5816             : //
    5817             : // TODO / OPTIMIZE (Bug 1316806): We may be able to avoid a full sync(), since
    5818             : // all we want is to save live registers that won't be saved by the callee or
    5819             : // that we need for outgoing args - we don't need to sync the locals.  We can
    5820             : // just push the necessary registers, it'll be like a lightweight sync.
    5821             : //
    5822             : // Even some of the pushing may be unnecessary if the registers will be consumed
    5823             : // by the call, because then what we want is parallel assignment to the argument
    5824             : // registers or onto the stack for outgoing arguments.  A sync() is just
    5825             : // simpler.
    5826             : 
    5827             : bool
    5828           0 : BaseCompiler::emitCall()
    5829             : {
    5830           0 :     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
    5831             : 
    5832             :     uint32_t funcIndex;
    5833           0 :     BaseOpIter::ValueVector args_;
    5834           0 :     if (!iter_.readCall(&funcIndex, &args_))
    5835           0 :         return false;
    5836             : 
    5837           0 :     if (deadCode_)
    5838           0 :         return true;
    5839             : 
    5840           0 :     sync();
    5841             : 
    5842           0 :     const Sig& sig = *env_.funcSigs[funcIndex];
    5843           0 :     bool import = env_.funcIsImport(funcIndex);
    5844             : 
    5845           0 :     uint32_t numArgs = sig.args().length();
    5846           0 :     size_t stackSpace = stackConsumed(numArgs);
    5847             : 
    5848           0 :     FunctionCall baselineCall(lineOrBytecode);
    5849           0 :     beginCall(baselineCall, UseABI::Wasm, import ? InterModule::True : InterModule::False);
    5850             : 
    5851           0 :     if (!emitCallArgs(sig.args(), baselineCall))
    5852           0 :         return false;
    5853             : 
    5854           0 :     if (import)
    5855           0 :         callImport(env_.funcImportGlobalDataOffsets[funcIndex], baselineCall);
    5856             :     else
    5857           0 :         callDefinition(funcIndex, baselineCall);
    5858             : 
    5859           0 :     endCall(baselineCall, stackSpace);
    5860             : 
    5861           0 :     popValueStackBy(numArgs);
    5862             : 
    5863           0 :     if (!IsVoid(sig.ret()))
    5864           0 :         pushReturned(baselineCall, sig.ret());
    5865             : 
    5866           0 :     return true;
    5867             : }
    5868             : 
    5869             : bool
    5870           0 : BaseCompiler::emitCallIndirect()
    5871             : {
    5872           0 :     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
    5873             : 
    5874             :     uint32_t sigIndex;
    5875             :     Nothing callee_;
    5876           0 :     BaseOpIter::ValueVector args_;
    5877           0 :     if (!iter_.readCallIndirect(&sigIndex, &callee_, &args_))
    5878           0 :         return false;
    5879             : 
    5880           0 :     if (deadCode_)
    5881           0 :         return true;
    5882             : 
    5883           0 :     sync();
    5884             : 
    5885           0 :     const SigWithId& sig = env_.sigs[sigIndex];
    5886             : 
    5887             :     // Stack: ... arg1 .. argn callee
    5888             : 
    5889           0 :     uint32_t numArgs = sig.args().length();
    5890           0 :     size_t stackSpace = stackConsumed(numArgs + 1);
    5891             : 
    5892             :     // The arguments must be at the stack top for emitCallArgs, so pop the
    5893             :     // callee if it is on top.  Note this only pops the compiler's stack,
    5894             :     // not the CPU stack.
    5895             : 
    5896           0 :     Stk callee = stk_.popCopy();
    5897             : 
    5898           0 :     FunctionCall baselineCall(lineOrBytecode);
    5899           0 :     beginCall(baselineCall, UseABI::Wasm, InterModule::True);
    5900             : 
    5901           0 :     if (!emitCallArgs(sig.args(), baselineCall))
    5902           0 :         return false;
    5903             : 
    5904           0 :     callIndirect(sigIndex, callee, baselineCall);
    5905             : 
    5906           0 :     endCall(baselineCall, stackSpace);
    5907             : 
    5908           0 :     popValueStackBy(numArgs);
    5909             : 
    5910           0 :     if (!IsVoid(sig.ret()))
    5911           0 :         pushReturned(baselineCall, sig.ret());
    5912             : 
    5913           0 :     return true;
    5914             : }
    5915             : 
    5916             : void
    5917           0 : BaseCompiler::emitRound(RoundingMode roundingMode, ValType operandType)
    5918             : {
    5919           0 :     if (operandType == ValType::F32) {
    5920           0 :         RegF32 f0 = popF32();
    5921           0 :         roundF32(roundingMode, f0);
    5922           0 :         pushF32(f0);
    5923           0 :     } else if (operandType == ValType::F64) {
    5924           0 :         RegF64 f0 = popF64();
    5925           0 :         roundF64(roundingMode, f0);
    5926           0 :         pushF64(f0);
    5927             :     } else {
    5928           0 :         MOZ_CRASH("unexpected type");
    5929             :     }
    5930           0 : }
    5931             : 
    5932             : bool
    5933           0 : BaseCompiler::emitUnaryMathBuiltinCall(SymbolicAddress callee, ValType operandType)
    5934             : {
    5935           0 :     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
    5936             : 
    5937             :     Nothing operand_;
    5938           0 :     if (!iter_.readUnary(operandType, &operand_))
    5939           0 :         return false;
    5940             : 
    5941           0 :     if (deadCode_)
    5942           0 :         return true;
    5943             : 
    5944             :     RoundingMode roundingMode;
    5945           0 :     if (IsRoundingFunction(callee, &roundingMode) && supportsRoundInstruction(roundingMode)) {
    5946           0 :         emitRound(roundingMode, operandType);
    5947           0 :         return true;
    5948             :     }
    5949             : 
    5950           0 :     sync();
    5951             : 
    5952           0 :     ValTypeVector& signature = operandType == ValType::F32 ? SigF_ : SigD_;
    5953           0 :     ExprType retType = operandType == ValType::F32 ? ExprType::F32 : ExprType::F64;
    5954           0 :     uint32_t numArgs = signature.length();
    5955           0 :     size_t stackSpace = stackConsumed(numArgs);
    5956             : 
    5957           0 :     FunctionCall baselineCall(lineOrBytecode);
    5958           0 :     beginCall(baselineCall, UseABI::System, InterModule::False);
    5959             : 
    5960           0 :     if (!emitCallArgs(signature, baselineCall))
    5961           0 :         return false;
    5962             : 
    5963           0 :     builtinCall(callee, baselineCall);
    5964             : 
    5965           0 :     endCall(baselineCall, stackSpace);
    5966             : 
    5967           0 :     popValueStackBy(numArgs);
    5968             : 
    5969           0 :     pushReturned(baselineCall, retType);
    5970             : 
    5971           0 :     return true;
    5972             : }
    5973             : 
    5974             : #ifdef INT_DIV_I64_CALLOUT
    5975             : void
    5976             : BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType)
    5977             : {
    5978             :     MOZ_ASSERT(operandType == ValType::I64);
    5979             :     MOZ_ASSERT(!deadCode_);
    5980             : 
    5981             :     sync();
    5982             : 
    5983             :     needI64(abiReturnRegI64);
    5984             : 
    5985             :     RegI64 rhs = popI64();
    5986             :     RegI64 srcDest = popI64ToSpecific(abiReturnRegI64);
    5987             : 
    5988             :     Label done;
    5989             : 
    5990             :     checkDivideByZeroI64(rhs);
    5991             : 
    5992             :     if (callee == SymbolicAddress::DivI64)
    5993             :         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
    5994             :     else if (callee == SymbolicAddress::ModI64)
    5995             :         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
    5996             : 
    5997             :     masm.setupWasmABICall();
    5998             :     masm.passABIArg(srcDest.high);
    5999             :     masm.passABIArg(srcDest.low);
    6000             :     masm.passABIArg(rhs.high);
    6001             :     masm.passABIArg(rhs.low);
    6002             :     masm.callWithABI(bytecodeOffset(), callee);
    6003             : 
    6004             :     masm.bind(&done);
    6005             : 
    6006             :     freeI64(rhs);
    6007             :     pushI64(srcDest);
    6008             : }
    6009             : #endif // INT_DIV_I64_CALLOUT
    6010             : 
    6011             : #ifdef I64_TO_FLOAT_CALLOUT
    6012             : bool
    6013             : BaseCompiler::emitConvertInt64ToFloatingCallout(SymbolicAddress callee, ValType operandType,
    6014             :                                                 ValType resultType)
    6015             : {
    6016             :     sync();
    6017             : 
    6018             :     RegI64 input = popI64();
    6019             : 
    6020             :     FunctionCall call(0);
    6021             : 
    6022             :     masm.setupWasmABICall();
    6023             : # ifdef JS_NUNBOX32
    6024             :     masm.passABIArg(input.high);
    6025             :     masm.passABIArg(input.low);
    6026             : # else
    6027             :     MOZ_CRASH("BaseCompiler platform hook: emitConvertInt64ToFloatingCallout");
    6028             : # endif
    6029             :     masm.callWithABI(bytecodeOffset(), callee,
    6030             :                      resultType == ValType::F32 ? MoveOp::FLOAT32 : MoveOp::DOUBLE);
    6031             : 
    6032             :     freeI64(input);
    6033             : 
    6034             :     if (resultType == ValType::F32)
    6035             :         pushF32(captureReturnedF32(call));
    6036             :     else
    6037             :         pushF64(captureReturnedF64(call));
    6038             : 
    6039             :     return true;
    6040             : }
    6041             : #endif // I64_TO_FLOAT_CALLOUT
    6042             : 
    6043             : #ifdef FLOAT_TO_I64_CALLOUT
    6044             : // `Callee` always takes a double, so a float32 input must be converted.
    6045             : bool
    6046             : BaseCompiler::emitConvertFloatingToInt64Callout(SymbolicAddress callee, ValType operandType,
    6047             :                                                 ValType resultType)
    6048             : {
    6049             :     RegF64 doubleInput;
    6050             :     if (operandType == ValType::F32) {
    6051             :         doubleInput = needF64();
    6052             :         RegF32 input = popF32();
    6053             :         masm.convertFloat32ToDouble(input, doubleInput);
    6054             :         freeF32(input);
    6055             :     } else {
    6056             :         doubleInput = popF64();
    6057             :     }
    6058             : 
    6059             :     // We may need the value after the call for the ool check.
    6060             :     RegF64 otherReg = needF64();
    6061             :     moveF64(doubleInput, otherReg);
    6062             :     pushF64(otherReg);
    6063             : 
    6064             :     sync();
    6065             : 
    6066             :     FunctionCall call(0);
    6067             : 
    6068             :     masm.setupWasmABICall();
    6069             :     masm.passABIArg(doubleInput, MoveOp::DOUBLE);
    6070             :     masm.callWithABI(bytecodeOffset(), callee);
    6071             : 
    6072             :     freeF64(doubleInput);
    6073             : 
    6074             :     RegI64 rv = captureReturnedI64();
    6075             : 
    6076             :     RegF64 inputVal = popF64();
    6077             : 
    6078             :     bool isUnsigned = callee == SymbolicAddress::TruncateDoubleToUint64;
    6079             : 
    6080             :     // The OOL check just succeeds or fails, it does not generate a value.
    6081             :     OutOfLineCode* ool = new (alloc_) OutOfLineTruncateCheckF32OrF64ToI64(AnyReg(inputVal),
    6082             :                                                                           isUnsigned,
    6083             :                                                                           bytecodeOffset());
    6084             :     ool = addOutOfLineCode(ool);
    6085             :     if (!ool)
    6086             :         return false;
    6087             : 
    6088             :     masm.branch64(Assembler::Equal, rv, Imm64(0x8000000000000000), ool->entry());
    6089             :     masm.bind(ool->rejoin());
    6090             : 
    6091             :     pushI64(rv);
    6092             :     freeF64(inputVal);
    6093             : 
    6094             :     return true;
    6095             : }
    6096             : #endif // FLOAT_TO_I64_CALLOUT
    6097             : 
    6098             : bool
    6099           0 : BaseCompiler::emitGetLocal()
    6100             : {
    6101             :     uint32_t slot;
    6102           0 :     if (!iter_.readGetLocal(locals_, &slot))
    6103           0 :         return false;
    6104             : 
    6105           0 :     if (deadCode_)
    6106           0 :         return true;
    6107             : 
    6108             :     // Local loads are pushed unresolved, ie, they may be deferred
    6109             :     // until needed, until they may be affected by a store, or until a
    6110             :     // sync.  This is intended to reduce register pressure.
    6111             : 
    6112           0 :     switch (locals_[slot]) {
    6113             :       case ValType::I32:
    6114           0 :         pushLocalI32(slot);
    6115           0 :         break;
    6116             :       case ValType::I64:
    6117           0 :         pushLocalI64(slot);
    6118           0 :         break;
    6119             :       case ValType::F64:
    6120           0 :         pushLocalF64(slot);
    6121           0 :         break;
    6122             :       case ValType::F32:
    6123           0 :         pushLocalF32(slot);
    6124           0 :         break;
    6125             :       default:
    6126           0 :         MOZ_CRASH("Local variable type");
    6127             :     }
    6128             : 
    6129           0 :     return true;
    6130             : }
    6131             : 
    6132             : template<bool isSetLocal>
    6133             : bool
    6134           0 : BaseCompiler::emitSetOrTeeLocal(uint32_t slot)
    6135             : {
    6136           0 :     if (deadCode_)
    6137           0 :         return true;
    6138             : 
    6139           0 :     bceLocalIsUpdated(slot);
    6140           0 :     switch (locals_[slot]) {
    6141             :       case ValType::I32: {
    6142           0 :         RegI32 rv = popI32();
    6143           0 :         syncLocal(slot);
    6144           0 :         storeToFrameI32(rv, frameOffsetFromSlot(slot, MIRType::Int32));
    6145             :         if (isSetLocal)
    6146           0 :             freeI32(rv);
    6147             :         else
    6148           0 :             pushI32(rv);
    6149           0 :         break;
    6150             :       }
    6151             :       case ValType::I64: {
    6152           0 :         RegI64 rv = popI64();
    6153           0 :         syncLocal(slot);
    6154           0 :         storeToFrameI64(rv, frameOffsetFromSlot(slot, MIRType::Int64));
    6155             :         if (isSetLocal)
    6156           0 :             freeI64(rv);
    6157             :         else
    6158           0 :             pushI64(rv);
    6159           0 :         break;
    6160             :       }
    6161             :       case ValType::F64: {
    6162           0 :         RegF64 rv = popF64();
    6163           0 :         syncLocal(slot);
    6164           0 :         storeToFrameF64(rv, frameOffsetFromSlot(slot, MIRType::Double));
    6165             :         if (isSetLocal)
    6166           0 :             freeF64(rv);
    6167             :         else
    6168           0 :             pushF64(rv);
    6169           0 :         break;
    6170             :       }
    6171             :       case ValType::F32: {
    6172           0 :         RegF32 rv = popF32();
    6173           0 :         syncLocal(slot);
    6174           0 :         storeToFrameF32(rv, frameOffsetFromSlot(slot, MIRType::Float32));
    6175             :         if (isSetLocal)
    6176           0 :             freeF32(rv);
    6177             :         else
    6178           0 :             pushF32(rv);
    6179           0 :         break;
    6180             :       }
    6181             :       default:
    6182           0 :         MOZ_CRASH("Local variable type");
    6183             :     }
    6184             : 
    6185           0 :     return true;
    6186             : }
    6187             : 
    6188             : bool
    6189           0 : BaseCompiler::emitSetLocal()
    6190             : {
    6191             :     uint32_t slot;
    6192             :     Nothing unused_value;
    6193           0 :     if (!iter_.readSetLocal(locals_, &slot, &unused_value))
    6194           0 :         return false;
    6195           0 :     return emitSetOrTeeLocal<true>(slot);
    6196             : }
    6197             : 
    6198             : bool
    6199           0 : BaseCompiler::emitTeeLocal()
    6200             : {
    6201             :     uint32_t slot;
    6202             :     Nothing unused_value;
    6203           0 :     if (!iter_.readTeeLocal(locals_, &slot, &unused_value))
    6204           0 :         return false;
    6205           0 :     return emitSetOrTeeLocal<false>(slot);
    6206             : }
    6207             : 
    6208             : bool
    6209           0 : BaseCompiler::emitGetGlobal()
    6210             : {
    6211             :     uint32_t id;
    6212           0 :     if (!iter_.readGetGlobal(&id))
    6213           0 :         return false;
    6214             : 
    6215           0 :     if (deadCode_)
    6216           0 :         return true;
    6217             : 
    6218           0 :     const GlobalDesc& global = env_.globals[id];
    6219             : 
    6220           0 :     if (global.isConstant()) {
    6221           0 :         Val value = global.constantValue();
    6222           0 :         switch (value.type()) {
    6223             :           case ValType::I32:
    6224           0 :             pushI32(value.i32());
    6225           0 :             break;
    6226             :           case ValType::I64:
    6227           0 :             pushI64(value.i64());
    6228           0 :             break;
    6229             :           case ValType::F32:
    6230           0 :             pushF32(value.f32());
    6231           0 :             break;
    6232             :           case ValType::F64:
    6233           0 :             pushF64(value.f64());
    6234           0 :             break;
    6235             :           default:
    6236           0 :             MOZ_CRASH("Global constant type");
    6237             :         }
    6238           0 :         return true;
    6239             :     }
    6240             : 
    6241           0 :     switch (global.type()) {
    6242             :       case ValType::I32: {
    6243           0 :         RegI32 rv = needI32();
    6244           0 :         loadGlobalVarI32(global.offset(), rv);
    6245           0 :         pushI32(rv);
    6246           0 :         break;
    6247             :       }
    6248             :       case ValType::I64: {
    6249           0 :         RegI64 rv = needI64();
    6250           0 :         loadGlobalVarI64(global.offset(), rv);
    6251           0 :         pushI64(rv);
    6252           0 :         break;
    6253             :       }
    6254             :       case ValType::F32: {
    6255           0 :         RegF32 rv = needF32();
    6256           0 :         loadGlobalVarF32(global.offset(), rv);
    6257           0 :         pushF32(rv);
    6258           0 :         break;
    6259             :       }
    6260             :       case ValType::F64: {
    6261           0 :         RegF64 rv = needF64();
    6262           0 :         loadGlobalVarF64(global.offset(), rv);
    6263           0 :         pushF64(rv);
    6264           0 :         break;
    6265             :       }
    6266             :       default:
    6267           0 :         MOZ_CRASH("Global variable type");
    6268             :         break;
    6269             :     }
    6270           0 :     return true;
    6271             : }
    6272             : 
    6273             : bool
    6274           0 : BaseCompiler::emitSetGlobal()
    6275             : {
    6276             :     uint32_t id;
    6277             :     Nothing unused_value;
    6278           0 :     if (!iter_.readSetGlobal(&id, &unused_value))
    6279           0 :         return false;
    6280             : 
    6281           0 :     if (deadCode_)
    6282           0 :         return true;
    6283             : 
    6284           0 :     const GlobalDesc& global = env_.globals[id];
    6285             : 
    6286           0 :     switch (global.type()) {
    6287             :       case ValType::I32: {
    6288           0 :         RegI32 rv = popI32();
    6289           0 :         storeGlobalVarI32(global.offset(), rv);
    6290           0 :         freeI32(rv);
    6291           0 :         break;
    6292             :       }
    6293             :       case ValType::I64: {
    6294           0 :         RegI64 rv = popI64();
    6295           0 :         storeGlobalVarI64(global.offset(), rv);
    6296           0 :         freeI64(rv);
    6297           0 :         break;
    6298             :       }
    6299             :       case ValType::F32: {
    6300           0 :         RegF32 rv = popF32();
    6301           0 :         storeGlobalVarF32(global.offset(), rv);
    6302           0 :         freeF32(rv);
    6303           0 :         break;
    6304             :       }
    6305             :       case ValType::F64: {
    6306           0 :         RegF64 rv = popF64();
    6307           0 :         storeGlobalVarF64(global.offset(), rv);
    6308           0 :         freeF64(rv);
    6309           0 :         break;
    6310             :       }
    6311             :       default:
    6312           0 :         MOZ_CRASH("Global variable type");
    6313             :         break;
    6314             :     }
    6315           0 :     return true;
    6316             : }
    6317             : 
    6318             : // Bounds check elimination.
    6319             : //
    6320             : // We perform BCE on two kinds of address expressions: on constant heap pointers
    6321             : // that are known to be in the heap or will be handled by the out-of-bounds trap
    6322             : // handler; and on local variables that have been checked in dominating code
    6323             : // without being updated since.
    6324             : //
    6325             : // For an access through a constant heap pointer + an offset we can eliminate
    6326             : // the bounds check if the sum of the address and offset is below the sum of the
    6327             : // minimum memory length and the offset guard length.
    6328             : //
    6329             : // For an access through a local variable + an offset we can eliminate the
    6330             : // bounds check if the local variable has already been checked and has not been
    6331             : // updated since, and the offset is less than the guard limit.
    6332             : //
    6333             : // To track locals for which we can eliminate checks we use a bit vector
    6334             : // bceSafe_ that has a bit set for those locals whose bounds have been checked
    6335             : // and which have not subsequently been set.  Initially this vector is zero.
    6336             : //
    6337             : // In straight-line code a bit is set when we perform a bounds check on an
    6338             : // access via the local and is reset when the variable is updated.
    6339             : //
    6340             : // In control flow, the bit vector is manipulated as follows.  Each ControlItem
    6341             : // has a value bceSafeOnEntry, which is the value of bceSafe_ on entry to the
    6342             : // item, and a value bceSafeOnExit, which is initially ~0.  On a branch (br,
    6343             : // brIf, brTable), we always AND the branch target's bceSafeOnExit with the
    6344             : // value of bceSafe_ at the branch point.  On exiting an item by falling out of
    6345             : // it, provided we're not in dead code, we AND the current value of bceSafe_
    6346             : // into the item's bceSafeOnExit.  Additional processing depends on the item
    6347             : // type:
    6348             : //
    6349             : //  - After a block, set bceSafe_ to the block's bceSafeOnExit.
    6350             : //
    6351             : //  - On loop entry, after pushing the ControlItem, set bceSafe_ to zero; the
    6352             : //    back edges would otherwise require us to iterate to a fixedpoint.
    6353             : //
    6354             : //  - After a loop, the bceSafe_ is left unchanged, because only fallthrough
    6355             : //    control flow will reach that point and the bceSafe_ value represents the
    6356             : //    correct state of the fallthrough path.
    6357             : //
    6358             : //  - Set bceSafe_ to the ControlItem's bceSafeOnEntry at both the 'then' branch
    6359             : //    and the 'else' branch.
    6360             : //
    6361             : //  - After an if-then-else, set bceSafe_ to the if-then-else's bceSafeOnExit.
    6362             : //
    6363             : //  - After an if-then, set bceSafe_ to the if-then's bceSafeOnExit AND'ed with
    6364             : //    the if-then's bceSafeOnEntry.
    6365             : //
    6366             : // Finally, when the debugger allows locals to be mutated we must disable BCE
    6367             : // for references via a local, by returning immediately from bceCheckLocal if
    6368             : // debugEnabled_ is true.
    6369             : 
    6370             : // TODO / OPTIMIZE (bug 1329576): There are opportunities to generate better
    6371             : // code by not moving a constant address with a zero offset into a register.
    6372             : 
    6373             : BaseCompiler::RegI32
    6374           0 : BaseCompiler::popMemoryAccess(MemoryAccessDesc* access, bool* omitBoundsCheck)
    6375             : {
    6376             :     // Caller must initialize.
    6377           0 :     MOZ_ASSERT(!*omitBoundsCheck);
    6378             : 
    6379             :     int32_t addrTmp;
    6380           0 :     if (popConstI32(&addrTmp)) {
    6381           0 :         uint32_t addr = addrTmp;
    6382             : 
    6383           0 :         uint64_t ea = uint64_t(addr) + uint64_t(access->offset());
    6384           0 :         uint64_t limit = uint64_t(env_.minMemoryLength) + uint64_t(wasm::OffsetGuardLimit);
    6385             : 
    6386           0 :         *omitBoundsCheck = ea < limit;
    6387             : 
    6388             :         // Fold the offset into the pointer if we can, as this is always
    6389             :         // beneficial.
    6390             : 
    6391           0 :         if (ea <= UINT32_MAX) {
    6392           0 :             addr = uint32_t(ea);
    6393           0 :             access->clearOffset();
    6394             :         }
    6395             : 
    6396           0 :         RegI32 r = needI32();
    6397           0 :         loadConstI32(r, int32_t(addr));
    6398           0 :         return r;
    6399             :     }
    6400             : 
    6401             :     uint32_t local;
    6402           0 :     if (peekLocalI32(&local))
    6403           0 :         bceCheckLocal(access, local, omitBoundsCheck);
    6404             : 
    6405           0 :     return popI32();
    6406             : }
    6407             : 
    6408             : BaseCompiler::RegI32
    6409           0 : BaseCompiler::maybeLoadTlsForAccess(bool omitBoundsCheck)
    6410             : {
    6411           0 :     RegI32 tls = invalidI32();
    6412           0 :     if (needTlsForAccess(omitBoundsCheck)) {
    6413           0 :         tls = needI32();
    6414           0 :         masm.loadWasmTlsRegFromFrame(tls);
    6415             :     }
    6416           0 :     return tls;
    6417             : }
    6418             : 
    6419             : bool
    6420           0 : BaseCompiler::emitLoad(ValType type, Scalar::Type viewType)
    6421             : {
    6422           0 :     LinearMemoryAddress<Nothing> addr;
    6423           0 :     if (!iter_.readLoad(type, Scalar::byteSize(viewType), &addr))
    6424           0 :         return false;
    6425             : 
    6426           0 :     if (deadCode_)
    6427           0 :         return true;
    6428             : 
    6429           0 :     bool omitBoundsCheck = false;
    6430           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(bytecodeOffset()));
    6431             : 
    6432           0 :     size_t temps = loadTemps(access);
    6433           0 :     MOZ_ASSERT(temps <= 3);
    6434           0 :     RegI32 tmp1 = temps >= 1 ? needI32() : invalidI32();
    6435           0 :     RegI32 tmp2 = temps >= 2 ? needI32() : invalidI32();
    6436           0 :     RegI32 tmp3 = temps >= 3 ? needI32() : invalidI32();
    6437           0 :     RegI32 tls = invalidI32();
    6438             : 
    6439           0 :     switch (type) {
    6440             :       case ValType::I32: {
    6441           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6442             : #ifdef JS_CODEGEN_ARM
    6443             :         RegI32 rv = IsUnaligned(access) ? needI32() : rp;
    6444             : #else
    6445           0 :         RegI32 rv = rp;
    6446             : #endif
    6447           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6448           0 :         if (!load(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp1, tmp2, tmp3))
    6449           0 :             return false;
    6450           0 :         pushI32(rv);
    6451           0 :         if (rp != rv)
    6452           0 :             freeI32(rp);
    6453           0 :         break;
    6454             :       }
    6455             :       case ValType::I64: {
    6456           0 :         RegI64 rv;
    6457           0 :         RegI32 rp;
    6458             : #ifdef JS_CODEGEN_X86
    6459             :         rv = abiReturnRegI64;
    6460             :         needI64(rv);
    6461             :         rp = popMemoryAccess(&access, &omitBoundsCheck);
    6462             : #else
    6463           0 :         rp = popMemoryAccess(&access, &omitBoundsCheck);
    6464           0 :         rv = needI64();
    6465             : #endif
    6466           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6467           0 :         if (!load(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp1, tmp2, tmp3))
    6468           0 :             return false;
    6469           0 :         pushI64(rv);
    6470           0 :         freeI32(rp);
    6471           0 :         break;
    6472             :       }
    6473             :       case ValType::F32: {
    6474           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6475           0 :         RegF32 rv = needF32();
    6476           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6477           0 :         if (!load(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp1, tmp2, tmp3))
    6478           0 :             return false;
    6479           0 :         pushF32(rv);
    6480           0 :         freeI32(rp);
    6481           0 :         break;
    6482             :       }
    6483             :       case ValType::F64: {
    6484           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6485           0 :         RegF64 rv = needF64();
    6486           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6487           0 :         if (!load(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp1, tmp2, tmp3))
    6488           0 :             return false;
    6489           0 :         pushF64(rv);
    6490           0 :         freeI32(rp);
    6491           0 :         break;
    6492             :       }
    6493             :       default:
    6494           0 :         MOZ_CRASH("load type");
    6495             :         break;
    6496             :     }
    6497             : 
    6498           0 :     if (tls != invalidI32())
    6499           0 :         freeI32(tls);
    6500             : 
    6501           0 :     MOZ_ASSERT(temps <= 3);
    6502           0 :     if (temps >= 1)
    6503           0 :         freeI32(tmp1);
    6504           0 :     if (temps >= 2)
    6505           0 :         freeI32(tmp2);
    6506           0 :     if (temps >= 3)
    6507           0 :         freeI32(tmp3);
    6508             : 
    6509           0 :     return true;
    6510             : }
    6511             : 
    6512             : bool
    6513           0 : BaseCompiler::emitStore(ValType resultType, Scalar::Type viewType)
    6514             : {
    6515           0 :     LinearMemoryAddress<Nothing> addr;
    6516             :     Nothing unused_value;
    6517           0 :     if (!iter_.readStore(resultType, Scalar::byteSize(viewType), &addr, &unused_value))
    6518           0 :         return false;
    6519             : 
    6520           0 :     if (deadCode_)
    6521           0 :         return true;
    6522             : 
    6523           0 :     bool omitBoundsCheck = false;
    6524           0 :     MemoryAccessDesc access(viewType, addr.align, addr.offset, Some(bytecodeOffset()));
    6525             : 
    6526           0 :     size_t temps = storeTemps(access, resultType);
    6527             : 
    6528           0 :     MOZ_ASSERT(temps <= 1);
    6529           0 :     RegI32 tmp = temps >= 1 ? needI32() : invalidI32();
    6530           0 :     RegI32 tls = invalidI32();
    6531             : 
    6532           0 :     switch (resultType) {
    6533             :       case ValType::I32: {
    6534           0 :         RegI32 rv = popI32();
    6535           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6536           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6537           0 :         if (!store(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp))
    6538           0 :             return false;
    6539           0 :         freeI32(rp);
    6540           0 :         freeI32(rv);
    6541           0 :         break;
    6542             :       }
    6543             :       case ValType::I64: {
    6544           0 :         RegI64 rv = popI64();
    6545           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6546           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6547           0 :         if (!store(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp))
    6548           0 :             return false;
    6549           0 :         freeI32(rp);
    6550           0 :         freeI64(rv);
    6551           0 :         break;
    6552             :       }
    6553             :       case ValType::F32: {
    6554           0 :         RegF32 rv = popF32();
    6555           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6556           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6557           0 :         if (!store(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp))
    6558           0 :             return false;
    6559           0 :         freeI32(rp);
    6560           0 :         freeF32(rv);
    6561           0 :         break;
    6562             :       }
    6563             :       case ValType::F64: {
    6564           0 :         RegF64 rv = popF64();
    6565           0 :         RegI32 rp = popMemoryAccess(&access, &omitBoundsCheck);
    6566           0 :         tls = maybeLoadTlsForAccess(omitBoundsCheck);
    6567           0 :         if (!store(&access, tls, rp, omitBoundsCheck, AnyReg(rv), tmp))
    6568           0 :             return false;
    6569           0 :         freeI32(rp);
    6570           0 :         freeF64(rv);
    6571           0 :         break;
    6572             :       }
    6573             :       default:
    6574           0 :         MOZ_CRASH("store type");
    6575             :         break;
    6576             :     }
    6577             : 
    6578           0 :     if (tls != invalidI32())
    6579           0 :         freeI32(tls);
    6580             : 
    6581           0 :     MOZ_ASSERT(temps <= 1);
    6582           0 :     if (temps >= 1)
    6583           0 :         freeI32(tmp);
    6584             : 
    6585           0 :     return true;
    6586             : }
    6587             : 
    6588             : bool
    6589           0 : BaseCompiler::emitSelect()
    6590             : {
    6591             :     StackType type;
    6592             :     Nothing unused_trueValue;
    6593             :     Nothing unused_falseValue;
    6594             :     Nothing unused_condition;
    6595           0 :     if (!iter_.readSelect(&type, &unused_trueValue, &unused_falseValue, &unused_condition))
    6596           0 :         return false;
    6597             : 
    6598           0 :     if (deadCode_) {
    6599           0 :         resetLatentOp();
    6600           0 :         return true;
    6601             :     }
    6602             : 
    6603             :     // I32 condition on top, then false, then true.
    6604             : 
    6605           0 :     Label done;
    6606           0 :     BranchState b(&done);
    6607           0 :     emitBranchSetup(&b);
    6608             : 
    6609           0 :     switch (NonAnyToValType(type)) {
    6610             :       case ValType::I32: {
    6611           0 :         RegI32 r0, r1;
    6612           0 :         pop2xI32(&r0, &r1);
    6613           0 :         emitBranchPerform(&b);
    6614           0 :         moveI32(r1, r0);
    6615           0 :         masm.bind(&done);
    6616           0 :         freeI32(r1);
    6617           0 :         pushI32(r0);
    6618           0 :         break;
    6619             :       }
    6620             :       case ValType::I64: {
    6621             : #ifdef JS_CODEGEN_X86
    6622             :         // There may be as many as four Int64 values in registers at a time: two
    6623             :         // for the latent branch operands, and two for the true/false values we
    6624             :         // normally pop before executing the branch.  On x86 this is one value
    6625             :         // too many, so we need to generate more complicated code here, and for
    6626             :         // simplicity's sake we do so even if the branch operands are not Int64.
    6627             :         // However, the resulting control flow diamond is complicated since the
    6628             :         // arms of the diamond will have to stay synchronized with respect to
    6629             :         // their evaluation stack and regalloc state.  To simplify further, we
    6630             :         // use a double branch and a temporary boolean value for now.
    6631             :         RegI32 tmp = needI32();
    6632             :         loadConstI32(tmp, 0);
    6633             :         emitBranchPerform(&b);
    6634             :         loadConstI32(tmp, 1);
    6635             :         masm.bind(&done);
    6636             : 
    6637             :         Label trueValue;
    6638             :         RegI64 r0, r1;
    6639             :         pop2xI64(&r0, &r1);
    6640             :         masm.branch32(Assembler::Equal, tmp, Imm32(0), &trueValue);
    6641             :         moveI64(r1, r0);
    6642             :         masm.bind(&trueValue);
    6643             :         freeI32(tmp);
    6644             :         freeI64(r1);
    6645             :         pushI64(r0);
    6646             : #else
    6647           0 :         RegI64 r0, r1;
    6648           0 :         pop2xI64(&r0, &r1);
    6649           0 :         emitBranchPerform(&b);
    6650           0 :         moveI64(r1, r0);
    6651           0 :         masm.bind(&done);
    6652           0 :         freeI64(r1);
    6653           0 :         pushI64(r0);
    6654             : #endif
    6655           0 :         break;
    6656             :       }
    6657             :       case ValType::F32: {
    6658           0 :         RegF32 r0, r1;
    6659           0 :         pop2xF32(&r0, &r1);
    6660           0 :         emitBranchPerform(&b);
    6661           0 :         moveF32(r1, r0);
    6662           0 :         masm.bind(&done);
    6663           0 :         freeF32(r1);
    6664           0 :         pushF32(r0);
    6665           0 :         break;
    6666             :       }
    6667             :       case ValType::F64: {
    6668           0 :         RegF64 r0, r1;
    6669           0 :         pop2xF64(&r0, &r1);
    6670           0 :         emitBranchPerform(&b);
    6671           0 :         moveF64(r1, r0);
    6672           0 :         masm.bind(&done);
    6673           0 :         freeF64(r1);
    6674           0 :         pushF64(r0);
    6675           0 :         break;
    6676             :       }
    6677             :       default: {
    6678           0 :         MOZ_CRASH("select type");
    6679             :       }
    6680             :     }
    6681             : 
    6682           0 :     return true;
    6683             : }
    6684             : 
    6685             : void
    6686           0 : BaseCompiler::emitCompareI32(Assembler::Condition compareOp, ValType compareType)
    6687             : {
    6688           0 :     MOZ_ASSERT(compareType == ValType::I32);
    6689             : 
    6690           0 :     if (sniffConditionalControlCmp(compareOp, compareType))
    6691           0 :         return;
    6692             : 
    6693             :     int32_t c;
    6694           0 :     if (popConstI32(&c)) {
    6695           0 :         RegI32 r0 = popI32();
    6696           0 :         masm.cmp32Set(compareOp, r0, Imm32(c), r0);
    6697           0 :         pushI32(r0);
    6698             :     } else {
    6699           0 :         RegI32 r0, r1;
    6700           0 :         pop2xI32(&r0, &r1);
    6701           0 :         masm.cmp32Set(compareOp, r0, r1, r0);
    6702           0 :         freeI32(r1);
    6703           0 :         pushI32(r0);
    6704             :     }
    6705             : }
    6706             : 
    6707             : void
    6708           0 : BaseCompiler::emitCompareI64(Assembler::Condition compareOp, ValType compareType)
    6709             : {
    6710           0 :     MOZ_ASSERT(compareType == ValType::I64);
    6711             : 
    6712           0 :     if (sniffConditionalControlCmp(compareOp, compareType))
    6713           0 :         return;
    6714             : 
    6715           0 :     RegI64 r0, r1;
    6716           0 :     pop2xI64(&r0, &r1);
    6717           0 :     RegI32 i0(fromI64(r0));
    6718           0 :     cmp64Set(compareOp, r0, r1, i0);
    6719           0 :     freeI64(r1);
    6720           0 :     freeI64Except(r0, i0);
    6721           0 :     pushI32(i0);
    6722             : }
    6723             : 
    6724             : void
    6725           0 : BaseCompiler::emitCompareF32(Assembler::DoubleCondition compareOp, ValType compareType)
    6726             : {
    6727           0 :     MOZ_ASSERT(compareType == ValType::F32);
    6728             : 
    6729           0 :     if (sniffConditionalControlCmp(compareOp, compareType))
    6730           0 :         return;
    6731             : 
    6732           0 :     Label across;
    6733           0 :     RegF32 r0, r1;
    6734           0 :     pop2xF32(&r0, &r1);
    6735           0 :     RegI32 i0 = needI32();
    6736           0 :     masm.mov(ImmWord(1), i0);
    6737           0 :     masm.branchFloat(compareOp, r0, r1, &across);
    6738           0 :     masm.mov(ImmWord(0), i0);
    6739           0 :     masm.bind(&across);
    6740           0 :     freeF32(r0);
    6741           0 :     freeF32(r1);
    6742           0 :     pushI32(i0);
    6743             : }
    6744             : 
    6745             : void
    6746           0 : BaseCompiler::emitCompareF64(Assembler::DoubleCondition compareOp, ValType compareType)
    6747             : {
    6748           0 :     MOZ_ASSERT(compareType == ValType::F64);
    6749             : 
    6750           0 :     if (sniffConditionalControlCmp(compareOp, compareType))
    6751           0 :         return;
    6752             : 
    6753           0 :     Label across;
    6754           0 :     RegF64 r0, r1;
    6755           0 :     pop2xF64(&r0, &r1);
    6756           0 :     RegI32 i0 = needI32();
    6757           0 :     masm.mov(ImmWord(1), i0);
    6758           0 :     masm.branchDouble(compareOp, r0, r1, &across);
    6759           0 :     masm.mov(ImmWord(0), i0);
    6760           0 :     masm.bind(&across);
    6761           0 :     freeF64(r0);
    6762           0 :     freeF64(r1);
    6763           0 :     pushI32(i0);
    6764             : }
    6765             : 
    6766             : bool
    6767           0 : BaseCompiler::emitGrowMemory()
    6768             : {
    6769           0 :     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
    6770             : 
    6771             :     Nothing arg;
    6772           0 :     if (!iter_.readGrowMemory(&arg))
    6773           0 :         return false;
    6774             : 
    6775           0 :     if (deadCode_)
    6776           0 :         return true;
    6777             : 
    6778           0 :     sync();
    6779             : 
    6780           0 :     uint32_t numArgs = 1;
    6781           0 :     size_t stackSpace = stackConsumed(numArgs);
    6782             : 
    6783           0 :     FunctionCall baselineCall(lineOrBytecode);
    6784           0 :     beginCall(baselineCall, UseABI::System, InterModule::True);
    6785             : 
    6786           0 :     ABIArg instanceArg = reservePointerArgument(baselineCall);
    6787             : 
    6788           0 :     startCallArgs(baselineCall, stackArgAreaSize(SigPI_));
    6789           0 :     passArg(baselineCall, ValType::I32, peek(0));
    6790           0 :     builtinInstanceMethodCall(SymbolicAddress::GrowMemory, instanceArg, baselineCall);
    6791           0 :     endCall(baselineCall, stackSpace);
    6792             : 
    6793           0 :     popValueStackBy(numArgs);
    6794             : 
    6795           0 :     pushReturned(baselineCall, ExprType::I32);
    6796             : 
    6797           0 :     return true;
    6798             : }
    6799             : 
    6800             : bool
    6801           0 : BaseCompiler::emitCurrentMemory()
    6802             : {
    6803           0 :     uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
    6804             : 
    6805           0 :     if (!iter_.readCurrentMemory())
    6806           0 :         return false;
    6807             : 
    6808           0 :     if (deadCode_)
    6809           0 :         return true;
    6810             : 
    6811           0 :     sync();
    6812             : 
    6813           0 :     FunctionCall baselineCall(lineOrBytecode);
    6814           0 :     beginCall(baselineCall, UseABI::System, InterModule::False);
    6815             : 
    6816           0 :     ABIArg instanceArg = reservePointerArgument(baselineCall);
    6817             : 
    6818           0 :     startCallArgs(baselineCall, stackArgAreaSize(SigP_));
    6819           0 :     builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, instanceArg, baselineCall);
    6820           0 :     endCall(baselineCall, 0);
    6821             : 
    6822           0 :     pushReturned(baselineCall, ExprType::I32);
    6823             : 
    6824           0 :     return true;
    6825             : }
    6826             : 
    6827             : bool
    6828           0 : BaseCompiler::emitBody()
    6829             : {
    6830           0 :     if (!iter_.readFunctionStart(func_.sig().ret()))
    6831           0 :         return false;
    6832             : 
    6833           0 :     initControl(controlItem());
    6834             : 
    6835           0 :     uint32_t overhead = 0;
    6836             : 
    6837             :     for (;;) {
    6838             : 
    6839             :         Nothing unused_a, unused_b;
    6840             : 
    6841             : #ifdef DEBUG
    6842           0 :         performRegisterLeakCheck();
    6843             : #endif
    6844             : 
    6845             : #define emitBinary(doEmit, type) \
    6846             :         iter_.readBinary(type, &unused_a, &unused_b) && (deadCode_ || (doEmit(), true))
    6847             : 
    6848             : #define emitUnary(doEmit, type) \
    6849             :         iter_.readUnary(type, &unused_a) && (deadCode_ || (doEmit(), true))
    6850             : 
    6851             : #define emitComparison(doEmit, operandType, compareOp) \
    6852             :         iter_.readComparison(operandType, &unused_a, &unused_b) && \
    6853             :             (deadCode_ || (doEmit(compareOp, operandType), true))
    6854             : 
    6855             : #define emitConversion(doEmit, inType, outType) \
    6856             :         iter_.readConversion(inType, outType, &unused_a) && (deadCode_ || (doEmit(), true))
    6857             : 
    6858             : #define emitConversionOOM(doEmit, inType, outType) \
    6859             :         iter_.readConversion(inType, outType, &unused_a) && (deadCode_ || doEmit())
    6860             : 
    6861             : #define emitCalloutConversionOOM(doEmit, symbol, inType, outType) \
    6862             :         iter_.readConversion(inType, outType, &unused_a) && \
    6863             :             (deadCode_ || doEmit(symbol, inType, outType))
    6864             : 
    6865             : #define emitIntDivCallout(doEmit, symbol, type) \
    6866             :         iter_.readBinary(type, &unused_a, &unused_b) && (deadCode_ || (doEmit(symbol, type), true))
    6867             : 
    6868             : #define CHECK(E)      if (!(E)) return false
    6869             : #define NEXT()        continue
    6870             : #define CHECK_NEXT(E) if (!(E)) return false; continue
    6871             : 
    6872             :         // TODO / EVALUATE (bug 1316845): Not obvious that this attempt at
    6873             :         // reducing overhead is really paying off relative to making the check
    6874             :         // every iteration.
    6875             : 
    6876           0 :         if (overhead == 0) {
    6877             :             // Check every 50 expressions -- a happy medium between
    6878             :             // memory usage and checking overhead.
    6879           0 :             overhead = 50;
    6880             : 
    6881             :             // Checking every 50 expressions should be safe, as the
    6882             :             // baseline JIT does very little allocation per expression.
    6883           0 :             CHECK(alloc_.ensureBallast());
    6884             : 
    6885             :             // The pushiest opcode is LOOP, which pushes two values
    6886             :             // per instance.
    6887           0 :             CHECK(stk_.reserve(stk_.length() + overhead * 2));
    6888             :         }
    6889             : 
    6890           0 :         overhead--;
    6891             : 
    6892           0 :         OpBytes op;
    6893           0 :         CHECK(iter_.readOp(&op));
    6894             : 
    6895             :         // When debugEnabled_, every operator has breakpoint site but Op::End.
    6896           0 :         if (debugEnabled_ && op.b0 != (uint16_t)Op::End) {
    6897             :             // TODO sync only registers that can be clobbered by the exit
    6898             :             // prologue/epilogue or disable these registers for use in
    6899             :             // baseline compiler when debugEnabled_ is set.
    6900           0 :             sync();
    6901             : 
    6902           0 :             insertBreakablePoint(CallSiteDesc::Breakpoint);
    6903             :         }
    6904             : 
    6905           0 :         switch (op.b0) {
    6906             :           case uint16_t(Op::End):
    6907           0 :             if (!emitEnd())
    6908           0 :                 return false;
    6909             : 
    6910           0 :             if (iter_.controlStackEmpty()) {
    6911           0 :                 if (!deadCode_)
    6912           0 :                     doReturn(func_.sig().ret(), PopStack(false));
    6913           0 :                 return iter_.readFunctionEnd(iter_.end());
    6914             :             }
    6915           0 :             NEXT();
    6916             : 
    6917             :           // Control opcodes
    6918             :           case uint16_t(Op::Nop):
    6919           0 :             CHECK_NEXT(iter_.readNop());
    6920             :           case uint16_t(Op::Drop):
    6921           0 :             CHECK_NEXT(emitDrop());
    6922             :           case uint16_t(Op::Block):
    6923           0 :             CHECK_NEXT(emitBlock());
    6924             :           case uint16_t(Op::Loop):
    6925           0 :             CHECK_NEXT(emitLoop());
    6926             :           case uint16_t(Op::If):
    6927           0 :             CHECK_NEXT(emitIf());
    6928             :           case uint16_t(Op::Else):
    6929           0 :             CHECK_NEXT(emitElse());
    6930             :           case uint16_t(Op::Br):
    6931           0 :             CHECK_NEXT(emitBr());
    6932             :           case uint16_t(Op::BrIf):
    6933           0 :             CHECK_NEXT(emitBrIf());
    6934             :           case uint16_t(Op::BrTable):
    6935           0 :             CHECK_NEXT(emitBrTable());
    6936             :           case uint16_t(Op::Return):
    6937           0 :             CHECK_NEXT(emitReturn());
    6938             :           case uint16_t(Op::Unreachable):
    6939           0 :             CHECK(iter_.readUnreachable());
    6940           0 :             if (!deadCode_) {
    6941           0 :                 unreachableTrap();
    6942           0 :                 deadCode_ = true;
    6943             :             }
    6944           0 :             NEXT();
    6945             : 
    6946             :           // Calls
    6947             :           case uint16_t(Op::Call):
    6948           0 :             CHECK_NEXT(emitCall());
    6949             :           case uint16_t(Op::CallIndirect):
    6950           0 :             CHECK_NEXT(emitCallIndirect());
    6951             : 
    6952             :           // Locals and globals
    6953             :           case uint16_t(Op::GetLocal):
    6954           0 :             CHECK_NEXT(emitGetLocal());
    6955             :           case uint16_t(Op::SetLocal):
    6956           0 :             CHECK_NEXT(emitSetLocal());
    6957             :           case uint16_t(Op::TeeLocal):
    6958           0 :             CHECK_NEXT(emitTeeLocal());
    6959             :           case uint16_t(Op::GetGlobal):
    6960           0 :             CHECK_NEXT(emitGetGlobal());
    6961             :           case uint16_t(Op::SetGlobal):
    6962           0 :             CHECK_NEXT(emitSetGlobal());
    6963             : 
    6964             :           // Select
    6965             :           case uint16_t(Op::Select):
    6966           0 :             CHECK_NEXT(emitSelect());
    6967             : 
    6968             :           // I32
    6969             :           case uint16_t(Op::I32Const): {
    6970             :             int32_t i32;
    6971           0 :             CHECK(iter_.readI32Const(&i32));
    6972           0 :             if (!deadCode_)
    6973           0 :                 pushI32(i32);
    6974           0 :             NEXT();
    6975             :           }
    6976             :           case uint16_t(Op::I32Add):
    6977           0 :             CHECK_NEXT(emitBinary(emitAddI32, ValType::I32));
    6978             :           case uint16_t(Op::I32Sub):
    6979           0 :             CHECK_NEXT(emitBinary(emitSubtractI32, ValType::I32));
    6980             :           case uint16_t(Op::I32Mul):
    6981           0 :             CHECK_NEXT(emitBinary(emitMultiplyI32, ValType::I32));
    6982             :           case uint16_t(Op::I32DivS):
    6983           0 :             CHECK_NEXT(emitBinary(emitQuotientI32, ValType::I32));
    6984             :           case uint16_t(Op::I32DivU):
    6985           0 :             CHECK_NEXT(emitBinary(emitQuotientU32, ValType::I32));
    6986             :           case uint16_t(Op::I32RemS):
    6987           0 :             CHECK_NEXT(emitBinary(emitRemainderI32, ValType::I32));
    6988             :           case uint16_t(Op::I32RemU):
    6989           0 :             CHECK_NEXT(emitBinary(emitRemainderU32, ValType::I32));
    6990             :           case uint16_t(Op::I32Eqz):
    6991           0 :             CHECK_NEXT(emitConversion(emitEqzI32, ValType::I32, ValType::I32));
    6992             :           case uint16_t(Op::I32TruncSF32):
    6993           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<false>, ValType::F32, ValType::I32));
    6994             :           case uint16_t(Op::I32TruncUF32):
    6995           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<true>, ValType::F32, ValType::I32));
    6996             :           case uint16_t(Op::I32TruncSF64):
    6997           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<false>, ValType::F64, ValType::I32));
    6998             :           case uint16_t(Op::I32TruncUF64):
    6999           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<true>, ValType::F64, ValType::I32));
    7000             :           case uint16_t(Op::I32WrapI64):
    7001           0 :             CHECK_NEXT(emitConversion(emitWrapI64ToI32, ValType::I64, ValType::I32));
    7002             :           case uint16_t(Op::I32ReinterpretF32):
    7003           0 :             CHECK_NEXT(emitConversion(emitReinterpretF32AsI32, ValType::F32, ValType::I32));
    7004             :           case uint16_t(Op::I32Clz):
    7005           0 :             CHECK_NEXT(emitUnary(emitClzI32, ValType::I32));
    7006             :           case uint16_t(Op::I32Ctz):
    7007           0 :             CHECK_NEXT(emitUnary(emitCtzI32, ValType::I32));
    7008             :           case uint16_t(Op::I32Popcnt):
    7009           0 :             CHECK_NEXT(emitUnary(emitPopcntI32, ValType::I32));
    7010             :           case uint16_t(Op::I32Or):
    7011           0 :             CHECK_NEXT(emitBinary(emitOrI32, ValType::I32));
    7012             :           case uint16_t(Op::I32And):
    7013           0 :             CHECK_NEXT(emitBinary(emitAndI32, ValType::I32));
    7014             :           case uint16_t(Op::I32Xor):
    7015           0 :             CHECK_NEXT(emitBinary(emitXorI32, ValType::I32));
    7016             :           case uint16_t(Op::I32Shl):
    7017           0 :             CHECK_NEXT(emitBinary(emitShlI32, ValType::I32));
    7018             :           case uint16_t(Op::I32ShrS):
    7019           0 :             CHECK_NEXT(emitBinary(emitShrI32, ValType::I32));
    7020             :           case uint16_t(Op::I32ShrU):
    7021           0 :             CHECK_NEXT(emitBinary(emitShrU32, ValType::I32));
    7022             :           case uint16_t(Op::I32Load8S):
    7023           0 :             CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int8));
    7024             :           case uint16_t(Op::I32Load8U):
    7025           0 :             CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint8));
    7026             :           case uint16_t(Op::I32Load16S):
    7027           0 :             CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int16));
    7028             :           case uint16_t(Op::I32Load16U):
    7029           0 :             CHECK_NEXT(emitLoad(ValType::I32, Scalar::Uint16));
    7030             :           case uint16_t(Op::I32Load):
    7031           0 :             CHECK_NEXT(emitLoad(ValType::I32, Scalar::Int32));
    7032             :           case uint16_t(Op::I32Store8):
    7033           0 :             CHECK_NEXT(emitStore(ValType::I32, Scalar::Int8));
    7034             :           case uint16_t(Op::I32Store16):
    7035           0 :             CHECK_NEXT(emitStore(ValType::I32, Scalar::Int16));
    7036             :           case uint16_t(Op::I32Store):
    7037           0 :             CHECK_NEXT(emitStore(ValType::I32, Scalar::Int32));
    7038             :           case uint16_t(Op::I32Rotr):
    7039           0 :             CHECK_NEXT(emitBinary(emitRotrI32, ValType::I32));
    7040             :           case uint16_t(Op::I32Rotl):
    7041           0 :             CHECK_NEXT(emitBinary(emitRotlI32, ValType::I32));
    7042             : 
    7043             :           // I64
    7044             :           case uint16_t(Op::I64Const): {
    7045             :             int64_t i64;
    7046           0 :             CHECK(iter_.readI64Const(&i64));
    7047           0 :             if (!deadCode_)
    7048           0 :                 pushI64(i64);
    7049           0 :             NEXT();
    7050             :           }
    7051             :           case uint16_t(Op::I64Add):
    7052           0 :             CHECK_NEXT(emitBinary(emitAddI64, ValType::I64));
    7053             :           case uint16_t(Op::I64Sub):
    7054           0 :             CHECK_NEXT(emitBinary(emitSubtractI64, ValType::I64));
    7055             :           case uint16_t(Op::I64Mul):
    7056           0 :             CHECK_NEXT(emitBinary(emitMultiplyI64, ValType::I64));
    7057             :           case uint16_t(Op::I64DivS):
    7058             : #ifdef INT_DIV_I64_CALLOUT
    7059             :             CHECK_NEXT(emitIntDivCallout(emitDivOrModI64BuiltinCall, SymbolicAddress::DivI64,
    7060             :                                          ValType::I64));
    7061             : #else
    7062           0 :             CHECK_NEXT(emitBinary(emitQuotientI64, ValType::I64));
    7063             : #endif
    7064             :           case uint16_t(Op::I64DivU):
    7065             : #ifdef INT_DIV_I64_CALLOUT
    7066             :             CHECK_NEXT(emitIntDivCallout(emitDivOrModI64BuiltinCall, SymbolicAddress::UDivI64,
    7067             :                                          ValType::I64));
    7068             : #else
    7069           0 :             CHECK_NEXT(emitBinary(emitQuotientU64, ValType::I64));
    7070             : #endif
    7071             :           case uint16_t(Op::I64RemS):
    7072             : #ifdef INT_DIV_I64_CALLOUT
    7073             :             CHECK_NEXT(emitIntDivCallout(emitDivOrModI64BuiltinCall, SymbolicAddress::ModI64,
    7074             :                                          ValType::I64));
    7075             : #else
    7076           0 :             CHECK_NEXT(emitBinary(emitRemainderI64, ValType::I64));
    7077             : #endif
    7078             :           case uint16_t(Op::I64RemU):
    7079             : #ifdef INT_DIV_I64_CALLOUT
    7080             :             CHECK_NEXT(emitIntDivCallout(emitDivOrModI64BuiltinCall, SymbolicAddress::UModI64,
    7081             :                                          ValType::I64));
    7082             : #else
    7083           0 :             CHECK_NEXT(emitBinary(emitRemainderU64, ValType::I64));
    7084             : #endif
    7085             :           case uint16_t(Op::I64TruncSF32):
    7086             : #ifdef FLOAT_TO_I64_CALLOUT
    7087             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
    7088             :                                                 SymbolicAddress::TruncateDoubleToInt64,
    7089             :                                                 ValType::F32, ValType::I64));
    7090             : #else
    7091           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<false>, ValType::F32, ValType::I64));
    7092             : #endif
    7093             :           case uint16_t(Op::I64TruncUF32):
    7094             : #ifdef FLOAT_TO_I64_CALLOUT
    7095             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
    7096             :                                                 SymbolicAddress::TruncateDoubleToUint64,
    7097             :                                                 ValType::F32, ValType::I64));
    7098             : #else
    7099           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<true>, ValType::F32, ValType::I64));
    7100             : #endif
    7101             :           case uint16_t(Op::I64TruncSF64):
    7102             : #ifdef FLOAT_TO_I64_CALLOUT
    7103             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
    7104             :                                                 SymbolicAddress::TruncateDoubleToInt64,
    7105             :                                                 ValType::F64, ValType::I64));
    7106             : #else
    7107           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<false>, ValType::F64, ValType::I64));
    7108             : #endif
    7109             :           case uint16_t(Op::I64TruncUF64):
    7110             : #ifdef FLOAT_TO_I64_CALLOUT
    7111             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
    7112             :                                                 SymbolicAddress::TruncateDoubleToUint64,
    7113             :                                                 ValType::F64, ValType::I64));
    7114             : #else
    7115           0 :             CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<true>, ValType::F64, ValType::I64));
    7116             : #endif
    7117             :           case uint16_t(Op::I64ExtendSI32):
    7118           0 :             CHECK_NEXT(emitConversion(emitExtendI32ToI64, ValType::I32, ValType::I64));
    7119             :           case uint16_t(Op::I64ExtendUI32):
    7120           0 :             CHECK_NEXT(emitConversion(emitExtendU32ToI64, ValType::I32, ValType::I64));
    7121             :           case uint16_t(Op::I64ReinterpretF64):
    7122           0 :             CHECK_NEXT(emitConversion(emitReinterpretF64AsI64, ValType::F64, ValType::I64));
    7123             :           case uint16_t(Op::I64Or):
    7124           0 :             CHECK_NEXT(emitBinary(emitOrI64, ValType::I64));
    7125             :           case uint16_t(Op::I64And):
    7126           0 :             CHECK_NEXT(emitBinary(emitAndI64, ValType::I64));
    7127             :           case uint16_t(Op::I64Xor):
    7128           0 :             CHECK_NEXT(emitBinary(emitXorI64, ValType::I64));
    7129             :           case uint16_t(Op::I64Shl):
    7130           0 :             CHECK_NEXT(emitBinary(emitShlI64, ValType::I64));
    7131             :           case uint16_t(Op::I64ShrS):
    7132           0 :             CHECK_NEXT(emitBinary(emitShrI64, ValType::I64));
    7133             :           case uint16_t(Op::I64ShrU):
    7134           0 :             CHECK_NEXT(emitBinary(emitShrU64, ValType::I64));
    7135             :           case uint16_t(Op::I64Rotr):
    7136           0 :             CHECK_NEXT(emitBinary(emitRotrI64, ValType::I64));
    7137             :           case uint16_t(Op::I64Rotl):
    7138           0 :             CHECK_NEXT(emitBinary(emitRotlI64, ValType::I64));
    7139             :           case uint16_t(Op::I64Clz):
    7140           0 :             CHECK_NEXT(emitUnary(emitClzI64, ValType::I64));
    7141             :           case uint16_t(Op::I64Ctz):
    7142           0 :             CHECK_NEXT(emitUnary(emitCtzI64, ValType::I64));
    7143             :           case uint16_t(Op::I64Popcnt):
    7144           0 :             CHECK_NEXT(emitUnary(emitPopcntI64, ValType::I64));
    7145             :           case uint16_t(Op::I64Eqz):
    7146           0 :             CHECK_NEXT(emitConversion(emitEqzI64, ValType::I64, ValType::I32));
    7147             :           case uint16_t(Op::I64Load8S):
    7148           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int8));
    7149             :           case uint16_t(Op::I64Load16S):
    7150           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int16));
    7151             :           case uint16_t(Op::I64Load32S):
    7152           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int32));
    7153             :           case uint16_t(Op::I64Load8U):
    7154           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint8));
    7155             :           case uint16_t(Op::I64Load16U):
    7156           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint16));
    7157             :           case uint16_t(Op::I64Load32U):
    7158           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Uint32));
    7159             :           case uint16_t(Op::I64Load):
    7160           0 :             CHECK_NEXT(emitLoad(ValType::I64, Scalar::Int64));
    7161             :           case uint16_t(Op::I64Store8):
    7162           0 :             CHECK_NEXT(emitStore(ValType::I64, Scalar::Int8));
    7163             :           case uint16_t(Op::I64Store16):
    7164           0 :             CHECK_NEXT(emitStore(ValType::I64, Scalar::Int16));
    7165             :           case uint16_t(Op::I64Store32):
    7166           0 :             CHECK_NEXT(emitStore(ValType::I64, Scalar::Int32));
    7167             :           case uint16_t(Op::I64Store):
    7168           0 :             CHECK_NEXT(emitStore(ValType::I64, Scalar::Int64));
    7169             : 
    7170             :           // F32
    7171             :           case uint16_t(Op::F32Const): {
    7172             :             float f32;
    7173           0 :             CHECK(iter_.readF32Const(&f32));
    7174           0 :             if (!deadCode_)
    7175           0 :                 pushF32(f32);
    7176           0 :             NEXT();
    7177             :           }
    7178             :           case uint16_t(Op::F32Add):
    7179           0 :             CHECK_NEXT(emitBinary(emitAddF32, ValType::F32));
    7180             :           case uint16_t(Op::F32Sub):
    7181           0 :             CHECK_NEXT(emitBinary(emitSubtractF32, ValType::F32));
    7182             :           case uint16_t(Op::F32Mul):
    7183           0 :             CHECK_NEXT(emitBinary(emitMultiplyF32, ValType::F32));
    7184             :           case uint16_t(Op::F32Div):
    7185           0 :             CHECK_NEXT(emitBinary(emitDivideF32, ValType::F32));
    7186             :           case uint16_t(Op::F32Min):
    7187           0 :             CHECK_NEXT(emitBinary(emitMinF32, ValType::F32));
    7188             :           case uint16_t(Op::F32Max):
    7189           0 :             CHECK_NEXT(emitBinary(emitMaxF32, ValType::F32));
    7190             :           case uint16_t(Op::F32Neg):
    7191           0 :             CHECK_NEXT(emitUnary(emitNegateF32, ValType::F32));
    7192             :           case uint16_t(Op::F32Abs):
    7193           0 :             CHECK_NEXT(emitUnary(emitAbsF32, ValType::F32));
    7194             :           case uint16_t(Op::F32Sqrt):
    7195           0 :             CHECK_NEXT(emitUnary(emitSqrtF32, ValType::F32));
    7196             :           case uint16_t(Op::F32Ceil):
    7197           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::CeilF, ValType::F32));
    7198             :           case uint16_t(Op::F32Floor):
    7199           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::FloorF, ValType::F32));
    7200             :           case uint16_t(Op::F32DemoteF64):
    7201           0 :             CHECK_NEXT(emitConversion(emitConvertF64ToF32, ValType::F64, ValType::F32));
    7202             :           case uint16_t(Op::F32ConvertSI32):
    7203           0 :             CHECK_NEXT(emitConversion(emitConvertI32ToF32, ValType::I32, ValType::F32));
    7204             :           case uint16_t(Op::F32ConvertUI32):
    7205           0 :             CHECK_NEXT(emitConversion(emitConvertU32ToF32, ValType::I32, ValType::F32));
    7206             :           case uint16_t(Op::F32ConvertSI64):
    7207             : #ifdef I64_TO_FLOAT_CALLOUT
    7208             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
    7209             :                                                 SymbolicAddress::Int64ToFloat32,
    7210             :                                                 ValType::I64, ValType::F32));
    7211             : #else
    7212           0 :             CHECK_NEXT(emitConversion(emitConvertI64ToF32, ValType::I64, ValType::F32));
    7213             : #endif
    7214             :           case uint16_t(Op::F32ConvertUI64):
    7215             : #ifdef I64_TO_FLOAT_CALLOUT
    7216             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
    7217             :                                                 SymbolicAddress::Uint64ToFloat32,
    7218             :                                                 ValType::I64, ValType::F32));
    7219             : #else
    7220           0 :             CHECK_NEXT(emitConversion(emitConvertU64ToF32, ValType::I64, ValType::F32));
    7221             : #endif
    7222             :           case uint16_t(Op::F32ReinterpretI32):
    7223           0 :             CHECK_NEXT(emitConversion(emitReinterpretI32AsF32, ValType::I32, ValType::F32));
    7224             :           case uint16_t(Op::F32Load):
    7225           0 :             CHECK_NEXT(emitLoad(ValType::F32, Scalar::Float32));
    7226             :           case uint16_t(Op::F32Store):
    7227           0 :             CHECK_NEXT(emitStore(ValType::F32, Scalar::Float32));
    7228             :           case uint16_t(Op::F32CopySign):
    7229           0 :             CHECK_NEXT(emitBinary(emitCopysignF32, ValType::F32));
    7230             :           case uint16_t(Op::F32Nearest):
    7231           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntF, ValType::F32));
    7232             :           case uint16_t(Op::F32Trunc):
    7233           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TruncF, ValType::F32));
    7234             : 
    7235             :           // F64
    7236             :           case uint16_t(Op::F64Const): {
    7237             :             double f64;
    7238           0 :             CHECK(iter_.readF64Const(&f64));
    7239           0 :             if (!deadCode_)
    7240           0 :                 pushF64(f64);
    7241           0 :             NEXT();
    7242             :           }
    7243             :           case uint16_t(Op::F64Add):
    7244           0 :             CHECK_NEXT(emitBinary(emitAddF64, ValType::F64));
    7245             :           case uint16_t(Op::F64Sub):
    7246           0 :             CHECK_NEXT(emitBinary(emitSubtractF64, ValType::F64));
    7247             :           case uint16_t(Op::F64Mul):
    7248           0 :             CHECK_NEXT(emitBinary(emitMultiplyF64, ValType::F64));
    7249             :           case uint16_t(Op::F64Div):
    7250           0 :             CHECK_NEXT(emitBinary(emitDivideF64, ValType::F64));
    7251             :           case uint16_t(Op::F64Min):
    7252           0 :             CHECK_NEXT(emitBinary(emitMinF64, ValType::F64));
    7253             :           case uint16_t(Op::F64Max):
    7254           0 :             CHECK_NEXT(emitBinary(emitMaxF64, ValType::F64));
    7255             :           case uint16_t(Op::F64Neg):
    7256           0 :             CHECK_NEXT(emitUnary(emitNegateF64, ValType::F64));
    7257             :           case uint16_t(Op::F64Abs):
    7258           0 :             CHECK_NEXT(emitUnary(emitAbsF64, ValType::F64));
    7259             :           case uint16_t(Op::F64Sqrt):
    7260           0 :             CHECK_NEXT(emitUnary(emitSqrtF64, ValType::F64));
    7261             :           case uint16_t(Op::F64Ceil):
    7262           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::CeilD, ValType::F64));
    7263             :           case uint16_t(Op::F64Floor):
    7264           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::FloorD, ValType::F64));
    7265             :           case uint16_t(Op::F64PromoteF32):
    7266           0 :             CHECK_NEXT(emitConversion(emitConvertF32ToF64, ValType::F32, ValType::F64));
    7267             :           case uint16_t(Op::F64ConvertSI32):
    7268           0 :             CHECK_NEXT(emitConversion(emitConvertI32ToF64, ValType::I32, ValType::F64));
    7269             :           case uint16_t(Op::F64ConvertUI32):
    7270           0 :             CHECK_NEXT(emitConversion(emitConvertU32ToF64, ValType::I32, ValType::F64));
    7271             :           case uint16_t(Op::F64ConvertSI64):
    7272             : #ifdef I64_TO_FLOAT_CALLOUT
    7273             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
    7274             :                                                 SymbolicAddress::Int64ToDouble,
    7275             :                                                 ValType::I64, ValType::F64));
    7276             : #else
    7277           0 :             CHECK_NEXT(emitConversion(emitConvertI64ToF64, ValType::I64, ValType::F64));
    7278             : #endif
    7279             :           case uint16_t(Op::F64ConvertUI64):
    7280             : #ifdef I64_TO_FLOAT_CALLOUT
    7281             :             CHECK_NEXT(emitCalloutConversionOOM(emitConvertInt64ToFloatingCallout,
    7282             :                                                 SymbolicAddress::Uint64ToDouble,
    7283             :                                                 ValType::I64, ValType::F64));
    7284             : #else
    7285           0 :             CHECK_NEXT(emitConversion(emitConvertU64ToF64, ValType::I64, ValType::F64));
    7286             : #endif
    7287             :           case uint16_t(Op::F64Load):
    7288           0 :             CHECK_NEXT(emitLoad(ValType::F64, Scalar::Float64));
    7289             :           case uint16_t(Op::F64Store):
    7290           0 :             CHECK_NEXT(emitStore(ValType::F64, Scalar::Float64));
    7291             :           case uint16_t(Op::F64ReinterpretI64):
    7292           0 :             CHECK_NEXT(emitConversion(emitReinterpretI64AsF64, ValType::I64, ValType::F64));
    7293             :           case uint16_t(Op::F64CopySign):
    7294           0 :             CHECK_NEXT(emitBinary(emitCopysignF64, ValType::F64));
    7295             :           case uint16_t(Op::F64Nearest):
    7296           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::NearbyIntD, ValType::F64));
    7297             :           case uint16_t(Op::F64Trunc):
    7298           0 :             CHECK_NEXT(emitUnaryMathBuiltinCall(SymbolicAddress::TruncD, ValType::F64));
    7299             : 
    7300             :           // Comparisons
    7301             :           case uint16_t(Op::I32Eq):
    7302           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::Equal));
    7303             :           case uint16_t(Op::I32Ne):
    7304           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::NotEqual));
    7305             :           case uint16_t(Op::I32LtS):
    7306           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::LessThan));
    7307             :           case uint16_t(Op::I32LeS):
    7308           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::LessThanOrEqual));
    7309             :           case uint16_t(Op::I32GtS):
    7310           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::GreaterThan));
    7311             :           case uint16_t(Op::I32GeS):
    7312           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::GreaterThanOrEqual));
    7313             :           case uint16_t(Op::I32LtU):
    7314           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::Below));
    7315             :           case uint16_t(Op::I32LeU):
    7316           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::BelowOrEqual));
    7317             :           case uint16_t(Op::I32GtU):
    7318           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::Above));
    7319             :           case uint16_t(Op::I32GeU):
    7320           0 :             CHECK_NEXT(emitComparison(emitCompareI32, ValType::I32, Assembler::AboveOrEqual));
    7321             :           case uint16_t(Op::I64Eq):
    7322           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::Equal));
    7323             :           case uint16_t(Op::I64Ne):
    7324           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::NotEqual));
    7325             :           case uint16_t(Op::I64LtS):
    7326           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::LessThan));
    7327             :           case uint16_t(Op::I64LeS):
    7328           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::LessThanOrEqual));
    7329             :           case uint16_t(Op::I64GtS):
    7330           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::GreaterThan));
    7331             :           case uint16_t(Op::I64GeS):
    7332           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::GreaterThanOrEqual));
    7333             :           case uint16_t(Op::I64LtU):
    7334           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::Below));
    7335             :           case uint16_t(Op::I64LeU):
    7336           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::BelowOrEqual));
    7337             :           case uint16_t(Op::I64GtU):
    7338           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::Above));
    7339             :           case uint16_t(Op::I64GeU):
    7340           0 :             CHECK_NEXT(emitComparison(emitCompareI64, ValType::I64, Assembler::AboveOrEqual));
    7341             :           case uint16_t(Op::F32Eq):
    7342           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleEqual));
    7343             :           case uint16_t(Op::F32Ne):
    7344           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleNotEqualOrUnordered));
    7345             :           case uint16_t(Op::F32Lt):
    7346           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleLessThan));
    7347             :           case uint16_t(Op::F32Le):
    7348           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleLessThanOrEqual));
    7349             :           case uint16_t(Op::F32Gt):
    7350           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleGreaterThan));
    7351             :           case uint16_t(Op::F32Ge):
    7352           0 :             CHECK_NEXT(emitComparison(emitCompareF32, ValType::F32, Assembler::DoubleGreaterThanOrEqual));
    7353             :           case uint16_t(Op::F64Eq):
    7354           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleEqual));
    7355             :           case uint16_t(Op::F64Ne):
    7356           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleNotEqualOrUnordered));
    7357             :           case uint16_t(Op::F64Lt):
    7358           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleLessThan));
    7359             :           case uint16_t(Op::F64Le):
    7360           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleLessThanOrEqual));
    7361             :           case uint16_t(Op::F64Gt):
    7362           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleGreaterThan));
    7363             :           case uint16_t(Op::F64Ge):
    7364           0 :             CHECK_NEXT(emitComparison(emitCompareF64, ValType::F64, Assembler::DoubleGreaterThanOrEqual));
    7365             : 
    7366             :           // Memory Related
    7367             :           case uint16_t(Op::GrowMemory):
    7368           0 :             CHECK_NEXT(emitGrowMemory());
    7369             :           case uint16_t(Op::CurrentMemory):
    7370           0 :             CHECK_NEXT(emitCurrentMemory());
    7371             : 
    7372             :           default:
    7373           0 :             return iter_.unrecognizedOpcode(&op);
    7374             :         }
    7375             : 
    7376             : #undef CHECK
    7377             : #undef NEXT
    7378             : #undef CHECK_NEXT
    7379             : #undef emitBinary
    7380             : #undef emitUnary
    7381             : #undef emitComparison
    7382             : #undef emitConversion
    7383             : #undef emitConversionOOM
    7384             : #undef emitCalloutConversionOOM
    7385             : 
    7386             :         MOZ_CRASH("unreachable");
    7387           0 :     }
    7388             : 
    7389             :     MOZ_CRASH("unreachable");
    7390             : }
    7391             : 
    7392             : bool
    7393           0 : BaseCompiler::emitFunction()
    7394             : {
    7395           0 :     beginFunction();
    7396             : 
    7397           0 :     if (!emitBody())
    7398           0 :         return false;
    7399             : 
    7400           0 :     if (!endFunction())
    7401           0 :         return false;
    7402             : 
    7403           0 :     return true;
    7404             : }
    7405             : 
    7406           0 : BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
    7407             :                            Decoder& decoder,
    7408             :                            const FuncBytes& func,
    7409             :                            const ValTypeVector& locals,
    7410             :                            bool debugEnabled,
    7411             :                            TempAllocator* alloc,
    7412           0 :                            MacroAssembler* masm)
    7413             :     : env_(env),
    7414             :       iter_(env, decoder),
    7415             :       func_(func),
    7416             :       lastReadCallSite_(0),
    7417             :       alloc_(*alloc),
    7418             :       locals_(locals),
    7419             :       localSize_(0),
    7420             :       varLow_(0),
    7421             :       varHigh_(0),
    7422             :       maxFramePushed_(0),
    7423             :       deadCode_(false),
    7424             :       debugEnabled_(debugEnabled),
    7425             :       bceSafe_(0),
    7426             :       stackAddOffset_(0),
    7427             :       latentOp_(LatentOp::None),
    7428             :       latentType_(ValType::I32),
    7429             :       latentIntCmp_(Assembler::Equal),
    7430             :       latentDoubleCmp_(Assembler::DoubleEqual),
    7431             :       masm(*masm),
    7432           0 :       availGPR_(GeneralRegisterSet::All()),
    7433           0 :       availFPU_(FloatRegisterSet::All()),
    7434             : #ifdef DEBUG
    7435             :       scratchRegisterTaken_(false),
    7436             : #endif
    7437             : #ifdef JS_CODEGEN_X64
    7438           0 :       specific_rax(RegI64(Register64(rax))),
    7439           0 :       specific_rcx(RegI64(Register64(rcx))),
    7440           0 :       specific_rdx(RegI64(Register64(rdx))),
    7441             : #endif
    7442             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86)
    7443             :       specific_eax(RegI32(eax)),
    7444             :       specific_ecx(RegI32(ecx)),
    7445             :       specific_edx(RegI32(edx)),
    7446             : #endif
    7447             : #ifdef JS_CODEGEN_X86
    7448             :       singleByteRegs_(GeneralRegisterSet(Registers::SingleByteRegs)),
    7449             :       abiReturnRegI64(RegI64(Register64(edx, eax))),
    7450             : #endif
    7451             : #ifdef JS_CODEGEN_ARM
    7452             :       abiReturnRegI64(ReturnReg64),
    7453             : #endif
    7454             :       joinRegI32(RegI32(ReturnReg)),
    7455             :       joinRegI64(RegI64(ReturnReg64)),
    7456             :       joinRegF32(RegF32(ReturnFloat32Reg)),
    7457           0 :       joinRegF64(RegF64(ReturnDoubleReg))
    7458             : {
    7459             :     // jit/RegisterAllocator.h: RegisterAllocator::RegisterAllocator()
    7460             : 
    7461             : #if defined(JS_CODEGEN_X64)
    7462           0 :     availGPR_.take(HeapReg);
    7463             : #elif defined(JS_CODEGEN_ARM)
    7464             :     availGPR_.take(HeapReg);
    7465             :     availGPR_.take(ScratchRegARM);
    7466             : #elif defined(JS_CODEGEN_ARM64)
    7467             :     availGPR_.take(HeapReg);
    7468             :     availGPR_.take(HeapLenReg);
    7469             : #elif defined(JS_CODEGEN_X86)
    7470             :     availGPR_.take(ScratchRegX86);
    7471             : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
    7472             :     availGPR_.take(HeapReg);
    7473             : #endif
    7474           0 :     availGPR_.take(FramePointer);
    7475             : 
    7476             : #ifdef DEBUG
    7477           0 :     setupRegisterLeakCheck();
    7478             : #endif
    7479           0 : }
    7480             : 
    7481             : bool
    7482           0 : BaseCompiler::init()
    7483             : {
    7484           0 :     if (!SigD_.append(ValType::F64))
    7485           0 :         return false;
    7486           0 :     if (!SigF_.append(ValType::F32))
    7487           0 :         return false;
    7488           0 :     if (!SigP_.append(MIRType::Pointer))
    7489           0 :         return false;
    7490           0 :     if (!SigPI_.append(MIRType::Pointer) || !SigPI_.append(MIRType::Int32))
    7491           0 :         return false;
    7492           0 :     if (!SigI64I64_.append(ValType::I64) || !SigI64I64_.append(ValType::I64))
    7493           0 :         return false;
    7494             : 
    7495           0 :     const ValTypeVector& args = func_.sig().args();
    7496             : 
    7497           0 :     if (!localInfo_.resize(locals_.length()))
    7498           0 :         return false;
    7499             : 
    7500           0 :     BaseLocalIter i(locals_, args.length(), debugEnabled_);
    7501           0 :     varLow_ = i.reservedSize();
    7502           0 :     for (; !i.done() && i.index() < args.length(); i++) {
    7503           0 :         MOZ_ASSERT(i.isArg());
    7504           0 :         Local& l = localInfo_[i.index()];
    7505           0 :         l.init(i.mirType(), i.frameOffset());
    7506           0 :         varLow_ = i.currentLocalSize();
    7507             :     }
    7508             : 
    7509           0 :     varHigh_ = varLow_;
    7510           0 :     for (; !i.done() ; i++) {
    7511           0 :         MOZ_ASSERT(!i.isArg());
    7512           0 :         Local& l = localInfo_[i.index()];
    7513           0 :         l.init(i.mirType(), i.frameOffset());
    7514           0 :         varHigh_ = i.currentLocalSize();
    7515             :     }
    7516             : 
    7517           0 :     localSize_ = AlignBytes(varHigh_, 16u);
    7518             : 
    7519           0 :     addInterruptCheck();
    7520             : 
    7521           0 :     return true;
    7522             : }
    7523             : 
    7524             : FuncOffsets
    7525           0 : BaseCompiler::finish()
    7526             : {
    7527           0 :     MOZ_ASSERT(done(), "all bytes must be consumed");
    7528           0 :     MOZ_ASSERT(func_.callSiteLineNums().length() == lastReadCallSite_);
    7529             : 
    7530           0 :     masm.flushBuffer();
    7531             : 
    7532           0 :     return offsets_;
    7533             : }
    7534             : 
    7535             : } // wasm
    7536             : } // js
    7537             : 
    7538             : bool
    7539           0 : js::wasm::BaselineCanCompile()
    7540             : {
    7541             :     // On all platforms we require signals for Wasm.
    7542             :     // If we made it this far we must have signals.
    7543           0 :     MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
    7544             : 
    7545             : #if defined(JS_CODEGEN_ARM)
    7546             :     // Simplifying assumption: require SDIV and UDIV.
    7547             :     //
    7548             :     // I have no good data on ARM populations allowing me to say that
    7549             :     // X% of devices in the market implement SDIV and UDIV.  However,
    7550             :     // they are definitely implemented on the Cortex-A7 and Cortex-A15
    7551             :     // and on all ARMv8 systems.
    7552             :     if (!HasIDIV())
    7553             :         return false;
    7554             : #endif
    7555             : 
    7556             : #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
    7557           0 :     return true;
    7558             : #else
    7559             :     return false;
    7560             : #endif
    7561             : }
    7562             : 
    7563             : bool
    7564           0 : js::wasm::BaselineCompileFunction(CompileTask* task, FuncCompileUnit* unit, UniqueChars *error)
    7565             : {
    7566           0 :     MOZ_ASSERT(task->tier() == Tier::Baseline);
    7567           0 :     MOZ_ASSERT(task->env().kind == ModuleKind::Wasm);
    7568             : 
    7569           0 :     const FuncBytes& func = unit->func();
    7570             : 
    7571           0 :     Decoder d(func.bytes().begin(), func.bytes().end(), func.lineOrBytecode(), error);
    7572             : 
    7573             :     // Build the local types vector.
    7574             : 
    7575           0 :     ValTypeVector locals;
    7576           0 :     if (!locals.appendAll(func.sig().args()))
    7577           0 :         return false;
    7578           0 :     if (!DecodeLocalEntries(d, task->env().kind, &locals))
    7579           0 :         return false;
    7580             : 
    7581             :     // The MacroAssembler will sometimes access the jitContext.
    7582             : 
    7583           0 :     JitContext jitContext(&task->alloc());
    7584             : 
    7585             :     // One-pass baseline compilation.
    7586             : 
    7587           0 :     BaseCompiler f(task->env(), d, func, locals, task->debugEnabled(), &task->alloc(), &task->masm());
    7588           0 :     if (!f.init())
    7589           0 :         return false;
    7590             : 
    7591           0 :     if (!f.emitFunction())
    7592           0 :         return false;
    7593             : 
    7594           0 :     unit->finish(f.finish());
    7595           0 :     return true;
    7596             : }
    7597             : 
    7598             : #undef INT_DIV_I64_CALLOUT
    7599             : #undef I64_TO_FLOAT_CALLOUT
    7600             : #undef FLOAT_TO_I64_CALLOUT

Generated by: LCOV version 1.13