LCOV - code coverage report
Current view: top level - js/src/jit - LIR.h (source / functions) Hit Total Coverage
Test: output.info Lines: 635 740 85.8 %
Date: 2017-07-14 16:53:18 Functions: 381 1121 34.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             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef jit_LIR_h
       8             : #define jit_LIR_h
       9             : 
      10             : // This file declares the core data structures for LIR: storage allocations for
      11             : // inputs and outputs, as well as the interface instructions must conform to.
      12             : 
      13             : #include "mozilla/Array.h"
      14             : 
      15             : #include "jit/Bailouts.h"
      16             : #include "jit/FixedList.h"
      17             : #include "jit/InlineList.h"
      18             : #include "jit/JitAllocPolicy.h"
      19             : #include "jit/LOpcodes.h"
      20             : #include "jit/MIR.h"
      21             : #include "jit/MIRGraph.h"
      22             : #include "jit/Registers.h"
      23             : #include "jit/Safepoints.h"
      24             : 
      25             : namespace js {
      26             : namespace jit {
      27             : 
      28             : class LUse;
      29             : class LGeneralReg;
      30             : class LFloatReg;
      31             : class LStackSlot;
      32             : class LArgument;
      33             : class LConstantIndex;
      34             : class MBasicBlock;
      35             : class MIRGenerator;
      36             : 
      37             : static const uint32_t VREG_INCREMENT = 1;
      38             : 
      39             : static const uint32_t THIS_FRAME_ARGSLOT = 0;
      40             : 
      41             : #if defined(JS_NUNBOX32)
      42             : # define BOX_PIECES         2
      43             : static const uint32_t VREG_TYPE_OFFSET = 0;
      44             : static const uint32_t VREG_DATA_OFFSET = 1;
      45             : static const uint32_t TYPE_INDEX = 0;
      46             : static const uint32_t PAYLOAD_INDEX = 1;
      47             : static const uint32_t INT64LOW_INDEX = 0;
      48             : static const uint32_t INT64HIGH_INDEX = 1;
      49             : #elif defined(JS_PUNBOX64)
      50             : # define BOX_PIECES         1
      51             : #else
      52             : # error "Unknown!"
      53             : #endif
      54             : 
      55             : static const uint32_t INT64_PIECES = sizeof(int64_t) / sizeof(uintptr_t);
      56             : 
      57             : // Represents storage for an operand. For constants, the pointer is tagged
      58             : // with a single bit, and the untagged pointer is a pointer to a Value.
      59             : class LAllocation : public TempObject
      60             : {
      61             :     uintptr_t bits_;
      62             : 
      63             :     // 3 bits gives us enough for an interesting set of Kinds and also fits
      64             :     // within the alignment bits of pointers to Value, which are always
      65             :     // 8-byte aligned.
      66             :     static const uintptr_t KIND_BITS = 3;
      67             :     static const uintptr_t KIND_SHIFT = 0;
      68             :     static const uintptr_t KIND_MASK = (1 << KIND_BITS) - 1;
      69             : 
      70             :   protected:
      71             :     static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS;
      72             :     static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
      73             : 
      74             :   public:
      75             :     enum Kind {
      76             :         CONSTANT_VALUE, // MConstant*.
      77             :         CONSTANT_INDEX, // Constant arbitrary index.
      78             :         USE,            // Use of a virtual register, with physical allocation policy.
      79             :         GPR,            // General purpose register.
      80             :         FPU,            // Floating-point register.
      81             :         STACK_SLOT,     // Stack slot.
      82             :         ARGUMENT_SLOT   // Argument slot.
      83             :     };
      84             : 
      85             :     static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
      86             : 
      87             :   protected:
      88      224924 :     uint32_t data() const {
      89      224924 :         return uint32_t(bits_) >> DATA_SHIFT;
      90             :     }
      91        6415 :     void setData(uint32_t data) {
      92        6415 :         MOZ_ASSERT(data <= DATA_MASK);
      93        6415 :         bits_ &= ~(DATA_MASK << DATA_SHIFT);
      94        6415 :         bits_ |= (data << DATA_SHIFT);
      95        6415 :     }
      96       10060 :     void setKindAndData(Kind kind, uint32_t data) {
      97       10060 :         MOZ_ASSERT(data <= DATA_MASK);
      98       10060 :         bits_ = (uint32_t(kind) << KIND_SHIFT) | data << DATA_SHIFT;
      99       10060 :     }
     100             : 
     101        3645 :     LAllocation(Kind kind, uint32_t data) {
     102        3645 :         setKindAndData(kind, data);
     103        3645 :     }
     104             :     explicit LAllocation(Kind kind) {
     105             :         setKindAndData(kind, 0);
     106             :     }
     107             : 
     108             :   public:
     109       30114 :     LAllocation() : bits_(0)
     110             :     {
     111       30114 :         MOZ_ASSERT(isBogus());
     112       30114 :     }
     113             : 
     114             :     // The MConstant pointer must have its low bits cleared.
     115        1929 :     explicit LAllocation(const MConstant* c) {
     116        1929 :         MOZ_ASSERT(c);
     117        1929 :         bits_ = uintptr_t(c);
     118        1929 :         MOZ_ASSERT((bits_ & (KIND_MASK << KIND_SHIFT)) == 0);
     119        1929 :         bits_ |= CONSTANT_VALUE << KIND_SHIFT;
     120        1929 :     }
     121             :     inline explicit LAllocation(AnyRegister reg);
     122             : 
     123      266742 :     Kind kind() const {
     124      266742 :         return (Kind)((bits_ >> KIND_SHIFT) & KIND_MASK);
     125             :     }
     126             : 
     127      101153 :     bool isBogus() const {
     128      101153 :         return bits_ == 0;
     129             :     }
     130       67374 :     bool isUse() const {
     131       67374 :         return kind() == USE;
     132             :     }
     133        3960 :     bool isConstant() const {
     134        3960 :         return isConstantValue() || isConstantIndex();
     135             :     }
     136        4148 :     bool isConstantValue() const {
     137        4148 :         return kind() == CONSTANT_VALUE;
     138             :     }
     139        3477 :     bool isConstantIndex() const {
     140        3477 :         return kind() == CONSTANT_INDEX;
     141             :     }
     142       51442 :     bool isGeneralReg() const {
     143       51442 :         return kind() == GPR;
     144             :     }
     145       30603 :     bool isFloatReg() const {
     146       30603 :         return kind() == FPU;
     147             :     }
     148      100542 :     bool isStackSlot() const {
     149      100542 :         return kind() == STACK_SLOT;
     150             :     }
     151        8909 :     bool isArgument() const {
     152        8909 :         return kind() == ARGUMENT_SLOT;
     153             :     }
     154       32385 :     bool isRegister() const {
     155       32385 :         return isGeneralReg() || isFloatReg();
     156             :     }
     157             :     bool isRegister(bool needFloat) const {
     158             :         return needFloat ? isFloatReg() : isGeneralReg();
     159             :     }
     160       29352 :     bool isMemory() const {
     161       29352 :         return isStackSlot() || isArgument();
     162             :     }
     163             :     inline uint32_t memorySlot() const;
     164             :     inline LUse* toUse();
     165             :     inline const LUse* toUse() const;
     166             :     inline const LGeneralReg* toGeneralReg() const;
     167             :     inline const LFloatReg* toFloatReg() const;
     168             :     inline const LStackSlot* toStackSlot() const;
     169             :     inline const LArgument* toArgument() const;
     170             :     inline const LConstantIndex* toConstantIndex() const;
     171             :     inline AnyRegister toRegister() const;
     172             : 
     173         124 :     const MConstant* toConstant() const {
     174         124 :         MOZ_ASSERT(isConstantValue());
     175         124 :         return reinterpret_cast<const MConstant*>(bits_ & ~(KIND_MASK << KIND_SHIFT));
     176             :     }
     177             : 
     178       48238 :     bool operator ==(const LAllocation& other) const {
     179       48238 :         return bits_ == other.bits_;
     180             :     }
     181             : 
     182       61927 :     bool operator !=(const LAllocation& other) const {
     183       61927 :         return bits_ != other.bits_;
     184             :     }
     185             : 
     186       12510 :     HashNumber hash() const {
     187       12510 :         return bits_;
     188             :     }
     189             : 
     190             :     UniqueChars toString() const;
     191             :     bool aliases(const LAllocation& other) const;
     192             :     void dump() const;
     193             : };
     194             : 
     195             : class LUse : public LAllocation
     196             : {
     197             :     static const uint32_t POLICY_BITS = 3;
     198             :     static const uint32_t POLICY_SHIFT = 0;
     199             :     static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
     200             :     static const uint32_t REG_BITS = 6;
     201             :     static const uint32_t REG_SHIFT = POLICY_SHIFT + POLICY_BITS;
     202             :     static const uint32_t REG_MASK = (1 << REG_BITS) - 1;
     203             : 
     204             :     // Whether the physical register for this operand may be reused for a def.
     205             :     static const uint32_t USED_AT_START_BITS = 1;
     206             :     static const uint32_t USED_AT_START_SHIFT = REG_SHIFT + REG_BITS;
     207             :     static const uint32_t USED_AT_START_MASK = (1 << USED_AT_START_BITS) - 1;
     208             : 
     209             :   public:
     210             :     // Virtual registers get the remaining 19 bits.
     211             :     static const uint32_t VREG_BITS = DATA_BITS - (USED_AT_START_SHIFT + USED_AT_START_BITS);
     212             :     static const uint32_t VREG_SHIFT = USED_AT_START_SHIFT + USED_AT_START_BITS;
     213             :     static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
     214             : 
     215             :     enum Policy {
     216             :         // Input should be in a read-only register or stack slot.
     217             :         ANY,
     218             : 
     219             :         // Input must be in a read-only register.
     220             :         REGISTER,
     221             : 
     222             :         // Input must be in a specific, read-only register.
     223             :         FIXED,
     224             : 
     225             :         // Keep the used virtual register alive, and use whatever allocation is
     226             :         // available. This is similar to ANY but hints to the register allocator
     227             :         // that it is never useful to optimize this site.
     228             :         KEEPALIVE,
     229             : 
     230             :         // For snapshot inputs, indicates that the associated instruction will
     231             :         // write this input to its output register before bailing out.
     232             :         // The register allocator may thus allocate that output register, and
     233             :         // does not need to keep the virtual register alive (alternatively,
     234             :         // this may be treated as KEEPALIVE).
     235             :         RECOVERED_INPUT
     236             :     };
     237             : 
     238        6415 :     void set(Policy policy, uint32_t reg, bool usedAtStart) {
     239       12830 :         setKindAndData(USE, (policy << POLICY_SHIFT) |
     240        6415 :                             (reg << REG_SHIFT) |
     241       12830 :                             ((usedAtStart ? 1 : 0) << USED_AT_START_SHIFT));
     242        6415 :     }
     243             : 
     244             :   public:
     245         549 :     LUse(uint32_t vreg, Policy policy, bool usedAtStart = false) {
     246         549 :         set(policy, 0, usedAtStart);
     247         549 :         setVirtualRegister(vreg);
     248         549 :     }
     249        5806 :     explicit LUse(Policy policy, bool usedAtStart = false) {
     250        5806 :         set(policy, 0, usedAtStart);
     251        5806 :     }
     252          60 :     explicit LUse(Register reg, bool usedAtStart = false) {
     253          60 :         set(FIXED, reg.code(), usedAtStart);
     254          60 :     }
     255           0 :     explicit LUse(FloatRegister reg, bool usedAtStart = false) {
     256           0 :         set(FIXED, reg.code(), usedAtStart);
     257           0 :     }
     258           0 :     LUse(Register reg, uint32_t virtualRegister, bool usedAtStart = false) {
     259           0 :         set(FIXED, reg.code(), usedAtStart);
     260           0 :         setVirtualRegister(virtualRegister);
     261           0 :     }
     262             :     LUse(FloatRegister reg, uint32_t virtualRegister, bool usedAtStart = false) {
     263             :         set(FIXED, reg.code(), usedAtStart);
     264             :         setVirtualRegister(virtualRegister);
     265             :     }
     266             : 
     267        6415 :     void setVirtualRegister(uint32_t index) {
     268        6415 :         MOZ_ASSERT(index < VREG_MASK);
     269             : 
     270        6415 :         uint32_t old = data() & ~(VREG_MASK << VREG_SHIFT);
     271        6415 :         setData(old | (index << VREG_SHIFT));
     272        6415 :     }
     273             : 
     274      136849 :     Policy policy() const {
     275      136849 :         Policy policy = (Policy)((data() >> POLICY_SHIFT) & POLICY_MASK);
     276      136849 :         return policy;
     277             :     }
     278       26450 :     uint32_t virtualRegister() const {
     279       26450 :         uint32_t index = (data() >> VREG_SHIFT) & VREG_MASK;
     280       26450 :         MOZ_ASSERT(index != 0);
     281       26450 :         return index;
     282             :     }
     283         325 :     uint32_t registerCode() const {
     284         325 :         MOZ_ASSERT(policy() == FIXED);
     285         325 :         return (data() >> REG_SHIFT) & REG_MASK;
     286             :     }
     287       12090 :     bool isFixedRegister() const {
     288       12090 :         return policy() == FIXED;
     289             :     }
     290       13355 :     bool usedAtStart() const {
     291       13355 :         return !!((data() >> USED_AT_START_SHIFT) & USED_AT_START_MASK);
     292             :     }
     293             : };
     294             : 
     295             : static const uint32_t MAX_VIRTUAL_REGISTERS = LUse::VREG_MASK;
     296             : 
     297             : class LBoxAllocation
     298             : {
     299             : #ifdef JS_NUNBOX32
     300             :     LAllocation type_;
     301             :     LAllocation payload_;
     302             : #else
     303             :     LAllocation value_;
     304             : #endif
     305             : 
     306             :   public:
     307             : #ifdef JS_NUNBOX32
     308             :     LBoxAllocation(LAllocation type, LAllocation payload) : type_(type), payload_(payload) {}
     309             : 
     310             :     LAllocation type() const { return type_; }
     311             :     LAllocation payload() const { return payload_; }
     312             : #else
     313         160 :     explicit LBoxAllocation(LAllocation value) : value_(value) {}
     314             : 
     315         160 :     LAllocation value() const { return value_; }
     316             : #endif
     317             : };
     318             : 
     319             : template<class ValT>
     320             : class LInt64Value
     321             : {
     322             : #if JS_BITS_PER_WORD == 32
     323             :     ValT high_;
     324             :     ValT low_;
     325             : #else
     326             :     ValT value_;
     327             : #endif
     328             : 
     329             :   public:
     330             : #if JS_BITS_PER_WORD == 32
     331             :     LInt64Value(ValT high, ValT low) : high_(high), low_(low) {}
     332             : 
     333             :     ValT high() const { return high_; }
     334             :     ValT low() const { return low_; }
     335             : #else
     336           0 :     explicit LInt64Value(ValT value) : value_(value) {}
     337             : 
     338           0 :     ValT value() const { return value_; }
     339             : #endif
     340             : };
     341             : 
     342             : using LInt64Allocation = LInt64Value<LAllocation>;
     343             : 
     344             : class LGeneralReg : public LAllocation
     345             : {
     346             :   public:
     347        1806 :     explicit LGeneralReg(Register reg)
     348        1806 :       : LAllocation(GPR, reg.code())
     349        1806 :     { }
     350             : 
     351       12753 :     Register reg() const {
     352       12753 :         return Register::FromCode(data());
     353             :     }
     354             : };
     355             : 
     356             : class LFloatReg : public LAllocation
     357             : {
     358             :   public:
     359        1706 :     explicit LFloatReg(FloatRegister reg)
     360        1706 :       : LAllocation(FPU, reg.code())
     361        1706 :     { }
     362             : 
     363          74 :     FloatRegister reg() const {
     364          74 :         return FloatRegister::FromCode(data());
     365             :     }
     366             : };
     367             : 
     368             : // Arbitrary constant index.
     369             : class LConstantIndex : public LAllocation
     370             : {
     371          13 :     explicit LConstantIndex(uint32_t index)
     372          13 :       : LAllocation(CONSTANT_INDEX, index)
     373          13 :     { }
     374             : 
     375             :   public:
     376          13 :     static LConstantIndex FromIndex(uint32_t index) {
     377          13 :         return LConstantIndex(index);
     378             :     }
     379             : 
     380          69 :     uint32_t index() const {
     381          69 :         return data();
     382             :     }
     383             : };
     384             : 
     385             : // Stack slots are indices into the stack. The indices are byte indices.
     386             : class LStackSlot : public LAllocation
     387             : {
     388             :   public:
     389          84 :     explicit LStackSlot(uint32_t slot)
     390          84 :       : LAllocation(STACK_SLOT, slot)
     391          84 :     { }
     392             : 
     393       27896 :     uint32_t slot() const {
     394       27896 :         return data();
     395             :     }
     396             : };
     397             : 
     398             : // Arguments are reverse indices into the stack. The indices are byte indices.
     399             : class LArgument : public LAllocation
     400             : {
     401             :   public:
     402          36 :     explicit LArgument(uint32_t index)
     403          36 :       : LAllocation(ARGUMENT_SLOT, index)
     404          36 :     { }
     405             : 
     406         738 :     uint32_t index() const {
     407         738 :         return data();
     408             :     }
     409             : };
     410             : 
     411             : inline uint32_t
     412       19463 : LAllocation::memorySlot() const
     413             : {
     414       19463 :     MOZ_ASSERT(isMemory());
     415       19463 :     return isStackSlot() ? toStackSlot()->slot() : toArgument()->index();
     416             : }
     417             : 
     418             : // Represents storage for a definition.
     419             : class LDefinition
     420             : {
     421             :     // Bits containing policy, type, and virtual register.
     422             :     uint32_t bits_;
     423             : 
     424             :     // Before register allocation, this optionally contains a fixed policy.
     425             :     // Register allocation assigns this field to a physical policy if none is
     426             :     // fixed.
     427             :     //
     428             :     // Right now, pre-allocated outputs are limited to the following:
     429             :     //   * Physical argument stack slots.
     430             :     //   * Physical registers.
     431             :     LAllocation output_;
     432             : 
     433             :     static const uint32_t TYPE_BITS = 4;
     434             :     static const uint32_t TYPE_SHIFT = 0;
     435             :     static const uint32_t TYPE_MASK = (1 << TYPE_BITS) - 1;
     436             :     static const uint32_t POLICY_BITS = 2;
     437             :     static const uint32_t POLICY_SHIFT = TYPE_SHIFT + TYPE_BITS;
     438             :     static const uint32_t POLICY_MASK = (1 << POLICY_BITS) - 1;
     439             : 
     440             :     static const uint32_t VREG_BITS = (sizeof(uint32_t) * 8) - (POLICY_BITS + TYPE_BITS);
     441             :     static const uint32_t VREG_SHIFT = POLICY_SHIFT + POLICY_BITS;
     442             :     static const uint32_t VREG_MASK = (1 << VREG_BITS) - 1;
     443             : 
     444             :   public:
     445             :     // Note that definitions, by default, are always allocated a register,
     446             :     // unless the policy specifies that an input can be re-used and that input
     447             :     // is a stack slot.
     448             :     enum Policy {
     449             :         // The policy is predetermined by the LAllocation attached to this
     450             :         // definition. The allocation may be:
     451             :         //   * A register, which may not appear as any fixed temporary.
     452             :         //   * A stack slot or argument.
     453             :         //
     454             :         // Register allocation will not modify a fixed allocation.
     455             :         FIXED,
     456             : 
     457             :         // A random register of an appropriate class will be assigned.
     458             :         REGISTER,
     459             : 
     460             :         // One definition per instruction must re-use the first input
     461             :         // allocation, which (for now) must be a register.
     462             :         MUST_REUSE_INPUT
     463             :     };
     464             : 
     465             :     // This should be kept in sync with LIR.cpp's TypeChars.
     466             :     enum Type {
     467             :         GENERAL,      // Generic, integer or pointer-width data (GPR).
     468             :         INT32,        // int32 data (GPR).
     469             :         OBJECT,       // Pointer that may be collected as garbage (GPR).
     470             :         SLOTS,        // Slots/elements pointer that may be moved by minor GCs (GPR).
     471             :         FLOAT32,      // 32-bit floating-point value (FPU).
     472             :         DOUBLE,       // 64-bit floating-point value (FPU).
     473             :         SIMD128INT,   // 128-bit SIMD integer vector (FPU).
     474             :         SIMD128FLOAT, // 128-bit SIMD floating point vector (FPU).
     475             :         SINCOS,
     476             : #ifdef JS_NUNBOX32
     477             :         // A type virtual register must be followed by a payload virtual
     478             :         // register, as both will be tracked as a single gcthing.
     479             :         TYPE,
     480             :         PAYLOAD
     481             : #else
     482             :         BOX         // Joined box, for punbox systems. (GPR, gcthing)
     483             : #endif
     484             :     };
     485             : 
     486        1616 :     void set(uint32_t index, Type type, Policy policy) {
     487             :         JS_STATIC_ASSERT(MAX_VIRTUAL_REGISTERS <= VREG_MASK);
     488        1616 :         bits_ = (index << VREG_SHIFT) | (policy << POLICY_SHIFT) | (type << TYPE_SHIFT);
     489             :         MOZ_ASSERT_IF(!SupportsSimd, !isSimdType());
     490        1616 :     }
     491             : 
     492             :   public:
     493         621 :     LDefinition(uint32_t index, Type type, Policy policy = REGISTER) {
     494         621 :         set(index, type, policy);
     495         621 :     }
     496             : 
     497         958 :     explicit LDefinition(Type type, Policy policy = REGISTER) {
     498         958 :         set(0, type, policy);
     499         958 :     }
     500             : 
     501             :     LDefinition(Type type, const LAllocation& a)
     502             :       : output_(a)
     503             :     {
     504             :         set(0, type, FIXED);
     505             :     }
     506             : 
     507          37 :     LDefinition(uint32_t index, Type type, const LAllocation& a)
     508          37 :       : output_(a)
     509             :     {
     510          37 :         set(index, type, FIXED);
     511          37 :     }
     512             : 
     513        1285 :     LDefinition() : bits_(0)
     514             :     {
     515        1285 :         MOZ_ASSERT(isBogusTemp());
     516        1285 :     }
     517             : 
     518          86 :     static LDefinition BogusTemp() {
     519          86 :         return LDefinition();
     520             :     }
     521             : 
     522       92633 :     Policy policy() const {
     523       92633 :         return (Policy)((bits_ >> POLICY_SHIFT) & POLICY_MASK);
     524             :     }
     525      357709 :     Type type() const {
     526      357709 :         return (Type)((bits_ >> TYPE_SHIFT) & TYPE_MASK);
     527             :     }
     528       85279 :     bool isSimdType() const {
     529       85279 :         return type() == SIMD128INT || type() == SIMD128FLOAT;
     530             :     }
     531       43113 :     bool isCompatibleReg(const AnyRegister& r) const {
     532       43113 :         if (isFloatReg() && r.isFloat()) {
     533         656 :             if (type() == FLOAT32)
     534           0 :                 return r.fpu().isSingle();
     535         656 :             if (type() == DOUBLE)
     536         656 :                 return r.fpu().isDouble();
     537           0 :             if (isSimdType())
     538           0 :                 return r.fpu().isSimd128();
     539           0 :             MOZ_CRASH("Unexpected MDefinition type");
     540             :         }
     541       42457 :         return !isFloatReg() && !r.isFloat();
     542             :     }
     543         347 :     bool isCompatibleDef(const LDefinition& other) const {
     544             : #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
     545             :         if (isFloatReg() && other.isFloatReg())
     546             :             return type() == other.type();
     547             :         return !isFloatReg() && !other.isFloatReg();
     548             : #else
     549         347 :         return isFloatReg() == other.isFloatReg();
     550             : #endif
     551             :     }
     552             : 
     553       86529 :     bool isFloatReg() const {
     554       86529 :         return type() == FLOAT32 || type() == DOUBLE || isSimdType();
     555             :     }
     556       52378 :     uint32_t virtualRegister() const {
     557       52378 :         uint32_t index = (bits_ >> VREG_SHIFT) & VREG_MASK;
     558             :         //MOZ_ASSERT(index != 0);
     559       52378 :         return index;
     560             :     }
     561       67552 :     LAllocation* output() {
     562       67552 :         return &output_;
     563             :     }
     564       68338 :     const LAllocation* output() const {
     565       68338 :         return &output_;
     566             :     }
     567       71385 :     bool isFixed() const {
     568       71385 :         return policy() == FIXED;
     569             :     }
     570       69201 :     bool isBogusTemp() const {
     571       69201 :         return isFixed() && output()->isBogus();
     572             :     }
     573         404 :     void setVirtualRegister(uint32_t index) {
     574         404 :         MOZ_ASSERT(index < VREG_MASK);
     575         404 :         bits_ &= ~(VREG_MASK << VREG_SHIFT);
     576         404 :         bits_ |= index << VREG_SHIFT;
     577         404 :     }
     578        1064 :     void setOutput(const LAllocation& a) {
     579        1064 :         output_ = a;
     580        1064 :         if (!a.isUse()) {
     581        1064 :             bits_ &= ~(POLICY_MASK << POLICY_SHIFT);
     582        1064 :             bits_ |= FIXED << POLICY_SHIFT;
     583             :         }
     584        1064 :     }
     585          13 :     void setReusedInput(uint32_t operand) {
     586          13 :         output_ = LConstantIndex::FromIndex(operand);
     587          13 :     }
     588          69 :     uint32_t getReusedInput() const {
     589          69 :         MOZ_ASSERT(policy() == LDefinition::MUST_REUSE_INPUT);
     590          69 :         return output_.toConstantIndex()->index();
     591             :     }
     592             : 
     593         494 :     static inline Type TypeFrom(MIRType type) {
     594         494 :         switch (type) {
     595             :           case MIRType::Boolean:
     596             :           case MIRType::Int32:
     597             :             // The stack slot allocator doesn't currently support allocating
     598             :             // 1-byte slots, so for now we lower MIRType::Boolean into INT32.
     599             :             static_assert(sizeof(bool) <= sizeof(int32_t), "bool doesn't fit in an int32 slot");
     600         216 :             return LDefinition::INT32;
     601             :           case MIRType::String:
     602             :           case MIRType::Symbol:
     603             :           case MIRType::Object:
     604             :           case MIRType::ObjectOrNull:
     605         174 :             return LDefinition::OBJECT;
     606             :           case MIRType::Double:
     607           1 :             return LDefinition::DOUBLE;
     608             :           case MIRType::Float32:
     609           0 :             return LDefinition::FLOAT32;
     610             : #if defined(JS_PUNBOX64)
     611             :           case MIRType::Value:
     612          86 :             return LDefinition::BOX;
     613             : #endif
     614             :           case MIRType::SinCosDouble:
     615           0 :             return LDefinition::SINCOS;
     616             :           case MIRType::Slots:
     617             :           case MIRType::Elements:
     618          14 :             return LDefinition::SLOTS;
     619             :           case MIRType::Pointer:
     620           3 :             return LDefinition::GENERAL;
     621             : #if defined(JS_PUNBOX64)
     622             :           case MIRType::Int64:
     623           0 :             return LDefinition::GENERAL;
     624             : #endif
     625             :           case MIRType::Int8x16:
     626             :           case MIRType::Int16x8:
     627             :           case MIRType::Int32x4:
     628             :           case MIRType::Bool8x16:
     629             :           case MIRType::Bool16x8:
     630             :           case MIRType::Bool32x4:
     631           0 :             return LDefinition::SIMD128INT;
     632             :           case MIRType::Float32x4:
     633           0 :             return LDefinition::SIMD128FLOAT;
     634             :           default:
     635           0 :             MOZ_CRASH("unexpected type");
     636             :         }
     637             :     }
     638             : 
     639             :     UniqueChars toString() const;
     640             : 
     641             :     void dump() const;
     642             : };
     643             : 
     644             : using LInt64Definition = LInt64Value<LDefinition>;
     645             : 
     646             : // Forward declarations of LIR types.
     647             : #define LIROP(op) class L##op;
     648             :     LIR_OPCODE_LIST(LIROP)
     649             : #undef LIROP
     650             : 
     651             : class LSnapshot;
     652             : class LSafepoint;
     653             : class LInstruction;
     654             : class LElementVisitor;
     655             : 
     656             : // The common base class for LPhi and LInstruction.
     657             : class LNode
     658             : {
     659             :     uint32_t id_;
     660             :     LBlock* block_;
     661             : 
     662             :   protected:
     663             :     MDefinition* mir_;
     664             : 
     665             :   public:
     666        1963 :     LNode()
     667        1963 :       : id_(0),
     668             :         block_(nullptr),
     669        1963 :         mir_(nullptr)
     670        1963 :     { }
     671             : 
     672             :     enum Opcode {
     673             : #   define LIROP(name) LOp_##name,
     674             :         LIR_OPCODE_LIST(LIROP)
     675             : #   undef LIROP
     676             :         LOp_Invalid
     677             :     };
     678             : 
     679        1681 :     const char* opName() {
     680        1681 :         switch (op()) {
     681             : #   define LIR_NAME_INS(name)                   \
     682             :             case LOp_##name: return #name;
     683         109 :             LIR_OPCODE_LIST(LIR_NAME_INS)
     684             : #   undef LIR_NAME_INS
     685             :           default:
     686           0 :             return "Invalid";
     687             :         }
     688             :     }
     689             : 
     690             :     // Hook for opcodes to add extra high level detail about what code will be
     691             :     // emitted for the op.
     692        1420 :     virtual const char* extraName() const {
     693        1420 :         return nullptr;
     694             :     }
     695             : 
     696             :     virtual Opcode op() const = 0;
     697             : 
     698       10465 :     bool isInstruction() const {
     699       10465 :         return op() != LOp_Phi;
     700             :     }
     701             :     inline LInstruction* toInstruction();
     702             :     inline const LInstruction* toInstruction() const;
     703             : 
     704             :     // Returns the number of outputs of this instruction. If an output is
     705             :     // unallocated, it is an LDefinition, defining a virtual register.
     706             :     virtual size_t numDefs() const = 0;
     707             :     virtual LDefinition* getDef(size_t index) = 0;
     708             :     virtual void setDef(size_t index, const LDefinition& def) = 0;
     709             : 
     710             :     // Returns information about operands.
     711             :     virtual size_t numOperands() const = 0;
     712             :     virtual LAllocation* getOperand(size_t index) = 0;
     713             :     virtual void setOperand(size_t index, const LAllocation& a) = 0;
     714             : 
     715             :     // Returns information about temporary registers needed. Each temporary
     716             :     // register is an LDefinition with a fixed or virtual register and
     717             :     // either GENERAL, FLOAT32, or DOUBLE type.
     718             :     virtual size_t numTemps() const = 0;
     719             :     virtual LDefinition* getTemp(size_t index) = 0;
     720             :     virtual void setTemp(size_t index, const LDefinition& a) = 0;
     721             : 
     722             :     // Returns the number of successors of this instruction, if it is a control
     723             :     // transfer instruction, or zero otherwise.
     724             :     virtual size_t numSuccessors() const = 0;
     725             :     virtual MBasicBlock* getSuccessor(size_t i) const = 0;
     726             :     virtual void setSuccessor(size_t i, MBasicBlock* successor) = 0;
     727             : 
     728       19946 :     virtual bool isCall() const {
     729       19946 :         return false;
     730             :     }
     731             : 
     732             :     // Does this call preserve the given register?
     733             :     // By default, it is assumed that all registers are clobbered by a call.
     734        2205 :     virtual bool isCallPreserved(AnyRegister reg) const {
     735        2205 :         return false;
     736             :     }
     737             : 
     738      163689 :     uint32_t id() const {
     739      163689 :         return id_;
     740             :     }
     741        1534 :     void setId(uint32_t id) {
     742        1534 :         MOZ_ASSERT(!id_);
     743        1534 :         MOZ_ASSERT(id);
     744        1534 :         id_ = id;
     745        1534 :     }
     746         990 :     void setMir(MDefinition* mir) {
     747         990 :         mir_ = mir;
     748         990 :     }
     749       18130 :     MDefinition* mirRaw() const {
     750             :         /* Untyped MIR for this op. Prefer mir() methods in subclasses. */
     751       18130 :         return mir_;
     752             :     }
     753        4042 :     LBlock* block() const {
     754        4042 :         return block_;
     755             :     }
     756        1534 :     void setBlock(LBlock* block) {
     757        1534 :         block_ = block;
     758        1534 :     }
     759             : 
     760             :     // For an instruction which has a MUST_REUSE_INPUT output, whether that
     761             :     // output register will be restored to its original value when bailing out.
     762         879 :     virtual bool recoversInput() const {
     763         879 :         return false;
     764             :     }
     765             : 
     766             :     virtual void dump(GenericPrinter& out);
     767             :     void dump();
     768             :     static void printName(GenericPrinter& out, Opcode op);
     769             :     virtual void printName(GenericPrinter& out);
     770             :     virtual void printOperands(GenericPrinter& out);
     771             : 
     772             :   public:
     773             :     // Opcode testing and casts.
     774             : #   define LIROP(name)                                                      \
     775             :     bool is##name() const {                                                 \
     776             :         return op() == LOp_##name;                                          \
     777             :     }                                                                       \
     778             :     inline L##name* to##name();                                             \
     779             :     inline const L##name* to##name() const;
     780      156212 :     LIR_OPCODE_LIST(LIROP)
     781             : #   undef LIROP
     782             : 
     783             :     virtual void accept(LElementVisitor* visitor) = 0;
     784             : 
     785             : #define LIR_HEADER(opcode)                                                  \
     786             :     Opcode op() const {                                                     \
     787             :         return LInstruction::LOp_##opcode;                                  \
     788             :     }                                                                       \
     789             :     void accept(LElementVisitor* visitor) {                                 \
     790             :         visitor->setElement(this);                                          \
     791             :         visitor->visit##opcode(this);                                       \
     792             :     }
     793             : };
     794             : 
     795             : class LInstruction
     796             :   : public LNode
     797             :   , public TempObject
     798             :   , public InlineListNode<LInstruction>
     799             : {
     800             :     // This snapshot could be set after a ResumePoint.  It is used to restart
     801             :     // from the resume point pc.
     802             :     LSnapshot* snapshot_;
     803             : 
     804             :     // Structure capturing the set of stack slots and registers which are known
     805             :     // to hold either gcthings or Values.
     806             :     LSafepoint* safepoint_;
     807             : 
     808             :     LMoveGroup* inputMoves_;
     809             :     LMoveGroup* fixReuseMoves_;
     810             :     LMoveGroup* movesAfter_;
     811             : 
     812             :   protected:
     813        1788 :     LInstruction()
     814        1788 :       : snapshot_(nullptr),
     815             :         safepoint_(nullptr),
     816             :         inputMoves_(nullptr),
     817             :         fixReuseMoves_(nullptr),
     818        1788 :         movesAfter_(nullptr)
     819        1788 :     { }
     820             : 
     821             :   public:
     822      102750 :     LSnapshot* snapshot() const {
     823      102750 :         return snapshot_;
     824             :     }
     825      108860 :     LSafepoint* safepoint() const {
     826      108860 :         return safepoint_;
     827             :     }
     828         305 :     LMoveGroup* inputMoves() const {
     829         305 :         return inputMoves_;
     830             :     }
     831         283 :     void setInputMoves(LMoveGroup* moves) {
     832         283 :         inputMoves_ = moves;
     833         283 :     }
     834         294 :     LMoveGroup* fixReuseMoves() const {
     835         294 :         return fixReuseMoves_;
     836             :     }
     837           0 :     void setFixReuseMoves(LMoveGroup* moves) {
     838           0 :         fixReuseMoves_ = moves;
     839           0 :     }
     840           0 :     LMoveGroup* movesAfter() const {
     841           0 :         return movesAfter_;
     842             :     }
     843           0 :     void setMovesAfter(LMoveGroup* moves) {
     844           0 :         movesAfter_ = moves;
     845           0 :     }
     846             :     void assignSnapshot(LSnapshot* snapshot);
     847             :     void initSafepoint(TempAllocator& alloc);
     848             : 
     849             :     class InputIterator;
     850             : };
     851             : 
     852             : LInstruction*
     853         835 : LNode::toInstruction()
     854             : {
     855         835 :     MOZ_ASSERT(isInstruction());
     856         835 :     return static_cast<LInstruction*>(this);
     857             : }
     858             : 
     859             : const LInstruction*
     860        9093 : LNode::toInstruction() const
     861             : {
     862        9093 :     MOZ_ASSERT(isInstruction());
     863        9093 :     return static_cast<const LInstruction*>(this);
     864             : }
     865             : 
     866             : class LElementVisitor
     867             : {
     868             :     LNode* ins_;
     869             : 
     870             :   protected:
     871             :     jsbytecode* lastPC_;
     872             :     jsbytecode* lastNotInlinedPC_;
     873             : 
     874         323 :     LNode* instruction() {
     875         323 :         return ins_;
     876             :     }
     877             : 
     878             :   public:
     879        3362 :     void setElement(LNode* ins) {
     880        3362 :         ins_ = ins;
     881        3362 :         if (ins->mirRaw()) {
     882        1630 :             lastPC_ = ins->mirRaw()->trackedPc();
     883        1630 :             if (ins->mirRaw()->trackedTree())
     884        1630 :                 lastNotInlinedPC_ = ins->mirRaw()->profilerLeavePc();
     885             :         }
     886        3362 :     }
     887             : 
     888           8 :     LElementVisitor()
     889           8 :       : ins_(nullptr),
     890             :         lastPC_(nullptr),
     891           8 :         lastNotInlinedPC_(nullptr)
     892           8 :     {}
     893             : 
     894             :   public:
     895             : #define VISIT_INS(op) virtual void visit##op(L##op*) { MOZ_CRASH("NYI: " #op); }
     896           0 :     LIR_OPCODE_LIST(VISIT_INS)
     897             : #undef VISIT_INS
     898             : };
     899             : 
     900             : typedef InlineList<LInstruction>::iterator LInstructionIterator;
     901             : typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
     902             : 
     903             : class MPhi;
     904             : 
     905             : // Phi is a pseudo-instruction that emits no code, and is an annotation for the
     906             : // register allocator. Like its equivalent in MIR, phis are collected at the
     907             : // top of blocks and are meant to be executed in parallel, choosing the input
     908             : // corresponding to the predecessor taken in the control flow graph.
     909             : class LPhi final : public LNode
     910             : {
     911             :     LAllocation* const inputs_;
     912             :     LDefinition def_;
     913             : 
     914             :   public:
     915         216 :     LIR_HEADER(Phi)
     916             : 
     917         175 :     LPhi(MPhi* ins, LAllocation* inputs)
     918         175 :         : inputs_(inputs)
     919             :     {
     920         175 :         setMir(ins);
     921         175 :     }
     922             : 
     923         350 :     size_t numDefs() const {
     924         350 :         return 1;
     925             :     }
     926        1225 :     LDefinition* getDef(size_t index) {
     927        1225 :         MOZ_ASSERT(index == 0);
     928        1225 :         return &def_;
     929             :     }
     930         175 :     void setDef(size_t index, const LDefinition& def) {
     931         175 :         MOZ_ASSERT(index == 0);
     932         175 :         def_ = def;
     933         175 :     }
     934        2772 :     size_t numOperands() const {
     935        2772 :         return mir_->toPhi()->numOperands();
     936             :     }
     937        1720 :     LAllocation* getOperand(size_t index) {
     938        1720 :         MOZ_ASSERT(index < numOperands());
     939        1720 :         return &inputs_[index];
     940             :     }
     941         430 :     void setOperand(size_t index, const LAllocation& a) {
     942         430 :         MOZ_ASSERT(index < numOperands());
     943         430 :         inputs_[index] = a;
     944         430 :     }
     945           0 :     size_t numTemps() const {
     946           0 :         return 0;
     947             :     }
     948           0 :     LDefinition* getTemp(size_t index) {
     949           0 :         MOZ_CRASH("no temps");
     950             :     }
     951           0 :     void setTemp(size_t index, const LDefinition& temp) {
     952           0 :         MOZ_CRASH("no temps");
     953             :     }
     954           0 :     size_t numSuccessors() const {
     955           0 :         return 0;
     956             :     }
     957           0 :     MBasicBlock* getSuccessor(size_t i) const {
     958           0 :         MOZ_CRASH("no successors");
     959             :     }
     960           0 :     void setSuccessor(size_t i, MBasicBlock*) {
     961           0 :         MOZ_CRASH("no successors");
     962             :     }
     963             : };
     964             : 
     965             : class LMoveGroup;
     966             : class LBlock
     967             : {
     968             :     MBasicBlock* block_;
     969             :     FixedList<LPhi> phis_;
     970             :     InlineList<LInstruction> instructions_;
     971             :     LMoveGroup* entryMoveGroup_;
     972             :     LMoveGroup* exitMoveGroup_;
     973             :     Label label_;
     974             : 
     975             :   public:
     976             :     explicit LBlock(MBasicBlock* block);
     977             :     MOZ_MUST_USE bool init(TempAllocator& alloc);
     978             : 
     979        1359 :     void add(LInstruction* ins) {
     980        1359 :         ins->setBlock(this);
     981        1359 :         instructions_.pushBack(ins);
     982        1359 :     }
     983       18940 :     size_t numPhis() const {
     984       18940 :         return phis_.length();
     985             :     }
     986        6109 :     LPhi* getPhi(size_t index) {
     987        6109 :         return &phis_[index];
     988             :     }
     989           0 :     const LPhi* getPhi(size_t index) const {
     990           0 :         return &phis_[index];
     991             :     }
     992      114204 :     MBasicBlock* mir() const {
     993      114204 :         return block_;
     994             :     }
     995        4366 :     LInstructionIterator begin() {
     996        4366 :         return instructions_.begin();
     997             :     }
     998             :     LInstructionIterator begin(LInstruction* at) {
     999             :         return instructions_.begin(at);
    1000             :     }
    1001       11837 :     LInstructionIterator end() {
    1002       11837 :         return instructions_.end();
    1003             :     }
    1004        7666 :     LInstructionReverseIterator rbegin() {
    1005        7666 :         return instructions_.rbegin();
    1006             :     }
    1007       18956 :     LInstructionReverseIterator rbegin(LInstruction* at) {
    1008       18956 :         return instructions_.rbegin(at);
    1009             :     }
    1010      109733 :     LInstructionReverseIterator rend() {
    1011      109733 :         return instructions_.rend();
    1012             :     }
    1013             :     InlineList<LInstruction>& instructions() {
    1014             :         return instructions_;
    1015             :     }
    1016           0 :     void insertAfter(LInstruction* at, LInstruction* ins) {
    1017           0 :         instructions_.insertAfter(at, ins);
    1018           0 :     }
    1019         429 :     void insertBefore(LInstruction* at, LInstruction* ins) {
    1020         429 :         instructions_.insertBefore(at, ins);
    1021         429 :     }
    1022           0 :     const LNode* firstElementWithId() const {
    1023           0 :         return !phis_.empty()
    1024           0 :                ? static_cast<const LNode*>(getPhi(0))
    1025           0 :                : firstInstructionWithId();
    1026             :     }
    1027           0 :     uint32_t firstId() const {
    1028           0 :         return firstElementWithId()->id();
    1029             :     }
    1030           0 :     uint32_t lastId() const {
    1031           0 :         return lastInstructionWithId()->id();
    1032             :     }
    1033             :     const LInstruction* firstInstructionWithId() const;
    1034         403 :     const LInstruction* lastInstructionWithId() const {
    1035         403 :         const LInstruction* last = *instructions_.rbegin();
    1036         403 :         MOZ_ASSERT(last->id());
    1037             :         // The last instruction is a control flow instruction which does not have
    1038             :         // any output.
    1039         403 :         MOZ_ASSERT(last->numDefs() == 0);
    1040         403 :         return last;
    1041             :     }
    1042             : 
    1043             :     // Return the label to branch to when branching to this block.
    1044         506 :     Label* label() {
    1045         506 :         MOZ_ASSERT(!isTrivial());
    1046         506 :         return &label_;
    1047             :     }
    1048             : 
    1049             :     LMoveGroup* getEntryMoveGroup(TempAllocator& alloc);
    1050             :     LMoveGroup* getExitMoveGroup(TempAllocator& alloc);
    1051             : 
    1052             :     // Test whether this basic block is empty except for a simple goto, and
    1053             :     // which is not forming a loop. No code will be emitted for such blocks.
    1054        1911 :     bool isTrivial() {
    1055        1911 :         return begin()->isGoto() && !mir()->isLoopHeader();
    1056             :     }
    1057             : 
    1058             :     void dump(GenericPrinter& out);
    1059             :     void dump();
    1060             : };
    1061             : 
    1062             : namespace details {
    1063             :     template <size_t Defs, size_t Temps>
    1064        1788 :     class LInstructionFixedDefsTempsHelper : public LInstruction
    1065             :     {
    1066             :         mozilla::Array<LDefinition, Defs> defs_;
    1067             :         mozilla::Array<LDefinition, Temps> temps_;
    1068             : 
    1069             :       public:
    1070      158338 :         size_t numDefs() const final override {
    1071      158338 :             return Defs;
    1072             :         }
    1073       53089 :         LDefinition* getDef(size_t index) final override {
    1074       53089 :             return &defs_[index];
    1075             :         }
    1076      133866 :         size_t numTemps() const final override {
    1077      133866 :             return Temps;
    1078             :         }
    1079       28441 :         LDefinition* getTemp(size_t index) final override {
    1080       28441 :             return &temps_[index];
    1081             :         }
    1082             : 
    1083         573 :         void setDef(size_t index, const LDefinition& def) final override {
    1084         573 :             defs_[index] = def;
    1085         573 :         }
    1086         387 :         void setTemp(size_t index, const LDefinition& a) final override {
    1087         387 :             temps_[index] = a;
    1088         387 :         }
    1089             :         void setInt64Temp(size_t index, const LInt64Definition& a) {
    1090             : #if JS_BITS_PER_WORD == 32
    1091             :             temps_[index] = a.low();
    1092             :             temps_[index + 1] = a.high();
    1093             : #else
    1094             :             temps_[index] = a.value();
    1095             : #endif
    1096             :         }
    1097             : 
    1098           0 :         size_t numSuccessors() const override {
    1099           0 :             return 0;
    1100             :         }
    1101           0 :         MBasicBlock* getSuccessor(size_t i) const override {
    1102           0 :             MOZ_ASSERT(false);
    1103             :             return nullptr;
    1104             :         }
    1105           0 :         void setSuccessor(size_t i, MBasicBlock* successor) override {
    1106           0 :             MOZ_ASSERT(false);
    1107             :         }
    1108             : 
    1109             :         // Default accessors, assuming a single input and output, respectively.
    1110          66 :         const LAllocation* input() {
    1111          66 :             MOZ_ASSERT(numOperands() == 1);
    1112          66 :             return getOperand(0);
    1113             :         }
    1114         288 :         const LDefinition* output() {
    1115         288 :             MOZ_ASSERT(numDefs() == 1);
    1116         288 :             return getDef(0);
    1117             :         }
    1118             :     };
    1119             : } // namespace details
    1120             : 
    1121             : template <size_t Defs, size_t Operands, size_t Temps>
    1122        1788 : class LInstructionHelper : public details::LInstructionFixedDefsTempsHelper<Defs, Temps>
    1123             : {
    1124             :     mozilla::Array<LAllocation, Operands> operands_;
    1125             : 
    1126             :   public:
    1127       22696 :     size_t numOperands() const final override {
    1128       22696 :         return Operands;
    1129             :     }
    1130        5666 :     LAllocation* getOperand(size_t index) final override {
    1131        5666 :         return &operands_[index];
    1132             :     }
    1133         727 :     void setOperand(size_t index, const LAllocation& a) final override {
    1134         727 :         operands_[index] = a;
    1135         727 :     }
    1136         160 :     void setBoxOperand(size_t index, const LBoxAllocation& alloc) {
    1137             : #ifdef JS_NUNBOX32
    1138             :         operands_[index + TYPE_INDEX] = alloc.type();
    1139             :         operands_[index + PAYLOAD_INDEX] = alloc.payload();
    1140             : #else
    1141         160 :         operands_[index] = alloc.value();
    1142             : #endif
    1143         160 :     }
    1144           0 :     void setInt64Operand(size_t index, const LInt64Allocation& alloc) {
    1145             : #if JS_BITS_PER_WORD == 32
    1146             :         operands_[index + INT64LOW_INDEX] = alloc.low();
    1147             :         operands_[index + INT64HIGH_INDEX] = alloc.high();
    1148             : #else
    1149           0 :         operands_[index] = alloc.value();
    1150             : #endif
    1151           0 :     }
    1152           0 :     const LInt64Allocation getInt64Operand(size_t offset) {
    1153             : #if JS_BITS_PER_WORD == 32
    1154             :         return LInt64Allocation(operands_[offset + INT64HIGH_INDEX],
    1155             :                                 operands_[offset + INT64LOW_INDEX]);
    1156             : #else
    1157           0 :         return LInt64Allocation(operands_[offset]);
    1158             : #endif
    1159             :     }
    1160             : };
    1161             : 
    1162             : template<size_t Defs, size_t Temps>
    1163           0 : class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<Defs, Temps>
    1164             : {
    1165             :     FixedList<LAllocation> operands_;
    1166             : 
    1167             :   public:
    1168           0 :     MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) {
    1169           0 :         return operands_.init(alloc, length);
    1170             :     }
    1171           0 :     size_t numOperands() const final override {
    1172           0 :         return operands_.length();
    1173             :     }
    1174           0 :     LAllocation* getOperand(size_t index) final override {
    1175           0 :         return &operands_[index];
    1176             :     }
    1177           0 :     void setOperand(size_t index, const LAllocation& a) final override {
    1178           0 :         operands_[index] = a;
    1179           0 :     }
    1180             : };
    1181             : 
    1182             : template <size_t Defs, size_t Operands, size_t Temps>
    1183          38 : class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
    1184             : {
    1185             :   public:
    1186        1920 :     virtual bool isCall() const {
    1187        1920 :         return true;
    1188             :     }
    1189             : };
    1190             : 
    1191             : template <size_t Defs, size_t Temps>
    1192             : class LBinaryCallInstructionHelper : public LCallInstructionHelper<Defs, 2, Temps>
    1193             : {
    1194             :   public:
    1195             :     const LAllocation* lhs() {
    1196             :         return this->getOperand(0);
    1197             :     }
    1198             :     const LAllocation* rhs() {
    1199             :         return this->getOperand(1);
    1200             :     }
    1201             : };
    1202             : 
    1203             : class LRecoverInfo : public TempObject
    1204             : {
    1205             :   public:
    1206             :     typedef Vector<MNode*, 2, JitAllocPolicy> Instructions;
    1207             : 
    1208             :   private:
    1209             :     // List of instructions needed to recover the stack frames.
    1210             :     // Outer frames are stored before inner frames.
    1211             :     Instructions instructions_;
    1212             : 
    1213             :     // Cached offset where this resume point is encoded.
    1214             :     RecoverOffset recoverOffset_;
    1215             : 
    1216             :     explicit LRecoverInfo(TempAllocator& alloc);
    1217             :     MOZ_MUST_USE bool init(MResumePoint* mir);
    1218             : 
    1219             :     // Fill the instruction vector such as all instructions needed for the
    1220             :     // recovery are pushed before the current instruction.
    1221             :     MOZ_MUST_USE bool appendOperands(MNode* ins);
    1222             :     MOZ_MUST_USE bool appendDefinition(MDefinition* def);
    1223             :     MOZ_MUST_USE bool appendResumePoint(MResumePoint* rp);
    1224             :   public:
    1225             :     static LRecoverInfo* New(MIRGenerator* gen, MResumePoint* mir);
    1226             : 
    1227             :     // Resume point of the inner most function.
    1228        1213 :     MResumePoint* mir() const {
    1229        1213 :         return instructions_.back()->toResumePoint();
    1230             :     }
    1231         646 :     RecoverOffset recoverOffset() const {
    1232         646 :         return recoverOffset_;
    1233             :     }
    1234         174 :     void setRecoverOffset(RecoverOffset offset) {
    1235         174 :         MOZ_ASSERT(recoverOffset_ == INVALID_RECOVER_OFFSET);
    1236         174 :         recoverOffset_ = offset;
    1237         174 :     }
    1238             : 
    1239        1634 :     MNode** begin() {
    1240        1634 :         return instructions_.begin();
    1241             :     }
    1242        2043 :     MNode** end() {
    1243        2043 :         return instructions_.end();
    1244             :     }
    1245         174 :     size_t numInstructions() const {
    1246         174 :         return instructions_.length();
    1247             :     }
    1248             : 
    1249             :     class OperandIter
    1250             :     {
    1251             :       private:
    1252             :         MNode** it_;
    1253             :         MNode** end_;
    1254             :         size_t op_;
    1255             : 
    1256             :       public:
    1257         975 :         explicit OperandIter(LRecoverInfo* recoverInfo)
    1258         975 :           : it_(recoverInfo->begin()), end_(recoverInfo->end()), op_(0)
    1259             :         {
    1260         975 :             settle();
    1261         975 :         }
    1262             : 
    1263       21902 :         void settle() {
    1264       21902 :             while ((*it_)->numOperands() == 0) {
    1265           0 :                 ++it_;
    1266           0 :                 op_ = 0;
    1267             :             }
    1268       21902 :         }
    1269             : 
    1270       21902 :         MDefinition* operator*() {
    1271       21902 :             return (*it_)->getOperand(op_);
    1272             :         }
    1273        7321 :         MDefinition* operator ->() {
    1274        7321 :             return (*it_)->getOperand(op_);
    1275             :         }
    1276             : 
    1277       21902 :         OperandIter& operator ++() {
    1278       21902 :             ++op_;
    1279       21902 :             if (op_ == (*it_)->numOperands()) {
    1280        2043 :                 op_ = 0;
    1281        2043 :                 ++it_;
    1282             :             }
    1283       21902 :             if (!*this)
    1284       20927 :                 settle();
    1285             : 
    1286       21902 :             return *this;
    1287             :         }
    1288             : 
    1289       44779 :         explicit operator bool() const {
    1290       44779 :             return it_ == end_;
    1291             :         }
    1292             : 
    1293             : #ifdef DEBUG
    1294             :         bool canOptimizeOutIfUnused();
    1295             : #endif
    1296             :     };
    1297             : };
    1298             : 
    1299             : // An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,
    1300             : // they cannot be shared, as they are filled in by the register allocator in
    1301             : // order to capture the precise low-level stack state in between an
    1302             : // instruction's input and output. During code generation, LSnapshots are
    1303             : // compressed and saved in the compiled script.
    1304             : class LSnapshot : public TempObject
    1305             : {
    1306             :   private:
    1307             :     uint32_t numSlots_;
    1308             :     LAllocation* slots_;
    1309             :     LRecoverInfo* recoverInfo_;
    1310             :     SnapshotOffset snapshotOffset_;
    1311             :     BailoutId bailoutId_;
    1312             :     BailoutKind bailoutKind_;
    1313             : 
    1314             :     LSnapshot(LRecoverInfo* recover, BailoutKind kind);
    1315             :     MOZ_MUST_USE bool init(MIRGenerator* gen);
    1316             : 
    1317             :   public:
    1318             :     static LSnapshot* New(MIRGenerator* gen, LRecoverInfo* recover, BailoutKind kind);
    1319             : 
    1320       57440 :     size_t numEntries() const {
    1321       57440 :         return numSlots_;
    1322             :     }
    1323        5919 :     size_t numSlots() const {
    1324        5919 :         return numSlots_ / BOX_PIECES;
    1325             :     }
    1326        5596 :     LAllocation* payloadOfSlot(size_t i) {
    1327        5596 :         MOZ_ASSERT(i < numSlots());
    1328        5596 :         size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 1);
    1329        5596 :         return getEntry(entryIndex);
    1330             :     }
    1331             : #ifdef JS_NUNBOX32
    1332             :     LAllocation* typeOfSlot(size_t i) {
    1333             :         MOZ_ASSERT(i < numSlots());
    1334             :         size_t entryIndex = (i * BOX_PIECES) + (BOX_PIECES - 2);
    1335             :         return getEntry(entryIndex);
    1336             :     }
    1337             : #endif
    1338       44116 :     LAllocation* getEntry(size_t i) {
    1339       44116 :         MOZ_ASSERT(i < numSlots_);
    1340       44116 :         return &slots_[i];
    1341             :     }
    1342           1 :     void setEntry(size_t i, const LAllocation& alloc) {
    1343           1 :         MOZ_ASSERT(i < numSlots_);
    1344           1 :         slots_[i] = alloc;
    1345           1 :     }
    1346        1001 :     LRecoverInfo* recoverInfo() const {
    1347        1001 :         return recoverInfo_;
    1348             :     }
    1349         370 :     MResumePoint* mir() const {
    1350         370 :         return recoverInfo()->mir();
    1351             :     }
    1352        1008 :     SnapshotOffset snapshotOffset() const {
    1353        1008 :         return snapshotOffset_;
    1354             :     }
    1355           0 :     BailoutId bailoutId() const {
    1356           0 :         return bailoutId_;
    1357             :     }
    1358         323 :     void setSnapshotOffset(SnapshotOffset offset) {
    1359         323 :         MOZ_ASSERT(snapshotOffset_ == INVALID_SNAPSHOT_OFFSET);
    1360         323 :         snapshotOffset_ = offset;
    1361         323 :     }
    1362           0 :     void setBailoutId(BailoutId id) {
    1363           0 :         MOZ_ASSERT(bailoutId_ == INVALID_BAILOUT_ID);
    1364           0 :         bailoutId_ = id;
    1365           0 :     }
    1366         323 :     BailoutKind bailoutKind() const {
    1367         323 :         return bailoutKind_;
    1368             :     }
    1369             :     void rewriteRecoveredInput(LUse input);
    1370             : };
    1371             : 
    1372             : struct SafepointSlotEntry {
    1373             :     // Flag indicating whether this is a slot in the stack or argument space.
    1374             :     uint32_t stack:1;
    1375             : 
    1376             :     // Byte offset of the slot, as in LStackSlot or LArgument.
    1377             :     uint32_t slot:31;
    1378             : 
    1379           0 :     SafepointSlotEntry() { }
    1380        1397 :     SafepointSlotEntry(bool stack, uint32_t slot)
    1381        1397 :       : stack(stack), slot(slot)
    1382        1397 :     { }
    1383             :     explicit SafepointSlotEntry(const LAllocation* a)
    1384             :       : stack(a->isStackSlot()), slot(a->memorySlot())
    1385             :     { }
    1386             : };
    1387             : 
    1388             : struct SafepointNunboxEntry {
    1389             :     uint32_t typeVreg;
    1390             :     LAllocation type;
    1391             :     LAllocation payload;
    1392             : 
    1393             :     SafepointNunboxEntry() { }
    1394             :     SafepointNunboxEntry(uint32_t typeVreg, LAllocation type, LAllocation payload)
    1395             :       : typeVreg(typeVreg), type(type), payload(payload)
    1396             :     { }
    1397             : };
    1398             : 
    1399             : class LSafepoint : public TempObject
    1400             : {
    1401             :     typedef SafepointSlotEntry SlotEntry;
    1402             :     typedef SafepointNunboxEntry NunboxEntry;
    1403             : 
    1404             :   public:
    1405             :     typedef Vector<SlotEntry, 0, JitAllocPolicy> SlotList;
    1406             :     typedef Vector<NunboxEntry, 0, JitAllocPolicy> NunboxList;
    1407             : 
    1408             :   private:
    1409             :     // The information in a safepoint describes the registers and gc related
    1410             :     // values that are live at the start of the associated instruction.
    1411             : 
    1412             :     // The set of registers which are live at an OOL call made within the
    1413             :     // instruction. This includes any registers for inputs which are not
    1414             :     // use-at-start, any registers for temps, and any registers live after the
    1415             :     // call except outputs of the instruction.
    1416             :     //
    1417             :     // For call instructions, the live regs are empty. Call instructions may
    1418             :     // have register inputs or temporaries, which will *not* be in the live
    1419             :     // registers: if passed to the call, the values passed will be marked via
    1420             :     // MarkJitExitFrame, and no registers can be live after the instruction
    1421             :     // except its outputs.
    1422             :     LiveRegisterSet liveRegs_;
    1423             : 
    1424             :     // The subset of liveRegs which contains gcthing pointers.
    1425             :     LiveGeneralRegisterSet gcRegs_;
    1426             : 
    1427             : #ifdef CHECK_OSIPOINT_REGISTERS
    1428             :     // Clobbered regs of the current instruction. This set is never written to
    1429             :     // the safepoint; it's only used by assertions during compilation.
    1430             :     LiveRegisterSet clobberedRegs_;
    1431             : #endif
    1432             : 
    1433             :     // Offset to a position in the safepoint stream, or
    1434             :     // INVALID_SAFEPOINT_OFFSET.
    1435             :     uint32_t safepointOffset_;
    1436             : 
    1437             :     // Assembler buffer displacement to OSI point's call location.
    1438             :     uint32_t osiCallPointOffset_;
    1439             : 
    1440             :     // List of slots which have gcthing pointers.
    1441             :     SlotList gcSlots_;
    1442             : 
    1443             :     // List of slots which have Values.
    1444             :     SlotList valueSlots_;
    1445             : 
    1446             : #ifdef JS_NUNBOX32
    1447             :     // List of registers (in liveRegs) and slots which contain pieces of Values.
    1448             :     NunboxList nunboxParts_;
    1449             : #elif JS_PUNBOX64
    1450             :     // The subset of liveRegs which have Values.
    1451             :     LiveGeneralRegisterSet valueRegs_;
    1452             : #endif
    1453             : 
    1454             :     // The subset of liveRegs which contains pointers to slots/elements.
    1455             :     LiveGeneralRegisterSet slotsOrElementsRegs_;
    1456             : 
    1457             :     // List of slots which have slots/elements pointers.
    1458             :     SlotList slotsOrElementsSlots_;
    1459             : 
    1460             :   public:
    1461        2384 :     void assertInvariants() {
    1462             :         // Every register in valueRegs and gcRegs should also be in liveRegs.
    1463             : #ifndef JS_NUNBOX32
    1464        2384 :         MOZ_ASSERT((valueRegs().bits() & ~liveRegs().gprs().bits()) == 0);
    1465             : #endif
    1466        2384 :         MOZ_ASSERT((gcRegs().bits() & ~liveRegs().gprs().bits()) == 0);
    1467        2384 :     }
    1468             : 
    1469         134 :     explicit LSafepoint(TempAllocator& alloc)
    1470         134 :       : safepointOffset_(INVALID_SAFEPOINT_OFFSET)
    1471             :       , osiCallPointOffset_(0)
    1472             :       , gcSlots_(alloc)
    1473             :       , valueSlots_(alloc)
    1474             : #ifdef JS_NUNBOX32
    1475             :       , nunboxParts_(alloc)
    1476             : #endif
    1477         134 :       , slotsOrElementsSlots_(alloc)
    1478             :     {
    1479         134 :       assertInvariants();
    1480         134 :     }
    1481         321 :     void addLiveRegister(AnyRegister reg) {
    1482         321 :         liveRegs_.addUnchecked(reg);
    1483         321 :         assertInvariants();
    1484         321 :     }
    1485        5544 :     const LiveRegisterSet& liveRegs() const {
    1486        5544 :         return liveRegs_;
    1487             :     }
    1488             : #ifdef CHECK_OSIPOINT_REGISTERS
    1489         206 :     void addClobberedRegister(AnyRegister reg) {
    1490         206 :         clobberedRegs_.addUnchecked(reg);
    1491         206 :         assertInvariants();
    1492         206 :     }
    1493           0 :     const LiveRegisterSet& clobberedRegs() const {
    1494           0 :         return clobberedRegs_;
    1495             :     }
    1496             : #endif
    1497         149 :     void addGcRegister(Register reg) {
    1498         149 :         gcRegs_.addUnchecked(reg);
    1499         149 :         assertInvariants();
    1500         149 :     }
    1501        2604 :     LiveGeneralRegisterSet gcRegs() const {
    1502        2604 :         return gcRegs_;
    1503             :     }
    1504         857 :     MOZ_MUST_USE bool addGcSlot(bool stack, uint32_t slot) {
    1505         857 :         bool result = gcSlots_.append(SlotEntry(stack, slot));
    1506         857 :         if (result)
    1507         857 :             assertInvariants();
    1508         857 :         return result;
    1509             :     }
    1510          39 :     SlotList& gcSlots() {
    1511          39 :         return gcSlots_;
    1512             :     }
    1513             : 
    1514          39 :     SlotList& slotsOrElementsSlots() {
    1515          39 :         return slotsOrElementsSlots_;
    1516             :     }
    1517          40 :     LiveGeneralRegisterSet slotsOrElementsRegs() const {
    1518          40 :         return slotsOrElementsRegs_;
    1519             :     }
    1520           1 :     void addSlotsOrElementsRegister(Register reg) {
    1521           1 :         slotsOrElementsRegs_.addUnchecked(reg);
    1522           1 :         assertInvariants();
    1523           1 :     }
    1524           0 :     MOZ_MUST_USE bool addSlotsOrElementsSlot(bool stack, uint32_t slot) {
    1525           0 :         bool result = slotsOrElementsSlots_.append(SlotEntry(stack, slot));
    1526           0 :         if (result)
    1527           0 :             assertInvariants();
    1528           0 :         return result;
    1529             :     }
    1530           1 :     MOZ_MUST_USE bool addSlotsOrElementsPointer(LAllocation alloc) {
    1531           1 :         if (alloc.isMemory())
    1532           0 :             return addSlotsOrElementsSlot(alloc.isStackSlot(), alloc.memorySlot());
    1533           1 :         MOZ_ASSERT(alloc.isRegister());
    1534           1 :         addSlotsOrElementsRegister(alloc.toRegister().gpr());
    1535           1 :         assertInvariants();
    1536           1 :         return true;
    1537             :     }
    1538           1 :     bool hasSlotsOrElementsPointer(LAllocation alloc) const {
    1539           1 :         if (alloc.isRegister())
    1540           1 :             return slotsOrElementsRegs().has(alloc.toRegister().gpr());
    1541           0 :         for (size_t i = 0; i < slotsOrElementsSlots_.length(); i++) {
    1542           0 :             const SlotEntry& entry = slotsOrElementsSlots_[i];
    1543           0 :             if (entry.stack == alloc.isStackSlot() && entry.slot == alloc.memorySlot())
    1544           0 :                 return true;
    1545             :         }
    1546           0 :         return false;
    1547             :     }
    1548             : 
    1549        1006 :     MOZ_MUST_USE bool addGcPointer(LAllocation alloc) {
    1550        1006 :         if (alloc.isMemory())
    1551         857 :             return addGcSlot(alloc.isStackSlot(), alloc.memorySlot());
    1552         149 :         if (alloc.isRegister())
    1553         149 :             addGcRegister(alloc.toRegister().gpr());
    1554         149 :         assertInvariants();
    1555         149 :         return true;
    1556             :     }
    1557             : 
    1558        3527 :     bool hasGcPointer(LAllocation alloc) const {
    1559        3527 :         if (alloc.isRegister())
    1560         181 :             return gcRegs().has(alloc.toRegister().gpr());
    1561        3346 :         MOZ_ASSERT(alloc.isMemory());
    1562       15650 :         for (size_t i = 0; i < gcSlots_.length(); i++) {
    1563       15650 :             if (gcSlots_[i].stack == alloc.isStackSlot() && gcSlots_[i].slot == alloc.memorySlot())
    1564        3346 :                 return true;
    1565             :         }
    1566           0 :         return false;
    1567             :     }
    1568             : 
    1569         540 :     MOZ_MUST_USE bool addValueSlot(bool stack, uint32_t slot) {
    1570         540 :         bool result = valueSlots_.append(SlotEntry(stack, slot));
    1571         540 :         if (result)
    1572         540 :             assertInvariants();
    1573         540 :         return result;
    1574             :     }
    1575          39 :     SlotList& valueSlots() {
    1576          39 :         return valueSlots_;
    1577             :     }
    1578             : 
    1579        2416 :     bool hasValueSlot(bool stack, uint32_t slot) const {
    1580        9214 :         for (size_t i = 0; i < valueSlots_.length(); i++) {
    1581        8674 :             if (valueSlots_[i].stack == stack && valueSlots_[i].slot == slot)
    1582        1876 :                 return true;
    1583             :         }
    1584         540 :         return false;
    1585             :     }
    1586             : 
    1587             : #ifdef JS_NUNBOX32
    1588             : 
    1589             :     MOZ_MUST_USE bool addNunboxParts(uint32_t typeVreg, LAllocation type, LAllocation payload) {
    1590             :         bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, payload));
    1591             :         if (result)
    1592             :             assertInvariants();
    1593             :         return result;
    1594             :     }
    1595             : 
    1596             :     MOZ_MUST_USE bool addNunboxType(uint32_t typeVreg, LAllocation type) {
    1597             :         for (size_t i = 0; i < nunboxParts_.length(); i++) {
    1598             :             if (nunboxParts_[i].type == type)
    1599             :                 return true;
    1600             :             if (nunboxParts_[i].type == LUse(typeVreg, LUse::ANY)) {
    1601             :                 nunboxParts_[i].type = type;
    1602             :                 return true;
    1603             :             }
    1604             :         }
    1605             : 
    1606             :         // vregs for nunbox pairs are adjacent, with the type coming first.
    1607             :         uint32_t payloadVreg = typeVreg + 1;
    1608             :         bool result = nunboxParts_.append(NunboxEntry(typeVreg, type, LUse(payloadVreg, LUse::ANY)));
    1609             :         if (result)
    1610             :             assertInvariants();
    1611             :         return result;
    1612             :     }
    1613             : 
    1614             :     MOZ_MUST_USE bool addNunboxPayload(uint32_t payloadVreg, LAllocation payload) {
    1615             :         for (size_t i = 0; i < nunboxParts_.length(); i++) {
    1616             :             if (nunboxParts_[i].payload == payload)
    1617             :                 return true;
    1618             :             if (nunboxParts_[i].payload == LUse(payloadVreg, LUse::ANY)) {
    1619             :                 nunboxParts_[i].payload = payload;
    1620             :                 return true;
    1621             :             }
    1622             :         }
    1623             : 
    1624             :         // vregs for nunbox pairs are adjacent, with the type coming first.
    1625             :         uint32_t typeVreg = payloadVreg - 1;
    1626             :         bool result = nunboxParts_.append(NunboxEntry(typeVreg, LUse(typeVreg, LUse::ANY), payload));
    1627             :         if (result)
    1628             :             assertInvariants();
    1629             :         return result;
    1630             :     }
    1631             : 
    1632             :     LAllocation findTypeAllocation(uint32_t typeVreg) {
    1633             :         // Look for some allocation for the specified type vreg, to go with a
    1634             :         // partial nunbox entry for the payload. Note that we don't need to
    1635             :         // look at the value slots in the safepoint, as these aren't used by
    1636             :         // register allocators which add partial nunbox entries.
    1637             :         for (size_t i = 0; i < nunboxParts_.length(); i++) {
    1638             :             if (nunboxParts_[i].typeVreg == typeVreg && !nunboxParts_[i].type.isUse())
    1639             :                 return nunboxParts_[i].type;
    1640             :         }
    1641             :         return LUse(typeVreg, LUse::ANY);
    1642             :     }
    1643             : 
    1644             : #ifdef DEBUG
    1645             :     bool hasNunboxPayload(LAllocation payload) const {
    1646             :         if (payload.isMemory() && hasValueSlot(payload.isStackSlot(), payload.memorySlot()))
    1647             :             return true;
    1648             :         for (size_t i = 0; i < nunboxParts_.length(); i++) {
    1649             :             if (nunboxParts_[i].payload == payload)
    1650             :                 return true;
    1651             :         }
    1652             :         return false;
    1653             :     }
    1654             : #endif
    1655             : 
    1656             :     NunboxList& nunboxParts() {
    1657             :         return nunboxParts_;
    1658             :     }
    1659             : 
    1660             : #elif JS_PUNBOX64
    1661             : 
    1662          26 :     void addValueRegister(Register reg) {
    1663          26 :         valueRegs_.add(reg);
    1664          26 :         assertInvariants();
    1665          26 :     }
    1666        2471 :     LiveGeneralRegisterSet valueRegs() const {
    1667        2471 :         return valueRegs_;
    1668             :     }
    1669             : 
    1670         566 :     MOZ_MUST_USE bool addBoxedValue(LAllocation alloc) {
    1671         566 :         if (alloc.isRegister()) {
    1672          26 :             Register reg = alloc.toRegister().gpr();
    1673          26 :             if (!valueRegs().has(reg))
    1674          26 :                 addValueRegister(reg);
    1675          26 :             return true;
    1676             :         }
    1677         540 :         if (hasValueSlot(alloc.isStackSlot(), alloc.memorySlot()))
    1678           0 :             return true;
    1679         540 :         return addValueSlot(alloc.isStackSlot(), alloc.memorySlot());
    1680             :     }
    1681             : 
    1682        1911 :     bool hasBoxedValue(LAllocation alloc) const {
    1683        1911 :         if (alloc.isRegister())
    1684          35 :             return valueRegs().has(alloc.toRegister().gpr());
    1685        1876 :         return hasValueSlot(alloc.isStackSlot(), alloc.memorySlot());
    1686             :     }
    1687             : 
    1688             : #endif // JS_PUNBOX64
    1689             : 
    1690          86 :     bool encoded() const {
    1691          86 :         return safepointOffset_ != INVALID_SAFEPOINT_OFFSET;
    1692             :     }
    1693          43 :     uint32_t offset() const {
    1694          43 :         MOZ_ASSERT(encoded());
    1695          43 :         return safepointOffset_;
    1696             :     }
    1697          39 :     void setOffset(uint32_t offset) {
    1698          39 :         safepointOffset_ = offset;
    1699          39 :     }
    1700             :     uint32_t osiReturnPointOffset() const {
    1701             :         // In general, pointer arithmetic on code is bad, but in this case,
    1702             :         // getting the return address from a call instruction, stepping over pools
    1703             :         // would be wrong.
    1704             :         return osiCallPointOffset_ + Assembler::PatchWrite_NearCallSize();
    1705             :     }
    1706         212 :     uint32_t osiCallPointOffset() const {
    1707         212 :         return osiCallPointOffset_;
    1708             :     }
    1709         134 :     void setOsiCallPointOffset(uint32_t osiCallPointOffset) {
    1710         134 :         MOZ_ASSERT(!osiCallPointOffset_);
    1711         134 :         osiCallPointOffset_ = osiCallPointOffset;
    1712         134 :     }
    1713             : };
    1714             : 
    1715             : class LInstruction::InputIterator
    1716             : {
    1717             :   private:
    1718             :     LInstruction& ins_;
    1719             :     size_t idx_;
    1720             :     bool snapshot_;
    1721             : 
    1722       38170 :     void handleOperandsEnd() {
    1723             :         // Iterate on the snapshot when iteration over all operands is done.
    1724       38170 :         if (!snapshot_ && idx_ == ins_.numOperands() && ins_.snapshot()) {
    1725        1304 :             idx_ = 0;
    1726        1304 :             snapshot_ = true;
    1727             :         }
    1728       38170 :     }
    1729             : 
    1730             : public:
    1731        6420 :     explicit InputIterator(LInstruction& ins) :
    1732             :       ins_(ins),
    1733             :       idx_(0),
    1734        6420 :       snapshot_(false)
    1735             :     {
    1736        6420 :         handleOperandsEnd();
    1737        6420 :     }
    1738             : 
    1739       69920 :     bool more() const {
    1740       69920 :         if (snapshot_)
    1741       57408 :             return idx_ < ins_.snapshot()->numEntries();
    1742       12512 :         if (idx_ < ins_.numOperands())
    1743        7396 :             return true;
    1744        5116 :         if (ins_.snapshot() && ins_.snapshot()->numEntries())
    1745           0 :             return true;
    1746        5116 :         return false;
    1747             :     }
    1748             : 
    1749          33 :     bool isSnapshotInput() const {
    1750          33 :         return snapshot_;
    1751             :     }
    1752             : 
    1753       31750 :     void next() {
    1754       31750 :         MOZ_ASSERT(more());
    1755       31750 :         idx_++;
    1756       31750 :         handleOperandsEnd();
    1757       31750 :     }
    1758             : 
    1759           0 :     void replace(const LAllocation& alloc) {
    1760           0 :         if (snapshot_)
    1761           0 :             ins_.snapshot()->setEntry(idx_, alloc);
    1762             :         else
    1763           0 :             ins_.setOperand(idx_, alloc);
    1764           0 :     }
    1765             : 
    1766       36052 :     LAllocation* operator*() const {
    1767       36052 :         if (snapshot_)
    1768       31468 :             return ins_.snapshot()->getEntry(idx_);
    1769        4584 :         return ins_.getOperand(idx_);
    1770             :     }
    1771             : 
    1772       22071 :     LAllocation* operator ->() const {
    1773       22071 :         return **this;
    1774             :     }
    1775             : };
    1776             : 
    1777             : class LIRGraph
    1778             : {
    1779             :     struct ValueHasher
    1780             :     {
    1781             :         typedef Value Lookup;
    1782         766 :         static HashNumber hash(const Value& v) {
    1783         766 :             return HashNumber(v.asRawBits());
    1784             :         }
    1785         755 :         static bool match(const Value& lhs, const Value& rhs) {
    1786         755 :             return lhs == rhs;
    1787             :         }
    1788             :     };
    1789             : 
    1790             :     FixedList<LBlock> blocks_;
    1791             :     Vector<Value, 0, JitAllocPolicy> constantPool_;
    1792             :     typedef HashMap<Value, uint32_t, ValueHasher, JitAllocPolicy> ConstantPoolMap;
    1793             :     ConstantPoolMap constantPoolMap_;
    1794             :     Vector<LInstruction*, 0, JitAllocPolicy> safepoints_;
    1795             :     Vector<LInstruction*, 0, JitAllocPolicy> nonCallSafepoints_;
    1796             :     uint32_t numVirtualRegisters_;
    1797             :     uint32_t numInstructions_;
    1798             : 
    1799             :     // Number of stack slots needed for local spills.
    1800             :     uint32_t localSlotCount_;
    1801             :     // Number of stack slots needed for argument construction for calls.
    1802             :     uint32_t argumentSlotCount_;
    1803             : 
    1804             :     // Snapshot taken before any LIR has been lowered.
    1805             :     LSnapshot* entrySnapshot_;
    1806             : 
    1807             :     MIRGraph& mir_;
    1808             : 
    1809             :   public:
    1810             :     explicit LIRGraph(MIRGraph* mir);
    1811             : 
    1812           8 :     MOZ_MUST_USE bool init() {
    1813           8 :         return constantPoolMap_.init() && blocks_.init(mir_.alloc(), mir_.numBlocks());
    1814             :     }
    1815        2825 :     MIRGraph& mir() const {
    1816        2825 :         return mir_;
    1817             :     }
    1818       13311 :     size_t numBlocks() const {
    1819       13311 :         return blocks_.length();
    1820             :     }
    1821       15857 :     LBlock* getBlock(size_t i) {
    1822       15857 :         return &blocks_[i];
    1823             :     }
    1824          16 :     uint32_t numBlockIds() const {
    1825          16 :         return mir_.numBlockIds();
    1826             :     }
    1827         403 :     MOZ_MUST_USE bool initBlock(MBasicBlock* mir) {
    1828         403 :         auto* block = &blocks_[mir->id()];
    1829         403 :         auto* lir = new (block) LBlock(mir);
    1830         403 :         return lir->init(mir_.alloc());
    1831             :     }
    1832        1062 :     uint32_t getVirtualRegister() {
    1833        1062 :         numVirtualRegisters_ += VREG_INCREMENT;
    1834        1062 :         return numVirtualRegisters_;
    1835             :     }
    1836        8980 :     uint32_t numVirtualRegisters() const {
    1837             :         // Virtual registers are 1-based, not 0-based, so add one as a
    1838             :         // convenience for 0-based arrays.
    1839        8980 :         return numVirtualRegisters_ + 1;
    1840             :     }
    1841        1534 :     uint32_t getInstructionId() {
    1842        1534 :         return numInstructions_++;
    1843             :     }
    1844          16 :     uint32_t numInstructions() const {
    1845          16 :         return numInstructions_;
    1846             :     }
    1847           8 :     void setLocalSlotCount(uint32_t localSlotCount) {
    1848           8 :         localSlotCount_ = localSlotCount;
    1849           8 :     }
    1850         658 :     uint32_t localSlotCount() const {
    1851         658 :         return localSlotCount_;
    1852             :     }
    1853             :     // Return the localSlotCount() value rounded up so that it satisfies the
    1854             :     // platform stack alignment requirement, and so that it's a multiple of
    1855             :     // the number of slots per Value.
    1856         119 :     uint32_t paddedLocalSlotCount() const {
    1857             :         // Round to JitStackAlignment, and implicitly to sizeof(Value) as
    1858             :         // JitStackAlignment is a multiple of sizeof(Value). These alignments
    1859             :         // are needed for spilling SIMD registers properly, and for
    1860             :         // StackOffsetOfPassedArg which rounds argument slots to 8-byte
    1861             :         // boundaries.
    1862         119 :         return AlignBytes(localSlotCount(), JitStackAlignment);
    1863             :     }
    1864         106 :     size_t paddedLocalSlotsSize() const {
    1865         106 :         return paddedLocalSlotCount();
    1866             :     }
    1867           8 :     void setArgumentSlotCount(uint32_t argumentSlotCount) {
    1868           8 :         argumentSlotCount_ = argumentSlotCount;
    1869           8 :     }
    1870         190 :     uint32_t argumentSlotCount() const {
    1871         190 :         return argumentSlotCount_;
    1872             :     }
    1873          21 :     size_t argumentsSize() const {
    1874          21 :         return argumentSlotCount() * sizeof(Value);
    1875             :     }
    1876          13 :     uint32_t totalSlotCount() const {
    1877          13 :         return paddedLocalSlotCount() + argumentsSize();
    1878             :     }
    1879             :     MOZ_MUST_USE bool addConstantToPool(const Value& v, uint32_t* index);
    1880          28 :     size_t numConstants() const {
    1881          28 :         return constantPool_.length();
    1882             :     }
    1883           3 :     Value* constantPool() {
    1884           3 :         return &constantPool_[0];
    1885             :     }
    1886           8 :     void setEntrySnapshot(LSnapshot* snapshot) {
    1887           8 :         MOZ_ASSERT(!entrySnapshot_);
    1888           8 :         entrySnapshot_ = snapshot;
    1889           8 :     }
    1890           8 :     LSnapshot* entrySnapshot() const {
    1891           8 :         MOZ_ASSERT(entrySnapshot_);
    1892           8 :         return entrySnapshot_;
    1893             :     }
    1894             :     bool noteNeedsSafepoint(LInstruction* ins);
    1895       14939 :     size_t numNonCallSafepoints() const {
    1896       14939 :         return nonCallSafepoints_.length();
    1897             :     }
    1898       14783 :     LInstruction* getNonCallSafepoint(size_t i) const {
    1899       14783 :         return nonCallSafepoints_[i];
    1900             :     }
    1901       10789 :     size_t numSafepoints() const {
    1902       10789 :         return safepoints_.length();
    1903             :     }
    1904       10182 :     LInstruction* getSafepoint(size_t i) const {
    1905       10182 :         return safepoints_[i];
    1906             :     }
    1907             : 
    1908             :     void dump(GenericPrinter& out);
    1909             :     void dump();
    1910             : };
    1911             : 
    1912        3349 : LAllocation::LAllocation(AnyRegister reg)
    1913             : {
    1914        3349 :     if (reg.isFloat())
    1915        1706 :         *this = LFloatReg(reg.fpu());
    1916             :     else
    1917        1643 :         *this = LGeneralReg(reg.gpr());
    1918        3349 : }
    1919             : 
    1920             : AnyRegister
    1921        9310 : LAllocation::toRegister() const
    1922             : {
    1923        9310 :     MOZ_ASSERT(isRegister());
    1924        9310 :     if (isFloatReg())
    1925          25 :         return AnyRegister(toFloatReg()->reg());
    1926        9285 :     return AnyRegister(toGeneralReg()->reg());
    1927             : }
    1928             : 
    1929             : } // namespace jit
    1930             : } // namespace js
    1931             : 
    1932             : #include "jit/shared/LIR-shared.h"
    1933             : #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
    1934             : # if defined(JS_CODEGEN_X86)
    1935             : #  include "jit/x86/LIR-x86.h"
    1936             : # elif defined(JS_CODEGEN_X64)
    1937             : #  include "jit/x64/LIR-x64.h"
    1938             : # endif
    1939             : # include "jit/x86-shared/LIR-x86-shared.h"
    1940             : #elif defined(JS_CODEGEN_ARM)
    1941             : # include "jit/arm/LIR-arm.h"
    1942             : #elif defined(JS_CODEGEN_ARM64)
    1943             : # include "jit/arm64/LIR-arm64.h"
    1944             : #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
    1945             : # if defined(JS_CODEGEN_MIPS32)
    1946             : #  include "jit/mips32/LIR-mips32.h"
    1947             : # elif defined(JS_CODEGEN_MIPS64)
    1948             : #  include "jit/mips64/LIR-mips64.h"
    1949             : # endif
    1950             : # include "jit/mips-shared/LIR-mips-shared.h"
    1951             : #elif defined(JS_CODEGEN_NONE)
    1952             : # include "jit/none/LIR-none.h"
    1953             : #else
    1954             : # error "Unknown architecture!"
    1955             : #endif
    1956             : 
    1957             : #undef LIR_HEADER
    1958             : 
    1959             : namespace js {
    1960             : namespace jit {
    1961             : 
    1962             : #define LIROP(name)                                                         \
    1963             :     L##name* LNode::to##name()                                              \
    1964             :     {                                                                       \
    1965             :         MOZ_ASSERT(is##name());                                             \
    1966             :         return static_cast<L##name*>(this);                                \
    1967             :     }                                                                       \
    1968             :     const L##name* LNode::to##name() const                                  \
    1969             :     {                                                                       \
    1970             :         MOZ_ASSERT(is##name());                                             \
    1971             :         return static_cast<const L##name*>(this);                          \
    1972             :     }
    1973       29851 :     LIR_OPCODE_LIST(LIROP)
    1974             : #undef LIROP
    1975             : 
    1976             : #define LALLOC_CAST(type)                                                   \
    1977             :     L##type* LAllocation::to##type() {                                      \
    1978             :         MOZ_ASSERT(is##type());                                             \
    1979             :         return static_cast<L##type*>(this);                                \
    1980             :     }
    1981             : #define LALLOC_CONST_CAST(type)                                             \
    1982             :     const L##type* LAllocation::to##type() const {                          \
    1983             :         MOZ_ASSERT(is##type());                                             \
    1984             :         return static_cast<const L##type*>(this);                          \
    1985             :     }
    1986             : 
    1987       13169 : LALLOC_CAST(Use)
    1988       14047 : LALLOC_CONST_CAST(Use)
    1989       12753 : LALLOC_CONST_CAST(GeneralReg)
    1990          74 : LALLOC_CONST_CAST(FloatReg)
    1991       27896 : LALLOC_CONST_CAST(StackSlot)
    1992         738 : LALLOC_CONST_CAST(Argument)
    1993          69 : LALLOC_CONST_CAST(ConstantIndex)
    1994             : 
    1995             : #undef LALLOC_CAST
    1996             : 
    1997             : #ifdef JS_NUNBOX32
    1998             : static inline signed
    1999             : OffsetToOtherHalfOfNunbox(LDefinition::Type type)
    2000             : {
    2001             :     MOZ_ASSERT(type == LDefinition::TYPE || type == LDefinition::PAYLOAD);
    2002             :     signed offset = (type == LDefinition::TYPE)
    2003             :                     ? PAYLOAD_INDEX - TYPE_INDEX
    2004             :                     : TYPE_INDEX - PAYLOAD_INDEX;
    2005             :     return offset;
    2006             : }
    2007             : 
    2008             : static inline void
    2009             : AssertTypesFormANunbox(LDefinition::Type type1, LDefinition::Type type2)
    2010             : {
    2011             :     MOZ_ASSERT((type1 == LDefinition::TYPE && type2 == LDefinition::PAYLOAD) ||
    2012             :                (type2 == LDefinition::TYPE && type1 == LDefinition::PAYLOAD));
    2013             : }
    2014             : 
    2015             : static inline unsigned
    2016             : OffsetOfNunboxSlot(LDefinition::Type type)
    2017             : {
    2018             :     if (type == LDefinition::PAYLOAD)
    2019             :         return NUNBOX32_PAYLOAD_OFFSET;
    2020             :     return NUNBOX32_TYPE_OFFSET;
    2021             : }
    2022             : 
    2023             : // Note that stack indexes for LStackSlot are modelled backwards, so a
    2024             : // double-sized slot starting at 2 has its next word at 1, *not* 3.
    2025             : static inline unsigned
    2026             : BaseOfNunboxSlot(LDefinition::Type type, unsigned slot)
    2027             : {
    2028             :     if (type == LDefinition::PAYLOAD)
    2029             :         return slot + NUNBOX32_PAYLOAD_OFFSET;
    2030             :     return slot + NUNBOX32_TYPE_OFFSET;
    2031             : }
    2032             : #endif
    2033             : 
    2034             : } // namespace jit
    2035             : } // namespace js
    2036             : 
    2037             : #endif /* jit_LIR_h */

Generated by: LCOV version 1.13