LCOV - code coverage report
Current view: top level - js/src/jit - MIR.h (source / functions) Hit Total Coverage
Test: output.info Lines: 2073 6360 32.6 %
Date: 2017-07-14 16:53:18 Functions: 1371 4662 29.4 %
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             : /*
       8             :  * Everything needed to build actual MIR instructions: the actual opcodes and
       9             :  * instructions, the instruction interface, and use chains.
      10             :  */
      11             : 
      12             : #ifndef jit_MIR_h
      13             : #define jit_MIR_h
      14             : 
      15             : #include "mozilla/Alignment.h"
      16             : #include "mozilla/Array.h"
      17             : #include "mozilla/Attributes.h"
      18             : #include "mozilla/MacroForEach.h"
      19             : 
      20             : #include "builtin/SIMD.h"
      21             : #include "jit/AtomicOp.h"
      22             : #include "jit/BaselineIC.h"
      23             : #include "jit/FixedList.h"
      24             : #include "jit/InlineList.h"
      25             : #include "jit/JitAllocPolicy.h"
      26             : #include "jit/MacroAssembler.h"
      27             : #include "jit/MOpcodes.h"
      28             : #include "jit/TypedObjectPrediction.h"
      29             : #include "jit/TypePolicy.h"
      30             : #include "js/HeapAPI.h"
      31             : #include "vm/ArrayObject.h"
      32             : #include "vm/EnvironmentObject.h"
      33             : #include "vm/RegExpObject.h"
      34             : #include "vm/SharedMem.h"
      35             : #include "vm/TypedArrayObject.h"
      36             : #include "vm/UnboxedObject.h"
      37             : 
      38             : namespace js {
      39             : 
      40             : class StringObject;
      41             : 
      42             : namespace jit {
      43             : 
      44             : class BaselineInspector;
      45             : class Range;
      46             : 
      47             : template <typename T>
      48             : struct ResultWithOOM {
      49             :     T value;
      50             :     bool oom;
      51             : 
      52             :     static ResultWithOOM<T> ok(T val) {
      53             :         return { val, false };
      54             :     }
      55             :     static ResultWithOOM<T> fail() {
      56             :         return { T(), true };
      57             :     }
      58             : };
      59             : 
      60             : static inline
      61        5855 : MIRType MIRTypeFromValue(const js::Value& vp)
      62             : {
      63        5855 :     if (vp.isDouble())
      64          30 :         return MIRType::Double;
      65        5825 :     if (vp.isMagic()) {
      66         970 :         switch (vp.whyMagic()) {
      67             :           case JS_OPTIMIZED_ARGUMENTS:
      68           2 :             return MIRType::MagicOptimizedArguments;
      69             :           case JS_OPTIMIZED_OUT:
      70         808 :             return MIRType::MagicOptimizedOut;
      71             :           case JS_ELEMENTS_HOLE:
      72           0 :             return MIRType::MagicHole;
      73             :           case JS_IS_CONSTRUCTING:
      74         141 :             return MIRType::MagicIsConstructing;
      75             :           case JS_UNINITIALIZED_LEXICAL:
      76          19 :             return MIRType::MagicUninitializedLexical;
      77             :           default:
      78           0 :             MOZ_ASSERT_UNREACHABLE("Unexpected magic constant");
      79             :         }
      80             :     }
      81        4855 :     return MIRTypeFromValueType(vp.extractNonDoubleType());
      82             : }
      83             : 
      84             : // If simdType is one of the SIMD types suported by Ion, set mirType to the
      85             : // corresponding MIRType, and return true.
      86             : //
      87             : // If simdType is not suported by Ion, return false.
      88             : static inline MOZ_MUST_USE
      89           0 : bool MaybeSimdTypeToMIRType(SimdType type, MIRType* mirType)
      90             : {
      91           0 :     switch (type) {
      92             :       case SimdType::Uint32x4:
      93           0 :       case SimdType::Int32x4:     *mirType = MIRType::Int32x4;   return true;
      94             :       case SimdType::Uint16x8:
      95           0 :       case SimdType::Int16x8:     *mirType = MIRType::Int16x8;   return true;
      96             :       case SimdType::Uint8x16:
      97           0 :       case SimdType::Int8x16:     *mirType = MIRType::Int8x16;   return true;
      98           0 :       case SimdType::Float32x4:   *mirType = MIRType::Float32x4; return true;
      99           0 :       case SimdType::Bool32x4:    *mirType = MIRType::Bool32x4;  return true;
     100           0 :       case SimdType::Bool16x8:    *mirType = MIRType::Bool16x8;  return true;
     101           0 :       case SimdType::Bool8x16:    *mirType = MIRType::Bool8x16;  return true;
     102           0 :       default:                    return false;
     103             :     }
     104             : }
     105             : 
     106             : // Convert a SimdType to the corresponding MIRType, or crash.
     107             : //
     108             : // Note that this is not an injective mapping: SimdType has signed and unsigned
     109             : // integer types that map to the same MIRType.
     110             : static inline
     111           0 : MIRType SimdTypeToMIRType(SimdType type)
     112             : {
     113           0 :     MIRType ret = MIRType::None;
     114           0 :     JS_ALWAYS_TRUE(MaybeSimdTypeToMIRType(type, &ret));
     115           0 :     return ret;
     116             : }
     117             : 
     118             : static inline
     119           0 : SimdType MIRTypeToSimdType(MIRType type)
     120             : {
     121           0 :     switch (type) {
     122           0 :       case MIRType::Int32x4:   return SimdType::Int32x4;
     123           0 :       case MIRType::Int16x8:   return SimdType::Int16x8;
     124           0 :       case MIRType::Int8x16:   return SimdType::Int8x16;
     125           0 :       case MIRType::Float32x4: return SimdType::Float32x4;
     126           0 :       case MIRType::Bool32x4:  return SimdType::Bool32x4;
     127           0 :       case MIRType::Bool16x8:  return SimdType::Bool16x8;
     128           0 :       case MIRType::Bool8x16:  return SimdType::Bool8x16;
     129           0 :       default:                break;
     130             :     }
     131           0 :     MOZ_CRASH("unhandled MIRType");
     132             : }
     133             : 
     134             : // Get the boolean MIRType with the same shape as type.
     135             : static inline
     136           0 : MIRType MIRTypeToBooleanSimdType(MIRType type)
     137             : {
     138           0 :     return SimdTypeToMIRType(GetBooleanSimdType(MIRTypeToSimdType(type)));
     139             : }
     140             : 
     141             : #define MIR_FLAG_LIST(_)                                                        \
     142             :     _(InWorklist)                                                               \
     143             :     _(EmittedAtUses)                                                            \
     144             :     _(Commutative)                                                              \
     145             :     _(Movable)       /* Allow passes like LICM to move this instruction */      \
     146             :     _(Lowered)       /* (Debug only) has a virtual register */                  \
     147             :     _(Guard)         /* Not removable if uses == 0 */                           \
     148             :                                                                                 \
     149             :     /* Flag an instruction to be considered as a Guard if the instructions
     150             :      * bails out on some inputs.
     151             :      *
     152             :      * Some optimizations can replace an instruction, and leave its operands
     153             :      * unused. When the type information of the operand got used as a
     154             :      * predicate of the transformation, then we have to flag the operands as
     155             :      * GuardRangeBailouts.
     156             :      *
     157             :      * This flag prevents further optimization of instructions, which
     158             :      * might remove the run-time checks (bailout conditions) used as a
     159             :      * predicate of the previous transformation.
     160             :      */                                                                         \
     161             :     _(GuardRangeBailouts)                                                       \
     162             :                                                                                 \
     163             :     /* Keep the flagged instruction in resume points and do not substitute this
     164             :      * instruction by an UndefinedValue. This might be used by call inlining
     165             :      * when a function argument is not used by the inlined instructions.
     166             :      */                                                                         \
     167             :     _(ImplicitlyUsed)                                                           \
     168             :                                                                                 \
     169             :     /* The instruction has been marked dead for lazy removal from resume
     170             :      * points.
     171             :      */                                                                         \
     172             :     _(Unused)                                                                   \
     173             :                                                                                 \
     174             :     /* When a branch is removed, the uses of multiple instructions are removed.
     175             :      * The removal of branches is based on hypotheses.  These hypotheses might
     176             :      * fail, in which case we need to bailout from the current code.
     177             :      *
     178             :      * When we implement a destructive optimization, we need to consider the
     179             :      * failing cases, and consider the fact that we might resume the execution
     180             :      * into a branch which was removed from the compiler.  As such, a
     181             :      * destructive optimization need to take into acount removed branches.
     182             :      *
     183             :      * In order to let destructive optimizations know about removed branches, we
     184             :      * have to annotate instructions with the UseRemoved flag.  This flag
     185             :      * annotates instruction which were used in removed branches.
     186             :      */                                                                         \
     187             :     _(UseRemoved)                                                               \
     188             :                                                                                 \
     189             :     /* Marks if the current instruction should go to the bailout paths instead
     190             :      * of producing code as part of the control flow.  This flag can only be set
     191             :      * on instructions which are only used by ResumePoint or by other flagged
     192             :      * instructions.
     193             :      */                                                                         \
     194             :     _(RecoveredOnBailout)                                                       \
     195             :                                                                                 \
     196             :     /* Some instructions might represent an object, but the memory of these
     197             :      * objects might be incomplete if we have not recovered all the stores which
     198             :      * were supposed to happen before. This flag is used to annotate
     199             :      * instructions which might return a pointer to a memory area which is not
     200             :      * yet fully initialized. This flag is used to ensure that stores are
     201             :      * executed before returning the value.
     202             :      */                                                                         \
     203             :     _(IncompleteObject)                                                         \
     204             :                                                                                 \
     205             :     /* The current instruction got discarded from the MIR Graph. This is useful
     206             :      * when we want to iterate over resume points and instructions, while
     207             :      * handling instructions which are discarded without reporting to the
     208             :      * iterator.
     209             :      */                                                                         \
     210             :     _(Discarded)
     211             : 
     212             : class MDefinition;
     213             : class MInstruction;
     214             : class MBasicBlock;
     215             : class MNode;
     216             : class MUse;
     217             : class MPhi;
     218             : class MIRGraph;
     219             : class MResumePoint;
     220             : class MControlInstruction;
     221             : 
     222             : // Represents a use of a node.
     223             : class MUse : public TempObject, public InlineListNode<MUse>
     224             : {
     225             :     // Grant access to setProducerUnchecked.
     226             :     friend class MDefinition;
     227             :     friend class MPhi;
     228             : 
     229             :     MDefinition* producer_; // MDefinition that is being used.
     230             :     MNode* consumer_;       // The node that is using this operand.
     231             : 
     232             :     // Low-level unchecked edit method for replaceAllUsesWith and
     233             :     // MPhi::removeOperand. This doesn't update use lists!
     234             :     // replaceAllUsesWith and MPhi::removeOperand do that manually.
     235       38821 :     void setProducerUnchecked(MDefinition* producer) {
     236       38821 :         MOZ_ASSERT(consumer_);
     237       38821 :         MOZ_ASSERT(producer_);
     238       38821 :         MOZ_ASSERT(producer);
     239       38821 :         producer_ = producer;
     240       38821 :     }
     241             : 
     242             :   public:
     243             :     // Default constructor for use in vectors.
     244       11936 :     MUse()
     245       11936 :       : producer_(nullptr), consumer_(nullptr)
     246       11936 :     { }
     247             : 
     248             :     // Move constructor for use in vectors. When an MUse is moved, it stays
     249             :     // in its containing use list.
     250         294 :     MUse(MUse&& other)
     251         588 :       : InlineListNode<MUse>(mozilla::Move(other)),
     252         588 :         producer_(other.producer_), consumer_(other.consumer_)
     253         294 :     { }
     254             : 
     255             :     // Construct an MUse initialized with |producer| and |consumer|.
     256        5763 :     MUse(MDefinition* producer, MNode* consumer)
     257        5763 :     {
     258        5763 :         initUnchecked(producer, consumer);
     259        5763 :     }
     260             : 
     261             :     // Set this use, which was previously clear.
     262             :     inline void init(MDefinition* producer, MNode* consumer);
     263             :     // Like init, but works even when the use contains uninitialized data.
     264             :     inline void initUnchecked(MDefinition* producer, MNode* consumer);
     265             :     // Like initUnchecked, but set the producer to nullptr.
     266             :     inline void initUncheckedWithoutProducer(MNode* consumer);
     267             :     // Set this use, which was not previously clear.
     268             :     inline void replaceProducer(MDefinition* producer);
     269             :     // Clear this use.
     270             :     inline void releaseProducer();
     271             : 
     272     1899384 :     MDefinition* producer() const {
     273     1899384 :         MOZ_ASSERT(producer_ != nullptr);
     274     1899384 :         return producer_;
     275             :     }
     276      491152 :     bool hasProducer() const {
     277      491152 :         return producer_ != nullptr;
     278             :     }
     279     3335420 :     MNode* consumer() const {
     280     3335420 :         MOZ_ASSERT(consumer_ != nullptr);
     281     3335420 :         return consumer_;
     282             :     }
     283             : 
     284             : #ifdef DEBUG
     285             :     // Return the operand index of this MUse in its consumer. This is DEBUG-only
     286             :     // as normal code should instead to call indexOf on the casted consumer
     287             :     // directly, to allow it to be devirtualized and inlined.
     288             :     size_t index() const;
     289             : #endif
     290             : };
     291             : 
     292             : typedef InlineList<MUse>::iterator MUseIterator;
     293             : 
     294             : // A node is an entry in the MIR graph. It has two kinds:
     295             : //   MInstruction: an instruction which appears in the IR stream.
     296             : //   MResumePoint: a list of instructions that correspond to the state of the
     297             : //                 interpreter/Baseline stack.
     298             : //
     299             : // Nodes can hold references to MDefinitions. Each MDefinition has a list of
     300             : // nodes holding such a reference (its use chain).
     301             : class MNode : public TempObject
     302             : {
     303             :   protected:
     304             :     MBasicBlock* block_;    // Containing basic block.
     305             : 
     306             :   public:
     307             :     enum Kind {
     308             :         Definition,
     309             :         ResumePoint
     310             :     };
     311             : 
     312       24340 :     MNode()
     313       24340 :       : block_(nullptr)
     314       24340 :     { }
     315             : 
     316        8996 :     explicit MNode(MBasicBlock* block)
     317        8996 :       : block_(block)
     318        8996 :     { }
     319             : 
     320             :     virtual Kind kind() const = 0;
     321             : 
     322             :     // Returns the definition at a given operand.
     323             :     virtual MDefinition* getOperand(size_t index) const = 0;
     324             :     virtual size_t numOperands() const = 0;
     325             :     virtual size_t indexOf(const MUse* u) const = 0;
     326             : 
     327      932887 :     bool isDefinition() const {
     328      932887 :         return kind() == Definition;
     329             :     }
     330       32332 :     bool isResumePoint() const {
     331       32332 :         return kind() == ResumePoint;
     332             :     }
     333     2331087 :     MBasicBlock* block() const {
     334     2331087 :         return block_;
     335             :     }
     336             :     MBasicBlock* caller() const;
     337             : 
     338             :     // Sets an already set operand, updating use information. If you're looking
     339             :     // for setOperand, this is probably what you want.
     340             :     virtual void replaceOperand(size_t index, MDefinition* operand) = 0;
     341             : 
     342             :     // Resets the operand to an uninitialized state, breaking the link
     343             :     // with the previous operand's producer.
     344        2485 :     void releaseOperand(size_t index) {
     345        2485 :         getUseFor(index)->releaseProducer();
     346        2485 :     }
     347        2066 :     bool hasOperand(size_t index) const {
     348        2066 :         return getUseFor(index)->hasProducer();
     349             :     }
     350             : 
     351             :     inline MDefinition* toDefinition();
     352             :     inline MResumePoint* toResumePoint();
     353             : 
     354             :     virtual MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const;
     355             : 
     356             :     virtual void dump(GenericPrinter& out) const = 0;
     357             :     virtual void dump() const = 0;
     358             : 
     359             :   protected:
     360             :     // Need visibility on getUseFor to avoid O(n^2) complexity.
     361             :     friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
     362             : 
     363             :     // Gets the MUse corresponding to given operand.
     364             :     virtual MUse* getUseFor(size_t index) = 0;
     365             :     virtual const MUse* getUseFor(size_t index) const = 0;
     366             : };
     367             : 
     368             : class AliasSet {
     369             :   private:
     370             :     uint32_t flags_;
     371             : 
     372             :   public:
     373             :     enum Flag {
     374             :         None_             = 0,
     375             :         ObjectFields      = 1 << 0, // shape, class, slots, length etc.
     376             :         Element           = 1 << 1, // A Value member of obj->elements or
     377             :                                     // a typed object.
     378             :         UnboxedElement    = 1 << 2, // An unboxed scalar or reference member of
     379             :                                     // a typed array, typed object, or unboxed
     380             :                                     // object.
     381             :         DynamicSlot       = 1 << 3, // A Value member of obj->slots.
     382             :         FixedSlot         = 1 << 4, // A Value member of obj->fixedSlots().
     383             :         DOMProperty       = 1 << 5, // A DOM property
     384             :         FrameArgument     = 1 << 6, // An argument kept on the stack frame
     385             :         WasmGlobalVar     = 1 << 7, // An asm.js/wasm global var
     386             :         WasmHeap          = 1 << 8, // An asm.js/wasm heap load
     387             :         WasmHeapMeta      = 1 << 9, // The asm.js/wasm heap base pointer and
     388             :                                     // bounds check limit, in Tls.
     389             :         TypedArrayLength  = 1 << 10,// A typed array's length
     390             :         Last              = TypedArrayLength,
     391             :         Any               = Last | (Last - 1),
     392             : 
     393             :         NumCategories     = 11,
     394             : 
     395             :         // Indicates load or store.
     396             :         Store_            = 1 << 31
     397             :     };
     398             : 
     399             :     static_assert((1 << NumCategories) - 1 == Any,
     400             :                   "NumCategories must include all flags present in Any");
     401             : 
     402       41007 :     explicit AliasSet(uint32_t flags)
     403       41007 :       : flags_(flags)
     404             :     {
     405       41007 :     }
     406             : 
     407             :   public:
     408             :     static const char* Name(size_t flag);
     409             : 
     410        3146 :     inline bool isNone() const {
     411        3146 :         return flags_ == None_;
     412             :     }
     413         898 :     uint32_t flags() const {
     414         898 :         return flags_ & Any;
     415             :     }
     416       38242 :     inline bool isStore() const {
     417       38242 :         return !!(flags_ & Store_);
     418             :     }
     419         447 :     inline bool isLoad() const {
     420         447 :         return !isStore() && !isNone();
     421             :     }
     422             :     inline AliasSet operator |(const AliasSet& other) const {
     423             :         return AliasSet(flags_ | other.flags_);
     424             :     }
     425           0 :     inline AliasSet operator&(const AliasSet& other) const {
     426           0 :         return AliasSet(flags_ & other.flags_);
     427             :     }
     428       29877 :     static AliasSet None() {
     429       29877 :         return AliasSet(None_);
     430             :     }
     431        3627 :     static AliasSet Load(uint32_t flags) {
     432        3627 :         MOZ_ASSERT(flags && !(flags & Store_));
     433        3627 :         return AliasSet(flags);
     434             :     }
     435        7503 :     static AliasSet Store(uint32_t flags) {
     436        7503 :         MOZ_ASSERT(flags && !(flags & Store_));
     437        7503 :         return AliasSet(flags | Store_);
     438             :     }
     439          17 :     static uint32_t BoxedOrUnboxedElements(JSValueType type) {
     440          17 :         return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement;
     441             :     }
     442             : };
     443             : 
     444             : typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector;
     445             : typedef Vector<MInstruction*, 6, JitAllocPolicy> MInstructionVector;
     446             : typedef Vector<MDefinition*, 1, JitAllocPolicy> MStoreVector;
     447             : 
     448             : class StoreDependency : public TempObject
     449             : {
     450             :     MStoreVector all_;
     451             : 
     452             :   public:
     453           0 :     explicit StoreDependency(TempAllocator& alloc)
     454           0 :       : all_(alloc)
     455           0 :     { }
     456             : 
     457           0 :     MOZ_MUST_USE bool init(MDefinitionVector& all) {
     458           0 :         if (!all_.appendAll(all))
     459           0 :             return false;
     460           0 :         return true;
     461             :     }
     462             : 
     463           0 :     MStoreVector& get() {
     464           0 :         return all_;
     465             :     }
     466             : };
     467             : 
     468             : // An MDefinition is an SSA name.
     469             : class MDefinition : public MNode
     470             : {
     471             :     friend class MBasicBlock;
     472             : 
     473             :   public:
     474             :     enum Opcode {
     475             : #   define DEFINE_OPCODES(op) Op_##op,
     476             :         MIR_OPCODE_LIST(DEFINE_OPCODES)
     477             : #   undef DEFINE_OPCODES
     478             :         Op_Invalid
     479             :     };
     480             : 
     481             :   private:
     482             :     InlineList<MUse> uses_;        // Use chain.
     483             :     uint32_t id_;                  // Instruction ID, which after block re-ordering
     484             :                                    // is sorted within a basic block.
     485             :     uint32_t flags_;               // Bit flags.
     486             :     Range* range_;                 // Any computed range for this def.
     487             :     MIRType resultType_;           // Representation of result type.
     488             :     TemporaryTypeSet* resultTypeSet_; // Optional refinement of the result type.
     489             :     union {
     490             :         MDefinition* loadDependency_;      // Implicit dependency (store, call, etc.) of this
     491             :         StoreDependency* storeDependency_; // instruction. Used by alias analysis, GVN and LICM.
     492             :         uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers.
     493             :     };
     494             : 
     495             :     // Track bailouts by storing the current pc in MIR instruction. Also used
     496             :     // for profiling and keeping track of what the last known pc was.
     497             :     const BytecodeSite* trackedSite_;
     498             : 
     499             :   private:
     500             :     enum Flag {
     501             :         None = 0,
     502             : #   define DEFINE_FLAG(flag) flag,
     503             :         MIR_FLAG_LIST(DEFINE_FLAG)
     504             : #   undef DEFINE_FLAG
     505             :         Total
     506             :     };
     507             : 
     508     1106883 :     bool hasFlags(uint32_t flags) const {
     509     1106883 :         return (flags_ & flags) == flags;
     510             :     }
     511        3016 :     void removeFlags(uint32_t flags) {
     512        3016 :         flags_ &= ~flags;
     513        3016 :     }
     514       33153 :     void setFlags(uint32_t flags) {
     515       33153 :         flags_ |= flags;
     516       33153 :     }
     517             : 
     518             :   protected:
     519       24371 :     void setBlock(MBasicBlock* block) {
     520       24371 :         block_ = block;
     521       24371 :     }
     522             : 
     523             :     static HashNumber addU32ToHash(HashNumber hash, uint32_t data);
     524             : 
     525             :   public:
     526       24340 :     MDefinition()
     527       24340 :       : id_(0),
     528             :         flags_(0),
     529             :         range_(nullptr),
     530             :         resultType_(MIRType::None),
     531             :         resultTypeSet_(nullptr),
     532             :         loadDependency_(nullptr),
     533       24340 :         trackedSite_(nullptr)
     534       24340 :     { }
     535             : 
     536             :     // Copying a definition leaves the list of uses and the block empty.
     537           0 :     explicit MDefinition(const MDefinition& other)
     538           0 :       : id_(0),
     539           0 :         flags_(other.flags_),
     540           0 :         range_(other.range_),
     541           0 :         resultType_(other.resultType_),
     542           0 :         resultTypeSet_(other.resultTypeSet_),
     543           0 :         loadDependency_(other.loadDependency_),
     544           0 :         trackedSite_(other.trackedSite_)
     545           0 :     { }
     546             : 
     547             :     virtual Opcode op() const = 0;
     548             :     virtual const char* opName() const = 0;
     549             :     virtual void accept(MDefinitionVisitor* visitor) = 0;
     550             : 
     551             :     void printName(GenericPrinter& out) const;
     552             :     static void PrintOpcodeName(GenericPrinter& out, Opcode op);
     553             :     virtual void printOpcode(GenericPrinter& out) const;
     554             :     void dump(GenericPrinter& out) const override;
     555             :     void dump() const override;
     556             :     void dumpLocation(GenericPrinter& out) const;
     557             :     void dumpLocation() const;
     558             : 
     559             :     // For LICM.
     560         486 :     virtual bool neverHoist() const { return false; }
     561             : 
     562             :     // Also for LICM. Test whether this definition is likely to be a call, which
     563             :     // would clobber all or many of the floating-point registers, such that
     564             :     // hoisting floating-point constants out of containing loops isn't likely to
     565             :     // be worthwhile.
     566        1583 :     virtual bool possiblyCalls() const { return false; }
     567             : 
     568       21643 :     void setTrackedSite(const BytecodeSite* site) {
     569       21643 :         MOZ_ASSERT(site);
     570       21643 :         trackedSite_ = site;
     571       21643 :     }
     572        2249 :     const BytecodeSite* trackedSite() const {
     573        2249 :         return trackedSite_;
     574             :     }
     575        3318 :     jsbytecode* trackedPc() const {
     576        3318 :         return trackedSite_ ? trackedSite_->pc() : nullptr;
     577             :     }
     578        4437 :     InlineScriptTree* trackedTree() const {
     579        4437 :         return trackedSite_ ? trackedSite_->tree() : nullptr;
     580             :     }
     581        1630 :     TrackedOptimizations* trackedOptimizations() const {
     582        3260 :         return trackedSite_ && trackedSite_->hasOptimizations()
     583        1630 :                ? trackedSite_->optimizations()
     584        1630 :                : nullptr;
     585             :     }
     586             : 
     587             :     JSScript* profilerLeaveScript() const {
     588             :         return trackedTree()->outermostCaller()->script();
     589             :     }
     590             : 
     591        1659 :     jsbytecode* profilerLeavePc() const {
     592             :         // If this is in a top-level function, use the pc directly.
     593        1659 :         if (trackedTree()->isOutermostCaller())
     594        1326 :             return trackedPc();
     595             : 
     596             :         // Walk up the InlineScriptTree chain to find the top-most callPC
     597         333 :         InlineScriptTree* curTree = trackedTree();
     598         333 :         InlineScriptTree* callerTree = curTree->caller();
     599         365 :         while (!callerTree->isOutermostCaller()) {
     600          16 :             curTree = callerTree;
     601          16 :             callerTree = curTree->caller();
     602             :         }
     603             : 
     604             :         // Return the callPc of the topmost inlined script.
     605         333 :         return curTree->callerPc();
     606             :     }
     607             : 
     608             :     // Return the range of this value, *before* any bailout checks. Contrast
     609             :     // this with the type() method, and the Range constructor which takes an
     610             :     // MDefinition*, which describe the value *after* any bailout checks.
     611             :     //
     612             :     // Warning: Range analysis is removing the bit-operations such as '| 0' at
     613             :     // the end of the transformations. Using this function to analyse any
     614             :     // operands after the truncate phase of the range analysis will lead to
     615             :     // errors. Instead, one should define the collectRangeInfoPreTrunc() to set
     616             :     // the right set of flags which are dependent on the range of the inputs.
     617        1552 :     Range* range() const {
     618        1552 :         MOZ_ASSERT(type() != MIRType::None);
     619        1552 :         return range_;
     620             :     }
     621         191 :     void setRange(Range* range) {
     622         191 :         MOZ_ASSERT(type() != MIRType::None);
     623         191 :         range_ = range;
     624         191 :     }
     625             : 
     626             :     virtual HashNumber valueHash() const;
     627         190 :     virtual bool congruentTo(const MDefinition* ins) const {
     628         190 :         return false;
     629             :     }
     630             :     bool congruentIfOperandsEqual(const MDefinition* ins) const;
     631             :     virtual MDefinition* foldsTo(TempAllocator& alloc);
     632             :     virtual void analyzeEdgeCasesForward();
     633             :     virtual void analyzeEdgeCasesBackward();
     634             : 
     635             :     // When a floating-point value is used by nodes which would prefer to
     636             :     // recieve integer inputs, we may be able to help by computing our result
     637             :     // into an integer directly.
     638             :     //
     639             :     // A value can be truncated in 4 differents ways:
     640             :     //   1. Ignore Infinities (x / 0 --> 0).
     641             :     //   2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
     642             :     //   3. Ignore negative zeros. (-0 --> 0)
     643             :     //   4. Ignore remainder. (3 / 4 --> 0)
     644             :     //
     645             :     // Indirect truncation is used to represent that we are interested in the
     646             :     // truncated result, but only if it can safely flow into operations which
     647             :     // are computed modulo 2^32, such as (2) and (3). Infinities are not safe,
     648             :     // as they would have absorbed other math operations. Remainders are not
     649             :     // safe, as fractions can be scaled up by multiplication.
     650             :     //
     651             :     // Division is a particularly interesting node here because it covers all 4
     652             :     // cases even when its own operands are integers.
     653             :     //
     654             :     // Note that these enum values are ordered from least value-modifying to
     655             :     // most value-modifying, and code relies on this ordering.
     656             :     enum TruncateKind {
     657             :         // No correction.
     658             :         NoTruncate = 0,
     659             :         // An integer is desired, but we can't skip bailout checks.
     660             :         TruncateAfterBailouts = 1,
     661             :         // The value will be truncated after some arithmetic (see above).
     662             :         IndirectTruncate = 2,
     663             :         // Direct and infallible truncation to int32.
     664             :         Truncate = 3
     665             :     };
     666             : 
     667           0 :     static const char * TruncateKindString(TruncateKind kind) {
     668           0 :         switch(kind) {
     669             :           case NoTruncate:
     670           0 :             return "NoTruncate";
     671             :           case TruncateAfterBailouts:
     672           0 :             return "TruncateAfterBailouts";
     673             :           case IndirectTruncate:
     674           0 :             return "IndirectTruncate";
     675             :           case Truncate:
     676           0 :             return "Truncate";
     677             :           default:
     678           0 :             MOZ_CRASH("Unknown truncate kind.");
     679             :         }
     680             :     }
     681             : 
     682             :     // |needTruncation| records the truncation kind of the results, such that it
     683             :     // can be used to truncate the operands of this instruction.  If
     684             :     // |needTruncation| function returns true, then the |truncate| function is
     685             :     // called on the same instruction to mutate the instruction, such as
     686             :     // updating the return type, the range and the specialization of the
     687             :     // instruction.
     688             :     virtual bool needTruncation(TruncateKind kind);
     689             :     virtual void truncate();
     690             : 
     691             :     // Determine what kind of truncate this node prefers for the operand at the
     692             :     // given index.
     693             :     virtual TruncateKind operandTruncateKind(size_t index) const;
     694             : 
     695             :     // Compute an absolute or symbolic range for the value of this node.
     696         833 :     virtual void computeRange(TempAllocator& alloc) {
     697         833 :     }
     698             : 
     699             :     // Collect information from the pre-truncated ranges.
     700        1470 :     virtual void collectRangeInfoPreTrunc() {
     701        1470 :     }
     702             : 
     703      183960 :     MNode::Kind kind() const override {
     704      183960 :         return MNode::Definition;
     705             :     }
     706             : 
     707       10696 :     uint32_t id() const {
     708       10696 :         MOZ_ASSERT(block_);
     709       10696 :         return id_;
     710             :     }
     711       31587 :     void setId(uint32_t id) {
     712       31587 :         id_ = id;
     713       31587 :     }
     714             : 
     715             : #define FLAG_ACCESSOR(flag) \
     716             :     bool is##flag() const {\
     717             :         return hasFlags(1 << flag);\
     718             :     }\
     719             :     void set##flag() {\
     720             :         MOZ_ASSERT(!hasFlags(1 << flag));\
     721             :         setFlags(1 << flag);\
     722             :     }\
     723             :     void setNot##flag() {\
     724             :         MOZ_ASSERT(hasFlags(1 << flag));\
     725             :         removeFlags(1 << flag);\
     726             :     }\
     727             :     void set##flag##Unchecked() {\
     728             :         setFlags(1 << flag);\
     729             :     } \
     730             :     void setNot##flag##Unchecked() {\
     731             :         removeFlags(1 << flag);\
     732             :     }
     733             : 
     734     1115605 :     MIR_FLAG_LIST(FLAG_ACCESSOR)
     735             : #undef FLAG_ACCESSOR
     736             : 
     737             :     // Return the type of this value. This may be speculative, and enforced
     738             :     // dynamically with the use of bailout checks. If all the bailout checks
     739             :     // pass, the value will have this type.
     740             :     //
     741             :     // Unless this is an MUrsh that has bailouts disabled, which, as a special
     742             :     // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type()
     743             :     // is MIRType::Int32.
     744      625747 :     MIRType type() const {
     745      625747 :         return resultType_;
     746             :     }
     747             : 
     748       33114 :     TemporaryTypeSet* resultTypeSet() const {
     749       33114 :         return resultTypeSet_;
     750             :     }
     751             :     bool emptyResultTypeSet() const;
     752             : 
     753        6883 :     bool mightBeType(MIRType type) const {
     754        6883 :         MOZ_ASSERT(type != MIRType::Value);
     755        6883 :         MOZ_ASSERT(type != MIRType::ObjectOrNull);
     756             : 
     757        6883 :         if (type == this->type())
     758          64 :             return true;
     759             : 
     760        6819 :         if (this->type() == MIRType::ObjectOrNull)
     761           0 :             return type == MIRType::Object || type == MIRType::Null;
     762             : 
     763        6819 :         if (this->type() == MIRType::Value)
     764        2359 :             return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type);
     765             : 
     766        4460 :         return false;
     767             :     }
     768             : 
     769             :     bool mightBeMagicType() const;
     770             : 
     771             :     bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
     772             : 
     773             :     // Float32 specialization operations (see big comment in IonAnalysis before the Float32
     774             :     // specialization algorithm).
     775           0 :     virtual bool isFloat32Commutative() const { return false; }
     776          66 :     virtual bool canProduceFloat32() const { return false; }
     777           0 :     virtual bool canConsumeFloat32(MUse* use) const { return false; }
     778           0 :     virtual void trySpecializeFloat32(TempAllocator& alloc) {}
     779             : #ifdef DEBUG
     780             :     // Used during the pass that checks that Float32 flow into valid MDefinitions
     781           0 :     virtual bool isConsistentFloat32Use(MUse* use) const {
     782           0 :         return type() == MIRType::Float32 || canConsumeFloat32(use);
     783             :     }
     784             : #endif
     785             : 
     786             :     // Returns the beginning of this definition's use chain.
     787       59303 :     MUseIterator usesBegin() const {
     788       59303 :         return uses_.begin();
     789             :     }
     790             : 
     791             :     // Returns the end of this definition's use chain.
     792      595952 :     MUseIterator usesEnd() const {
     793      595952 :         return uses_.end();
     794             :     }
     795             : 
     796         617 :     bool canEmitAtUses() const {
     797         617 :         return !isEmittedAtUses();
     798             :     }
     799             : 
     800             :     // Removes a use at the given position
     801       18320 :     void removeUse(MUse* use) {
     802       18320 :         uses_.remove(use);
     803       18320 :     }
     804             : 
     805             : #if defined(DEBUG) || defined(JS_JITSPEW)
     806             :     // Number of uses of this instruction. This function is only available
     807             :     // in DEBUG mode since it requires traversing the list. Most users should
     808             :     // use hasUses() or hasOneUse() instead.
     809             :     size_t useCount() const;
     810             : 
     811             :     // Number of uses of this instruction (only counting MDefinitions, ignoring
     812             :     // MResumePoints). This function is only available in DEBUG mode since it
     813             :     // requires traversing the list. Most users should use hasUses() or
     814             :     // hasOneUse() instead.
     815             :     size_t defUseCount() const;
     816             : #endif
     817             : 
     818             :     // Test whether this MDefinition has exactly one use.
     819             :     bool hasOneUse() const;
     820             : 
     821             :     // Test whether this MDefinition has exactly one use.
     822             :     // (only counting MDefinitions, ignoring MResumePoints)
     823             :     bool hasOneDefUse() const;
     824             : 
     825             :     // Test whether this MDefinition has at least one use.
     826             :     // (only counting MDefinitions, ignoring MResumePoints)
     827             :     bool hasDefUses() const;
     828             : 
     829             :     // Test whether this MDefinition has at least one non-recovered use.
     830             :     // (only counting MDefinitions, ignoring MResumePoints)
     831             :     bool hasLiveDefUses() const;
     832             : 
     833       75681 :     bool hasUses() const {
     834       75681 :         return !uses_.empty();
     835             :     }
     836             : 
     837        2170 :     void addUse(MUse* use) {
     838        2170 :         MOZ_ASSERT(use->producer() == this);
     839        2170 :         uses_.pushFront(use);
     840        2170 :     }
     841      141469 :     void addUseUnchecked(MUse* use) {
     842      141469 :         MOZ_ASSERT(use->producer() == this);
     843      141469 :         uses_.pushFrontUnchecked(use);
     844      141469 :     }
     845         473 :     void replaceUse(MUse* old, MUse* now) {
     846         473 :         MOZ_ASSERT(now->producer() == this);
     847         473 :         uses_.replace(old, now);
     848         473 :     }
     849             : 
     850             :     // Replace the current instruction by a dominating instruction |dom| in all
     851             :     // uses of the current instruction.
     852             :     void replaceAllUsesWith(MDefinition* dom);
     853             : 
     854             :     // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
     855             :     void justReplaceAllUsesWith(MDefinition* dom);
     856             : 
     857             :     // Like justReplaceAllUsesWith, but doesn't replace its own use to the
     858             :     // dominating instruction (which would introduce a circular dependency).
     859             :     void justReplaceAllUsesWithExcept(MDefinition* dom);
     860             : 
     861             :     // Replace the current instruction by an optimized-out constant in all uses
     862             :     // of the current instruction. Note, that optimized-out constant should not
     863             :     // be observed, and thus they should not flow in any computation.
     864             :     MOZ_MUST_USE bool optimizeOutAllUses(TempAllocator& alloc);
     865             : 
     866             :     // Replace the current instruction by a dominating instruction |dom| in all
     867             :     // instruction, but keep the current instruction for resume point and
     868             :     // instruction which are recovered on bailouts.
     869             :     void replaceAllLiveUsesWith(MDefinition* dom);
     870             : 
     871             :     // Mark this instruction as having replaced all uses of ins, as during GVN,
     872             :     // returning false if the replacement should not be performed. For use when
     873             :     // GVN eliminates instructions which are not equivalent to one another.
     874          57 :     virtual MOZ_MUST_USE bool updateForReplacement(MDefinition* ins) {
     875          57 :         return true;
     876             :     }
     877             : 
     878        1138 :     void setVirtualRegister(uint32_t vreg) {
     879        1138 :         virtualRegister_ = vreg;
     880        1138 :         setLoweredUnchecked();
     881        1138 :     }
     882        6554 :     uint32_t virtualRegister() const {
     883        6554 :         MOZ_ASSERT(isLowered());
     884        6554 :         return virtualRegister_;
     885             :     }
     886             : 
     887             :   public:
     888             :     // Opcode testing and casts.
     889      597703 :     template<typename MIRType> bool is() const {
     890      597703 :         return op() == MIRType::classOpcode;
     891             :     }
     892       19099 :     template<typename MIRType> MIRType* to() {
     893       19099 :         MOZ_ASSERT(this->is<MIRType>());
     894       19099 :         return static_cast<MIRType*>(this);
     895             :     }
     896        4576 :     template<typename MIRType> const MIRType* to() const {
     897        4576 :         MOZ_ASSERT(this->is<MIRType>());
     898        4576 :         return static_cast<const MIRType*>(this);
     899             :     }
     900             : #   define OPCODE_CASTS(opcode)           \
     901             :     bool is##opcode() const {             \
     902             :         return this->is<M##opcode>();     \
     903             :     }                                     \
     904             :     M##opcode* to##opcode() {             \
     905             :         return this->to<M##opcode>();     \
     906             :     }                                     \
     907             :     const M##opcode* to##opcode() const { \
     908             :         return this->to<M##opcode>();     \
     909             :     }
     910      597705 :     MIR_OPCODE_LIST(OPCODE_CASTS)
     911             : #   undef OPCODE_CASTS
     912             : 
     913             :     inline MConstant* maybeConstantValue();
     914             : 
     915             :     inline MInstruction* toInstruction();
     916             :     inline const MInstruction* toInstruction() const;
     917       59679 :     bool isInstruction() const {
     918       59679 :         return !isPhi();
     919             :     }
     920             : 
     921       21063 :     virtual bool isControlInstruction() const {
     922       21063 :         return false;
     923             :     }
     924             :     inline MControlInstruction* toControlInstruction();
     925             : 
     926       25072 :     void setResultType(MIRType type) {
     927       25072 :         resultType_ = type;
     928       25072 :     }
     929       10750 :     void setResultTypeSet(TemporaryTypeSet* types) {
     930       10750 :         resultTypeSet_ = types;
     931       10750 :     }
     932        5665 :     virtual AliasSet getAliasSet() const {
     933             :         // Instructions are effectful by default.
     934        5665 :         return AliasSet::Store(AliasSet::Any);
     935             :     }
     936             : 
     937       14513 :     MDefinition* dependency() const {
     938       14513 :         if (getAliasSet().isStore())
     939         304 :             return nullptr;
     940       14209 :         return loadDependency_;
     941             :     }
     942         281 :     void setDependency(MDefinition* dependency) {
     943         281 :         MOZ_ASSERT(!getAliasSet().isStore());
     944         281 :         loadDependency_ = dependency;
     945         281 :     }
     946           0 :     void setStoreDependency(StoreDependency* dependency) {
     947           0 :         MOZ_ASSERT(getAliasSet().isStore());
     948           0 :         storeDependency_ = dependency;
     949           0 :     }
     950           0 :     StoreDependency* storeDependency() {
     951           0 :         MOZ_ASSERT_IF(!getAliasSet().isStore(), !storeDependency_);
     952           0 :         return storeDependency_;
     953             :     }
     954       21111 :     bool isEffectful() const {
     955       21111 :         return getAliasSet().isStore();
     956             :     }
     957             : 
     958             : #ifdef DEBUG
     959         120 :     virtual bool needsResumePoint() const {
     960             :         // Return whether this instruction should have its own resume point.
     961         120 :         return isEffectful();
     962             :     }
     963             : #endif
     964             : 
     965             :     enum class AliasType : uint32_t {
     966             :         NoAlias = 0,
     967             :         MayAlias = 1,
     968             :         MustAlias = 2
     969             :     };
     970         101 :     virtual AliasType mightAlias(const MDefinition* store) const {
     971             :         // Return whether this load may depend on the specified store, given
     972             :         // that the alias sets intersect. This may be refined to exclude
     973             :         // possible aliasing in cases where alias set flags are too imprecise.
     974         101 :         if (!(getAliasSet().flags() & store->getAliasSet().flags()))
     975           0 :             return AliasType::NoAlias;
     976         101 :         MOZ_ASSERT(!isEffectful() && store->isEffectful());
     977         101 :         return AliasType::MayAlias;
     978             :     }
     979             : 
     980        1473 :     virtual bool canRecoverOnBailout() const {
     981        1473 :         return false;
     982             :     }
     983             : };
     984             : 
     985             : // An MUseDefIterator walks over uses in a definition, skipping any use that is
     986             : // not a definition. Items from the use list must not be deleted during
     987             : // iteration.
     988             : class MUseDefIterator
     989             : {
     990             :     const MDefinition* def_;
     991             :     MUseIterator current_;
     992             : 
     993        4383 :     MUseIterator search(MUseIterator start) {
     994        4383 :         MUseIterator i(start);
     995       68837 :         for (; i != def_->usesEnd(); i++) {
     996       35478 :             if (i->consumer()->isDefinition())
     997        3251 :                 return i;
     998             :         }
     999        1132 :         return def_->usesEnd();
    1000             :     }
    1001             : 
    1002             :   public:
    1003        1253 :     explicit MUseDefIterator(const MDefinition* def)
    1004        1253 :       : def_(def),
    1005        1253 :         current_(search(def->usesBegin()))
    1006        1253 :     { }
    1007             : 
    1008        4383 :     explicit operator bool() const {
    1009        4383 :         return current_ != def_->usesEnd();
    1010             :     }
    1011        3130 :     MUseDefIterator operator ++() {
    1012        3130 :         MOZ_ASSERT(current_ != def_->usesEnd());
    1013        3130 :         ++current_;
    1014        3130 :         current_ = search(current_);
    1015        3130 :         return *this;
    1016             :     }
    1017        3130 :     MUseDefIterator operator ++(int) {
    1018        3130 :         MUseDefIterator old(*this);
    1019        3130 :         operator++();
    1020        3130 :         return old;
    1021             :     }
    1022        1027 :     MUse* use() const {
    1023        1027 :         return *current_;
    1024             :     }
    1025        4656 :     MDefinition* def() const {
    1026        4656 :         return current_->consumer()->toDefinition();
    1027             :     }
    1028             : };
    1029             : 
    1030             : #ifdef DEBUG
    1031             : bool
    1032             : IonCompilationCanUseNurseryPointers();
    1033             : #endif
    1034             : 
    1035             : // Helper class to check that GC pointers embedded in MIR instructions are in
    1036             : // in the nursery only when the store buffer has been marked as needing to
    1037             : // cancel all ion compilations. Otherwise, off-thread Ion compilation and
    1038             : // nursery GCs can happen in parallel, so it's invalid to store pointers to
    1039             : // nursery things. There's no need to root these pointers, as GC is suppressed
    1040             : // during compilation and off-thread compilations are canceled on major GCs.
    1041             : template <typename T>
    1042             : class CompilerGCPointer
    1043             : {
    1044             :     js::gc::Cell* ptr_;
    1045             : 
    1046             :   public:
    1047        1397 :     explicit CompilerGCPointer(T ptr)
    1048        1397 :       : ptr_(ptr)
    1049             :     {
    1050        1397 :         MOZ_ASSERT_IF(IsInsideNursery(ptr), IonCompilationCanUseNurseryPointers());
    1051        1397 :         MOZ_ASSERT_IF(!CurrentThreadIsIonCompiling(), TlsContext.get()->suppressGC);
    1052        1397 :     }
    1053             : 
    1054         424 :     operator T() const { return static_cast<T>(ptr_); }
    1055          73 :     T operator->() const { return static_cast<T>(ptr_); }
    1056             : 
    1057             :   private:
    1058             :     CompilerGCPointer() = delete;
    1059             :     CompilerGCPointer(const CompilerGCPointer<T>&) = delete;
    1060             :     CompilerGCPointer<T>& operator=(const CompilerGCPointer<T>&) = delete;
    1061             : };
    1062             : 
    1063             : typedef CompilerGCPointer<JSObject*> CompilerObject;
    1064             : typedef CompilerGCPointer<NativeObject*> CompilerNativeObject;
    1065             : typedef CompilerGCPointer<JSFunction*> CompilerFunction;
    1066             : typedef CompilerGCPointer<JSScript*> CompilerScript;
    1067             : typedef CompilerGCPointer<PropertyName*> CompilerPropertyName;
    1068             : typedef CompilerGCPointer<Shape*> CompilerShape;
    1069             : typedef CompilerGCPointer<ObjectGroup*> CompilerObjectGroup;
    1070             : 
    1071             : class MRootList : public TempObject
    1072             : {
    1073             :   public:
    1074             :     using RootVector = Vector<void*, 0, JitAllocPolicy>;
    1075             : 
    1076             :   private:
    1077             :     mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit, mozilla::Maybe<RootVector>> roots_;
    1078             : 
    1079             :     MRootList(const MRootList&) = delete;
    1080             :     void operator=(const MRootList&) = delete;
    1081             : 
    1082             :   public:
    1083             :     explicit MRootList(TempAllocator& alloc);
    1084             : 
    1085             :     void trace(JSTracer* trc);
    1086             : 
    1087             :     template <typename T>
    1088         389 :     MOZ_MUST_USE bool append(T ptr) {
    1089         389 :         if (ptr)
    1090         389 :             return roots_[JS::MapTypeToRootKind<T>::kind]->append(ptr);
    1091           0 :         return true;
    1092             :     }
    1093             : 
    1094             :     template <typename T>
    1095          74 :     MOZ_MUST_USE bool append(const CompilerGCPointer<T>& ptr) {
    1096          74 :         return append(static_cast<T>(ptr));
    1097             :     }
    1098           0 :     MOZ_MUST_USE bool append(const ReceiverGuard& guard) {
    1099           0 :         return append(guard.group) && append(guard.shape);
    1100             :     }
    1101             : };
    1102             : 
    1103             : // An instruction is an SSA name that is inserted into a basic block's IR
    1104             : // stream.
    1105             : class MInstruction
    1106             :   : public MDefinition,
    1107             :     public InlineListNode<MInstruction>
    1108             : {
    1109             :     MResumePoint* resumePoint_;
    1110             : 
    1111             :   protected:
    1112             :     // All MInstructions are using the "MFoo::New(alloc)" notation instead of
    1113             :     // the TempObject new operator. This code redefines the new operator as
    1114             :     // protected, and delegates to the TempObject new operator. Thus, the
    1115             :     // following code prevents calls to "new(alloc) MFoo" outside the MFoo
    1116             :     // members.
    1117         217 :     inline void* operator new(size_t nbytes, TempAllocator::Fallible view) throw() {
    1118         217 :         return TempObject::operator new(nbytes, view);
    1119             :     }
    1120       21395 :     inline void* operator new(size_t nbytes, TempAllocator& alloc) {
    1121       21395 :         return TempObject::operator new(nbytes, alloc);
    1122             :     }
    1123             :     template <class T>
    1124             :     inline void* operator new(size_t nbytes, T* pos) {
    1125             :         return TempObject::operator new(nbytes, pos);
    1126             :     }
    1127             : 
    1128             :   public:
    1129       21612 :     MInstruction()
    1130       21612 :       : resumePoint_(nullptr)
    1131       21612 :     { }
    1132             : 
    1133             :     // Copying an instruction leaves the block and resume point as empty.
    1134           0 :     explicit MInstruction(const MInstruction& other)
    1135           0 :       : MDefinition(other),
    1136           0 :         resumePoint_(nullptr)
    1137           0 :     { }
    1138             : 
    1139             :     // Convenient function used for replacing a load by the value of the store
    1140             :     // if the types are match, and boxing the value if they do not match.
    1141             :     MDefinition* foldsToStore(TempAllocator& alloc);
    1142             : 
    1143             :     void setResumePoint(MResumePoint* resumePoint);
    1144             : 
    1145             :     // Used to transfer the resume point to the rewritten instruction.
    1146             :     void stealResumePoint(MInstruction* ins);
    1147             :     void moveResumePointAsEntry();
    1148             :     void clearResumePoint();
    1149      103627 :     MResumePoint* resumePoint() const {
    1150      103627 :         return resumePoint_;
    1151             :     }
    1152             : 
    1153             :     // For instructions which can be cloned with new inputs, with all other
    1154             :     // information being the same. clone() implementations do not need to worry
    1155             :     // about cloning generic MInstruction/MDefinition state like flags and
    1156             :     // resume points.
    1157           0 :     virtual bool canClone() const {
    1158           0 :         return false;
    1159             :     }
    1160           0 :     virtual MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const {
    1161           0 :         MOZ_CRASH();
    1162             :     }
    1163             : 
    1164             :     // MIR instructions containing GC pointers should override this to append
    1165             :     // these pointers to the root list.
    1166        1621 :     virtual bool appendRoots(MRootList& roots) const {
    1167        1621 :         return true;
    1168             :     }
    1169             : 
    1170             :     // Instructions needing to hook into type analysis should return a
    1171             :     // TypePolicy.
    1172             :     virtual TypePolicy* typePolicy() = 0;
    1173             :     virtual MIRType typePolicySpecialization() = 0;
    1174             : };
    1175             : 
    1176             : #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                       \
    1177             :     static const Opcode classOpcode = MDefinition::Op_##opcode;             \
    1178             :     using MThisOpcode = M##opcode;                                          \
    1179             :     Opcode op() const override {                                            \
    1180             :         return classOpcode;                                                 \
    1181             :     }                                                                       \
    1182             :     const char* opName() const override {                                   \
    1183             :         return #opcode;                                                     \
    1184             :     }                                                                       \
    1185             :     void accept(MDefinitionVisitor* visitor) override {                     \
    1186             :         visitor->visit##opcode(this);                                       \
    1187             :     }
    1188             : 
    1189             : #define INSTRUCTION_HEADER(opcode)                                          \
    1190             :     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)                           \
    1191             :     virtual TypePolicy* typePolicy() override;                              \
    1192             :     virtual MIRType typePolicySpecialization() override;
    1193             : 
    1194             : #define ALLOW_CLONE(typename)                                               \
    1195             :     bool canClone() const override {                                        \
    1196             :         return true;                                                        \
    1197             :     }                                                                       \
    1198             :     MInstruction* clone(TempAllocator& alloc,                               \
    1199             :                         const MDefinitionVector& inputs) const override {   \
    1200             :         MInstruction* res = new(alloc) typename(*this);                     \
    1201             :         for (size_t i = 0; i < numOperands(); i++)                          \
    1202             :             res->replaceOperand(i, inputs[i]);                              \
    1203             :         return res;                                                         \
    1204             :     }
    1205             : 
    1206             : // Adds MFoo::New functions which are mirroring the arguments of the
    1207             : // constructors. Opcodes which are using this macro can be called with a
    1208             : // TempAllocator, or the fallible version of the TempAllocator.
    1209             : #define TRIVIAL_NEW_WRAPPERS                                                \
    1210             :     template <typename... Args>                                             \
    1211             :     static MThisOpcode* New(TempAllocator& alloc, Args&&... args) {         \
    1212             :         return new(alloc) MThisOpcode(mozilla::Forward<Args>(args)...);     \
    1213             :     }                                                                       \
    1214             :     template <typename... Args>                                             \
    1215             :     static MThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args)  \
    1216             :     {                                                                       \
    1217             :         return new(alloc) MThisOpcode(mozilla::Forward<Args>(args)...);     \
    1218             :     }
    1219             : 
    1220             : 
    1221             : // These macros are used as a syntactic sugar for writting getOperand
    1222             : // accessors. They are meant to be used in the body of MIR Instructions as
    1223             : // follows:
    1224             : //
    1225             : //   public:
    1226             : //     INSTRUCTION_HEADER(Foo)
    1227             : //     NAMED_OPERANDS((0, lhs), (1, rhs))
    1228             : //
    1229             : // The above example defines 2 accessors, one named "lhs" accessing the first
    1230             : // operand, and a one named "rhs" accessing the second operand.
    1231             : #define NAMED_OPERAND_ACCESSOR(Index, Name)                                 \
    1232             :     MDefinition* Name() const {                                             \
    1233             :         return getOperand(Index);                                           \
    1234             :     }
    1235             : #define NAMED_OPERAND_ACCESSOR_APPLY(Args)                                  \
    1236             :     NAMED_OPERAND_ACCESSOR Args
    1237             : #define NAMED_OPERANDS(...)                                                 \
    1238             :     MOZ_FOR_EACH(NAMED_OPERAND_ACCESSOR_APPLY, (), (__VA_ARGS__))
    1239             : 
    1240             : template <size_t Arity>
    1241             : class MAryInstruction : public MInstruction
    1242             : {
    1243             :     mozilla::Array<MUse, Arity> operands_;
    1244             : 
    1245             :   protected:
    1246       29873 :     MUse* getUseFor(size_t index) final override {
    1247       29873 :         return &operands_[index];
    1248             :     }
    1249         233 :     const MUse* getUseFor(size_t index) const final override {
    1250         233 :         return &operands_[index];
    1251             :     }
    1252       10393 :     void initOperand(size_t index, MDefinition* operand) {
    1253       10393 :         operands_[index].init(operand, this);
    1254       10393 :     }
    1255             : 
    1256             :   public:
    1257       60795 :     MDefinition* getOperand(size_t index) const final override {
    1258       60795 :         return operands_[index].producer();
    1259             :     }
    1260      104443 :     size_t numOperands() const final override {
    1261      104443 :         return Arity;
    1262             :     }
    1263             : #ifdef DEBUG
    1264             :     static const size_t staticNumOperands = Arity;
    1265             : #endif
    1266       30159 :     size_t indexOf(const MUse* u) const final override {
    1267       30159 :         MOZ_ASSERT(u >= &operands_[0]);
    1268       30159 :         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
    1269       30159 :         return u - &operands_[0];
    1270             :     }
    1271         119 :     void replaceOperand(size_t index, MDefinition* operand) final override {
    1272         119 :         operands_[index].replaceProducer(operand);
    1273         119 :     }
    1274             : 
    1275       16287 :     MAryInstruction() { }
    1276             : 
    1277           0 :     explicit MAryInstruction(const MAryInstruction<Arity>& other)
    1278           0 :       : MInstruction(other)
    1279             :     {
    1280           0 :         for (int i = 0; i < (int) Arity; i++) // N.B. use |int| to avoid warnings when Arity == 0
    1281           0 :             operands_[i].init(other.operands_[i].producer(), this);
    1282           0 :     }
    1283             : };
    1284             : 
    1285        8187 : class MNullaryInstruction
    1286             :   : public MAryInstruction<0>,
    1287             :     public NoTypePolicy::Data
    1288             : { };
    1289             : 
    1290           0 : class MUnaryInstruction : public MAryInstruction<1>
    1291             : {
    1292             :   protected:
    1293        5885 :     explicit MUnaryInstruction(MDefinition* ins)
    1294        5885 :     {
    1295        5885 :         initOperand(0, ins);
    1296        5885 :     }
    1297             : 
    1298             :   public:
    1299        1430 :     NAMED_OPERANDS((0, input))
    1300             : };
    1301             : 
    1302           0 : class MBinaryInstruction : public MAryInstruction<2>
    1303             : {
    1304             :   protected:
    1305        2120 :     MBinaryInstruction(MDefinition* left, MDefinition* right)
    1306        2120 :     {
    1307        2120 :         initOperand(0, left);
    1308        2120 :         initOperand(1, right);
    1309        2120 :     }
    1310             : 
    1311             :   public:
    1312        1972 :     NAMED_OPERANDS((0, lhs), (1, rhs))
    1313           0 :     void swapOperands() {
    1314           0 :         MDefinition* temp = getOperand(0);
    1315           0 :         replaceOperand(0, getOperand(1));
    1316           0 :         replaceOperand(1, temp);
    1317           0 :     }
    1318             : 
    1319             :   protected:
    1320         173 :     HashNumber valueHash() const
    1321             :     {
    1322         173 :         MDefinition* lhs = getOperand(0);
    1323         173 :         MDefinition* rhs = getOperand(1);
    1324             : 
    1325         173 :         return op() + lhs->id() + rhs->id();
    1326             :     }
    1327          93 :     bool binaryCongruentTo(const MDefinition* ins) const
    1328             :     {
    1329          93 :         if (op() != ins->op())
    1330           0 :             return false;
    1331             : 
    1332          93 :         if (type() != ins->type())
    1333           0 :             return false;
    1334             : 
    1335          93 :         if (isEffectful() || ins->isEffectful())
    1336           0 :             return false;
    1337             : 
    1338          93 :         const MDefinition* left = getOperand(0);
    1339          93 :         const MDefinition* right = getOperand(1);
    1340             :         const MDefinition* tmp;
    1341             : 
    1342          93 :         if (isCommutative() && left->id() > right->id()) {
    1343           2 :             tmp = right;
    1344           2 :             right = left;
    1345           2 :             left = tmp;
    1346             :         }
    1347             : 
    1348          93 :         const MBinaryInstruction* bi = static_cast<const MBinaryInstruction*>(ins);
    1349          93 :         const MDefinition* insLeft = bi->getOperand(0);
    1350          93 :         const MDefinition* insRight = bi->getOperand(1);
    1351          93 :         if (isCommutative() && insLeft->id() > insRight->id()) {
    1352           2 :             tmp = insRight;
    1353           2 :             insRight = insLeft;
    1354           2 :             insLeft = tmp;
    1355             :         }
    1356             : 
    1357          93 :         return left == insLeft &&
    1358          93 :                right == insRight;
    1359             :     }
    1360             : 
    1361             :   public:
    1362             :     // Return if the operands to this instruction are both unsigned.
    1363             :     static bool unsignedOperands(MDefinition* left, MDefinition* right);
    1364             :     bool unsignedOperands();
    1365             : 
    1366             :     // Replace any wrapping operands with the underlying int32 operands
    1367             :     // in case of unsigned operands.
    1368             :     void replaceWithUnsignedOperands();
    1369             : };
    1370             : 
    1371           0 : class MTernaryInstruction : public MAryInstruction<3>
    1372             : {
    1373             :   protected:
    1374           9 :     MTernaryInstruction(MDefinition* first, MDefinition* second, MDefinition* third)
    1375           9 :     {
    1376           9 :         initOperand(0, first);
    1377           9 :         initOperand(1, second);
    1378           9 :         initOperand(2, third);
    1379           9 :     }
    1380             : 
    1381             :   protected:
    1382           0 :     HashNumber valueHash() const
    1383             :     {
    1384           0 :         MDefinition* first = getOperand(0);
    1385           0 :         MDefinition* second = getOperand(1);
    1386           0 :         MDefinition* third = getOperand(2);
    1387             : 
    1388           0 :         return op() + first->id() + second->id() + third->id();
    1389             :     }
    1390             : };
    1391             : 
    1392           0 : class MQuaternaryInstruction : public MAryInstruction<4>
    1393             : {
    1394             :   protected:
    1395           0 :     MQuaternaryInstruction(MDefinition* first, MDefinition* second,
    1396             :                            MDefinition* third, MDefinition* fourth)
    1397           0 :     {
    1398           0 :         initOperand(0, first);
    1399           0 :         initOperand(1, second);
    1400           0 :         initOperand(2, third);
    1401           0 :         initOperand(3, fourth);
    1402           0 :     }
    1403             : 
    1404             :   protected:
    1405           0 :     HashNumber valueHash() const
    1406             :     {
    1407           0 :         MDefinition* first = getOperand(0);
    1408           0 :         MDefinition* second = getOperand(1);
    1409           0 :         MDefinition* third = getOperand(2);
    1410           0 :         MDefinition* fourth = getOperand(3);
    1411             : 
    1412           0 :         return op() + first->id() + second->id() +
    1413           0 :                       third->id() + fourth->id();
    1414             :     }
    1415             : };
    1416             : 
    1417             : template <class T>
    1418        1214 : class MVariadicT : public T
    1419             : {
    1420             :     FixedList<MUse> operands_;
    1421             : 
    1422             :   protected:
    1423        1214 :     MOZ_MUST_USE bool init(TempAllocator& alloc, size_t length) {
    1424        1214 :         return operands_.init(alloc, length);
    1425             :     }
    1426        4877 :     void initOperand(size_t index, MDefinition* operand) {
    1427             :         // FixedList doesn't initialize its elements, so do an unchecked init.
    1428        4877 :         operands_[index].initUnchecked(operand, this);
    1429        4877 :     }
    1430        9041 :     MUse* getUseFor(size_t index) final override {
    1431        9041 :         return &operands_[index];
    1432             :     }
    1433          51 :     const MUse* getUseFor(size_t index) const final override {
    1434          51 :         return &operands_[index];
    1435             :     }
    1436             : 
    1437             :   public:
    1438             :     // Will assert if called before initialization.
    1439       21747 :     MDefinition* getOperand(size_t index) const final override {
    1440       21747 :         return operands_[index].producer();
    1441             :     }
    1442       17553 :     size_t numOperands() const final override {
    1443       17553 :         return operands_.length();
    1444             :     }
    1445        8886 :     size_t indexOf(const MUse* u) const final override {
    1446        8886 :         MOZ_ASSERT(u >= &operands_[0]);
    1447        8886 :         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
    1448        8886 :         return u - &operands_[0];
    1449             :     }
    1450         127 :     void replaceOperand(size_t index, MDefinition* operand) final override {
    1451         127 :         operands_[index].replaceProducer(operand);
    1452         127 :     }
    1453             : };
    1454             : 
    1455             : typedef MVariadicT<MInstruction> MVariadicInstruction;
    1456             : 
    1457             : // Generates an LSnapshot without further effect.
    1458         150 : class MStart : public MNullaryInstruction
    1459             : {
    1460             :   public:
    1461        3586 :     INSTRUCTION_HEADER(Start)
    1462         150 :     TRIVIAL_NEW_WRAPPERS
    1463             : };
    1464             : 
    1465             : // Instruction marking on entrypoint for on-stack replacement.
    1466             : // OSR may occur at loop headers (at JSOP_TRACE).
    1467             : // There is at most one MOsrEntry per MIRGraph.
    1468             : class MOsrEntry : public MNullaryInstruction
    1469             : {
    1470             :   protected:
    1471           4 :     MOsrEntry() {
    1472           4 :         setResultType(MIRType::Pointer);
    1473           4 :     }
    1474             : 
    1475             :   public:
    1476        2431 :     INSTRUCTION_HEADER(OsrEntry)
    1477           4 :     TRIVIAL_NEW_WRAPPERS
    1478             : };
    1479             : 
    1480             : // No-op instruction. This cannot be moved or eliminated, and is intended for
    1481             : // anchoring resume points at arbitrary points in a block.
    1482           0 : class MNop : public MNullaryInstruction
    1483             : {
    1484             :   protected:
    1485         795 :     MNop() {
    1486         795 :     }
    1487             : 
    1488             :   public:
    1489       25152 :     INSTRUCTION_HEADER(Nop)
    1490         795 :     TRIVIAL_NEW_WRAPPERS
    1491             : 
    1492        1755 :     AliasSet getAliasSet() const override {
    1493        1755 :         return AliasSet::None();
    1494             :     }
    1495             : 
    1496           0 :     ALLOW_CLONE(MNop)
    1497             : };
    1498             : 
    1499             : // Truncation barrier. This is intended for protecting its input against
    1500             : // follow-up truncation optimizations.
    1501             : class MLimitedTruncate
    1502             :   : public MUnaryInstruction,
    1503             :     public ConvertToInt32Policy<0>::Data
    1504             : {
    1505             :   public:
    1506             :     TruncateKind truncate_;
    1507             :     TruncateKind truncateLimit_;
    1508             : 
    1509             :   protected:
    1510           8 :     MLimitedTruncate(MDefinition* input, TruncateKind limit)
    1511           8 :       : MUnaryInstruction(input),
    1512             :         truncate_(NoTruncate),
    1513           8 :         truncateLimit_(limit)
    1514             :     {
    1515           8 :         setResultType(MIRType::Int32);
    1516           8 :         setResultTypeSet(input->resultTypeSet());
    1517           8 :         setMovable();
    1518           8 :     }
    1519             : 
    1520             :   public:
    1521        1350 :     INSTRUCTION_HEADER(LimitedTruncate)
    1522           8 :     TRIVIAL_NEW_WRAPPERS
    1523             : 
    1524          42 :     AliasSet getAliasSet() const override {
    1525          42 :         return AliasSet::None();
    1526             :     }
    1527             : 
    1528             :     void computeRange(TempAllocator& alloc) override;
    1529             :     bool needTruncation(TruncateKind kind) override;
    1530             :     TruncateKind operandTruncateKind(size_t index) const override;
    1531           5 :     TruncateKind truncateKind() const {
    1532           5 :         return truncate_;
    1533             :     }
    1534           0 :     void setTruncateKind(TruncateKind kind) {
    1535           0 :         truncate_ = kind;
    1536           0 :     }
    1537             : };
    1538             : 
    1539             : // A constant js::Value.
    1540           0 : class MConstant : public MNullaryInstruction
    1541             : {
    1542             :     struct Payload {
    1543             :         union {
    1544             :             bool b;
    1545             :             int32_t i32;
    1546             :             int64_t i64;
    1547             :             float f;
    1548             :             double d;
    1549             :             JSString* str;
    1550             :             JS::Symbol* sym;
    1551             :             JSObject* obj;
    1552             :             uint64_t asBits;
    1553             :         };
    1554        5904 :         Payload() : asBits(0) {}
    1555             :     };
    1556             : 
    1557             :     Payload payload_;
    1558             : 
    1559             :     static_assert(sizeof(Payload) == sizeof(uint64_t),
    1560             :                   "asBits must be big enough for all payload bits");
    1561             : 
    1562             : #ifdef DEBUG
    1563             :     void assertInitializedPayload() const;
    1564             : #else
    1565             :     void assertInitializedPayload() const {}
    1566             : #endif
    1567             : 
    1568             :   protected:
    1569             :     MConstant(const Value& v, CompilerConstraintList* constraints);
    1570             :     explicit MConstant(JSObject* obj);
    1571             :     explicit MConstant(float f);
    1572             :     explicit MConstant(int64_t i);
    1573             : 
    1574             :   public:
    1575      171006 :     INSTRUCTION_HEADER(Constant)
    1576             :     static MConstant* New(TempAllocator& alloc, const Value& v,
    1577             :                           CompilerConstraintList* constraints = nullptr);
    1578             :     static MConstant* New(TempAllocator::Fallible alloc, const Value& v,
    1579             :                           CompilerConstraintList* constraints = nullptr);
    1580             :     static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type);
    1581             :     static MConstant* NewFloat32(TempAllocator& alloc, double d);
    1582             :     static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
    1583             :     static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
    1584           0 :     static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
    1585           0 :         return new(alloc) MConstant(*src);
    1586             :     }
    1587             : 
    1588             :     // Try to convert this constant to boolean, similar to js::ToBoolean.
    1589             :     // Returns false if the type is MIRType::Magic*.
    1590             :     bool MOZ_MUST_USE valueToBoolean(bool* res) const;
    1591             : 
    1592             :     // Like valueToBoolean, but returns the result directly instead of using
    1593             :     // an outparam. Should not be used if this constant might be a magic value.
    1594           0 :     bool valueToBooleanInfallible() const {
    1595             :         bool res;
    1596           0 :         MOZ_ALWAYS_TRUE(valueToBoolean(&res));
    1597           0 :         return res;
    1598             :     }
    1599             : 
    1600             :     void printOpcode(GenericPrinter& out) const override;
    1601             : 
    1602             :     HashNumber valueHash() const override;
    1603             :     bool congruentTo(const MDefinition* ins) const override;
    1604             : 
    1605        8125 :     AliasSet getAliasSet() const override {
    1606        8125 :         return AliasSet::None();
    1607             :     }
    1608             : 
    1609         430 :     MOZ_MUST_USE bool updateForReplacement(MDefinition* def) override {
    1610         430 :         MConstant* c = def->toConstant();
    1611             :         // During constant folding, we don't want to replace a float32
    1612             :         // value by a double value.
    1613         430 :         if (type() == MIRType::Float32)
    1614           0 :             return c->type() == MIRType::Float32;
    1615         430 :         if (type() == MIRType::Double)
    1616           0 :             return c->type() != MIRType::Float32;
    1617         430 :         return true;
    1618             :     }
    1619             : 
    1620             :     void computeRange(TempAllocator& alloc) override;
    1621             :     bool needTruncation(TruncateKind kind) override;
    1622             :     void truncate() override;
    1623             : 
    1624             :     bool canProduceFloat32() const override;
    1625             : 
    1626           0 :     ALLOW_CLONE(MConstant)
    1627             : 
    1628        3394 :     bool equals(const MConstant* other) const {
    1629        3394 :         assertInitializedPayload();
    1630        3394 :         return type() == other->type() && payload_.asBits == other->payload_.asBits;
    1631             :     }
    1632             : 
    1633         299 :     bool toBoolean() const {
    1634         299 :         MOZ_ASSERT(type() == MIRType::Boolean);
    1635         299 :         return payload_.b;
    1636             :     }
    1637         382 :     int32_t toInt32() const {
    1638         382 :         MOZ_ASSERT(type() == MIRType::Int32);
    1639         382 :         return payload_.i32;
    1640             :     }
    1641           0 :     int64_t toInt64() const {
    1642           0 :         MOZ_ASSERT(type() == MIRType::Int64);
    1643           0 :         return payload_.i64;
    1644             :     }
    1645          14 :     bool isInt32(int32_t i) const {
    1646          14 :         return type() == MIRType::Int32 && payload_.i32 == i;
    1647             :     }
    1648           8 :     const double& toDouble() const {
    1649           8 :         MOZ_ASSERT(type() == MIRType::Double);
    1650           8 :         return payload_.d;
    1651             :     }
    1652           0 :     const float& toFloat32() const {
    1653           0 :         MOZ_ASSERT(type() == MIRType::Float32);
    1654           0 :         return payload_.f;
    1655             :     }
    1656         123 :     JSString* toString() const {
    1657         123 :         MOZ_ASSERT(type() == MIRType::String);
    1658         123 :         return payload_.str;
    1659             :     }
    1660           5 :     JS::Symbol* toSymbol() const {
    1661           5 :         MOZ_ASSERT(type() == MIRType::Symbol);
    1662           5 :         return payload_.sym;
    1663             :     }
    1664         416 :     JSObject& toObject() const {
    1665         416 :         MOZ_ASSERT(type() == MIRType::Object);
    1666         416 :         return *payload_.obj;
    1667             :     }
    1668         136 :     JSObject* toObjectOrNull() const {
    1669         136 :         if (type() == MIRType::Object)
    1670         136 :             return payload_.obj;
    1671           0 :         MOZ_ASSERT(type() == MIRType::Null);
    1672           0 :         return nullptr;
    1673             :     }
    1674             : 
    1675         482 :     bool isTypeRepresentableAsDouble() const {
    1676         482 :         return IsTypeRepresentableAsDouble(type());
    1677             :     }
    1678         143 :     double numberToDouble() const {
    1679         143 :         MOZ_ASSERT(isTypeRepresentableAsDouble());
    1680         143 :         if (type() == MIRType::Int32)
    1681         135 :             return toInt32();
    1682           8 :         if (type() == MIRType::Double)
    1683           8 :             return toDouble();
    1684           0 :         return toFloat32();
    1685             :     }
    1686             : 
    1687             :     // Convert this constant to a js::Value. Float32 constants will be stored
    1688             :     // as DoubleValue and NaNs are canonicalized. Callers must be careful: not
    1689             :     // all constants can be represented by js::Value (wasm supports int64).
    1690             :     Value toJSValue() const;
    1691             : 
    1692             :     bool appendRoots(MRootList& roots) const override;
    1693             : };
    1694             : 
    1695             : // Floating-point value as created by wasm. Just a constant value, used to
    1696             : // effectively inhibite all the MIR optimizations. This uses the same LIR nodes
    1697             : // as a MConstant of the same type would.
    1698             : class MWasmFloatConstant : public MNullaryInstruction
    1699             : {
    1700             :     union {
    1701             :         float f32_;
    1702             :         double f64_;
    1703             :         uint64_t bits_;
    1704             :     } u;
    1705             : 
    1706           0 :     explicit MWasmFloatConstant(MIRType type)
    1707           0 :     {
    1708           0 :         u.bits_ = 0;
    1709           0 :         setResultType(type);
    1710           0 :     }
    1711             : 
    1712             :   public:
    1713           0 :     INSTRUCTION_HEADER(WasmFloatConstant)
    1714             : 
    1715           0 :     static MWasmFloatConstant* NewDouble(TempAllocator& alloc, double d) {
    1716           0 :         auto* ret = new(alloc) MWasmFloatConstant(MIRType::Double);
    1717           0 :         ret->u.f64_ = d;
    1718           0 :         return ret;
    1719             :     }
    1720             : 
    1721           0 :     static MWasmFloatConstant* NewFloat32(TempAllocator& alloc, float f) {
    1722           0 :         auto* ret = new(alloc) MWasmFloatConstant(MIRType::Float32);
    1723           0 :         ret->u.f32_ = f;
    1724           0 :         return ret;
    1725             :     }
    1726             : 
    1727             :     HashNumber valueHash() const override;
    1728             :     bool congruentTo(const MDefinition* ins) const override;
    1729           0 :     AliasSet getAliasSet() const override { return AliasSet::None(); }
    1730             : 
    1731           0 :     const double& toDouble() const {
    1732           0 :         MOZ_ASSERT(type() == MIRType::Double);
    1733           0 :         return u.f64_;
    1734             :     }
    1735           0 :     const float& toFloat32() const {
    1736           0 :         MOZ_ASSERT(type() == MIRType::Float32);
    1737           0 :         return u.f32_;
    1738             :     }
    1739             : };
    1740             : 
    1741             : // Generic constructor of SIMD valuesX4.
    1742           0 : class MSimdValueX4
    1743             :   : public MQuaternaryInstruction,
    1744             :     public Mix4Policy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
    1745             :                       SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
    1746             : {
    1747             :   protected:
    1748           0 :     MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w)
    1749           0 :       : MQuaternaryInstruction(x, y, z, w)
    1750             :     {
    1751           0 :         MOZ_ASSERT(IsSimdType(type));
    1752           0 :         MOZ_ASSERT(SimdTypeToLength(type) == 4);
    1753             : 
    1754           0 :         setMovable();
    1755           0 :         setResultType(type);
    1756           0 :     }
    1757             : 
    1758             :   public:
    1759           0 :     INSTRUCTION_HEADER(SimdValueX4)
    1760           0 :     TRIVIAL_NEW_WRAPPERS
    1761             : 
    1762           0 :     bool canConsumeFloat32(MUse* use) const override {
    1763           0 :         return SimdTypeToLaneType(type()) == MIRType::Float32;
    1764             :     }
    1765             : 
    1766           0 :     AliasSet getAliasSet() const override {
    1767           0 :         return AliasSet::None();
    1768             :     }
    1769             : 
    1770           0 :     bool congruentTo(const MDefinition* ins) const override {
    1771           0 :         return congruentIfOperandsEqual(ins);
    1772             :     }
    1773             : 
    1774             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    1775             : 
    1776           0 :     ALLOW_CLONE(MSimdValueX4)
    1777             : };
    1778             : 
    1779             : // Generic constructor of SIMD values with identical lanes.
    1780           0 : class MSimdSplat
    1781             :   : public MUnaryInstruction,
    1782             :     public SimdScalarPolicy<0>::Data
    1783             : {
    1784             :   protected:
    1785           0 :     MSimdSplat(MDefinition* v, MIRType type)
    1786           0 :       : MUnaryInstruction(v)
    1787             :     {
    1788           0 :         MOZ_ASSERT(IsSimdType(type));
    1789           0 :         setMovable();
    1790           0 :         setResultType(type);
    1791           0 :     }
    1792             : 
    1793             :   public:
    1794           0 :     INSTRUCTION_HEADER(SimdSplat)
    1795           0 :     TRIVIAL_NEW_WRAPPERS
    1796             : 
    1797           0 :     bool canConsumeFloat32(MUse* use) const override {
    1798           0 :         return SimdTypeToLaneType(type()) == MIRType::Float32;
    1799             :     }
    1800             : 
    1801           0 :     AliasSet getAliasSet() const override {
    1802           0 :         return AliasSet::None();
    1803             :     }
    1804             : 
    1805           0 :     bool congruentTo(const MDefinition* ins) const override {
    1806           0 :         return congruentIfOperandsEqual(ins);
    1807             :     }
    1808             : 
    1809             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    1810             : 
    1811           0 :     ALLOW_CLONE(MSimdSplat)
    1812             : };
    1813             : 
    1814             : // A constant SIMD value.
    1815           0 : class MSimdConstant
    1816             :   : public MNullaryInstruction
    1817             : {
    1818             :     SimdConstant value_;
    1819             : 
    1820             :   protected:
    1821           0 :     MSimdConstant(const SimdConstant& v, MIRType type) : value_(v) {
    1822           0 :         MOZ_ASSERT(IsSimdType(type));
    1823           0 :         setMovable();
    1824           0 :         setResultType(type);
    1825           0 :     }
    1826             : 
    1827             :   public:
    1828           0 :     INSTRUCTION_HEADER(SimdConstant)
    1829           0 :     TRIVIAL_NEW_WRAPPERS
    1830             : 
    1831           0 :     bool congruentTo(const MDefinition* ins) const override {
    1832           0 :         if (!ins->isSimdConstant())
    1833           0 :             return false;
    1834             :         // Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
    1835           0 :         if (type() != ins->type())
    1836           0 :             return false;
    1837           0 :         return value() == ins->toSimdConstant()->value();
    1838             :     }
    1839             : 
    1840           0 :     const SimdConstant& value() const {
    1841           0 :         return value_;
    1842             :     }
    1843             : 
    1844           0 :     AliasSet getAliasSet() const override {
    1845           0 :         return AliasSet::None();
    1846             :     }
    1847             : 
    1848           0 :     ALLOW_CLONE(MSimdConstant)
    1849             : };
    1850             : 
    1851             : // Converts all lanes of a given vector into the type of another vector
    1852           0 : class MSimdConvert
    1853             :   : public MUnaryInstruction,
    1854             :     public SimdPolicy<0>::Data
    1855             : {
    1856             :     // When either fromType or toType is an integer vector, should it be treated
    1857             :     // as signed or unsigned. Note that we don't support int-int conversions -
    1858             :     // use MSimdReinterpretCast for that.
    1859             :     SimdSign sign_;
    1860             :     wasm::BytecodeOffset bytecodeOffset_;
    1861             : 
    1862           0 :     MSimdConvert(MDefinition* obj, MIRType toType, SimdSign sign,
    1863             :                  wasm::BytecodeOffset bytecodeOffset)
    1864           0 :       : MUnaryInstruction(obj), sign_(sign), bytecodeOffset_(bytecodeOffset)
    1865             :     {
    1866           0 :         MIRType fromType = obj->type();
    1867           0 :         MOZ_ASSERT(IsSimdType(fromType));
    1868           0 :         MOZ_ASSERT(IsSimdType(toType));
    1869             :         // All conversions are int <-> float, so signedness is required.
    1870           0 :         MOZ_ASSERT(sign != SimdSign::NotApplicable);
    1871             : 
    1872           0 :         setResultType(toType);
    1873           0 :         specialization_ = fromType; // expects fromType as input
    1874             : 
    1875           0 :         setMovable();
    1876           0 :         if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
    1877             :             // Does the extra range check => do not remove
    1878           0 :             setGuard();
    1879             :         }
    1880           0 :     }
    1881             : 
    1882           0 :     static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign,
    1883             :                              wasm::BytecodeOffset bytecodeOffset)
    1884             :     {
    1885           0 :         return new (alloc) MSimdConvert(obj, toType, sign, bytecodeOffset);
    1886             :     }
    1887             : 
    1888             :   public:
    1889           0 :     INSTRUCTION_HEADER(SimdConvert)
    1890             : 
    1891             :     // Create a MSimdConvert instruction and add it to the basic block.
    1892             :     // Possibly create and add an equivalent sequence of instructions instead if
    1893             :     // the current target doesn't support the requested conversion directly.
    1894             :     // Return the inserted MInstruction that computes the converted value.
    1895             :     static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
    1896             :                                       MIRType toType, SimdSign sign,
    1897             :                                       wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset());
    1898             : 
    1899           0 :     SimdSign signedness() const {
    1900           0 :         return sign_;
    1901             :     }
    1902           0 :     wasm::BytecodeOffset bytecodeOffset() const {
    1903           0 :         return bytecodeOffset_;
    1904             :     }
    1905             : 
    1906           0 :     AliasSet getAliasSet() const override {
    1907           0 :         return AliasSet::None();
    1908             :     }
    1909           0 :     bool congruentTo(const MDefinition* ins) const override {
    1910           0 :         if (!congruentIfOperandsEqual(ins))
    1911           0 :             return false;
    1912           0 :         const MSimdConvert* other = ins->toSimdConvert();
    1913           0 :         return sign_ == other->sign_;
    1914             :     }
    1915           0 :     ALLOW_CLONE(MSimdConvert)
    1916             : };
    1917             : 
    1918             : // Casts bits of a vector input to another SIMD type (doesn't generate code).
    1919           0 : class MSimdReinterpretCast
    1920             :   : public MUnaryInstruction,
    1921             :     public SimdPolicy<0>::Data
    1922             : {
    1923           0 :     MSimdReinterpretCast(MDefinition* obj, MIRType toType)
    1924           0 :       : MUnaryInstruction(obj)
    1925             :     {
    1926           0 :         MIRType fromType = obj->type();
    1927           0 :         MOZ_ASSERT(IsSimdType(fromType));
    1928           0 :         MOZ_ASSERT(IsSimdType(toType));
    1929           0 :         setMovable();
    1930           0 :         setResultType(toType);
    1931           0 :         specialization_ = fromType; // expects fromType as input
    1932           0 :     }
    1933             : 
    1934             :   public:
    1935           0 :     INSTRUCTION_HEADER(SimdReinterpretCast)
    1936           0 :     TRIVIAL_NEW_WRAPPERS
    1937             : 
    1938           0 :     AliasSet getAliasSet() const override {
    1939           0 :         return AliasSet::None();
    1940             :     }
    1941           0 :     bool congruentTo(const MDefinition* ins) const override {
    1942           0 :         return congruentIfOperandsEqual(ins);
    1943             :     }
    1944           0 :     ALLOW_CLONE(MSimdReinterpretCast)
    1945             : };
    1946             : 
    1947             : // Extracts a lane element from a given vector type, given by its lane symbol.
    1948             : //
    1949             : // For integer SIMD types, a SimdSign must be provided so the lane value can be
    1950             : // converted to a scalar correctly.
    1951           0 : class MSimdExtractElement
    1952             :   : public MUnaryInstruction,
    1953             :     public SimdPolicy<0>::Data
    1954             : {
    1955             :   protected:
    1956             :     unsigned lane_;
    1957             :     SimdSign sign_;
    1958             : 
    1959           0 :     MSimdExtractElement(MDefinition* obj, MIRType laneType, unsigned lane, SimdSign sign)
    1960           0 :       : MUnaryInstruction(obj), lane_(lane), sign_(sign)
    1961             :     {
    1962           0 :         MIRType vecType = obj->type();
    1963           0 :         MOZ_ASSERT(IsSimdType(vecType));
    1964           0 :         MOZ_ASSERT(lane < SimdTypeToLength(vecType));
    1965           0 :         MOZ_ASSERT(!IsSimdType(laneType));
    1966           0 :         MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType),
    1967             :                    "Signedness must be specified for integer SIMD extractLanes");
    1968             :         // The resulting type should match the lane type.
    1969             :         // Allow extracting boolean lanes directly into an Int32 (for wasm).
    1970             :         // Allow extracting Uint32 lanes into a double.
    1971             :         //
    1972             :         // We also allow extracting Uint32 lanes into a MIRType::Int32. This is
    1973             :         // equivalent to extracting the Uint32 lane to a double and then
    1974             :         // applying MTruncateToInt32, but it bypasses the conversion to/from
    1975             :         // double.
    1976           0 :         MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
    1977             :                    (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) ||
    1978             :                    (vecType == MIRType::Int32x4 && laneType == MIRType::Double &&
    1979             :                     sign == SimdSign::Unsigned));
    1980             : 
    1981           0 :         setMovable();
    1982           0 :         specialization_ = vecType;
    1983           0 :         setResultType(laneType);
    1984           0 :     }
    1985             : 
    1986             :   public:
    1987           0 :     INSTRUCTION_HEADER(SimdExtractElement)
    1988           0 :     TRIVIAL_NEW_WRAPPERS
    1989             : 
    1990           0 :     unsigned lane() const {
    1991           0 :         return lane_;
    1992             :     }
    1993             : 
    1994           0 :     SimdSign signedness() const {
    1995           0 :         return sign_;
    1996             :     }
    1997             : 
    1998           0 :     AliasSet getAliasSet() const override {
    1999           0 :         return AliasSet::None();
    2000             :     }
    2001           0 :     bool congruentTo(const MDefinition* ins) const override {
    2002           0 :         if (!ins->isSimdExtractElement())
    2003           0 :             return false;
    2004           0 :         const MSimdExtractElement* other = ins->toSimdExtractElement();
    2005           0 :         if (other->lane_ != lane_ || other->sign_ != sign_)
    2006           0 :             return false;
    2007           0 :         return congruentIfOperandsEqual(other);
    2008             :     }
    2009           0 :     ALLOW_CLONE(MSimdExtractElement)
    2010             : };
    2011             : 
    2012             : // Replaces the datum in the given lane by a scalar value of the same type.
    2013           0 : class MSimdInsertElement
    2014             :   : public MBinaryInstruction,
    2015             :     public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
    2016             : {
    2017             :   private:
    2018             :     unsigned lane_;
    2019             : 
    2020           0 :     MSimdInsertElement(MDefinition* vec, MDefinition* val, unsigned lane)
    2021           0 :       : MBinaryInstruction(vec, val), lane_(lane)
    2022             :     {
    2023           0 :         MIRType type = vec->type();
    2024           0 :         MOZ_ASSERT(IsSimdType(type));
    2025           0 :         MOZ_ASSERT(lane < SimdTypeToLength(type));
    2026           0 :         setMovable();
    2027           0 :         setResultType(type);
    2028           0 :     }
    2029             : 
    2030             :   public:
    2031           0 :     INSTRUCTION_HEADER(SimdInsertElement)
    2032           0 :     TRIVIAL_NEW_WRAPPERS
    2033           0 :     NAMED_OPERANDS((0, vector), (1, value))
    2034             : 
    2035           0 :     unsigned lane() const {
    2036           0 :         return lane_;
    2037             :     }
    2038             : 
    2039           0 :     bool canConsumeFloat32(MUse* use) const override {
    2040           0 :         return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32;
    2041             :     }
    2042             : 
    2043           0 :     AliasSet getAliasSet() const override {
    2044           0 :         return AliasSet::None();
    2045             :     }
    2046             : 
    2047           0 :     bool congruentTo(const MDefinition* ins) const override {
    2048           0 :         return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
    2049             :     }
    2050             : 
    2051             :     void printOpcode(GenericPrinter& out) const override;
    2052             : 
    2053           0 :     ALLOW_CLONE(MSimdInsertElement)
    2054             : };
    2055             : 
    2056             : // Returns true if all lanes are true.
    2057           0 : class MSimdAllTrue
    2058             :   : public MUnaryInstruction,
    2059             :     public SimdPolicy<0>::Data
    2060             : {
    2061             :   protected:
    2062           0 :     explicit MSimdAllTrue(MDefinition* obj, MIRType result)
    2063           0 :       : MUnaryInstruction(obj)
    2064             :     {
    2065           0 :         MIRType simdType = obj->type();
    2066           0 :         MOZ_ASSERT(IsBooleanSimdType(simdType));
    2067           0 :         MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
    2068           0 :         setResultType(result);
    2069           0 :         specialization_ = simdType;
    2070           0 :         setMovable();
    2071           0 :     }
    2072             : 
    2073             :   public:
    2074           0 :     INSTRUCTION_HEADER(SimdAllTrue)
    2075           0 :     TRIVIAL_NEW_WRAPPERS
    2076             : 
    2077           0 :     AliasSet getAliasSet() const override {
    2078           0 :         return AliasSet::None();
    2079             :     }
    2080           0 :     bool congruentTo(const MDefinition* ins) const override {
    2081           0 :         return congruentIfOperandsEqual(ins);
    2082             :     }
    2083           0 :     ALLOW_CLONE(MSimdAllTrue)
    2084             : };
    2085             : 
    2086             : // Returns true if any lane is true.
    2087           0 : class MSimdAnyTrue
    2088             :   : public MUnaryInstruction,
    2089             :     public SimdPolicy<0>::Data
    2090             : {
    2091             :   protected:
    2092           0 :     explicit MSimdAnyTrue(MDefinition* obj, MIRType result)
    2093           0 :       : MUnaryInstruction(obj)
    2094             :     {
    2095           0 :         MIRType simdType = obj->type();
    2096           0 :         MOZ_ASSERT(IsBooleanSimdType(simdType));
    2097           0 :         MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
    2098           0 :         setResultType(result);
    2099           0 :         specialization_ = simdType;
    2100           0 :         setMovable();
    2101           0 :     }
    2102             : 
    2103             :   public:
    2104           0 :     INSTRUCTION_HEADER(SimdAnyTrue)
    2105           0 :     TRIVIAL_NEW_WRAPPERS
    2106             : 
    2107           0 :     AliasSet getAliasSet() const override {
    2108           0 :         return AliasSet::None();
    2109             :     }
    2110           0 :     bool congruentTo(const MDefinition* ins) const override {
    2111           0 :         return congruentIfOperandsEqual(ins);
    2112             :     }
    2113             : 
    2114           0 :     ALLOW_CLONE(MSimdAnyTrue)
    2115             : };
    2116             : 
    2117             : // Base for the MSimdSwizzle and MSimdShuffle classes.
    2118             : class MSimdShuffleBase
    2119             : {
    2120             :   protected:
    2121             :     // As of now, there are at most 16 lanes. For each lane, we need to know
    2122             :     // which input we choose and which of the lanes we choose.
    2123             :     mozilla::Array<uint8_t, 16> lane_;
    2124             :     uint32_t arity_;
    2125             : 
    2126           0 :     MSimdShuffleBase(const uint8_t lanes[], MIRType type)
    2127           0 :     {
    2128           0 :         arity_ = SimdTypeToLength(type);
    2129           0 :         for (unsigned i = 0; i < arity_; i++)
    2130           0 :             lane_[i] = lanes[i];
    2131           0 :     }
    2132             : 
    2133           0 :     bool sameLanes(const MSimdShuffleBase* other) const {
    2134           0 :         return arity_ == other->arity_ &&
    2135           0 :                memcmp(&lane_[0], &other->lane_[0], arity_) == 0;
    2136             :     }
    2137             : 
    2138             :   public:
    2139           0 :     unsigned numLanes() const {
    2140           0 :         return arity_;
    2141             :     }
    2142             : 
    2143           0 :     unsigned lane(unsigned i) const {
    2144           0 :         MOZ_ASSERT(i < arity_);
    2145           0 :         return lane_[i];
    2146             :     }
    2147             : 
    2148           0 :     bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
    2149           0 :         return arity_ == 4 && lane(0) == x && lane(1) == y && lane(2) == z &&
    2150           0 :                lane(3) == w;
    2151             :     }
    2152             : };
    2153             : 
    2154             : // Applies a swizzle operation to the input, putting the input lanes as
    2155             : // indicated in the output register's lanes. This implements the SIMD.js
    2156             : // "swizzle" function, that takes one vector and an array of lane indexes.
    2157           0 : class MSimdSwizzle
    2158             :   : public MUnaryInstruction,
    2159             :     public MSimdShuffleBase,
    2160             :     public NoTypePolicy::Data
    2161             : {
    2162             :   protected:
    2163           0 :     MSimdSwizzle(MDefinition* obj, const uint8_t lanes[])
    2164           0 :       : MUnaryInstruction(obj), MSimdShuffleBase(lanes, obj->type())
    2165             :     {
    2166           0 :         for (unsigned i = 0; i < arity_; i++)
    2167           0 :             MOZ_ASSERT(lane(i) < arity_);
    2168           0 :         setResultType(obj->type());
    2169           0 :         setMovable();
    2170           0 :     }
    2171             : 
    2172             :   public:
    2173           0 :     INSTRUCTION_HEADER(SimdSwizzle)
    2174           0 :     TRIVIAL_NEW_WRAPPERS
    2175             : 
    2176           0 :     bool congruentTo(const MDefinition* ins) const override {
    2177           0 :         if (!ins->isSimdSwizzle())
    2178           0 :             return false;
    2179           0 :         const MSimdSwizzle* other = ins->toSimdSwizzle();
    2180           0 :         return sameLanes(other) && congruentIfOperandsEqual(other);
    2181             :     }
    2182             : 
    2183           0 :     AliasSet getAliasSet() const override {
    2184           0 :         return AliasSet::None();
    2185             :     }
    2186             : 
    2187             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    2188             : 
    2189           0 :     ALLOW_CLONE(MSimdSwizzle)
    2190             : };
    2191             : 
    2192             : // A "general shuffle" is a swizzle or a shuffle with non-constant lane
    2193             : // indices.  This is the one that Ion inlines and it can be folded into a
    2194             : // MSimdSwizzle/MSimdShuffle if lane indices are constant.  Performance of
    2195             : // general swizzle/shuffle does not really matter, as we expect to get
    2196             : // constant indices most of the time.
    2197             : class MSimdGeneralShuffle :
    2198             :     public MVariadicInstruction,
    2199             :     public SimdShufflePolicy::Data
    2200             : {
    2201             :     unsigned numVectors_;
    2202             :     unsigned numLanes_;
    2203             : 
    2204             :   protected:
    2205           0 :     MSimdGeneralShuffle(unsigned numVectors, unsigned numLanes, MIRType type)
    2206           0 :       : numVectors_(numVectors), numLanes_(numLanes)
    2207             :     {
    2208           0 :         MOZ_ASSERT(IsSimdType(type));
    2209           0 :         MOZ_ASSERT(SimdTypeToLength(type) == numLanes_);
    2210             : 
    2211           0 :         setResultType(type);
    2212           0 :         specialization_ = type;
    2213           0 :         setGuard(); // throws if lane index is out of bounds
    2214           0 :         setMovable();
    2215           0 :     }
    2216             : 
    2217             :   public:
    2218           0 :     INSTRUCTION_HEADER(SimdGeneralShuffle);
    2219           0 :     TRIVIAL_NEW_WRAPPERS
    2220             : 
    2221           0 :     MOZ_MUST_USE bool init(TempAllocator& alloc) {
    2222           0 :         return MVariadicInstruction::init(alloc, numVectors_ + numLanes_);
    2223             :     }
    2224           0 :     void setVector(unsigned i, MDefinition* vec) {
    2225           0 :         MOZ_ASSERT(i < numVectors_);
    2226           0 :         initOperand(i, vec);
    2227           0 :     }
    2228           0 :     void setLane(unsigned i, MDefinition* laneIndex) {
    2229           0 :         MOZ_ASSERT(i < numLanes_);
    2230           0 :         initOperand(numVectors_ + i, laneIndex);
    2231           0 :     }
    2232             : 
    2233           0 :     unsigned numVectors() const {
    2234           0 :         return numVectors_;
    2235             :     }
    2236           0 :     unsigned numLanes() const {
    2237           0 :         return numLanes_;
    2238             :     }
    2239           0 :     MDefinition* vector(unsigned i) const {
    2240           0 :         MOZ_ASSERT(i < numVectors_);
    2241           0 :         return getOperand(i);
    2242             :     }
    2243           0 :     MDefinition* lane(unsigned i) const {
    2244           0 :         MOZ_ASSERT(i < numLanes_);
    2245           0 :         return getOperand(numVectors_ + i);
    2246             :     }
    2247             : 
    2248           0 :     bool congruentTo(const MDefinition* ins) const override {
    2249           0 :         if (!ins->isSimdGeneralShuffle())
    2250           0 :             return false;
    2251           0 :         const MSimdGeneralShuffle* other = ins->toSimdGeneralShuffle();
    2252           0 :         return numVectors_ == other->numVectors() &&
    2253           0 :                numLanes_ == other->numLanes() &&
    2254           0 :                congruentIfOperandsEqual(other);
    2255             :     }
    2256             : 
    2257             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    2258             : 
    2259           0 :     AliasSet getAliasSet() const override {
    2260           0 :         return AliasSet::None();
    2261             :     }
    2262             : };
    2263             : 
    2264             : // Applies a shuffle operation to the inputs. The lane indexes select a source
    2265             : // lane from the concatenation of the two input vectors.
    2266           0 : class MSimdShuffle
    2267             :   : public MBinaryInstruction,
    2268             :     public MSimdShuffleBase,
    2269             :     public NoTypePolicy::Data
    2270             : {
    2271           0 :     MSimdShuffle(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[])
    2272           0 :       : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(lanes, lhs->type())
    2273             :     {
    2274           0 :         MOZ_ASSERT(IsSimdType(lhs->type()));
    2275           0 :         MOZ_ASSERT(IsSimdType(rhs->type()));
    2276           0 :         MOZ_ASSERT(lhs->type() == rhs->type());
    2277           0 :         for (unsigned i = 0; i < arity_; i++)
    2278           0 :             MOZ_ASSERT(lane(i) < 2 * arity_);
    2279           0 :         setResultType(lhs->type());
    2280           0 :         setMovable();
    2281           0 :     }
    2282             : 
    2283             :   public:
    2284           0 :     INSTRUCTION_HEADER(SimdShuffle)
    2285             : 
    2286           0 :     static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs,
    2287             :                              const uint8_t lanes[])
    2288             :     {
    2289           0 :         unsigned arity = SimdTypeToLength(lhs->type());
    2290             : 
    2291             :         // Swap operands so that new lanes come from LHS in majority.
    2292             :         // In the balanced case, swap operands if needs be, in order to be able
    2293             :         // to do only one vshufps on x86.
    2294           0 :         unsigned lanesFromLHS = 0;
    2295           0 :         for (unsigned i = 0; i < arity; i++) {
    2296           0 :             if (lanes[i] < arity)
    2297           0 :                 lanesFromLHS++;
    2298             :         }
    2299             : 
    2300           0 :         if (lanesFromLHS < arity / 2 ||
    2301           0 :             (arity == 4 && lanesFromLHS == 2 && lanes[0] >= 4 && lanes[1] >= 4)) {
    2302           0 :             mozilla::Array<uint8_t, 16> newLanes;
    2303           0 :             for (unsigned i = 0; i < arity; i++)
    2304           0 :                 newLanes[i] = (lanes[i] + arity) % (2 * arity);
    2305           0 :             return New(alloc, rhs, lhs, &newLanes[0]);
    2306             :         }
    2307             : 
    2308             :         // If all lanes come from the same vector, just use swizzle instead.
    2309           0 :         if (lanesFromLHS == arity)
    2310           0 :             return MSimdSwizzle::New(alloc, lhs, lanes);
    2311             : 
    2312           0 :         return new(alloc) MSimdShuffle(lhs, rhs, lanes);
    2313             :     }
    2314             : 
    2315           0 :     bool congruentTo(const MDefinition* ins) const override {
    2316           0 :         if (!ins->isSimdShuffle())
    2317           0 :             return false;
    2318           0 :         const MSimdShuffle* other = ins->toSimdShuffle();
    2319           0 :         return sameLanes(other) && binaryCongruentTo(other);
    2320             :     }
    2321             : 
    2322           0 :     AliasSet getAliasSet() const override {
    2323           0 :         return AliasSet::None();
    2324             :     }
    2325             : 
    2326           0 :     ALLOW_CLONE(MSimdShuffle)
    2327             : };
    2328             : 
    2329           0 : class MSimdUnaryArith
    2330             :   : public MUnaryInstruction,
    2331             :     public SimdSameAsReturnedTypePolicy<0>::Data
    2332             : {
    2333             :   public:
    2334             :     enum Operation {
    2335             : #define OP_LIST_(OP) OP,
    2336             :         FOREACH_FLOAT_SIMD_UNOP(OP_LIST_)
    2337             :         neg,
    2338             :         not_
    2339             : #undef OP_LIST_
    2340             :     };
    2341             : 
    2342           0 :     static const char* OperationName(Operation op) {
    2343           0 :         switch (op) {
    2344           0 :           case abs:                         return "abs";
    2345           0 :           case neg:                         return "neg";
    2346           0 :           case not_:                        return "not";
    2347           0 :           case reciprocalApproximation:     return "reciprocalApproximation";
    2348           0 :           case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation";
    2349           0 :           case sqrt:                        return "sqrt";
    2350             :         }
    2351           0 :         MOZ_CRASH("unexpected operation");
    2352             :     }
    2353             : 
    2354             :   private:
    2355             :     Operation operation_;
    2356             : 
    2357           0 :     MSimdUnaryArith(MDefinition* def, Operation op)
    2358           0 :       : MUnaryInstruction(def), operation_(op)
    2359             :     {
    2360           0 :         MIRType type = def->type();
    2361           0 :         MOZ_ASSERT(IsSimdType(type));
    2362           0 :         MOZ_ASSERT_IF(IsIntegerSimdType(type), op == neg || op == not_);
    2363           0 :         setResultType(type);
    2364           0 :         setMovable();
    2365           0 :     }
    2366             : 
    2367             :   public:
    2368           0 :     INSTRUCTION_HEADER(SimdUnaryArith)
    2369           0 :     TRIVIAL_NEW_WRAPPERS
    2370             : 
    2371           0 :     Operation operation() const { return operation_; }
    2372             : 
    2373           0 :     AliasSet getAliasSet() const override {
    2374           0 :         return AliasSet::None();
    2375             :     }
    2376             : 
    2377           0 :     bool congruentTo(const MDefinition* ins) const override {
    2378           0 :         return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
    2379             :     }
    2380             : 
    2381             :     void printOpcode(GenericPrinter& out) const override;
    2382             : 
    2383           0 :     ALLOW_CLONE(MSimdUnaryArith);
    2384             : };
    2385             : 
    2386             : // Compares each value of a SIMD vector to each corresponding lane's value of
    2387             : // another SIMD vector, and returns a boolean vector containing the results of
    2388             : // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
    2389             : // When comparing integer vectors, a SimdSign must be provided to request signed
    2390             : // or unsigned comparison.
    2391           0 : class MSimdBinaryComp
    2392             :   : public MBinaryInstruction,
    2393             :     public SimdAllPolicy::Data
    2394             : {
    2395             :   public:
    2396             :     enum Operation {
    2397             : #define NAME_(x) x,
    2398             :         FOREACH_COMP_SIMD_OP(NAME_)
    2399             : #undef NAME_
    2400             :     };
    2401             : 
    2402           0 :     static const char* OperationName(Operation op) {
    2403           0 :         switch (op) {
    2404             : #define NAME_(x) case x: return #x;
    2405           0 :         FOREACH_COMP_SIMD_OP(NAME_)
    2406             : #undef NAME_
    2407             :         }
    2408           0 :         MOZ_CRASH("unexpected operation");
    2409             :     }
    2410             : 
    2411             :   private:
    2412             :     Operation operation_;
    2413             :     SimdSign sign_;
    2414             : 
    2415           0 :     MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
    2416           0 :       : MBinaryInstruction(left, right), operation_(op), sign_(sign)
    2417             :     {
    2418           0 :         MOZ_ASSERT(left->type() == right->type());
    2419           0 :         MIRType opType = left->type();
    2420           0 :         MOZ_ASSERT(IsSimdType(opType));
    2421           0 :         MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType),
    2422             :                    "Signedness must be specified for integer SIMD compares");
    2423           0 :         setResultType(MIRTypeToBooleanSimdType(opType));
    2424           0 :         specialization_ = opType;
    2425           0 :         setMovable();
    2426           0 :         if (op == equal || op == notEqual)
    2427           0 :             setCommutative();
    2428           0 :     }
    2429             : 
    2430           0 :     static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    2431             :                                 Operation op, SimdSign sign)
    2432             :     {
    2433           0 :         return new (alloc) MSimdBinaryComp(left, right, op, sign);
    2434             :     }
    2435             : 
    2436             :   public:
    2437           0 :     INSTRUCTION_HEADER(SimdBinaryComp)
    2438             : 
    2439             :     // Create a MSimdBinaryComp or an equivalent sequence of instructions
    2440             :     // supported by the current target.
    2441             :     // Add all instructions to the basic block |addTo|.
    2442             :     static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    2443             :                                       MDefinition* right, Operation op, SimdSign sign);
    2444             : 
    2445           0 :     AliasSet getAliasSet() const override
    2446             :     {
    2447           0 :         return AliasSet::None();
    2448             :     }
    2449             : 
    2450           0 :     Operation operation() const { return operation_; }
    2451           0 :     SimdSign signedness() const { return sign_; }
    2452           0 :     MIRType specialization() const { return specialization_; }
    2453             : 
    2454             :     // Swap the operands and reverse the comparison predicate.
    2455           0 :     void reverse() {
    2456           0 :         switch (operation()) {
    2457           0 :           case greaterThan:        operation_ = lessThan; break;
    2458           0 :           case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
    2459           0 :           case lessThan:           operation_ = greaterThan; break;
    2460           0 :           case lessThanOrEqual:    operation_ = greaterThanOrEqual; break;
    2461             :           case equal:
    2462             :           case notEqual:
    2463           0 :             break;
    2464           0 :           default: MOZ_CRASH("Unexpected compare operation");
    2465             :         }
    2466           0 :         swapOperands();
    2467           0 :     }
    2468             : 
    2469           0 :     bool congruentTo(const MDefinition* ins) const override {
    2470           0 :         if (!binaryCongruentTo(ins))
    2471           0 :             return false;
    2472           0 :         const MSimdBinaryComp* other = ins->toSimdBinaryComp();
    2473           0 :         return specialization_ == other->specialization() &&
    2474           0 :                operation_ == other->operation() &&
    2475           0 :                sign_ == other->signedness();
    2476             :     }
    2477             : 
    2478             :     void printOpcode(GenericPrinter& out) const override;
    2479             : 
    2480           0 :     ALLOW_CLONE(MSimdBinaryComp)
    2481             : };
    2482             : 
    2483           0 : class MSimdBinaryArith
    2484             :   : public MBinaryInstruction,
    2485             :     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
    2486             : {
    2487             :   public:
    2488             :     enum Operation {
    2489             : #define OP_LIST_(OP) Op_##OP,
    2490             :         FOREACH_NUMERIC_SIMD_BINOP(OP_LIST_)
    2491             :         FOREACH_FLOAT_SIMD_BINOP(OP_LIST_)
    2492             : #undef OP_LIST_
    2493             :     };
    2494             : 
    2495           0 :     static const char* OperationName(Operation op) {
    2496           0 :         switch (op) {
    2497             : #define OP_CASE_LIST_(OP) case Op_##OP: return #OP;
    2498           0 :           FOREACH_NUMERIC_SIMD_BINOP(OP_CASE_LIST_)
    2499           0 :           FOREACH_FLOAT_SIMD_BINOP(OP_CASE_LIST_)
    2500             : #undef OP_CASE_LIST_
    2501             :         }
    2502           0 :         MOZ_CRASH("unexpected operation");
    2503             :     }
    2504             : 
    2505             :   private:
    2506             :     Operation operation_;
    2507             : 
    2508           0 :     MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op)
    2509           0 :       : MBinaryInstruction(left, right), operation_(op)
    2510             :     {
    2511           0 :         MOZ_ASSERT(left->type() == right->type());
    2512           0 :         MIRType type = left->type();
    2513           0 :         MOZ_ASSERT(IsSimdType(type));
    2514           0 :         MOZ_ASSERT_IF(IsIntegerSimdType(type), op == Op_add || op == Op_sub || op == Op_mul);
    2515           0 :         setResultType(type);
    2516           0 :         setMovable();
    2517           0 :         if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max)
    2518           0 :             setCommutative();
    2519           0 :     }
    2520             : 
    2521           0 :     static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    2522             :                                  Operation op)
    2523             :     {
    2524           0 :         return new (alloc) MSimdBinaryArith(left, right, op);
    2525             :     }
    2526             : 
    2527             :   public:
    2528           0 :     INSTRUCTION_HEADER(SimdBinaryArith)
    2529             : 
    2530             :     // Create an MSimdBinaryArith instruction and add it to the basic block. Possibly
    2531             :     // create and add an equivalent sequence of instructions instead if the
    2532             :     // current target doesn't support the requested shift operation directly.
    2533             :     static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    2534             :                                       MDefinition* right, Operation op);
    2535             : 
    2536           0 :     AliasSet getAliasSet() const override {
    2537           0 :         return AliasSet::None();
    2538             :     }
    2539             : 
    2540           0 :     Operation operation() const { return operation_; }
    2541             : 
    2542           0 :     bool congruentTo(const MDefinition* ins) const override {
    2543           0 :         if (!binaryCongruentTo(ins))
    2544           0 :             return false;
    2545           0 :         return operation_ == ins->toSimdBinaryArith()->operation();
    2546             :     }
    2547             : 
    2548             :     void printOpcode(GenericPrinter& out) const override;
    2549             : 
    2550           0 :     ALLOW_CLONE(MSimdBinaryArith)
    2551             : };
    2552             : 
    2553           0 : class MSimdBinarySaturating
    2554             :   : public MBinaryInstruction,
    2555             :     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data
    2556             : {
    2557             :   public:
    2558             :     enum Operation
    2559             :     {
    2560             :         add,
    2561             :         sub,
    2562             :     };
    2563             : 
    2564           0 :     static const char* OperationName(Operation op)
    2565             :     {
    2566           0 :         switch (op) {
    2567             :           case add:
    2568           0 :             return "add";
    2569             :           case sub:
    2570           0 :             return "sub";
    2571             :         }
    2572           0 :         MOZ_CRASH("unexpected operation");
    2573             :     }
    2574             : 
    2575             :   private:
    2576             :     Operation operation_;
    2577             :     SimdSign sign_;
    2578             : 
    2579           0 :     MSimdBinarySaturating(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
    2580           0 :       : MBinaryInstruction(left, right)
    2581             :       , operation_(op)
    2582           0 :       , sign_(sign)
    2583             :     {
    2584           0 :         MOZ_ASSERT(left->type() == right->type());
    2585           0 :         MIRType type = left->type();
    2586           0 :         MOZ_ASSERT(type == MIRType::Int8x16 || type == MIRType::Int16x8);
    2587           0 :         setResultType(type);
    2588           0 :         setMovable();
    2589           0 :         if (op == add)
    2590           0 :             setCommutative();
    2591           0 :     }
    2592             : 
    2593             :   public:
    2594           0 :     INSTRUCTION_HEADER(SimdBinarySaturating)
    2595           0 :     TRIVIAL_NEW_WRAPPERS
    2596             : 
    2597           0 :     AliasSet getAliasSet() const override { return AliasSet::None(); }
    2598             : 
    2599           0 :     Operation operation() const { return operation_; }
    2600           0 :     SimdSign signedness() const { return sign_; }
    2601             : 
    2602           0 :     bool congruentTo(const MDefinition* ins) const override
    2603             :     {
    2604           0 :         if (!binaryCongruentTo(ins))
    2605           0 :             return false;
    2606           0 :         return operation_ == ins->toSimdBinarySaturating()->operation() &&
    2607           0 :                sign_ == ins->toSimdBinarySaturating()->signedness();
    2608             :     }
    2609             : 
    2610             :     void printOpcode(GenericPrinter& out) const override;
    2611             : 
    2612           0 :     ALLOW_CLONE(MSimdBinarySaturating)
    2613             : };
    2614             : 
    2615           0 : class MSimdBinaryBitwise
    2616             :   : public MBinaryInstruction,
    2617             :     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
    2618             : {
    2619             :   public:
    2620             :     enum Operation {
    2621             :         and_,
    2622             :         or_,
    2623             :         xor_
    2624             :     };
    2625             : 
    2626           0 :     static const char* OperationName(Operation op) {
    2627           0 :         switch (op) {
    2628           0 :           case and_: return "and";
    2629           0 :           case or_:  return "or";
    2630           0 :           case xor_: return "xor";
    2631             :         }
    2632           0 :         MOZ_CRASH("unexpected operation");
    2633             :     }
    2634             : 
    2635             :   private:
    2636             :     Operation operation_;
    2637             : 
    2638           0 :     MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op)
    2639           0 :       : MBinaryInstruction(left, right), operation_(op)
    2640             :     {
    2641           0 :         MOZ_ASSERT(left->type() == right->type());
    2642           0 :         MIRType type = left->type();
    2643           0 :         MOZ_ASSERT(IsSimdType(type));
    2644           0 :         setResultType(type);
    2645           0 :         setMovable();
    2646           0 :         setCommutative();
    2647           0 :     }
    2648             : 
    2649             :   public:
    2650           0 :     INSTRUCTION_HEADER(SimdBinaryBitwise)
    2651           0 :     TRIVIAL_NEW_WRAPPERS
    2652             : 
    2653           0 :     AliasSet getAliasSet() const override {
    2654           0 :         return AliasSet::None();
    2655             :     }
    2656             : 
    2657           0 :     Operation operation() const { return operation_; }
    2658             : 
    2659           0 :     bool congruentTo(const MDefinition* ins) const override {
    2660           0 :         if (!binaryCongruentTo(ins))
    2661           0 :             return false;
    2662           0 :         return operation_ == ins->toSimdBinaryBitwise()->operation();
    2663             :     }
    2664             : 
    2665             :     void printOpcode(GenericPrinter& out) const override;
    2666             : 
    2667           0 :     ALLOW_CLONE(MSimdBinaryBitwise)
    2668             : };
    2669             : 
    2670           0 : class MSimdShift
    2671             :   : public MBinaryInstruction,
    2672             :     public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
    2673             : {
    2674             :   public:
    2675             :     enum Operation {
    2676             :         lsh,
    2677             :         rsh,
    2678             :         ursh
    2679             :     };
    2680             : 
    2681             :   private:
    2682             :     Operation operation_;
    2683             : 
    2684           0 :     MSimdShift(MDefinition* left, MDefinition* right, Operation op)
    2685           0 :       : MBinaryInstruction(left, right), operation_(op)
    2686             :     {
    2687           0 :         MIRType type = left->type();
    2688           0 :         MOZ_ASSERT(IsIntegerSimdType(type));
    2689           0 :         setResultType(type);
    2690           0 :         setMovable();
    2691           0 :     }
    2692             : 
    2693           0 :     static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    2694             :                            Operation op)
    2695             :     {
    2696           0 :         return new (alloc) MSimdShift(left, right, op);
    2697             :     }
    2698             : 
    2699             :   public:
    2700           0 :     INSTRUCTION_HEADER(SimdShift)
    2701             : 
    2702             :     // Create an MSimdShift instruction and add it to the basic block. Possibly
    2703             :     // create and add an equivalent sequence of instructions instead if the
    2704             :     // current target doesn't support the requested shift operation directly.
    2705             :     // Return the inserted MInstruction that computes the shifted value.
    2706             :     static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    2707             :                                       MDefinition* right, Operation op);
    2708             : 
    2709             :     // Get the relevant right shift operation given the signedness of a type.
    2710           0 :     static Operation rshForSign(SimdSign sign) {
    2711           0 :         return sign == SimdSign::Unsigned ? ursh : rsh;
    2712             :     }
    2713             : 
    2714           0 :     AliasSet getAliasSet() const override {
    2715           0 :         return AliasSet::None();
    2716             :     }
    2717             : 
    2718           0 :     Operation operation() const { return operation_; }
    2719             : 
    2720           0 :     static const char* OperationName(Operation op) {
    2721           0 :         switch (op) {
    2722           0 :           case lsh:  return "lsh";
    2723           0 :           case rsh:  return "rsh-arithmetic";
    2724           0 :           case ursh: return "rsh-logical";
    2725             :         }
    2726           0 :         MOZ_CRASH("unexpected operation");
    2727             :     }
    2728             : 
    2729             :     void printOpcode(GenericPrinter& out) const override;
    2730             : 
    2731           0 :     bool congruentTo(const MDefinition* ins) const override {
    2732           0 :         if (!binaryCongruentTo(ins))
    2733           0 :             return false;
    2734           0 :         return operation_ == ins->toSimdShift()->operation();
    2735             :     }
    2736             : 
    2737           0 :     ALLOW_CLONE(MSimdShift)
    2738             : };
    2739             : 
    2740           0 : class MSimdSelect
    2741             :   : public MTernaryInstruction,
    2742             :     public SimdSelectPolicy::Data
    2743             : {
    2744           0 :     MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs)
    2745           0 :       : MTernaryInstruction(mask, lhs, rhs)
    2746             :     {
    2747           0 :         MOZ_ASSERT(IsBooleanSimdType(mask->type()));
    2748           0 :         MOZ_ASSERT(lhs->type() == lhs->type());
    2749           0 :         MIRType type = lhs->type();
    2750           0 :         MOZ_ASSERT(IsSimdType(type));
    2751           0 :         setResultType(type);
    2752           0 :         specialization_ = type;
    2753           0 :         setMovable();
    2754           0 :     }
    2755             : 
    2756             :   public:
    2757           0 :     INSTRUCTION_HEADER(SimdSelect)
    2758           0 :     TRIVIAL_NEW_WRAPPERS
    2759             :     NAMED_OPERANDS((0, mask))
    2760             : 
    2761           0 :     AliasSet getAliasSet() const override {
    2762           0 :         return AliasSet::None();
    2763             :     }
    2764             : 
    2765           0 :     bool congruentTo(const MDefinition* ins) const override {
    2766           0 :         return congruentIfOperandsEqual(ins);
    2767             :     }
    2768             : 
    2769           0 :     ALLOW_CLONE(MSimdSelect)
    2770             : };
    2771             : 
    2772             : // Deep clone a constant JSObject.
    2773             : class MCloneLiteral
    2774             :   : public MUnaryInstruction,
    2775             :     public ObjectPolicy<0>::Data
    2776             : {
    2777             :   protected:
    2778           0 :     explicit MCloneLiteral(MDefinition* obj)
    2779           0 :       : MUnaryInstruction(obj)
    2780             :     {
    2781           0 :         setResultType(MIRType::Object);
    2782           0 :     }
    2783             : 
    2784             :   public:
    2785           0 :     INSTRUCTION_HEADER(CloneLiteral)
    2786           0 :     TRIVIAL_NEW_WRAPPERS
    2787             : };
    2788             : 
    2789             : class MParameter : public MNullaryInstruction
    2790             : {
    2791             :     int32_t index_;
    2792             : 
    2793         322 :     MParameter(int32_t index, TemporaryTypeSet* types)
    2794         322 :       : index_(index)
    2795             :     {
    2796         322 :         setResultType(MIRType::Value);
    2797         322 :         setResultTypeSet(types);
    2798         322 :     }
    2799             : 
    2800             :   public:
    2801       16188 :     INSTRUCTION_HEADER(Parameter)
    2802         322 :     TRIVIAL_NEW_WRAPPERS
    2803             : 
    2804             :     static const int32_t THIS_SLOT = -1;
    2805         366 :     int32_t index() const {
    2806         366 :         return index_;
    2807             :     }
    2808             :     void printOpcode(GenericPrinter& out) const override;
    2809             : 
    2810             :     HashNumber valueHash() const override;
    2811             :     bool congruentTo(const MDefinition* ins) const override;
    2812             : };
    2813             : 
    2814             : class MCallee : public MNullaryInstruction
    2815             : {
    2816             :   public:
    2817         162 :     MCallee()
    2818         162 :     {
    2819         162 :         setResultType(MIRType::Object);
    2820         162 :         setMovable();
    2821         162 :     }
    2822             : 
    2823             :   public:
    2824         910 :     INSTRUCTION_HEADER(Callee)
    2825         162 :     TRIVIAL_NEW_WRAPPERS
    2826             : 
    2827           5 :     bool congruentTo(const MDefinition* ins) const override {
    2828           5 :         return congruentIfOperandsEqual(ins);
    2829             :     }
    2830             : 
    2831          30 :     AliasSet getAliasSet() const override {
    2832          30 :         return AliasSet::None();
    2833             :     }
    2834             : };
    2835             : 
    2836             : class MIsConstructing : public MNullaryInstruction
    2837             : {
    2838             :   public:
    2839           0 :     MIsConstructing() {
    2840           0 :         setResultType(MIRType::Boolean);
    2841           0 :         setMovable();
    2842           0 :     }
    2843             : 
    2844             :   public:
    2845           0 :     INSTRUCTION_HEADER(IsConstructing)
    2846           0 :     TRIVIAL_NEW_WRAPPERS
    2847             : 
    2848           0 :     bool congruentTo(const MDefinition* ins) const override {
    2849           0 :         return congruentIfOperandsEqual(ins);
    2850             :     }
    2851           0 :     AliasSet getAliasSet() const override {
    2852           0 :         return AliasSet::None();
    2853             :     }
    2854             : };
    2855             : 
    2856             : class MControlInstruction : public MInstruction
    2857             : {
    2858             :   public:
    2859        4111 :     MControlInstruction()
    2860        4111 :     { }
    2861             : 
    2862             :     virtual size_t numSuccessors() const = 0;
    2863             :     virtual MBasicBlock* getSuccessor(size_t i) const = 0;
    2864             :     virtual void replaceSuccessor(size_t i, MBasicBlock* successor) = 0;
    2865             : 
    2866     1029825 :     bool isControlInstruction() const override {
    2867     1029825 :         return true;
    2868             :     }
    2869             : 
    2870             :     void printOpcode(GenericPrinter& out) const override;
    2871             : };
    2872             : 
    2873             : class MTableSwitch final
    2874             :   : public MControlInstruction,
    2875             :     public NoFloatPolicy<0>::Data
    2876             : {
    2877             :     // The successors of the tableswitch
    2878             :     // - First successor = the default case
    2879             :     // - Successors 2 and higher = the cases
    2880             :     Vector<MBasicBlock*, 0, JitAllocPolicy> successors_;
    2881             :     // Index into successors_ sorted on case index
    2882             :     Vector<size_t, 0, JitAllocPolicy> cases_;
    2883             : 
    2884             :     MUse operand_;
    2885             :     int32_t low_;
    2886             :     int32_t high_;
    2887             : 
    2888          44 :     void initOperand(size_t index, MDefinition* operand) {
    2889          44 :         MOZ_ASSERT(index == 0);
    2890          44 :         operand_.init(operand, this);
    2891          44 :     }
    2892             : 
    2893          44 :     MTableSwitch(TempAllocator& alloc, MDefinition* ins,
    2894             :                  int32_t low, int32_t high)
    2895          44 :       : successors_(alloc),
    2896             :         cases_(alloc),
    2897             :         low_(low),
    2898          44 :         high_(high)
    2899             :     {
    2900          44 :         initOperand(0, ins);
    2901          44 :     }
    2902             : 
    2903             :   protected:
    2904           0 :     MUse* getUseFor(size_t index) override {
    2905           0 :         MOZ_ASSERT(index == 0);
    2906           0 :         return &operand_;
    2907             :     }
    2908             : 
    2909           0 :     const MUse* getUseFor(size_t index) const override {
    2910           0 :         MOZ_ASSERT(index == 0);
    2911           0 :         return &operand_;
    2912             :     }
    2913             : 
    2914             :   public:
    2915           0 :     INSTRUCTION_HEADER(TableSwitch)
    2916             :     static MTableSwitch* New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high);
    2917             : 
    2918         748 :     size_t numSuccessors() const override {
    2919         748 :         return successors_.length();
    2920             :     }
    2921             : 
    2922         264 :     MOZ_MUST_USE bool addSuccessor(MBasicBlock* successor, size_t* index) {
    2923         264 :         MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2));
    2924         264 :         MOZ_ASSERT(!successors_.empty());
    2925         264 :         *index = successors_.length();
    2926         264 :         return successors_.append(successor);
    2927             :     }
    2928             : 
    2929         308 :     MBasicBlock* getSuccessor(size_t i) const override {
    2930         308 :         MOZ_ASSERT(i < numSuccessors());
    2931         308 :         return successors_[i];
    2932             :     }
    2933             : 
    2934           0 :     void replaceSuccessor(size_t i, MBasicBlock* successor) override {
    2935           0 :         MOZ_ASSERT(i < numSuccessors());
    2936           0 :         successors_[i] = successor;
    2937           0 :     }
    2938             : 
    2939         264 :     int32_t low() const {
    2940         264 :         return low_;
    2941             :     }
    2942             : 
    2943           0 :     int32_t high() const {
    2944           0 :         return high_;
    2945             :     }
    2946             : 
    2947           0 :     MBasicBlock* getDefault() const {
    2948           0 :         return getSuccessor(0);
    2949             :     }
    2950             : 
    2951           0 :     MBasicBlock* getCase(size_t i) const {
    2952           0 :         return getSuccessor(cases_[i]);
    2953             :     }
    2954             : 
    2955          44 :     MOZ_MUST_USE bool addDefault(MBasicBlock* block, size_t* index = nullptr) {
    2956          44 :         MOZ_ASSERT(successors_.empty());
    2957          44 :         if (index)
    2958          44 :             *index = 0;
    2959          44 :         return successors_.append(block);
    2960             :     }
    2961             : 
    2962         264 :     MOZ_MUST_USE bool addCase(size_t successorIndex) {
    2963         264 :         return cases_.append(successorIndex);
    2964             :     }
    2965             : 
    2966           0 :     size_t numCases() const {
    2967           0 :         return high() - low() + 1;
    2968             :     }
    2969             : 
    2970           0 :     MDefinition* getOperand(size_t index) const override {
    2971           0 :         MOZ_ASSERT(index == 0);
    2972           0 :         return operand_.producer();
    2973             :     }
    2974             : 
    2975           0 :     size_t numOperands() const override {
    2976           0 :         return 1;
    2977             :     }
    2978             : 
    2979           0 :     size_t indexOf(const MUse* u) const final override {
    2980           0 :         MOZ_ASSERT(u == getUseFor(0));
    2981           0 :         return 0;
    2982             :     }
    2983             : 
    2984           0 :     void replaceOperand(size_t index, MDefinition* operand) final override {
    2985           0 :         MOZ_ASSERT(index == 0);
    2986           0 :         operand_.replaceProducer(operand);
    2987           0 :     }
    2988             : 
    2989             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    2990             : };
    2991             : 
    2992             : template <size_t Arity, size_t Successors>
    2993        4063 : class MAryControlInstruction : public MControlInstruction
    2994             : {
    2995             :     mozilla::Array<MUse, Arity> operands_;
    2996             :     mozilla::Array<MBasicBlock*, Successors> successors_;
    2997             : 
    2998             :   protected:
    2999        4401 :     void setSuccessor(size_t index, MBasicBlock* successor) {
    3000        4401 :         successors_[index] = successor;
    3001        4401 :     }
    3002             : 
    3003        4901 :     MUse* getUseFor(size_t index) final override {
    3004        4901 :         return &operands_[index];
    3005             :     }
    3006          46 :     const MUse* getUseFor(size_t index) const final override {
    3007          46 :         return &operands_[index];
    3008             :     }
    3009        1495 :     void initOperand(size_t index, MDefinition* operand) {
    3010        1495 :         operands_[index].init(operand, this);
    3011        1495 :     }
    3012             : 
    3013             :   public:
    3014       11573 :     MDefinition* getOperand(size_t index) const final override {
    3015       11573 :         return operands_[index].producer();
    3016             :     }
    3017       27332 :     size_t numOperands() const final override {
    3018       27332 :         return Arity;
    3019             :     }
    3020        4727 :     size_t indexOf(const MUse* u) const final override {
    3021        4727 :         MOZ_ASSERT(u >= &operands_[0]);
    3022        4727 :         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
    3023        4727 :         return u - &operands_[0];
    3024             :     }
    3025          20 :     void replaceOperand(size_t index, MDefinition* operand) final override {
    3026          20 :         operands_[index].replaceProducer(operand);
    3027          20 :     }
    3028      140953 :     size_t numSuccessors() const final override {
    3029      140953 :         return Successors;
    3030             :     }
    3031       78800 :     MBasicBlock* getSuccessor(size_t i) const final override {
    3032       78800 :         return successors_[i];
    3033             :     }
    3034         136 :     void replaceSuccessor(size_t i, MBasicBlock* succ) final override {
    3035         136 :         successors_[i] = succ;
    3036         136 :     }
    3037             : };
    3038             : 
    3039             : // Jump to the start of another basic block.
    3040             : class MGoto
    3041             :   : public MAryControlInstruction<0, 1>,
    3042             :     public NoTypePolicy::Data
    3043             : {
    3044        2531 :     explicit MGoto(MBasicBlock* target) {
    3045        2531 :         setSuccessor(0, target);
    3046        2531 :     }
    3047             : 
    3048             :   public:
    3049       27160 :     INSTRUCTION_HEADER(Goto)
    3050             :     static MGoto* New(TempAllocator& alloc, MBasicBlock* target);
    3051             :     static MGoto* New(TempAllocator::Fallible alloc, MBasicBlock* target);
    3052             : 
    3053             :     // Variant that may patch the target later.
    3054             :     static MGoto* New(TempAllocator& alloc);
    3055             : 
    3056             :     static const size_t TargetIndex = 0;
    3057             : 
    3058         283 :     MBasicBlock* target() {
    3059         283 :         return getSuccessor(0);
    3060             :     }
    3061         504 :     AliasSet getAliasSet() const override {
    3062         504 :         return AliasSet::None();
    3063             :     }
    3064             : };
    3065             : 
    3066             : enum BranchDirection {
    3067             :     FALSE_BRANCH,
    3068             :     TRUE_BRANCH
    3069             : };
    3070             : 
    3071             : static inline BranchDirection
    3072          11 : NegateBranchDirection(BranchDirection dir)
    3073             : {
    3074          11 :     return (dir == FALSE_BRANCH) ? TRUE_BRANCH : FALSE_BRANCH;
    3075             : }
    3076             : 
    3077             : // Tests if the input instruction evaluates to true or false, and jumps to the
    3078             : // start of a corresponding basic block.
    3079             : class MTest
    3080             :   : public MAryControlInstruction<1, 2>,
    3081             :     public TestPolicy::Data
    3082             : {
    3083             :     bool operandMightEmulateUndefined_;
    3084             : 
    3085         933 :     MTest(MDefinition* ins, MBasicBlock* trueBranch, MBasicBlock* falseBranch)
    3086         933 :       : operandMightEmulateUndefined_(true)
    3087             :     {
    3088         933 :         initOperand(0, ins);
    3089         933 :         setSuccessor(0, trueBranch);
    3090         933 :         setSuccessor(1, falseBranch);
    3091         933 :     }
    3092             : 
    3093             :     // Variant which may patch the ifTrue branch later.
    3094           0 :     MTest(MDefinition* ins, MBasicBlock* falseBranch)
    3095           0 :       : MTest(ins, nullptr, falseBranch)
    3096           0 :     {}
    3097             : 
    3098             :   public:
    3099       10019 :     INSTRUCTION_HEADER(Test)
    3100         933 :     TRIVIAL_NEW_WRAPPERS
    3101         334 :     NAMED_OPERANDS((0, input))
    3102             : 
    3103             :     static const size_t TrueBranchIndex = 0;
    3104             : 
    3105        2014 :     MBasicBlock* ifTrue() const {
    3106        2014 :         return getSuccessor(0);
    3107             :     }
    3108        1007 :     MBasicBlock* ifFalse() const {
    3109        1007 :         return getSuccessor(1);
    3110             :     }
    3111          11 :     MBasicBlock* branchSuccessor(BranchDirection dir) const {
    3112          11 :         return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse();
    3113             :     }
    3114             : 
    3115         218 :     AliasSet getAliasSet() const override {
    3116         218 :         return AliasSet::None();
    3117             :     }
    3118             : 
    3119             :     // We cache whether our operand might emulate undefined, but we don't want
    3120             :     // to do that from New() or the constructor, since those can be called on
    3121             :     // background threads.  So make callers explicitly call it if they want us
    3122             :     // to check whether the operand might do this.  If this method is never
    3123             :     // called, we'll assume our operand can emulate undefined.
    3124             :     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
    3125             :     MDefinition* foldsDoubleNegation(TempAllocator& alloc);
    3126             :     MDefinition* foldsConstant(TempAllocator& alloc);
    3127             :     MDefinition* foldsTypes(TempAllocator& alloc);
    3128             :     MDefinition* foldsNeedlessControlFlow(TempAllocator& alloc);
    3129             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    3130             :     void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
    3131             :                                 bool* filtersNull);
    3132             : 
    3133         910 :     void markNoOperandEmulatesUndefined() {
    3134         910 :         operandMightEmulateUndefined_ = false;
    3135         910 :     }
    3136        1002 :     bool operandMightEmulateUndefined() const {
    3137        1002 :         return operandMightEmulateUndefined_;
    3138             :     }
    3139             : #ifdef DEBUG
    3140           0 :     bool isConsistentFloat32Use(MUse* use) const override {
    3141           0 :         return true;
    3142             :     }
    3143             : #endif
    3144             : };
    3145             : 
    3146             : // Equivalent to MTest(true, successor, fake), except without the foldsTo
    3147             : // method. This allows IonBuilder to insert fake CFG edges to magically protect
    3148             : // control flow for try-catch blocks.
    3149             : class MGotoWithFake
    3150             :   : public MAryControlInstruction<0, 2>,
    3151             :     public NoTypePolicy::Data
    3152             : {
    3153           2 :     MGotoWithFake(MBasicBlock* successor, MBasicBlock* fake)
    3154           2 :     {
    3155           2 :         setSuccessor(0, successor);
    3156           2 :         setSuccessor(1, fake);
    3157           2 :     }
    3158             : 
    3159             :   public:
    3160          25 :     INSTRUCTION_HEADER(GotoWithFake)
    3161           2 :     TRIVIAL_NEW_WRAPPERS
    3162             : 
    3163           1 :     MBasicBlock* target() const {
    3164           1 :         return getSuccessor(0);
    3165             :     }
    3166             : 
    3167           2 :     AliasSet getAliasSet() const override {
    3168           2 :         return AliasSet::None();
    3169             :     }
    3170             : };
    3171             : 
    3172             : // Returns from this function to the previous caller.
    3173             : class MReturn
    3174             :   : public MAryControlInstruction<1, 0>,
    3175             :     public BoxInputsPolicy::Data
    3176             : {
    3177         561 :     explicit MReturn(MDefinition* ins) {
    3178         561 :         initOperand(0, ins);
    3179         561 :     }
    3180             : 
    3181             :   public:
    3182        1137 :     INSTRUCTION_HEADER(Return)
    3183         561 :     TRIVIAL_NEW_WRAPPERS
    3184          60 :     NAMED_OPERANDS((0, input))
    3185             : 
    3186          35 :     AliasSet getAliasSet() const override {
    3187          35 :         return AliasSet::None();
    3188             :     }
    3189             : };
    3190             : 
    3191             : class MThrow
    3192             :   : public MAryControlInstruction<1, 0>,
    3193             :     public BoxInputsPolicy::Data
    3194             : {
    3195           1 :     explicit MThrow(MDefinition* ins) {
    3196           1 :         initOperand(0, ins);
    3197           1 :     }
    3198             : 
    3199             :   public:
    3200          27 :     INSTRUCTION_HEADER(Throw)
    3201           1 :     TRIVIAL_NEW_WRAPPERS
    3202             : 
    3203           3 :     virtual AliasSet getAliasSet() const override {
    3204           3 :         return AliasSet::None();
    3205             :     }
    3206           1 :     bool possiblyCalls() const override {
    3207           1 :         return true;
    3208             :     }
    3209             : };
    3210             : 
    3211             : // Fabricate a type set containing only the type of the specified object.
    3212             : TemporaryTypeSet*
    3213             : MakeSingletonTypeSet(CompilerConstraintList* constraints, JSObject* obj);
    3214             : 
    3215             : TemporaryTypeSet*
    3216             : MakeSingletonTypeSet(CompilerConstraintList* constraints, ObjectGroup* obj);
    3217             : 
    3218             : MOZ_MUST_USE bool
    3219             : MergeTypes(TempAllocator& alloc, MIRType* ptype, TemporaryTypeSet** ptypeSet,
    3220             :            MIRType newType, TemporaryTypeSet* newTypeSet);
    3221             : 
    3222             : bool
    3223             : TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes);
    3224             : 
    3225             : bool
    3226             : EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
    3227             :            MIRType type2, TemporaryTypeSet* typeset2);
    3228             : 
    3229             : bool
    3230             : CanStoreUnboxedType(TempAllocator& alloc,
    3231             :                     JSValueType unboxedType, MIRType input, TypeSet* inputTypes);
    3232             : 
    3233             : class MNewArray
    3234             :   : public MUnaryInstruction,
    3235             :     public NoTypePolicy::Data
    3236             : {
    3237             :   private:
    3238             :     // Number of elements to allocate for the array.
    3239             :     uint32_t length_;
    3240             : 
    3241             :     // Heap where the array should be allocated.
    3242             :     gc::InitialHeap initialHeap_;
    3243             : 
    3244             :     // Whether values written to this array should be converted to double first.
    3245             :     bool convertDoubleElements_;
    3246             : 
    3247             :     jsbytecode* pc_;
    3248             : 
    3249             :     bool vmCall_;
    3250             : 
    3251             :     MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
    3252             :               gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall = false);
    3253             : 
    3254             :   public:
    3255        2099 :     INSTRUCTION_HEADER(NewArray)
    3256           9 :     TRIVIAL_NEW_WRAPPERS
    3257             : 
    3258           0 :     static MNewArray* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
    3259             :                             uint32_t length, MConstant* templateConst,
    3260             :                             gc::InitialHeap initialHeap, jsbytecode* pc)
    3261             :     {
    3262           0 :         return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc, true);
    3263             :     }
    3264             : 
    3265          11 :     uint32_t length() const {
    3266          11 :         return length_;
    3267             :     }
    3268             : 
    3269          32 :     JSObject* templateObject() const {
    3270          32 :         return getOperand(0)->toConstant()->toObjectOrNull();
    3271             :     }
    3272             : 
    3273           3 :     gc::InitialHeap initialHeap() const {
    3274           3 :         return initialHeap_;
    3275             :     }
    3276             : 
    3277           0 :     jsbytecode* pc() const {
    3278           0 :         return pc_;
    3279             :     }
    3280             : 
    3281           6 :     bool isVMCall() const {
    3282           6 :         return vmCall_;
    3283             :     }
    3284             : 
    3285          20 :     bool convertDoubleElements() const {
    3286          20 :         return convertDoubleElements_;
    3287             :     }
    3288             : 
    3289             :     // NewArray is marked as non-effectful because all our allocations are
    3290             :     // either lazy when we are using "new Array(length)" or bounded by the
    3291             :     // script or the stack size when we are using "new Array(...)" or "[...]"
    3292             :     // notations.  So we might have to allocate the array twice if we bail
    3293             :     // during the computation of the first element of the square braket
    3294             :     // notation.
    3295          33 :     virtual AliasSet getAliasSet() const override {
    3296          33 :         return AliasSet::None();
    3297             :     }
    3298             : 
    3299             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3300           3 :     bool canRecoverOnBailout() const override {
    3301             :         // The template object can safely be used in the recover instruction
    3302             :         // because it can never be mutated by any other function execution.
    3303           3 :         return templateObject() != nullptr;
    3304             :     }
    3305             : };
    3306             : 
    3307             : class MNewArrayCopyOnWrite : public MNullaryInstruction
    3308             : {
    3309             :     CompilerGCPointer<ArrayObject*> templateObject_;
    3310             :     gc::InitialHeap initialHeap_;
    3311             : 
    3312           0 :     MNewArrayCopyOnWrite(CompilerConstraintList* constraints, ArrayObject* templateObject,
    3313             :                          gc::InitialHeap initialHeap)
    3314           0 :       : templateObject_(templateObject),
    3315           0 :         initialHeap_(initialHeap)
    3316             :     {
    3317           0 :         MOZ_ASSERT(!templateObject->isSingleton());
    3318           0 :         setResultType(MIRType::Object);
    3319           0 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
    3320           0 :     }
    3321             : 
    3322             :   public:
    3323           0 :     INSTRUCTION_HEADER(NewArrayCopyOnWrite)
    3324           0 :     TRIVIAL_NEW_WRAPPERS
    3325             : 
    3326           0 :     ArrayObject* templateObject() const {
    3327           0 :         return templateObject_;
    3328             :     }
    3329             : 
    3330           0 :     gc::InitialHeap initialHeap() const {
    3331           0 :         return initialHeap_;
    3332             :     }
    3333             : 
    3334           0 :     virtual AliasSet getAliasSet() const override {
    3335           0 :         return AliasSet::None();
    3336             :     }
    3337             : 
    3338           0 :     bool appendRoots(MRootList& roots) const override {
    3339           0 :         return roots.append(templateObject_);
    3340             :     }
    3341             : };
    3342             : 
    3343             : class MNewArrayDynamicLength
    3344             :   : public MUnaryInstruction,
    3345             :     public IntPolicy<0>::Data
    3346             : {
    3347             :     CompilerObject templateObject_;
    3348             :     gc::InitialHeap initialHeap_;
    3349             : 
    3350           0 :     MNewArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
    3351             :                            gc::InitialHeap initialHeap, MDefinition* length)
    3352           0 :       : MUnaryInstruction(length),
    3353             :         templateObject_(templateObject),
    3354           0 :         initialHeap_(initialHeap)
    3355             :     {
    3356           0 :         setGuard(); // Need to throw if length is negative.
    3357           0 :         setResultType(MIRType::Object);
    3358           0 :         if (!templateObject->isSingleton())
    3359           0 :             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
    3360           0 :     }
    3361             : 
    3362             :   public:
    3363           0 :     INSTRUCTION_HEADER(NewArrayDynamicLength)
    3364           0 :     TRIVIAL_NEW_WRAPPERS
    3365           0 :     NAMED_OPERANDS((0, length))
    3366             : 
    3367           0 :     JSObject* templateObject() const {
    3368           0 :         return templateObject_;
    3369             :     }
    3370           0 :     gc::InitialHeap initialHeap() const {
    3371           0 :         return initialHeap_;
    3372             :     }
    3373             : 
    3374           0 :     virtual AliasSet getAliasSet() const override {
    3375           0 :         return AliasSet::None();
    3376             :     }
    3377             : 
    3378           0 :     bool appendRoots(MRootList& roots) const override {
    3379           0 :         return roots.append(templateObject_);
    3380             :     }
    3381             : };
    3382             : 
    3383             : class MNewTypedArray
    3384             :   : public MUnaryInstruction,
    3385             :     public NoTypePolicy::Data
    3386             : {
    3387             :     gc::InitialHeap initialHeap_;
    3388             : 
    3389           0 :     MNewTypedArray(CompilerConstraintList* constraints, MConstant* templateConst,
    3390             :                    gc::InitialHeap initialHeap)
    3391           0 :       : MUnaryInstruction(templateConst),
    3392           0 :         initialHeap_(initialHeap)
    3393             :     {
    3394           0 :         MOZ_ASSERT(!templateObject()->isSingleton());
    3395           0 :         setResultType(MIRType::Object);
    3396           0 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
    3397           0 :     }
    3398             : 
    3399             :   public:
    3400           0 :     INSTRUCTION_HEADER(NewTypedArray)
    3401           0 :     TRIVIAL_NEW_WRAPPERS
    3402             : 
    3403           0 :     TypedArrayObject* templateObject() const {
    3404           0 :         return &getOperand(0)->toConstant()->toObject().as<TypedArrayObject>();
    3405             :     }
    3406             : 
    3407           0 :     gc::InitialHeap initialHeap() const {
    3408           0 :         return initialHeap_;
    3409             :     }
    3410             : 
    3411           0 :     virtual AliasSet getAliasSet() const override {
    3412           0 :         return AliasSet::None();
    3413             :     }
    3414             : 
    3415             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3416           0 :     bool canRecoverOnBailout() const override {
    3417           0 :         return true;
    3418             :     }
    3419             : };
    3420             : 
    3421             : class MNewTypedArrayDynamicLength
    3422             :   : public MUnaryInstruction,
    3423             :     public IntPolicy<0>::Data
    3424             : {
    3425             :     CompilerObject templateObject_;
    3426             :     gc::InitialHeap initialHeap_;
    3427             : 
    3428           0 :     MNewTypedArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
    3429             :                            gc::InitialHeap initialHeap, MDefinition* length)
    3430           0 :       : MUnaryInstruction(length),
    3431             :         templateObject_(templateObject),
    3432           0 :         initialHeap_(initialHeap)
    3433             :     {
    3434           0 :         setGuard(); // Need to throw if length is negative.
    3435           0 :         setResultType(MIRType::Object);
    3436           0 :         if (!templateObject->isSingleton())
    3437           0 :             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
    3438           0 :     }
    3439             : 
    3440             :   public:
    3441           0 :     INSTRUCTION_HEADER(NewTypedArrayDynamicLength)
    3442             : 
    3443           0 :     static MNewTypedArrayDynamicLength* New(TempAllocator& alloc, CompilerConstraintList* constraints,
    3444             :                                             JSObject* templateObject, gc::InitialHeap initialHeap,
    3445             :                                             MDefinition* length)
    3446             :     {
    3447           0 :         return new(alloc) MNewTypedArrayDynamicLength(constraints, templateObject, initialHeap, length);
    3448             :     }
    3449             : 
    3450           0 :     MDefinition* length() const {
    3451           0 :         return getOperand(0);
    3452             :     }
    3453           0 :     JSObject* templateObject() const {
    3454           0 :         return templateObject_;
    3455             :     }
    3456           0 :     gc::InitialHeap initialHeap() const {
    3457           0 :         return initialHeap_;
    3458             :     }
    3459             : 
    3460           0 :     virtual AliasSet getAliasSet() const override {
    3461           0 :         return AliasSet::None();
    3462             :     }
    3463             : 
    3464           0 :     bool appendRoots(MRootList& roots) const override {
    3465           0 :         return roots.append(templateObject_);
    3466             :     }
    3467             : };
    3468             : 
    3469             : class MNewObject
    3470             :   : public MUnaryInstruction,
    3471             :     public NoTypePolicy::Data
    3472             : {
    3473             :   public:
    3474             :     enum Mode { ObjectLiteral, ObjectCreate };
    3475             : 
    3476             :   private:
    3477             :     gc::InitialHeap initialHeap_;
    3478             :     Mode mode_;
    3479             :     bool vmCall_;
    3480             : 
    3481           7 :     MNewObject(CompilerConstraintList* constraints, MConstant* templateConst,
    3482             :                gc::InitialHeap initialHeap, Mode mode, bool vmCall = false)
    3483           7 :       : MUnaryInstruction(templateConst),
    3484             :         initialHeap_(initialHeap),
    3485             :         mode_(mode),
    3486           7 :         vmCall_(vmCall)
    3487             :     {
    3488           7 :         MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
    3489           7 :         setResultType(MIRType::Object);
    3490             : 
    3491           7 :         if (JSObject* obj = templateObject())
    3492           7 :             setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
    3493             : 
    3494             :         // The constant is kept separated in a MConstant, this way we can safely
    3495             :         // mark it during GC if we recover the object allocation.  Otherwise, by
    3496             :         // making it emittedAtUses, we do not produce register allocations for
    3497             :         // it and inline its content inside the code produced by the
    3498             :         // CodeGenerator.
    3499           7 :         if (templateConst->toConstant()->type() == MIRType::Object)
    3500           7 :             templateConst->setEmittedAtUses();
    3501           7 :     }
    3502             : 
    3503             :   public:
    3504        1981 :     INSTRUCTION_HEADER(NewObject)
    3505           7 :     TRIVIAL_NEW_WRAPPERS
    3506             : 
    3507           0 :     static MNewObject* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
    3508             :                              MConstant* templateConst, gc::InitialHeap initialHeap,
    3509             :                              Mode mode)
    3510             :     {
    3511           0 :         return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode, true);
    3512             :     }
    3513             : 
    3514           1 :     Mode mode() const {
    3515           1 :         return mode_;
    3516             :     }
    3517             : 
    3518          94 :     JSObject* templateObject() const {
    3519          94 :         return getOperand(0)->toConstant()->toObjectOrNull();
    3520             :     }
    3521             : 
    3522           1 :     gc::InitialHeap initialHeap() const {
    3523           1 :         return initialHeap_;
    3524             :     }
    3525             : 
    3526           2 :     bool isVMCall() const {
    3527           2 :         return vmCall_;
    3528             :     }
    3529             : 
    3530             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3531          61 :     bool canRecoverOnBailout() const override {
    3532             :         // The template object can safely be used in the recover instruction
    3533             :         // because it can never be mutated by any other function execution.
    3534          61 :         return templateObject() != nullptr;
    3535             :     }
    3536             : };
    3537             : 
    3538             : 
    3539             : class MNewIterator
    3540             :   : public MUnaryInstruction,
    3541             :     public NoTypePolicy::Data
    3542             : {
    3543             :   public:
    3544             :     enum Type {
    3545             :         ArrayIterator,
    3546             :         StringIterator,
    3547             :     };
    3548             : 
    3549             : private:
    3550             :     Type type_;
    3551             : 
    3552           4 :     MNewIterator(CompilerConstraintList* constraints, MConstant* templateConst, Type type)
    3553           4 :       : MUnaryInstruction(templateConst),
    3554           4 :         type_(type)
    3555             :     {
    3556           4 :         setResultType(MIRType::Object);
    3557           4 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
    3558           4 :         templateConst->setEmittedAtUses();
    3559           4 :     }
    3560             : 
    3561             :   public:
    3562        1652 :     INSTRUCTION_HEADER(NewIterator)
    3563           4 :     TRIVIAL_NEW_WRAPPERS
    3564             : 
    3565           0 :     Type type() const {
    3566           0 :         return type_;
    3567             :     }
    3568             : 
    3569          10 :     JSObject* templateObject() {
    3570          10 :         return getOperand(0)->toConstant()->toObjectOrNull();
    3571             :     }
    3572             : 
    3573          14 :     AliasSet getAliasSet() const override {
    3574          14 :         return AliasSet::None();
    3575             :     }
    3576             : 
    3577             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3578          47 :     bool canRecoverOnBailout() const override {
    3579          47 :         return true;
    3580             :     }
    3581             : };
    3582             : 
    3583             : 
    3584             : class MNewTypedObject : public MNullaryInstruction
    3585             : {
    3586             :     CompilerGCPointer<InlineTypedObject*> templateObject_;
    3587             :     gc::InitialHeap initialHeap_;
    3588             : 
    3589           0 :     MNewTypedObject(CompilerConstraintList* constraints,
    3590             :                     InlineTypedObject* templateObject,
    3591             :                     gc::InitialHeap initialHeap)
    3592           0 :       : templateObject_(templateObject),
    3593           0 :         initialHeap_(initialHeap)
    3594             :     {
    3595           0 :         setResultType(MIRType::Object);
    3596           0 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
    3597           0 :     }
    3598             : 
    3599             :   public:
    3600           0 :     INSTRUCTION_HEADER(NewTypedObject)
    3601           0 :     TRIVIAL_NEW_WRAPPERS
    3602             : 
    3603           0 :     InlineTypedObject* templateObject() const {
    3604           0 :         return templateObject_;
    3605             :     }
    3606             : 
    3607           0 :     gc::InitialHeap initialHeap() const {
    3608           0 :         return initialHeap_;
    3609             :     }
    3610             : 
    3611           0 :     virtual AliasSet getAliasSet() const override {
    3612           0 :         return AliasSet::None();
    3613             :     }
    3614             : 
    3615           0 :     bool appendRoots(MRootList& roots) const override {
    3616           0 :         return roots.append(templateObject_);
    3617             :     }
    3618             : };
    3619             : 
    3620             : class MTypedObjectDescr
    3621             :   : public MUnaryInstruction,
    3622             :     public SingleObjectPolicy::Data
    3623             : {
    3624             :   private:
    3625           0 :     explicit MTypedObjectDescr(MDefinition* object)
    3626           0 :       : MUnaryInstruction(object)
    3627             :     {
    3628           0 :         setResultType(MIRType::Object);
    3629           0 :         setMovable();
    3630           0 :     }
    3631             : 
    3632             :   public:
    3633           0 :     INSTRUCTION_HEADER(TypedObjectDescr)
    3634           0 :     TRIVIAL_NEW_WRAPPERS
    3635           0 :     NAMED_OPERANDS((0, object))
    3636             : 
    3637           0 :     bool congruentTo(const MDefinition* ins) const override {
    3638           0 :         return congruentIfOperandsEqual(ins);
    3639             :     }
    3640           0 :     AliasSet getAliasSet() const override {
    3641           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    3642             :     }
    3643             : };
    3644             : 
    3645             : // Generic way for constructing a SIMD object in IonMonkey, this instruction
    3646             : // takes as argument a SIMD instruction and returns a new SIMD object which
    3647             : // corresponds to the MIRType of its operand.
    3648             : class MSimdBox
    3649             :   : public MUnaryInstruction,
    3650             :     public NoTypePolicy::Data
    3651             : {
    3652             :   protected:
    3653             :     CompilerGCPointer<InlineTypedObject*> templateObject_;
    3654             :     SimdType simdType_;
    3655             :     gc::InitialHeap initialHeap_;
    3656             : 
    3657           0 :     MSimdBox(CompilerConstraintList* constraints,
    3658             :              MDefinition* op,
    3659             :              InlineTypedObject* templateObject,
    3660             :              SimdType simdType,
    3661             :              gc::InitialHeap initialHeap)
    3662           0 :       : MUnaryInstruction(op),
    3663             :         templateObject_(templateObject),
    3664             :         simdType_(simdType),
    3665           0 :         initialHeap_(initialHeap)
    3666             :     {
    3667           0 :         MOZ_ASSERT(IsSimdType(op->type()));
    3668           0 :         setMovable();
    3669           0 :         setResultType(MIRType::Object);
    3670           0 :         if (constraints)
    3671           0 :             setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
    3672           0 :     }
    3673             : 
    3674             :   public:
    3675           0 :     INSTRUCTION_HEADER(SimdBox)
    3676           0 :     TRIVIAL_NEW_WRAPPERS
    3677             : 
    3678           0 :     InlineTypedObject* templateObject() const {
    3679           0 :         return templateObject_;
    3680             :     }
    3681             : 
    3682           0 :     SimdType simdType() const {
    3683           0 :         return simdType_;
    3684             :     }
    3685             : 
    3686           0 :     gc::InitialHeap initialHeap() const {
    3687           0 :         return initialHeap_;
    3688             :     }
    3689             : 
    3690           0 :     bool congruentTo(const MDefinition* ins) const override {
    3691           0 :         if (!congruentIfOperandsEqual(ins))
    3692           0 :             return false;
    3693           0 :         const MSimdBox* box = ins->toSimdBox();
    3694           0 :         if (box->simdType() != simdType())
    3695           0 :             return false;
    3696           0 :         MOZ_ASSERT(box->templateObject() == templateObject());
    3697           0 :         if (box->initialHeap() != initialHeap())
    3698           0 :             return false;
    3699           0 :         return true;
    3700             :     }
    3701             : 
    3702           0 :     AliasSet getAliasSet() const override {
    3703           0 :         return AliasSet::None();
    3704             :     }
    3705             : 
    3706             :     void printOpcode(GenericPrinter& out) const override;
    3707             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3708           0 :     bool canRecoverOnBailout() const override {
    3709           0 :         return true;
    3710             :     }
    3711             : 
    3712           0 :     bool appendRoots(MRootList& roots) const override {
    3713           0 :         return roots.append(templateObject_);
    3714             :     }
    3715             : };
    3716             : 
    3717           0 : class MSimdUnbox
    3718             :   : public MUnaryInstruction,
    3719             :     public SingleObjectPolicy::Data
    3720             : {
    3721             :   protected:
    3722             :     SimdType simdType_;
    3723             : 
    3724           0 :     MSimdUnbox(MDefinition* op, SimdType simdType)
    3725           0 :       : MUnaryInstruction(op),
    3726           0 :         simdType_(simdType)
    3727             :     {
    3728           0 :         MIRType type = SimdTypeToMIRType(simdType);
    3729           0 :         MOZ_ASSERT(IsSimdType(type));
    3730           0 :         setGuard();
    3731           0 :         setMovable();
    3732           0 :         setResultType(type);
    3733           0 :     }
    3734             : 
    3735             :   public:
    3736           0 :     INSTRUCTION_HEADER(SimdUnbox)
    3737           0 :     TRIVIAL_NEW_WRAPPERS
    3738           0 :     ALLOW_CLONE(MSimdUnbox)
    3739             : 
    3740           0 :     SimdType simdType() const { return simdType_; }
    3741             : 
    3742             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    3743           0 :     bool congruentTo(const MDefinition* ins) const override {
    3744           0 :         if (!congruentIfOperandsEqual(ins))
    3745           0 :             return false;
    3746           0 :         return ins->toSimdUnbox()->simdType() == simdType();
    3747             :     }
    3748             : 
    3749           0 :     AliasSet getAliasSet() const override {
    3750           0 :         return AliasSet::None();
    3751             :     }
    3752             : 
    3753             :     void printOpcode(GenericPrinter& out) const override;
    3754             : };
    3755             : 
    3756             : // Creates a new derived type object. At runtime, this is just a call
    3757             : // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
    3758             : // compile to particularly optimized code. However, using a distinct
    3759             : // MIR for creating derived type objects allows the compiler to
    3760             : // optimize ephemeral typed objects as would be created for a
    3761             : // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
    3762             : // derived type object that aliases the memory of `a` itself. The
    3763             : // specific nature of `a.b` is revealed by using
    3764             : // `MNewDerivedTypedObject` rather than `MGetProperty` or what have
    3765             : // you. Moreover, the compiler knows that there are no side-effects,
    3766             : // so `MNewDerivedTypedObject` instructions can be reordered or pruned
    3767             : // as dead code.
    3768             : class MNewDerivedTypedObject
    3769             :   : public MTernaryInstruction,
    3770             :     public Mix3Policy<ObjectPolicy<0>,
    3771             :                       ObjectPolicy<1>,
    3772             :                       IntPolicy<2> >::Data
    3773             : {
    3774             :   private:
    3775             :     TypedObjectPrediction prediction_;
    3776             : 
    3777           0 :     MNewDerivedTypedObject(TypedObjectPrediction prediction,
    3778             :                            MDefinition* type,
    3779             :                            MDefinition* owner,
    3780             :                            MDefinition* offset)
    3781           0 :       : MTernaryInstruction(type, owner, offset),
    3782           0 :         prediction_(prediction)
    3783             :     {
    3784           0 :         setMovable();
    3785           0 :         setResultType(MIRType::Object);
    3786           0 :     }
    3787             : 
    3788             :   public:
    3789           0 :     INSTRUCTION_HEADER(NewDerivedTypedObject)
    3790           0 :     TRIVIAL_NEW_WRAPPERS
    3791           0 :     NAMED_OPERANDS((0, type), (1, owner), (2, offset))
    3792             : 
    3793           0 :     TypedObjectPrediction prediction() const {
    3794           0 :         return prediction_;
    3795             :     }
    3796             : 
    3797           0 :     virtual AliasSet getAliasSet() const override {
    3798           0 :         return AliasSet::None();
    3799             :     }
    3800             : 
    3801             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3802           0 :     bool canRecoverOnBailout() const override {
    3803           0 :         return true;
    3804             :     }
    3805             : };
    3806             : 
    3807             : // This vector is used when the recovered object is kept unboxed. We map the
    3808             : // offset of each property to the index of the corresponding operands in the
    3809             : // object state.
    3810           0 : struct OperandIndexMap : public TempObject
    3811             : {
    3812             :     // The number of properties is limited by scalar replacement. Thus we cannot
    3813             :     // have any large number of properties.
    3814             :     FixedList<uint8_t> map;
    3815             : 
    3816             :     MOZ_MUST_USE bool init(TempAllocator& alloc, JSObject* templateObject);
    3817             : };
    3818             : 
    3819             : // Represent the content of all slots of an object.  This instruction is not
    3820             : // lowered and is not used to generate code.
    3821             : class MObjectState
    3822             :   : public MVariadicInstruction,
    3823             :     public NoFloatPolicyAfter<1>::Data
    3824             : {
    3825             :   private:
    3826             :     uint32_t numSlots_;
    3827             :     uint32_t numFixedSlots_;        // valid if isUnboxed() == false.
    3828             :     OperandIndexMap* operandIndex_; // valid if isUnboxed() == true.
    3829             : 
    3830          84 :     bool isUnboxed() const {
    3831          84 :         return operandIndex_ != nullptr;
    3832             :     }
    3833             : 
    3834             :     MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex);
    3835             :     explicit MObjectState(MObjectState* state);
    3836             : 
    3837             :     MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj);
    3838             : 
    3839         171 :     void initSlot(uint32_t slot, MDefinition* def) {
    3840         171 :         initOperand(slot + 1, def);
    3841         171 :     }
    3842             : 
    3843             :   public:
    3844       14691 :     INSTRUCTION_HEADER(ObjectState)
    3845          69 :     NAMED_OPERANDS((0, object))
    3846             : 
    3847             :     // Return the template object of any object creation which can be recovered
    3848             :     // on bailout.
    3849             :     static JSObject* templateObjectOf(MDefinition* obj);
    3850             : 
    3851             :     static MObjectState* New(TempAllocator& alloc, MDefinition* obj);
    3852             :     static MObjectState* Copy(TempAllocator& alloc, MObjectState* state);
    3853             : 
    3854             :     // As we might do read of uninitialized properties, we have to copy the
    3855             :     // initial values from the template object.
    3856             :     MOZ_MUST_USE bool initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal);
    3857             : 
    3858          84 :     size_t numFixedSlots() const {
    3859          84 :         MOZ_ASSERT(!isUnboxed());
    3860          84 :         return numFixedSlots_;
    3861             :     }
    3862        1004 :     size_t numSlots() const {
    3863        1004 :         return numSlots_;
    3864             :     }
    3865             : 
    3866         600 :     MDefinition* getSlot(uint32_t slot) const {
    3867         600 :         return getOperand(slot + 1);
    3868             :     }
    3869         120 :     void setSlot(uint32_t slot, MDefinition* def) {
    3870         120 :         replaceOperand(slot + 1, def);
    3871         120 :     }
    3872             : 
    3873          42 :     bool hasFixedSlot(uint32_t slot) const {
    3874          42 :         return slot < numSlots() && slot < numFixedSlots();
    3875             :     }
    3876          15 :     MDefinition* getFixedSlot(uint32_t slot) const {
    3877          15 :         MOZ_ASSERT(slot < numFixedSlots());
    3878          15 :         return getSlot(slot);
    3879             :     }
    3880          27 :     void setFixedSlot(uint32_t slot, MDefinition* def) {
    3881          27 :         MOZ_ASSERT(slot < numFixedSlots());
    3882          27 :         setSlot(slot, def);
    3883          27 :     }
    3884             : 
    3885           0 :     bool hasDynamicSlot(uint32_t slot) const {
    3886           0 :         return numFixedSlots() < numSlots() && slot < numSlots() - numFixedSlots();
    3887             :     }
    3888           0 :     MDefinition* getDynamicSlot(uint32_t slot) const {
    3889           0 :         return getSlot(slot + numFixedSlots());
    3890             :     }
    3891           0 :     void setDynamicSlot(uint32_t slot, MDefinition* def) {
    3892           0 :         setSlot(slot + numFixedSlots(), def);
    3893           0 :     }
    3894             : 
    3895             :     // Interface reserved for unboxed objects.
    3896           0 :     bool hasOffset(uint32_t offset) const {
    3897           0 :         MOZ_ASSERT(isUnboxed());
    3898           0 :         return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0;
    3899             :     }
    3900           0 :     MDefinition* getOffset(uint32_t offset) const {
    3901           0 :         return getOperand(operandIndex_->map[offset]);
    3902             :     }
    3903           0 :     void setOffset(uint32_t offset, MDefinition* def) {
    3904           0 :         replaceOperand(operandIndex_->map[offset], def);
    3905           0 :     }
    3906             : 
    3907             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3908         167 :     bool canRecoverOnBailout() const override {
    3909         167 :         return true;
    3910             :     }
    3911             : };
    3912             : 
    3913             : // Represent the contents of all elements of an array.  This instruction is not
    3914             : // lowered and is not used to generate code.
    3915             : class MArrayState
    3916             :   : public MVariadicInstruction,
    3917             :     public NoFloatPolicyAfter<2>::Data
    3918             : {
    3919             :   private:
    3920             :     uint32_t numElements_;
    3921             : 
    3922             :     explicit MArrayState(MDefinition* arr);
    3923             : 
    3924             :     MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len);
    3925             : 
    3926           0 :     void initElement(uint32_t index, MDefinition* def) {
    3927           0 :         initOperand(index + 2, def);
    3928           0 :     }
    3929             : 
    3930             :   public:
    3931           0 :     INSTRUCTION_HEADER(ArrayState)
    3932           0 :     NAMED_OPERANDS((0, array), (1, initializedLength))
    3933             : 
    3934             :     static MArrayState* New(TempAllocator& alloc, MDefinition* arr, MDefinition* undefinedVal,
    3935             :                             MDefinition* initLength);
    3936             :     static MArrayState* Copy(TempAllocator& alloc, MArrayState* state);
    3937             : 
    3938           0 :     void setInitializedLength(MDefinition* def) {
    3939           0 :         replaceOperand(1, def);
    3940           0 :     }
    3941             : 
    3942             : 
    3943           0 :     size_t numElements() const {
    3944           0 :         return numElements_;
    3945             :     }
    3946             : 
    3947           0 :     MDefinition* getElement(uint32_t index) const {
    3948           0 :         return getOperand(index + 2);
    3949             :     }
    3950           0 :     void setElement(uint32_t index, MDefinition* def) {
    3951           0 :         replaceOperand(index + 2, def);
    3952           0 :     }
    3953             : 
    3954             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    3955           0 :     bool canRecoverOnBailout() const override {
    3956           0 :         return true;
    3957             :     }
    3958             : };
    3959             : 
    3960             : // Setting __proto__ in an object literal.
    3961             : class MMutateProto
    3962             :   : public MAryInstruction<2>,
    3963             :     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
    3964             : {
    3965             :   protected:
    3966           0 :     MMutateProto(MDefinition* obj, MDefinition* value)
    3967           0 :     {
    3968           0 :         initOperand(0, obj);
    3969           0 :         initOperand(1, value);
    3970           0 :         setResultType(MIRType::None);
    3971           0 :     }
    3972             : 
    3973             :   public:
    3974           0 :     INSTRUCTION_HEADER(MutateProto)
    3975           0 :     TRIVIAL_NEW_WRAPPERS
    3976           0 :     NAMED_OPERANDS((0, getObject), (1, getValue))
    3977             : 
    3978           0 :     bool possiblyCalls() const override {
    3979           0 :         return true;
    3980             :     }
    3981             : };
    3982             : 
    3983             : // Slow path for adding a property to an object without a known base.
    3984             : class MInitProp
    3985             :   : public MAryInstruction<2>,
    3986             :     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
    3987             : {
    3988             :     CompilerPropertyName name_;
    3989             : 
    3990             :   protected:
    3991           4 :     MInitProp(MDefinition* obj, PropertyName* name, MDefinition* value)
    3992           4 :       : name_(name)
    3993             :     {
    3994           4 :         initOperand(0, obj);
    3995           4 :         initOperand(1, value);
    3996           4 :         setResultType(MIRType::None);
    3997           4 :     }
    3998             : 
    3999             :   public:
    4000           0 :     INSTRUCTION_HEADER(InitProp)
    4001           4 :     TRIVIAL_NEW_WRAPPERS
    4002           0 :     NAMED_OPERANDS((0, getObject), (1, getValue))
    4003             : 
    4004           0 :     PropertyName* propertyName() const {
    4005           0 :         return name_;
    4006             :     }
    4007             : 
    4008           0 :     bool possiblyCalls() const override {
    4009           0 :         return true;
    4010             :     }
    4011             : 
    4012           0 :     bool appendRoots(MRootList& roots) const override {
    4013           0 :         return roots.append(name_);
    4014             :     }
    4015             : };
    4016             : 
    4017             : class MInitPropGetterSetter
    4018             :   : public MBinaryInstruction,
    4019             :     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
    4020             : {
    4021             :     CompilerPropertyName name_;
    4022             : 
    4023           0 :     MInitPropGetterSetter(MDefinition* obj, PropertyName* name, MDefinition* value)
    4024           0 :       : MBinaryInstruction(obj, value),
    4025           0 :         name_(name)
    4026           0 :     { }
    4027             : 
    4028             :   public:
    4029           0 :     INSTRUCTION_HEADER(InitPropGetterSetter)
    4030           0 :     TRIVIAL_NEW_WRAPPERS
    4031           0 :     NAMED_OPERANDS((0, object), (1, value))
    4032             : 
    4033           0 :     PropertyName* name() const {
    4034           0 :         return name_;
    4035             :     }
    4036             : 
    4037           0 :     bool appendRoots(MRootList& roots) const override {
    4038           0 :         return roots.append(name_);
    4039             :     }
    4040             : };
    4041             : 
    4042             : class MInitElem
    4043             :   : public MAryInstruction<3>,
    4044             :     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
    4045             : {
    4046          53 :     MInitElem(MDefinition* obj, MDefinition* id, MDefinition* value)
    4047          53 :     {
    4048          53 :         initOperand(0, obj);
    4049          53 :         initOperand(1, id);
    4050          53 :         initOperand(2, value);
    4051          53 :         setResultType(MIRType::None);
    4052          53 :     }
    4053             : 
    4054             :   public:
    4055          36 :     INSTRUCTION_HEADER(InitElem)
    4056          53 :     TRIVIAL_NEW_WRAPPERS
    4057           0 :     NAMED_OPERANDS((0, getObject), (1, getId), (2, getValue))
    4058             : 
    4059           0 :     bool possiblyCalls() const override {
    4060           0 :         return true;
    4061             :     }
    4062             : };
    4063             : 
    4064             : class MInitElemGetterSetter
    4065             :   : public MTernaryInstruction,
    4066             :     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
    4067             : {
    4068           0 :     MInitElemGetterSetter(MDefinition* obj, MDefinition* id, MDefinition* value)
    4069           0 :       : MTernaryInstruction(obj, id, value)
    4070           0 :     { }
    4071             : 
    4072             :   public:
    4073           0 :     INSTRUCTION_HEADER(InitElemGetterSetter)
    4074           0 :     TRIVIAL_NEW_WRAPPERS
    4075           0 :     NAMED_OPERANDS((0, object), (1, idValue), (2, value))
    4076             : 
    4077             : };
    4078             : 
    4079             : // WrappedFunction wraps a JSFunction so it can safely be used off-thread.
    4080             : // In particular, a function's flags can be modified on the active thread as
    4081             : // functions are relazified and delazified, so we must be careful not to access
    4082             : // these flags off-thread.
    4083             : class WrappedFunction : public TempObject
    4084             : {
    4085             :     CompilerFunction fun_;
    4086             :     uint16_t nargs_;
    4087             :     bool isNative_ : 1;
    4088             :     bool isConstructor_ : 1;
    4089             :     bool isClassConstructor_ : 1;
    4090             :     bool isSelfHostedBuiltin_ : 1;
    4091             : 
    4092             :   public:
    4093             :     explicit WrappedFunction(JSFunction* fun);
    4094           9 :     size_t nargs() const { return nargs_; }
    4095          36 :     bool isNative() const { return isNative_; }
    4096           0 :     bool isConstructor() const { return isConstructor_; }
    4097          18 :     bool isClassConstructor() const { return isClassConstructor_; }
    4098           0 :     bool isSelfHostedBuiltin() const { return isSelfHostedBuiltin_; }
    4099             : 
    4100             :     // fun->native() and fun->jitInfo() can safely be called off-thread: these
    4101             :     // fields never change.
    4102           9 :     JSNative native() const { return fun_->native(); }
    4103           1 :     const JSJitInfo* jitInfo() const { return fun_->jitInfo(); }
    4104             : 
    4105           9 :     JSFunction* rawJSFunction() const { return fun_; }
    4106             : 
    4107          24 :     bool appendRoots(MRootList& roots) const {
    4108          24 :         return roots.append(fun_);
    4109             :     }
    4110             : };
    4111             : 
    4112             : class MCall
    4113             :   : public MVariadicInstruction,
    4114             :     public CallPolicy::Data
    4115             : {
    4116             :   private:
    4117             :     // An MCall uses the MPrepareCall, MDefinition for the function, and
    4118             :     // MPassArg instructions. They are stored in the same list.
    4119             :     static const size_t FunctionOperandIndex   = 0;
    4120             :     static const size_t NumNonArgumentOperands = 1;
    4121             : 
    4122             :   protected:
    4123             :     // Monomorphic cache of single target from TI, or nullptr.
    4124             :     WrappedFunction* target_;
    4125             : 
    4126             :     // Original value of argc from the bytecode.
    4127             :     uint32_t numActualArgs_;
    4128             : 
    4129             :     // True if the call is for JSOP_NEW.
    4130             :     bool construct_:1;
    4131             : 
    4132             :     // True if the caller does not use the return value.
    4133             :     bool ignoresReturnValue_:1;
    4134             : 
    4135             :     bool needsArgCheck_:1;
    4136             : 
    4137        1145 :     MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue)
    4138        1145 :       : target_(target),
    4139             :         numActualArgs_(numActualArgs),
    4140             :         construct_(construct),
    4141             :         ignoresReturnValue_(ignoresReturnValue),
    4142        1145 :         needsArgCheck_(true)
    4143             :     {
    4144        1145 :         setResultType(MIRType::Value);
    4145        1145 :     }
    4146             : 
    4147             :   public:
    4148       10219 :     INSTRUCTION_HEADER(Call)
    4149             :     static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
    4150             :                       bool construct, bool ignoresReturnValue, bool isDOMCall);
    4151             : 
    4152        1145 :     void initFunction(MDefinition* func) {
    4153        1145 :         initOperand(FunctionOperandIndex, func);
    4154        1145 :     }
    4155             : 
    4156           9 :     bool needsArgCheck() const {
    4157           9 :         return needsArgCheck_;
    4158             :     }
    4159             : 
    4160          43 :     void disableArgCheck() {
    4161          43 :         needsArgCheck_ = false;
    4162          43 :     }
    4163          75 :     MDefinition* getFunction() const {
    4164          75 :         return getOperand(FunctionOperandIndex);
    4165             :     }
    4166           7 :     void replaceFunction(MInstruction* newfunc) {
    4167           7 :         replaceOperand(FunctionOperandIndex, newfunc);
    4168           7 :     }
    4169             : 
    4170             :     void addArg(size_t argnum, MDefinition* arg);
    4171             : 
    4172          71 :     MDefinition* getArg(uint32_t index) const {
    4173          71 :         return getOperand(NumNonArgumentOperands + index);
    4174             :     }
    4175             : 
    4176           0 :     static size_t IndexOfThis() {
    4177           0 :         return NumNonArgumentOperands;
    4178             :     }
    4179          41 :     static size_t IndexOfArgument(size_t index) {
    4180          41 :         return NumNonArgumentOperands + index + 1; // +1 to skip |this|.
    4181             :     }
    4182          81 :     static size_t IndexOfStackArg(size_t index) {
    4183          81 :         return NumNonArgumentOperands + index;
    4184             :     }
    4185             : 
    4186             :     // For TI-informed monomorphic callsites.
    4187          54 :     WrappedFunction* getSingleTarget() const {
    4188          54 :         return target_;
    4189             :     }
    4190             : 
    4191         108 :     bool isConstructing() const {
    4192         108 :         return construct_;
    4193             :     }
    4194             : 
    4195          27 :     bool ignoresReturnValue() const {
    4196          27 :         return ignoresReturnValue_;
    4197             :     }
    4198             : 
    4199             :     // The number of stack arguments is the max between the number of formal
    4200             :     // arguments and the number of actual arguments. The number of stack
    4201             :     // argument includes the |undefined| padding added in case of underflow.
    4202             :     // Includes |this|.
    4203         183 :     uint32_t numStackArgs() const {
    4204         183 :         return numOperands() - NumNonArgumentOperands;
    4205             :     }
    4206             : 
    4207             :     // Does not include |this|.
    4208         113 :     uint32_t numActualArgs() const {
    4209         113 :         return numActualArgs_;
    4210             :     }
    4211             : 
    4212          32 :     bool possiblyCalls() const override {
    4213          32 :         return true;
    4214             :     }
    4215             : 
    4216        1172 :     virtual bool isCallDOMNative() const {
    4217        1172 :         return false;
    4218             :     }
    4219             : 
    4220             :     // A method that can be called to tell the MCall to figure out whether it's
    4221             :     // movable or not.  This can't be done in the constructor, because it
    4222             :     // depends on the arguments to the call, and those aren't passed to the
    4223             :     // constructor but are set up later via addArg.
    4224        1145 :     virtual void computeMovable() {
    4225        1145 :     }
    4226             : 
    4227          58 :     bool appendRoots(MRootList& roots) const override {
    4228          58 :         if (target_)
    4229          24 :             return target_->appendRoots(roots);
    4230          34 :         return true;
    4231             :     }
    4232             : };
    4233             : 
    4234             : class MCallDOMNative : public MCall
    4235             : {
    4236             :     // A helper class for MCalls for DOM natives.  Note that this is NOT
    4237             :     // actually a separate MIR op from MCall, because all sorts of places use
    4238             :     // isCall() to check for calls and all we really want is to overload a few
    4239             :     // virtual things from MCall.
    4240             :   protected:
    4241           0 :     MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs)
    4242           0 :         : MCall(target, numActualArgs, false, false)
    4243             :     {
    4244           0 :         MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
    4245             : 
    4246             :         // If our jitinfo is not marked eliminatable, that means that our C++
    4247             :         // implementation is fallible or that it never wants to be eliminated or
    4248             :         // that we have no hope of ever doing the sort of argument analysis that
    4249             :         // would allow us to detemine that we're side-effect-free.  In the
    4250             :         // latter case we wouldn't get DCEd no matter what, but for the former
    4251             :         // two cases we have to explicitly say that we can't be DCEd.
    4252           0 :         if (!getJitInfo()->isEliminatable)
    4253           0 :             setGuard();
    4254           0 :     }
    4255             : 
    4256             :     friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
    4257             :                              size_t numActualArgs, bool construct, bool ignoresReturnValue,
    4258             :                              bool isDOMCall);
    4259             : 
    4260             :     const JSJitInfo* getJitInfo() const;
    4261             :   public:
    4262             :     virtual AliasSet getAliasSet() const override;
    4263             : 
    4264             :     virtual bool congruentTo(const MDefinition* ins) const override;
    4265             : 
    4266           0 :     virtual bool isCallDOMNative() const override {
    4267           0 :         return true;
    4268             :     }
    4269             : 
    4270             :     virtual void computeMovable() override;
    4271             : };
    4272             : 
    4273             : // fun.apply(self, arguments)
    4274             : class MApplyArgs
    4275             :   : public MAryInstruction<3>,
    4276             :     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
    4277             : {
    4278             :   protected:
    4279             :     // Monomorphic cache of single target from TI, or nullptr.
    4280             :     WrappedFunction* target_;
    4281             : 
    4282           0 :     MApplyArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, MDefinition* self)
    4283           0 :       : target_(target)
    4284             :     {
    4285           0 :         initOperand(0, fun);
    4286           0 :         initOperand(1, argc);
    4287           0 :         initOperand(2, self);
    4288           0 :         setResultType(MIRType::Value);
    4289           0 :     }
    4290             : 
    4291             :   public:
    4292           0 :     INSTRUCTION_HEADER(ApplyArgs)
    4293           0 :     TRIVIAL_NEW_WRAPPERS
    4294           0 :     NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis))
    4295             : 
    4296             :     // For TI-informed monomorphic callsites.
    4297           0 :     WrappedFunction* getSingleTarget() const {
    4298           0 :         return target_;
    4299             :     }
    4300             : 
    4301           0 :     bool possiblyCalls() const override {
    4302           0 :         return true;
    4303             :     }
    4304             : 
    4305           0 :     bool appendRoots(MRootList& roots) const override {
    4306           0 :         if (target_)
    4307           0 :             return target_->appendRoots(roots);
    4308           0 :         return true;
    4309             :     }
    4310             : };
    4311             : 
    4312             : // fun.apply(fn, array)
    4313             : class MApplyArray
    4314             :   : public MAryInstruction<3>,
    4315             :     public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >::Data
    4316             : {
    4317             :   protected:
    4318             :     // Monomorphic cache of single target from TI, or nullptr.
    4319             :     WrappedFunction* target_;
    4320             : 
    4321           0 :     MApplyArray(WrappedFunction* target, MDefinition* fun, MDefinition* elements, MDefinition* self)
    4322           0 :       : target_(target)
    4323             :     {
    4324           0 :         initOperand(0, fun);
    4325           0 :         initOperand(1, elements);
    4326           0 :         initOperand(2, self);
    4327           0 :         setResultType(MIRType::Value);
    4328           0 :     }
    4329             : 
    4330             :   public:
    4331           0 :     INSTRUCTION_HEADER(ApplyArray)
    4332           0 :     TRIVIAL_NEW_WRAPPERS
    4333           0 :     NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis))
    4334             : 
    4335             :     // For TI-informed monomorphic callsites.
    4336           0 :     WrappedFunction* getSingleTarget() const {
    4337           0 :         return target_;
    4338             :     }
    4339             : 
    4340           0 :     bool possiblyCalls() const override {
    4341           0 :         return true;
    4342             :     }
    4343             : 
    4344           0 :     bool appendRoots(MRootList& roots) const override {
    4345           0 :         if (target_)
    4346           0 :             return target_->appendRoots(roots);
    4347           0 :         return true;
    4348             :     }
    4349             : };
    4350             : 
    4351             : class MBail : public MNullaryInstruction
    4352             : {
    4353             :   protected:
    4354          35 :     explicit MBail(BailoutKind kind)
    4355          35 :       : MNullaryInstruction()
    4356             :     {
    4357          35 :         bailoutKind_ = kind;
    4358          35 :         setGuard();
    4359          35 :     }
    4360             : 
    4361             :   private:
    4362             :     BailoutKind bailoutKind_;
    4363             : 
    4364             :   public:
    4365        8648 :     INSTRUCTION_HEADER(Bail)
    4366             : 
    4367             :     static MBail*
    4368          35 :     New(TempAllocator& alloc, BailoutKind kind) {
    4369          35 :         return new(alloc) MBail(kind);
    4370             :     }
    4371             :     static MBail*
    4372           0 :     New(TempAllocator& alloc) {
    4373           0 :         return new(alloc) MBail(Bailout_Inevitable);
    4374             :     }
    4375             : 
    4376         204 :     AliasSet getAliasSet() const override {
    4377         204 :         return AliasSet::None();
    4378             :     }
    4379             : 
    4380          18 :     BailoutKind bailoutKind() const {
    4381          18 :         return bailoutKind_;
    4382             :     }
    4383             : };
    4384             : 
    4385          35 : class MUnreachable
    4386             :   : public MAryControlInstruction<0, 0>,
    4387             :     public NoTypePolicy::Data
    4388             : {
    4389             :   public:
    4390         632 :     INSTRUCTION_HEADER(Unreachable)
    4391          35 :     TRIVIAL_NEW_WRAPPERS
    4392             : 
    4393          36 :     AliasSet getAliasSet() const override {
    4394          36 :         return AliasSet::None();
    4395             :     }
    4396             : };
    4397             : 
    4398             : // This class serve as a way to force the encoding of a snapshot, even if there
    4399             : // is no resume point using it.  This is useful to run MAssertRecoveredOnBailout
    4400             : // assertions.
    4401             : class MEncodeSnapshot : public MNullaryInstruction
    4402             : {
    4403             :   protected:
    4404           0 :     MEncodeSnapshot()
    4405           0 :       : MNullaryInstruction()
    4406             :     {
    4407           0 :         setGuard();
    4408           0 :     }
    4409             : 
    4410             :   public:
    4411           0 :     INSTRUCTION_HEADER(EncodeSnapshot)
    4412             : 
    4413             :     static MEncodeSnapshot*
    4414           0 :     New(TempAllocator& alloc) {
    4415           0 :         return new(alloc) MEncodeSnapshot();
    4416             :     }
    4417             : };
    4418             : 
    4419             : class MAssertRecoveredOnBailout
    4420             :   : public MUnaryInstruction,
    4421             :     public NoTypePolicy::Data
    4422             : {
    4423             :   protected:
    4424             :     bool mustBeRecovered_;
    4425             : 
    4426           0 :     MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered)
    4427           0 :       : MUnaryInstruction(ins), mustBeRecovered_(mustBeRecovered)
    4428             :     {
    4429           0 :         setResultType(MIRType::Value);
    4430           0 :         setRecoveredOnBailout();
    4431           0 :         setGuard();
    4432           0 :     }
    4433             : 
    4434             :   public:
    4435           0 :     INSTRUCTION_HEADER(AssertRecoveredOnBailout)
    4436           0 :     TRIVIAL_NEW_WRAPPERS
    4437             : 
    4438             :     // Needed to assert that float32 instructions are correctly recovered.
    4439           0 :     bool canConsumeFloat32(MUse* use) const override { return true; }
    4440             : 
    4441             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    4442           0 :     bool canRecoverOnBailout() const override {
    4443           0 :         return true;
    4444             :     }
    4445             : };
    4446             : 
    4447             : class MAssertFloat32
    4448             :   : public MUnaryInstruction,
    4449             :     public NoTypePolicy::Data
    4450             : {
    4451             :   protected:
    4452             :     bool mustBeFloat32_;
    4453             : 
    4454           0 :     MAssertFloat32(MDefinition* value, bool mustBeFloat32)
    4455           0 :       : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
    4456             :     {
    4457           0 :     }
    4458             : 
    4459             :   public:
    4460           0 :     INSTRUCTION_HEADER(AssertFloat32)
    4461           0 :     TRIVIAL_NEW_WRAPPERS
    4462             : 
    4463           0 :     bool canConsumeFloat32(MUse* use) const override { return true; }
    4464             : 
    4465           0 :     bool mustBeFloat32() const { return mustBeFloat32_; }
    4466             : };
    4467             : 
    4468             : class MGetDynamicName
    4469             :   : public MAryInstruction<2>,
    4470             :     public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
    4471             : {
    4472             :   protected:
    4473           0 :     MGetDynamicName(MDefinition* envChain, MDefinition* name)
    4474           0 :     {
    4475           0 :         initOperand(0, envChain);
    4476           0 :         initOperand(1, name);
    4477           0 :         setResultType(MIRType::Value);
    4478           0 :     }
    4479             : 
    4480             :   public:
    4481           0 :     INSTRUCTION_HEADER(GetDynamicName)
    4482           0 :     NAMED_OPERANDS((0, getEnvironmentChain), (1, getName))
    4483             : 
    4484             :     static MGetDynamicName*
    4485           0 :     New(TempAllocator& alloc, MDefinition* envChain, MDefinition* name) {
    4486           0 :         return new(alloc) MGetDynamicName(envChain, name);
    4487             :     }
    4488             : 
    4489           0 :     bool possiblyCalls() const override {
    4490           0 :         return true;
    4491             :     }
    4492             : };
    4493             : 
    4494             : class MCallDirectEval
    4495             :   : public MAryInstruction<3>,
    4496             :     public Mix3Policy<ObjectPolicy<0>,
    4497             :                       StringPolicy<1>,
    4498             :                       BoxPolicy<2> >::Data
    4499             : {
    4500             :   protected:
    4501           0 :     MCallDirectEval(MDefinition* envChain, MDefinition* string,
    4502             :                     MDefinition* newTargetValue, jsbytecode* pc)
    4503           0 :         : pc_(pc)
    4504             :     {
    4505           0 :         initOperand(0, envChain);
    4506           0 :         initOperand(1, string);
    4507           0 :         initOperand(2, newTargetValue);
    4508           0 :         setResultType(MIRType::Value);
    4509           0 :     }
    4510             : 
    4511             :   public:
    4512           0 :     INSTRUCTION_HEADER(CallDirectEval)
    4513           0 :     NAMED_OPERANDS((0, getEnvironmentChain), (1, getString), (2, getNewTargetValue))
    4514             : 
    4515             :     static MCallDirectEval*
    4516           0 :     New(TempAllocator& alloc, MDefinition* envChain, MDefinition* string,
    4517             :         MDefinition* newTargetValue, jsbytecode* pc)
    4518             :     {
    4519           0 :         return new(alloc) MCallDirectEval(envChain, string, newTargetValue, pc);
    4520             :     }
    4521             : 
    4522           0 :     jsbytecode* pc() const {
    4523           0 :         return pc_;
    4524             :     }
    4525             : 
    4526           0 :     bool possiblyCalls() const override {
    4527           0 :         return true;
    4528             :     }
    4529             : 
    4530             :   private:
    4531             :     jsbytecode* pc_;
    4532             : };
    4533             : 
    4534           0 : class MCompare
    4535             :   : public MBinaryInstruction,
    4536             :     public ComparePolicy::Data
    4537             : {
    4538             :   public:
    4539             :     enum CompareType {
    4540             : 
    4541             :         // Anything compared to Undefined
    4542             :         Compare_Undefined,
    4543             : 
    4544             :         // Anything compared to Null
    4545             :         Compare_Null,
    4546             : 
    4547             :         // Undefined compared to Boolean
    4548             :         // Null      compared to Boolean
    4549             :         // Double    compared to Boolean
    4550             :         // String    compared to Boolean
    4551             :         // Symbol    compared to Boolean
    4552             :         // Object    compared to Boolean
    4553             :         // Value     compared to Boolean
    4554             :         Compare_Boolean,
    4555             : 
    4556             :         // Int32   compared to Int32
    4557             :         // Boolean compared to Boolean
    4558             :         Compare_Int32,
    4559             :         Compare_Int32MaybeCoerceBoth,
    4560             :         Compare_Int32MaybeCoerceLHS,
    4561             :         Compare_Int32MaybeCoerceRHS,
    4562             : 
    4563             :         // Int32 compared as unsigneds
    4564             :         Compare_UInt32,
    4565             : 
    4566             :         // Int64 compared to Int64.
    4567             :         Compare_Int64,
    4568             : 
    4569             :         // Int64 compared as unsigneds.
    4570             :         Compare_UInt64,
    4571             : 
    4572             :         // Double compared to Double
    4573             :         Compare_Double,
    4574             : 
    4575             :         Compare_DoubleMaybeCoerceLHS,
    4576             :         Compare_DoubleMaybeCoerceRHS,
    4577             : 
    4578             :         // Float compared to Float
    4579             :         Compare_Float32,
    4580             : 
    4581             :         // String compared to String
    4582             :         Compare_String,
    4583             : 
    4584             :         // Symbol compared to Symbol
    4585             :         Compare_Symbol,
    4586             : 
    4587             :         // Undefined compared to String
    4588             :         // Null      compared to String
    4589             :         // Boolean   compared to String
    4590             :         // Int32     compared to String
    4591             :         // Double    compared to String
    4592             :         // Object    compared to String
    4593             :         // Value     compared to String
    4594             :         Compare_StrictString,
    4595             : 
    4596             :         // Object compared to Object
    4597             :         Compare_Object,
    4598             : 
    4599             :         // Compare 2 values bitwise
    4600             :         Compare_Bitwise,
    4601             : 
    4602             :         // All other possible compares
    4603             :         Compare_Unknown
    4604             :     };
    4605             : 
    4606             :   private:
    4607             :     CompareType compareType_;
    4608             :     JSOp jsop_;
    4609             :     bool operandMightEmulateUndefined_;
    4610             :     bool operandsAreNeverNaN_;
    4611             : 
    4612             :     // When a floating-point comparison is converted to an integer comparison
    4613             :     // (when range analysis proves it safe), we need to convert the operands
    4614             :     // to integer as well.
    4615             :     bool truncateOperands_;
    4616             : 
    4617         269 :     MCompare(MDefinition* left, MDefinition* right, JSOp jsop)
    4618         269 :       : MBinaryInstruction(left, right),
    4619             :         compareType_(Compare_Unknown),
    4620             :         jsop_(jsop),
    4621             :         operandMightEmulateUndefined_(true),
    4622             :         operandsAreNeverNaN_(false),
    4623         269 :         truncateOperands_(false)
    4624             :     {
    4625         269 :         setResultType(MIRType::Boolean);
    4626         269 :         setMovable();
    4627         269 :     }
    4628             : 
    4629           0 :     MCompare(MDefinition* left, MDefinition* right, JSOp jsop, CompareType compareType)
    4630           0 :       : MCompare(left, right, jsop)
    4631             :     {
    4632           0 :         MOZ_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||
    4633             :                    compareType == Compare_Int64 || compareType == Compare_UInt64 ||
    4634             :                    compareType == Compare_Double || compareType == Compare_Float32);
    4635           0 :         compareType_ = compareType;
    4636           0 :         operandMightEmulateUndefined_ = false;
    4637           0 :         setResultType(MIRType::Int32);
    4638           0 :     }
    4639             : 
    4640             :   public:
    4641       20350 :     INSTRUCTION_HEADER(Compare)
    4642         269 :     TRIVIAL_NEW_WRAPPERS
    4643             : 
    4644             :     MOZ_MUST_USE bool tryFold(bool* result);
    4645             :     MOZ_MUST_USE bool evaluateConstantOperands(TempAllocator& alloc, bool* result);
    4646             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    4647             :     void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
    4648             :                                 bool* filtersNull);
    4649             : 
    4650        2868 :     CompareType compareType() const {
    4651        2868 :         return compareType_;
    4652             :     }
    4653         255 :     bool isInt32Comparison() const {
    4654         505 :         return compareType() == Compare_Int32 ||
    4655         250 :                compareType() == Compare_Int32MaybeCoerceBoth ||
    4656         255 :                compareType() == Compare_Int32MaybeCoerceLHS ||
    4657         255 :                compareType() == Compare_Int32MaybeCoerceRHS;
    4658             :     }
    4659          48 :     bool isDoubleComparison() const {
    4660          96 :         return compareType() == Compare_Double ||
    4661          96 :                compareType() == Compare_DoubleMaybeCoerceLHS ||
    4662          96 :                compareType() == Compare_DoubleMaybeCoerceRHS;
    4663             :     }
    4664           3 :     bool isFloat32Comparison() const {
    4665           3 :         return compareType() == Compare_Float32;
    4666             :     }
    4667         136 :     bool isNumericComparison() const {
    4668         136 :         return isInt32Comparison() ||
    4669         136 :                isDoubleComparison() ||
    4670         136 :                isFloat32Comparison();
    4671             :     }
    4672         269 :     void setCompareType(CompareType type) {
    4673         269 :         compareType_ = type;
    4674         269 :     }
    4675             :     MIRType inputType();
    4676             : 
    4677         505 :     JSOp jsop() const {
    4678         505 :         return jsop_;
    4679             :     }
    4680         258 :     void markNoOperandEmulatesUndefined() {
    4681         258 :         operandMightEmulateUndefined_ = false;
    4682         258 :     }
    4683         269 :     bool operandMightEmulateUndefined() const {
    4684         269 :         return operandMightEmulateUndefined_;
    4685             :     }
    4686           0 :     bool operandsAreNeverNaN() const {
    4687           0 :         return operandsAreNeverNaN_;
    4688             :     }
    4689         969 :     AliasSet getAliasSet() const override {
    4690             :         // Strict equality is never effectful.
    4691         969 :         if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
    4692         768 :             return AliasSet::None();
    4693         201 :         if (compareType_ == Compare_Unknown)
    4694           0 :             return AliasSet::Store(AliasSet::Any);
    4695         201 :         MOZ_ASSERT(compareType_ <= Compare_Bitwise);
    4696         201 :         return AliasSet::None();
    4697             :     }
    4698             : 
    4699             :     void printOpcode(GenericPrinter& out) const override;
    4700             :     void collectRangeInfoPreTrunc() override;
    4701             : 
    4702             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    4703           0 :     bool isFloat32Commutative() const override { return true; }
    4704             :     bool needTruncation(TruncateKind kind) override;
    4705             :     void truncate() override;
    4706             :     TruncateKind operandTruncateKind(size_t index) const override;
    4707             : 
    4708             :     static CompareType determineCompareType(JSOp op, MDefinition* left, MDefinition* right);
    4709             :     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
    4710             : 
    4711             : # ifdef DEBUG
    4712           0 :     bool isConsistentFloat32Use(MUse* use) const override {
    4713             :         // Both sides of the compare can be Float32
    4714           0 :         return compareType_ == Compare_Float32;
    4715             :     }
    4716             : # endif
    4717             : 
    4718           0 :     ALLOW_CLONE(MCompare)
    4719             : 
    4720             :   protected:
    4721             :     MOZ_MUST_USE bool tryFoldEqualOperands(bool* result);
    4722             :     MOZ_MUST_USE bool tryFoldTypeOf(bool* result);
    4723             : 
    4724          81 :     bool congruentTo(const MDefinition* ins) const override {
    4725          81 :         if (!binaryCongruentTo(ins))
    4726           0 :             return false;
    4727         162 :         return compareType() == ins->toCompare()->compareType() &&
    4728         162 :                jsop() == ins->toCompare()->jsop();
    4729             :     }
    4730             : };
    4731             : 
    4732             : // Takes a typed value and returns an untyped value.
    4733           0 : class MBox
    4734             :   : public MUnaryInstruction,
    4735             :     public NoTypePolicy::Data
    4736             : {
    4737         103 :     MBox(TempAllocator& alloc, MDefinition* ins)
    4738         103 :       : MUnaryInstruction(ins)
    4739             :     {
    4740         103 :         setResultType(MIRType::Value);
    4741         103 :         if (ins->resultTypeSet()) {
    4742          33 :             setResultTypeSet(ins->resultTypeSet());
    4743          70 :         } else if (ins->type() != MIRType::Value) {
    4744          70 :             TypeSet::Type ntype = ins->type() == MIRType::Object
    4745             :                                   ? TypeSet::AnyObjectType()
    4746          70 :                                   : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type()));
    4747          70 :             setResultTypeSet(alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype));
    4748             :         }
    4749         103 :         setMovable();
    4750         103 :     }
    4751             : 
    4752             :   public:
    4753       16770 :     INSTRUCTION_HEADER(Box)
    4754         103 :     static MBox* New(TempAllocator& alloc, MDefinition* ins)
    4755             :     {
    4756             :         // Cannot box a box.
    4757         103 :         MOZ_ASSERT(ins->type() != MIRType::Value);
    4758             : 
    4759         103 :         return new(alloc) MBox(alloc, ins);
    4760             :     }
    4761             : 
    4762         269 :     bool congruentTo(const MDefinition* ins) const override {
    4763         269 :         return congruentIfOperandsEqual(ins);
    4764             :     }
    4765        1505 :     AliasSet getAliasSet() const override {
    4766        1505 :         return AliasSet::None();
    4767             :     }
    4768             : 
    4769           0 :     ALLOW_CLONE(MBox)
    4770             : };
    4771             : 
    4772             : // Note: the op may have been inverted during lowering (to put constants in a
    4773             : // position where they can be immediates), so it is important to use the
    4774             : // lir->jsop() instead of the mir->jsop() when it is present.
    4775             : static inline Assembler::Condition
    4776          56 : JSOpToCondition(MCompare::CompareType compareType, JSOp op)
    4777             : {
    4778          56 :     bool isSigned = (compareType != MCompare::Compare_UInt32);
    4779          56 :     return JSOpToCondition(op, isSigned);
    4780             : }
    4781             : 
    4782             : // Takes a typed value and checks if it is a certain type. If so, the payload
    4783             : // is unpacked and returned as that type. Otherwise, it is considered a
    4784             : // deoptimization.
    4785           0 : class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
    4786             : {
    4787             :   public:
    4788             :     enum Mode {
    4789             :         Fallible,       // Check the type, and deoptimize if unexpected.
    4790             :         Infallible,     // Type guard is not necessary.
    4791             :         TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
    4792             :     };
    4793             : 
    4794             :   private:
    4795             :     Mode mode_;
    4796             :     BailoutKind bailoutKind_;
    4797             : 
    4798         361 :     MUnbox(MDefinition* ins, MIRType type, Mode mode, BailoutKind kind, TempAllocator& alloc)
    4799         361 :       : MUnaryInstruction(ins),
    4800         361 :         mode_(mode)
    4801             :     {
    4802             :         // Only allow unboxing a non MIRType::Value when input and output types
    4803             :         // don't match. This is often used to force a bailout. Boxing happens
    4804             :         // during type analysis.
    4805         361 :         MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type());
    4806             : 
    4807         361 :         MOZ_ASSERT(type == MIRType::Boolean ||
    4808             :                    type == MIRType::Int32   ||
    4809             :                    type == MIRType::Double  ||
    4810             :                    type == MIRType::String  ||
    4811             :                    type == MIRType::Symbol  ||
    4812             :                    type == MIRType::Object);
    4813             : 
    4814         361 :         TemporaryTypeSet* resultSet = ins->resultTypeSet();
    4815         361 :         if (resultSet && type == MIRType::Object)
    4816          34 :             resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc());
    4817             : 
    4818         361 :         setResultType(type);
    4819         361 :         setResultTypeSet(resultSet);
    4820         361 :         setMovable();
    4821             : 
    4822         361 :         if (mode_ == TypeBarrier || mode_ == Fallible)
    4823          98 :             setGuard();
    4824             : 
    4825         361 :         bailoutKind_ = kind;
    4826         361 :     }
    4827             :   public:
    4828       28524 :     INSTRUCTION_HEADER(Unbox)
    4829         361 :     static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode)
    4830             :     {
    4831             :         // Unless we were given a specific BailoutKind, pick a default based on
    4832             :         // the type we expect.
    4833             :         BailoutKind kind;
    4834         361 :         switch (type) {
    4835             :           case MIRType::Boolean:
    4836         247 :             kind = Bailout_NonBooleanInput;
    4837         247 :             break;
    4838             :           case MIRType::Int32:
    4839          15 :             kind = Bailout_NonInt32Input;
    4840          15 :             break;
    4841             :           case MIRType::Double:
    4842           0 :             kind = Bailout_NonNumericInput; // Int32s are fine too
    4843           0 :             break;
    4844             :           case MIRType::String:
    4845          32 :             kind = Bailout_NonStringInput;
    4846          32 :             break;
    4847             :           case MIRType::Symbol:
    4848           0 :             kind = Bailout_NonSymbolInput;
    4849           0 :             break;
    4850             :           case MIRType::Object:
    4851          67 :             kind = Bailout_NonObjectInput;
    4852          67 :             break;
    4853             :           default:
    4854           0 :             MOZ_CRASH("Given MIRType cannot be unboxed.");
    4855             :         }
    4856             : 
    4857         361 :         return new(alloc) MUnbox(ins, type, mode, kind, alloc);
    4858             :     }
    4859             : 
    4860             :     static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode,
    4861             :                        BailoutKind kind)
    4862             :     {
    4863             :         return new(alloc) MUnbox(ins, type, mode, kind, alloc);
    4864             :     }
    4865             : 
    4866        1020 :     Mode mode() const {
    4867        1020 :         return mode_;
    4868             :     }
    4869          81 :     BailoutKind bailoutKind() const {
    4870             :         // If infallible, no bailout should be generated.
    4871          81 :         MOZ_ASSERT(fallible());
    4872          81 :         return bailoutKind_;
    4873             :     }
    4874         408 :     bool fallible() const {
    4875         408 :         return mode() != Infallible;
    4876             :     }
    4877         268 :     bool congruentTo(const MDefinition* ins) const override {
    4878         268 :         if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
    4879           0 :             return false;
    4880         268 :         return congruentIfOperandsEqual(ins);
    4881             :     }
    4882             : 
    4883             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    4884             : 
    4885        1674 :     AliasSet getAliasSet() const override {
    4886        1674 :         return AliasSet::None();
    4887             :     }
    4888             :     void printOpcode(GenericPrinter& out) const override;
    4889           0 :     void makeInfallible() {
    4890             :         // Should only be called if we're already Infallible or TypeBarrier
    4891           0 :         MOZ_ASSERT(mode() != Fallible);
    4892           0 :         mode_ = Infallible;
    4893           0 :     }
    4894             : 
    4895           0 :     ALLOW_CLONE(MUnbox)
    4896             : };
    4897             : 
    4898             : class MGuardObject
    4899             :   : public MUnaryInstruction,
    4900             :     public SingleObjectPolicy::Data
    4901             : {
    4902           0 :     explicit MGuardObject(MDefinition* ins)
    4903           0 :       : MUnaryInstruction(ins)
    4904             :     {
    4905           0 :         setGuard();
    4906           0 :         setMovable();
    4907           0 :         setResultType(MIRType::Object);
    4908           0 :         setResultTypeSet(ins->resultTypeSet());
    4909           0 :     }
    4910             : 
    4911             :   public:
    4912           0 :     INSTRUCTION_HEADER(GuardObject)
    4913           0 :     TRIVIAL_NEW_WRAPPERS
    4914             : 
    4915           0 :     AliasSet getAliasSet() const override {
    4916           0 :         return AliasSet::None();
    4917             :     }
    4918             : };
    4919             : 
    4920             : class MGuardString
    4921             :   : public MUnaryInstruction,
    4922             :     public StringPolicy<0>::Data
    4923             : {
    4924             :     explicit MGuardString(MDefinition* ins)
    4925             :       : MUnaryInstruction(ins)
    4926             :     {
    4927             :         setGuard();
    4928             :         setMovable();
    4929             :         setResultType(MIRType::String);
    4930             :     }
    4931             : 
    4932             :   public:
    4933           0 :     INSTRUCTION_HEADER(GuardString)
    4934             :     TRIVIAL_NEW_WRAPPERS
    4935             : 
    4936           0 :     AliasSet getAliasSet() const override {
    4937           0 :         return AliasSet::None();
    4938             :     }
    4939             : };
    4940             : 
    4941             : class MPolyInlineGuard
    4942             :   : public MUnaryInstruction,
    4943             :     public SingleObjectPolicy::Data
    4944             : {
    4945           4 :     explicit MPolyInlineGuard(MDefinition* ins)
    4946           4 :       : MUnaryInstruction(ins)
    4947             :     {
    4948           4 :         setGuard();
    4949           4 :         setResultType(MIRType::Object);
    4950           4 :         setResultTypeSet(ins->resultTypeSet());
    4951           4 :     }
    4952             : 
    4953             :   public:
    4954        1036 :     INSTRUCTION_HEADER(PolyInlineGuard)
    4955           4 :     TRIVIAL_NEW_WRAPPERS
    4956             : 
    4957          30 :     AliasSet getAliasSet() const override {
    4958          30 :         return AliasSet::None();
    4959             :     }
    4960             : };
    4961             : 
    4962             : class MAssertRange
    4963             :   : public MUnaryInstruction,
    4964             :     public NoTypePolicy::Data
    4965             : {
    4966             :     // This is the range checked by the assertion. Don't confuse this with the
    4967             :     // range_ member or the range() accessor. Since MAssertRange doesn't return
    4968             :     // a value, it doesn't use those.
    4969             :     const Range* assertedRange_;
    4970             : 
    4971           0 :     MAssertRange(MDefinition* ins, const Range* assertedRange)
    4972           0 :       : MUnaryInstruction(ins), assertedRange_(assertedRange)
    4973             :     {
    4974           0 :         setGuard();
    4975           0 :         setResultType(MIRType::None);
    4976           0 :     }
    4977             : 
    4978             :   public:
    4979           0 :     INSTRUCTION_HEADER(AssertRange)
    4980           0 :     TRIVIAL_NEW_WRAPPERS
    4981             : 
    4982           0 :     const Range* assertedRange() const {
    4983           0 :         return assertedRange_;
    4984             :     }
    4985             : 
    4986           0 :     AliasSet getAliasSet() const override {
    4987           0 :         return AliasSet::None();
    4988             :     }
    4989             : 
    4990             :     void printOpcode(GenericPrinter& out) const override;
    4991             : };
    4992             : 
    4993             : // Caller-side allocation of |this| for |new|:
    4994             : // Given a templateobject, construct |this| for JSOP_NEW
    4995             : class MCreateThisWithTemplate
    4996             :   : public MUnaryInstruction,
    4997             :     public NoTypePolicy::Data
    4998             : {
    4999             :     gc::InitialHeap initialHeap_;
    5000             : 
    5001           0 :     MCreateThisWithTemplate(CompilerConstraintList* constraints, MConstant* templateConst,
    5002             :                             gc::InitialHeap initialHeap)
    5003           0 :       : MUnaryInstruction(templateConst),
    5004           0 :         initialHeap_(initialHeap)
    5005             :     {
    5006           0 :         setResultType(MIRType::Object);
    5007           0 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
    5008           0 :     }
    5009             : 
    5010             :   public:
    5011           0 :     INSTRUCTION_HEADER(CreateThisWithTemplate)
    5012           0 :     TRIVIAL_NEW_WRAPPERS
    5013             : 
    5014             :     // Template for |this|, provided by TI.
    5015           0 :     JSObject* templateObject() const {
    5016           0 :         return &getOperand(0)->toConstant()->toObject();
    5017             :     }
    5018             : 
    5019           0 :     gc::InitialHeap initialHeap() const {
    5020           0 :         return initialHeap_;
    5021             :     }
    5022             : 
    5023             :     // Although creation of |this| modifies global state, it is safely repeatable.
    5024           0 :     AliasSet getAliasSet() const override {
    5025           0 :         return AliasSet::None();
    5026             :     }
    5027             : 
    5028             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5029             :     bool canRecoverOnBailout() const override;
    5030             : };
    5031             : 
    5032             : // Caller-side allocation of |this| for |new|:
    5033             : // Given a prototype operand, construct |this| for JSOP_NEW.
    5034             : class MCreateThisWithProto
    5035             :   : public MTernaryInstruction,
    5036             :     public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
    5037             : {
    5038           0 :     MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
    5039           0 :       : MTernaryInstruction(callee, newTarget, prototype)
    5040             :     {
    5041           0 :         setResultType(MIRType::Object);
    5042           0 :     }
    5043             : 
    5044             :   public:
    5045           0 :     INSTRUCTION_HEADER(CreateThisWithProto)
    5046           0 :     TRIVIAL_NEW_WRAPPERS
    5047           0 :     NAMED_OPERANDS((0, getCallee), (1, getNewTarget), (2, getPrototype))
    5048             : 
    5049             :     // Although creation of |this| modifies global state, it is safely repeatable.
    5050           0 :     AliasSet getAliasSet() const override {
    5051           0 :         return AliasSet::None();
    5052             :     }
    5053           0 :     bool possiblyCalls() const override {
    5054           0 :         return true;
    5055             :     }
    5056             : };
    5057             : 
    5058             : // Caller-side allocation of |this| for |new|:
    5059             : // Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
    5060             : class MCreateThis
    5061             :   : public MBinaryInstruction,
    5062             :     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
    5063             : {
    5064         139 :     explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
    5065         139 :       : MBinaryInstruction(callee, newTarget)
    5066             :     {
    5067         139 :         setResultType(MIRType::Value);
    5068         139 :     }
    5069             : 
    5070             :   public:
    5071        1076 :     INSTRUCTION_HEADER(CreateThis)
    5072         139 :     TRIVIAL_NEW_WRAPPERS
    5073           8 :     NAMED_OPERANDS((0, getCallee), (1, getNewTarget))
    5074             : 
    5075             :     // Although creation of |this| modifies global state, it is safely repeatable.
    5076          54 :     AliasSet getAliasSet() const override {
    5077          54 :         return AliasSet::None();
    5078             :     }
    5079           4 :     bool possiblyCalls() const override {
    5080           4 :         return true;
    5081             :     }
    5082             : };
    5083             : 
    5084             : // Eager initialization of arguments object.
    5085             : class MCreateArgumentsObject
    5086             :   : public MUnaryInstruction,
    5087             :     public ObjectPolicy<0>::Data
    5088             : {
    5089             :     CompilerGCPointer<ArgumentsObject*> templateObj_;
    5090             : 
    5091         135 :     MCreateArgumentsObject(MDefinition* callObj, ArgumentsObject* templateObj)
    5092         135 :       : MUnaryInstruction(callObj),
    5093         135 :         templateObj_(templateObj)
    5094             :     {
    5095         135 :         setResultType(MIRType::Object);
    5096         135 :         setGuard();
    5097         135 :     }
    5098             : 
    5099             :   public:
    5100        1262 :     INSTRUCTION_HEADER(CreateArgumentsObject)
    5101         135 :     TRIVIAL_NEW_WRAPPERS
    5102           0 :     NAMED_OPERANDS((0, getCallObject))
    5103             : 
    5104           0 :     ArgumentsObject* templateObject() const {
    5105           0 :         return templateObj_;
    5106             :     }
    5107             : 
    5108           0 :     AliasSet getAliasSet() const override {
    5109           0 :         return AliasSet::None();
    5110             :     }
    5111             : 
    5112           0 :     bool possiblyCalls() const override {
    5113           0 :         return true;
    5114             :     }
    5115             : 
    5116           0 :     bool appendRoots(MRootList& roots) const override {
    5117           0 :         return roots.append(templateObj_);
    5118             :     }
    5119             : };
    5120             : 
    5121             : class MGetArgumentsObjectArg
    5122             :   : public MUnaryInstruction,
    5123             :     public ObjectPolicy<0>::Data
    5124             : {
    5125             :     size_t argno_;
    5126             : 
    5127          10 :     MGetArgumentsObjectArg(MDefinition* argsObject, size_t argno)
    5128          10 :       : MUnaryInstruction(argsObject),
    5129          10 :         argno_(argno)
    5130             :     {
    5131          10 :         setResultType(MIRType::Value);
    5132          10 :     }
    5133             : 
    5134             :   public:
    5135          40 :     INSTRUCTION_HEADER(GetArgumentsObjectArg)
    5136          10 :     TRIVIAL_NEW_WRAPPERS
    5137           0 :     NAMED_OPERANDS((0, getArgsObject))
    5138             : 
    5139           0 :     size_t argno() const {
    5140           0 :         return argno_;
    5141             :     }
    5142             : 
    5143           0 :     AliasSet getAliasSet() const override {
    5144           0 :         return AliasSet::Load(AliasSet::Any);
    5145             :     }
    5146             : };
    5147             : 
    5148             : class MSetArgumentsObjectArg
    5149             :   : public MBinaryInstruction,
    5150             :     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
    5151             : {
    5152             :     size_t argno_;
    5153             : 
    5154           2 :     MSetArgumentsObjectArg(MDefinition* argsObj, size_t argno, MDefinition* value)
    5155           2 :       : MBinaryInstruction(argsObj, value),
    5156           2 :         argno_(argno)
    5157             :     {
    5158           2 :     }
    5159             : 
    5160             :   public:
    5161           0 :     INSTRUCTION_HEADER(SetArgumentsObjectArg)
    5162           2 :     TRIVIAL_NEW_WRAPPERS
    5163           0 :     NAMED_OPERANDS((0, getArgsObject), (1, getValue))
    5164             : 
    5165           0 :     size_t argno() const {
    5166           0 :         return argno_;
    5167             :     }
    5168             : 
    5169           0 :     AliasSet getAliasSet() const override {
    5170           0 :         return AliasSet::Store(AliasSet::Any);
    5171             :     }
    5172             : };
    5173             : 
    5174             : class MRunOncePrologue
    5175             :   : public MNullaryInstruction
    5176             : {
    5177             :   protected:
    5178           0 :     MRunOncePrologue()
    5179           0 :     {
    5180           0 :         setGuard();
    5181           0 :     }
    5182             : 
    5183             :   public:
    5184           0 :     INSTRUCTION_HEADER(RunOncePrologue)
    5185           0 :     TRIVIAL_NEW_WRAPPERS
    5186             : 
    5187           0 :     bool possiblyCalls() const override {
    5188           0 :         return true;
    5189             :     }
    5190             : };
    5191             : 
    5192             : // Given a MIRType::Value A and a MIRType::Object B:
    5193             : // If the Value may be safely unboxed to an Object, return Object(A).
    5194             : // Otherwise, return B.
    5195             : // Used to implement return behavior for inlined constructors.
    5196             : class MReturnFromCtor
    5197             :   : public MAryInstruction<2>,
    5198             :     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
    5199             : {
    5200           0 :     MReturnFromCtor(MDefinition* value, MDefinition* object) {
    5201           0 :         initOperand(0, value);
    5202           0 :         initOperand(1, object);
    5203           0 :         setResultType(MIRType::Object);
    5204           0 :     }
    5205             : 
    5206             :   public:
    5207           0 :     INSTRUCTION_HEADER(ReturnFromCtor)
    5208           0 :     TRIVIAL_NEW_WRAPPERS
    5209           0 :     NAMED_OPERANDS((0, getValue), (1, getObject))
    5210             : 
    5211           0 :     AliasSet getAliasSet() const override {
    5212           0 :         return AliasSet::None();
    5213             :     }
    5214             : };
    5215             : 
    5216           0 : class MToFPInstruction
    5217             :   : public MUnaryInstruction,
    5218             :     public ToDoublePolicy::Data
    5219             : {
    5220             :   public:
    5221             :     // Types of values which can be converted.
    5222             :     enum ConversionKind {
    5223             :         NonStringPrimitives,
    5224             :         NonNullNonStringPrimitives,
    5225             :         NumbersOnly
    5226             :     };
    5227             : 
    5228             :   private:
    5229             :     ConversionKind conversion_;
    5230             : 
    5231             :   protected:
    5232           0 :     explicit MToFPInstruction(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
    5233           0 :       : MUnaryInstruction(def), conversion_(conversion)
    5234           0 :     { }
    5235             : 
    5236             :   public:
    5237           0 :     ConversionKind conversion() const {
    5238           0 :         return conversion_;
    5239             :     }
    5240             : };
    5241             : 
    5242             : // Converts a primitive (either typed or untyped) to a double. If the input is
    5243             : // not primitive at runtime, a bailout occurs.
    5244           0 : class MToDouble
    5245             :   : public MToFPInstruction
    5246             : {
    5247             :   private:
    5248             :     TruncateKind implicitTruncate_;
    5249             : 
    5250           0 :     explicit MToDouble(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
    5251           0 :       : MToFPInstruction(def, conversion), implicitTruncate_(NoTruncate)
    5252             :     {
    5253           0 :         setResultType(MIRType::Double);
    5254           0 :         setMovable();
    5255             : 
    5256             :         // An object might have "valueOf", which means it is effectful.
    5257             :         // ToNumber(symbol) throws.
    5258           0 :         if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
    5259           0 :             setGuard();
    5260           0 :     }
    5261             : 
    5262             :   public:
    5263           0 :     INSTRUCTION_HEADER(ToDouble)
    5264           0 :     TRIVIAL_NEW_WRAPPERS
    5265             : 
    5266             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5267           0 :     bool congruentTo(const MDefinition* ins) const override {
    5268           0 :         if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
    5269           0 :             return false;
    5270           0 :         return congruentIfOperandsEqual(ins);
    5271             :     }
    5272           0 :     AliasSet getAliasSet() const override {
    5273           0 :         return AliasSet::None();
    5274             :     }
    5275             : 
    5276             :     void computeRange(TempAllocator& alloc) override;
    5277             :     bool needTruncation(TruncateKind kind) override;
    5278             :     void truncate() override;
    5279             :     TruncateKind operandTruncateKind(size_t index) const override;
    5280             : 
    5281             : #ifdef DEBUG
    5282           0 :     bool isConsistentFloat32Use(MUse* use) const override { return true; }
    5283             : #endif
    5284             : 
    5285           0 :     TruncateKind truncateKind() const {
    5286           0 :         return implicitTruncate_;
    5287             :     }
    5288           0 :     void setTruncateKind(TruncateKind kind) {
    5289           0 :         implicitTruncate_ = Max(implicitTruncate_, kind);
    5290           0 :     }
    5291             : 
    5292             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5293           0 :     bool canRecoverOnBailout() const override {
    5294           0 :         if (input()->type() == MIRType::Value)
    5295           0 :             return false;
    5296           0 :         if (input()->type() == MIRType::Symbol)
    5297           0 :             return false;
    5298             : 
    5299           0 :         return true;
    5300             :     }
    5301             : 
    5302           0 :     ALLOW_CLONE(MToDouble)
    5303             : };
    5304             : 
    5305             : // Converts a primitive (either typed or untyped) to a float32. If the input is
    5306             : // not primitive at runtime, a bailout occurs.
    5307           0 : class MToFloat32
    5308             :   : public MToFPInstruction
    5309             : {
    5310             :   protected:
    5311             :     bool mustPreserveNaN_;
    5312             : 
    5313           0 :     explicit MToFloat32(MDefinition* def, ConversionKind conversion = NonStringPrimitives)
    5314           0 :       : MToFPInstruction(def, conversion),
    5315           0 :         mustPreserveNaN_(false)
    5316             :     {
    5317           0 :         setResultType(MIRType::Float32);
    5318           0 :         setMovable();
    5319             : 
    5320             :         // An object might have "valueOf", which means it is effectful.
    5321             :         // ToNumber(symbol) throws.
    5322           0 :         if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
    5323           0 :             setGuard();
    5324           0 :     }
    5325             : 
    5326           0 :     explicit MToFloat32(MDefinition* def, bool mustPreserveNaN)
    5327           0 :       : MToFloat32(def)
    5328             :     {
    5329           0 :         mustPreserveNaN_ = mustPreserveNaN;
    5330           0 :     }
    5331             : 
    5332             :   public:
    5333           0 :     INSTRUCTION_HEADER(ToFloat32)
    5334           0 :     TRIVIAL_NEW_WRAPPERS
    5335             : 
    5336             :     virtual MDefinition* foldsTo(TempAllocator& alloc) override;
    5337           0 :     bool congruentTo(const MDefinition* ins) const override {
    5338           0 :         if (!congruentIfOperandsEqual(ins))
    5339           0 :             return false;
    5340           0 :         auto* other = ins->toToFloat32();
    5341           0 :         return other->conversion() == conversion() &&
    5342           0 :                other->mustPreserveNaN_ == mustPreserveNaN_;
    5343             :     }
    5344           0 :     AliasSet getAliasSet() const override {
    5345           0 :         return AliasSet::None();
    5346             :     }
    5347             : 
    5348             :     void computeRange(TempAllocator& alloc) override;
    5349             : 
    5350           0 :     bool canConsumeFloat32(MUse* use) const override { return true; }
    5351           0 :     bool canProduceFloat32() const override { return true; }
    5352             : 
    5353             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5354           0 :     bool canRecoverOnBailout() const override {
    5355           0 :         return true;
    5356             :     }
    5357             : 
    5358           0 :     ALLOW_CLONE(MToFloat32)
    5359             : };
    5360             : 
    5361             : // Converts a uint32 to a double (coming from wasm).
    5362             : class MWasmUnsignedToDouble
    5363             :   : public MUnaryInstruction,
    5364             :     public NoTypePolicy::Data
    5365             : {
    5366           0 :     explicit MWasmUnsignedToDouble(MDefinition* def)
    5367           0 :       : MUnaryInstruction(def)
    5368             :     {
    5369           0 :         setResultType(MIRType::Double);
    5370           0 :         setMovable();
    5371           0 :     }
    5372             : 
    5373             :   public:
    5374           0 :     INSTRUCTION_HEADER(WasmUnsignedToDouble)
    5375           0 :     TRIVIAL_NEW_WRAPPERS
    5376             : 
    5377             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5378           0 :     bool congruentTo(const MDefinition* ins) const override {
    5379           0 :         return congruentIfOperandsEqual(ins);
    5380             :     }
    5381           0 :     AliasSet getAliasSet() const override {
    5382           0 :         return AliasSet::None();
    5383             :     }
    5384             : };
    5385             : 
    5386             : // Converts a uint32 to a float32 (coming from wasm).
    5387             : class MWasmUnsignedToFloat32
    5388             :   : public MUnaryInstruction,
    5389             :     public NoTypePolicy::Data
    5390             : {
    5391           0 :     explicit MWasmUnsignedToFloat32(MDefinition* def)
    5392           0 :       : MUnaryInstruction(def)
    5393             :     {
    5394           0 :         setResultType(MIRType::Float32);
    5395           0 :         setMovable();
    5396           0 :     }
    5397             : 
    5398             :   public:
    5399           0 :     INSTRUCTION_HEADER(WasmUnsignedToFloat32)
    5400           0 :     TRIVIAL_NEW_WRAPPERS
    5401             : 
    5402             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5403           0 :     bool congruentTo(const MDefinition* ins) const override {
    5404           0 :         return congruentIfOperandsEqual(ins);
    5405             :     }
    5406           0 :     AliasSet getAliasSet() const override {
    5407           0 :         return AliasSet::None();
    5408             :     }
    5409             : 
    5410           0 :     bool canProduceFloat32() const override { return true; }
    5411             : };
    5412             : 
    5413             : class MWrapInt64ToInt32
    5414             :   : public MUnaryInstruction,
    5415             :     public NoTypePolicy::Data
    5416             : {
    5417             :     bool bottomHalf_;
    5418             : 
    5419           0 :     explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf = true)
    5420           0 :       : MUnaryInstruction(def),
    5421           0 :         bottomHalf_(bottomHalf)
    5422             :     {
    5423           0 :         setResultType(MIRType::Int32);
    5424           0 :         setMovable();
    5425           0 :     }
    5426             : 
    5427             :   public:
    5428           0 :     INSTRUCTION_HEADER(WrapInt64ToInt32)
    5429           0 :     TRIVIAL_NEW_WRAPPERS
    5430             : 
    5431             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5432           0 :     bool congruentTo(const MDefinition* ins) const override {
    5433           0 :         if (!ins->isWrapInt64ToInt32())
    5434           0 :             return false;
    5435           0 :         if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf())
    5436           0 :             return false;
    5437           0 :         return congruentIfOperandsEqual(ins);
    5438             :     }
    5439           0 :     AliasSet getAliasSet() const override {
    5440           0 :         return AliasSet::None();
    5441             :     }
    5442             : 
    5443           0 :     bool bottomHalf() const {
    5444           0 :         return bottomHalf_;
    5445             :     }
    5446             : };
    5447             : 
    5448             : class MExtendInt32ToInt64
    5449             :   : public MUnaryInstruction,
    5450             :     public NoTypePolicy::Data
    5451             : {
    5452             :     bool isUnsigned_;
    5453             : 
    5454           0 :     MExtendInt32ToInt64(MDefinition* def, bool isUnsigned)
    5455           0 :       : MUnaryInstruction(def),
    5456           0 :         isUnsigned_(isUnsigned)
    5457             :     {
    5458           0 :         setResultType(MIRType::Int64);
    5459           0 :         setMovable();
    5460           0 :     }
    5461             : 
    5462             :   public:
    5463           0 :     INSTRUCTION_HEADER(ExtendInt32ToInt64)
    5464           0 :     TRIVIAL_NEW_WRAPPERS
    5465             : 
    5466           0 :     bool isUnsigned() const { return isUnsigned_; }
    5467             : 
    5468             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5469           0 :     bool congruentTo(const MDefinition* ins) const override {
    5470           0 :         if (!ins->isExtendInt32ToInt64())
    5471           0 :             return false;
    5472           0 :         if (ins->toExtendInt32ToInt64()->isUnsigned_ != isUnsigned_)
    5473           0 :             return false;
    5474           0 :         return congruentIfOperandsEqual(ins);
    5475             :     }
    5476           0 :     AliasSet getAliasSet() const override {
    5477           0 :         return AliasSet::None();
    5478             :     }
    5479             : };
    5480             : 
    5481             : class MWasmTruncateToInt64
    5482             :   : public MUnaryInstruction,
    5483             :     public NoTypePolicy::Data
    5484             : {
    5485             :     bool isUnsigned_;
    5486             :     wasm::BytecodeOffset bytecodeOffset_;
    5487             : 
    5488           0 :     MWasmTruncateToInt64(MDefinition* def, bool isUnsigned, wasm::BytecodeOffset bytecodeOffset)
    5489           0 :       : MUnaryInstruction(def),
    5490             :         isUnsigned_(isUnsigned),
    5491           0 :         bytecodeOffset_(bytecodeOffset)
    5492             :     {
    5493           0 :         setResultType(MIRType::Int64);
    5494           0 :         setGuard(); // neither removable nor movable because of possible side-effects.
    5495           0 :     }
    5496             : 
    5497             :   public:
    5498           0 :     INSTRUCTION_HEADER(WasmTruncateToInt64)
    5499           0 :     TRIVIAL_NEW_WRAPPERS
    5500             : 
    5501           0 :     bool isUnsigned() const { return isUnsigned_; }
    5502           0 :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
    5503             : 
    5504           0 :     bool congruentTo(const MDefinition* ins) const override {
    5505           0 :         return congruentIfOperandsEqual(ins) &&
    5506           0 :                ins->toWasmTruncateToInt64()->isUnsigned() == isUnsigned_;
    5507             :     }
    5508           0 :     AliasSet getAliasSet() const override {
    5509           0 :         return AliasSet::None();
    5510             :     }
    5511             : };
    5512             : 
    5513             : // Truncate a value to an int32, with wasm semantics: this will trap when the
    5514             : // value is out of range.
    5515             : class MWasmTruncateToInt32
    5516             :   : public MUnaryInstruction,
    5517             :     public NoTypePolicy::Data
    5518             : {
    5519             :     bool isUnsigned_;
    5520             :     wasm::BytecodeOffset bytecodeOffset_;
    5521             : 
    5522           0 :     explicit MWasmTruncateToInt32(MDefinition* def, bool isUnsigned,
    5523             :                                   wasm::BytecodeOffset bytecodeOffset)
    5524           0 :       : MUnaryInstruction(def), isUnsigned_(isUnsigned), bytecodeOffset_(bytecodeOffset)
    5525             :     {
    5526           0 :         setResultType(MIRType::Int32);
    5527           0 :         setGuard(); // neither removable nor movable because of possible side-effects.
    5528           0 :     }
    5529             : 
    5530             :   public:
    5531           0 :     INSTRUCTION_HEADER(WasmTruncateToInt32)
    5532           0 :     TRIVIAL_NEW_WRAPPERS
    5533             : 
    5534           0 :     bool isUnsigned() const {
    5535           0 :         return isUnsigned_;
    5536             :     }
    5537           0 :     wasm::BytecodeOffset bytecodeOffset() const {
    5538           0 :         return bytecodeOffset_;
    5539             :     }
    5540             : 
    5541             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5542             : 
    5543           0 :     bool congruentTo(const MDefinition* ins) const override {
    5544           0 :         return congruentIfOperandsEqual(ins) &&
    5545           0 :                ins->toWasmTruncateToInt32()->isUnsigned() == isUnsigned_;
    5546             :     }
    5547             : 
    5548           0 :     AliasSet getAliasSet() const override {
    5549           0 :         return AliasSet::None();
    5550             :     }
    5551             : };
    5552             : 
    5553             : class MInt64ToFloatingPoint
    5554             :   : public MUnaryInstruction,
    5555             :     public NoTypePolicy::Data
    5556             : {
    5557             :     bool isUnsigned_;
    5558             :     wasm::BytecodeOffset bytecodeOffset_;
    5559             : 
    5560           0 :     MInt64ToFloatingPoint(MDefinition* def, MIRType type, wasm::BytecodeOffset bytecodeOffset,
    5561             :                           bool isUnsigned)
    5562           0 :       : MUnaryInstruction(def),
    5563             :         isUnsigned_(isUnsigned),
    5564           0 :         bytecodeOffset_(bytecodeOffset)
    5565             :     {
    5566           0 :         MOZ_ASSERT(IsFloatingPointType(type));
    5567           0 :         setResultType(type);
    5568           0 :         setMovable();
    5569           0 :     }
    5570             : 
    5571             :   public:
    5572           0 :     INSTRUCTION_HEADER(Int64ToFloatingPoint)
    5573           0 :     TRIVIAL_NEW_WRAPPERS
    5574             : 
    5575           0 :     bool isUnsigned() const { return isUnsigned_; }
    5576             :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
    5577             : 
    5578           0 :     bool congruentTo(const MDefinition* ins) const override {
    5579           0 :         if (!ins->isInt64ToFloatingPoint())
    5580           0 :             return false;
    5581           0 :         if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_)
    5582           0 :             return false;
    5583           0 :         return congruentIfOperandsEqual(ins);
    5584             :     }
    5585           0 :     AliasSet getAliasSet() const override {
    5586           0 :         return AliasSet::None();
    5587             :     }
    5588             : };
    5589             : 
    5590             : // Converts a primitive (either typed or untyped) to an int32. If the input is
    5591             : // not primitive at runtime, a bailout occurs. If the input cannot be converted
    5592             : // to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
    5593           0 : class MToInt32
    5594             :   : public MUnaryInstruction,
    5595             :     public ToInt32Policy::Data
    5596             : {
    5597             :     bool canBeNegativeZero_;
    5598             :     MacroAssembler::IntConversionInputKind conversion_;
    5599             : 
    5600          18 :     explicit MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion =
    5601             :                                             MacroAssembler::IntConversion_Any)
    5602          18 :       : MUnaryInstruction(def),
    5603             :         canBeNegativeZero_(true),
    5604          18 :         conversion_(conversion)
    5605             :     {
    5606          18 :         setResultType(MIRType::Int32);
    5607          18 :         setMovable();
    5608             : 
    5609             :         // An object might have "valueOf", which means it is effectful.
    5610             :         // ToNumber(symbol) throws.
    5611          18 :         if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
    5612           0 :             setGuard();
    5613          18 :     }
    5614             : 
    5615             :   public:
    5616        1981 :     INSTRUCTION_HEADER(ToInt32)
    5617          18 :     TRIVIAL_NEW_WRAPPERS
    5618             : 
    5619             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5620             : 
    5621             :     // this only has backwards information flow.
    5622             :     void analyzeEdgeCasesBackward() override;
    5623             : 
    5624           1 :     bool canBeNegativeZero() const {
    5625           1 :         return canBeNegativeZero_;
    5626             :     }
    5627           1 :     void setCanBeNegativeZero(bool negativeZero) {
    5628           1 :         canBeNegativeZero_ = negativeZero;
    5629           1 :     }
    5630             : 
    5631          19 :     MacroAssembler::IntConversionInputKind conversion() const {
    5632          19 :         return conversion_;
    5633             :     }
    5634             : 
    5635           2 :     bool congruentTo(const MDefinition* ins) const override {
    5636           2 :         if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
    5637           0 :             return false;
    5638           2 :         return congruentIfOperandsEqual(ins);
    5639             :     }
    5640             : 
    5641          86 :     AliasSet getAliasSet() const override {
    5642          86 :         return AliasSet::None();
    5643             :     }
    5644             :     void computeRange(TempAllocator& alloc) override;
    5645             :     void collectRangeInfoPreTrunc() override;
    5646             : 
    5647             : #ifdef DEBUG
    5648           0 :     bool isConsistentFloat32Use(MUse* use) const override { return true; }
    5649             : #endif
    5650             : 
    5651           0 :     ALLOW_CLONE(MToInt32)
    5652             : };
    5653             : 
    5654             : // Converts a value or typed input to a truncated int32, for use with bitwise
    5655             : // operations. This is an infallible ValueToECMAInt32.
    5656           0 : class MTruncateToInt32
    5657             :   : public MUnaryInstruction,
    5658             :     public ToInt32Policy::Data
    5659             : {
    5660             :     wasm::BytecodeOffset bytecodeOffset_;
    5661             : 
    5662           4 :     explicit MTruncateToInt32(MDefinition* def,
    5663             :                               wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
    5664           4 :       : MUnaryInstruction(def),
    5665           4 :         bytecodeOffset_(bytecodeOffset)
    5666             :     {
    5667           4 :         setResultType(MIRType::Int32);
    5668           4 :         setMovable();
    5669             : 
    5670             :         // An object might have "valueOf", which means it is effectful.
    5671             :         // ToInt32(symbol) throws.
    5672           4 :         if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
    5673           0 :             setGuard();
    5674           4 :     }
    5675             : 
    5676             :   public:
    5677         525 :     INSTRUCTION_HEADER(TruncateToInt32)
    5678           4 :     TRIVIAL_NEW_WRAPPERS
    5679             : 
    5680             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5681             : 
    5682           6 :     bool congruentTo(const MDefinition* ins) const override {
    5683           6 :         return congruentIfOperandsEqual(ins);
    5684             :     }
    5685          44 :     AliasSet getAliasSet() const override {
    5686          44 :         return AliasSet::None();
    5687             :     }
    5688             : 
    5689             :     void computeRange(TempAllocator& alloc) override;
    5690             :     TruncateKind operandTruncateKind(size_t index) const override;
    5691             : # ifdef DEBUG
    5692           0 :     bool isConsistentFloat32Use(MUse* use) const override {
    5693           0 :         return true;
    5694             :     }
    5695             : #endif
    5696             : 
    5697             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5698           2 :     bool canRecoverOnBailout() const override {
    5699           2 :         return input()->type() < MIRType::Symbol;
    5700             :     }
    5701             : 
    5702           0 :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
    5703             : 
    5704           0 :     ALLOW_CLONE(MTruncateToInt32)
    5705             : };
    5706             : 
    5707             : // Converts any type to a string
    5708           0 : class MToString :
    5709             :   public MUnaryInstruction,
    5710             :   public ToStringPolicy::Data
    5711             : {
    5712           4 :     explicit MToString(MDefinition* def)
    5713           4 :       : MUnaryInstruction(def)
    5714             :     {
    5715           4 :         setResultType(MIRType::String);
    5716           4 :         setMovable();
    5717             : 
    5718             :         // Objects might override toString and Symbols throw. We bailout in
    5719             :         // those cases and run side-effects in baseline instead.
    5720           4 :         if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
    5721           0 :             setGuard();
    5722           4 :     }
    5723             : 
    5724             :   public:
    5725         924 :     INSTRUCTION_HEADER(ToString)
    5726           4 :     TRIVIAL_NEW_WRAPPERS
    5727             : 
    5728             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5729             : 
    5730          24 :     bool congruentTo(const MDefinition* ins) const override {
    5731          24 :         return congruentIfOperandsEqual(ins);
    5732             :     }
    5733             : 
    5734         112 :     AliasSet getAliasSet() const override {
    5735         112 :         return AliasSet::None();
    5736             :     }
    5737             : 
    5738           4 :     bool fallible() const {
    5739           8 :         return input()->mightBeType(MIRType::Object) ||
    5740           8 :                input()->mightBeType(MIRType::Symbol);
    5741             :     }
    5742             : 
    5743           0 :     ALLOW_CLONE(MToString)
    5744             : };
    5745             : 
    5746             : // Converts any type to an object or null value, throwing on undefined.
    5747           0 : class MToObjectOrNull :
    5748             :   public MUnaryInstruction,
    5749             :   public BoxInputsPolicy::Data
    5750             : {
    5751           0 :     explicit MToObjectOrNull(MDefinition* def)
    5752           0 :       : MUnaryInstruction(def)
    5753             :     {
    5754           0 :         setResultType(MIRType::ObjectOrNull);
    5755           0 :         setMovable();
    5756           0 :     }
    5757             : 
    5758             :   public:
    5759           0 :     INSTRUCTION_HEADER(ToObjectOrNull)
    5760           0 :     TRIVIAL_NEW_WRAPPERS
    5761             : 
    5762           0 :     bool congruentTo(const MDefinition* ins) const override {
    5763           0 :         return congruentIfOperandsEqual(ins);
    5764             :     }
    5765             : 
    5766           0 :     AliasSet getAliasSet() const override {
    5767           0 :         return AliasSet::None();
    5768             :     }
    5769             : 
    5770           0 :     ALLOW_CLONE(MToObjectOrNull)
    5771             : };
    5772             : 
    5773           0 : class MBitNot
    5774             :   : public MUnaryInstruction,
    5775             :     public BitwisePolicy::Data
    5776             : {
    5777             :   protected:
    5778           6 :     explicit MBitNot(MDefinition* input)
    5779           6 :       : MUnaryInstruction(input)
    5780             :     {
    5781           6 :         specialization_ = MIRType::None;
    5782           6 :         setResultType(MIRType::Int32);
    5783           6 :         setMovable();
    5784           6 :     }
    5785             : 
    5786             :   public:
    5787         518 :     INSTRUCTION_HEADER(BitNot)
    5788           6 :     TRIVIAL_NEW_WRAPPERS
    5789             : 
    5790             :     static MBitNot* NewInt32(TempAllocator& alloc, MDefinition* input);
    5791             : 
    5792             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5793           6 :     void setSpecialization(MIRType type) {
    5794           6 :         specialization_ = type;
    5795           6 :         setResultType(type);
    5796           6 :     }
    5797             : 
    5798           6 :     bool congruentTo(const MDefinition* ins) const override {
    5799           6 :         return congruentIfOperandsEqual(ins);
    5800             :     }
    5801          44 :     AliasSet getAliasSet() const override {
    5802          44 :         if (specialization_ == MIRType::None)
    5803           0 :             return AliasSet::Store(AliasSet::Any);
    5804          44 :         return AliasSet::None();
    5805             :     }
    5806             :     void computeRange(TempAllocator& alloc) override;
    5807             : 
    5808             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5809           0 :     bool canRecoverOnBailout() const override {
    5810           0 :         return specialization_ != MIRType::None;
    5811             :     }
    5812             : 
    5813           0 :     ALLOW_CLONE(MBitNot)
    5814             : };
    5815             : 
    5816             : class MTypeOf
    5817             :   : public MUnaryInstruction,
    5818             :     public BoxInputsPolicy::Data
    5819             : {
    5820             :     MIRType inputType_;
    5821             :     bool inputMaybeCallableOrEmulatesUndefined_;
    5822             : 
    5823           3 :     MTypeOf(MDefinition* def, MIRType inputType)
    5824           3 :       : MUnaryInstruction(def), inputType_(inputType),
    5825           3 :         inputMaybeCallableOrEmulatesUndefined_(true)
    5826             :     {
    5827           3 :         setResultType(MIRType::String);
    5828           3 :         setMovable();
    5829           3 :     }
    5830             : 
    5831             :   public:
    5832          32 :     INSTRUCTION_HEADER(TypeOf)
    5833           3 :     TRIVIAL_NEW_WRAPPERS
    5834             : 
    5835           0 :     MIRType inputType() const {
    5836           0 :         return inputType_;
    5837             :     }
    5838             : 
    5839             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5840             :     void cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints);
    5841             : 
    5842           3 :     bool inputMaybeCallableOrEmulatesUndefined() const {
    5843           3 :         return inputMaybeCallableOrEmulatesUndefined_;
    5844             :     }
    5845           3 :     void markInputNotCallableOrEmulatesUndefined() {
    5846           3 :         inputMaybeCallableOrEmulatesUndefined_ = false;
    5847           3 :     }
    5848             : 
    5849           0 :     AliasSet getAliasSet() const override {
    5850           0 :         return AliasSet::None();
    5851             :     }
    5852             : 
    5853           0 :     bool congruentTo(const MDefinition* ins) const override {
    5854           0 :         if (!ins->isTypeOf())
    5855           0 :             return false;
    5856           0 :         if (inputType() != ins->toTypeOf()->inputType())
    5857           0 :             return false;
    5858           0 :         if (inputMaybeCallableOrEmulatesUndefined() !=
    5859           0 :             ins->toTypeOf()->inputMaybeCallableOrEmulatesUndefined())
    5860             :         {
    5861           0 :             return false;
    5862             :         }
    5863           0 :         return congruentIfOperandsEqual(ins);
    5864             :     }
    5865             : 
    5866             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    5867           0 :     bool canRecoverOnBailout() const override {
    5868           0 :         return true;
    5869             :     }
    5870             : };
    5871             : 
    5872             : class MToAsync
    5873             :   : public MUnaryInstruction,
    5874             :     public SingleObjectPolicy::Data
    5875             : {
    5876           0 :     explicit MToAsync(MDefinition* unwrapped)
    5877           0 :       : MUnaryInstruction(unwrapped)
    5878             :     {
    5879           0 :         setResultType(MIRType::Object);
    5880           0 :     }
    5881             : 
    5882             :   public:
    5883           0 :     INSTRUCTION_HEADER(ToAsync)
    5884           0 :     TRIVIAL_NEW_WRAPPERS
    5885             : };
    5886             : 
    5887             : class MToAsyncGen
    5888             :   : public MUnaryInstruction,
    5889             :     public SingleObjectPolicy::Data
    5890             : {
    5891           0 :     explicit MToAsyncGen(MDefinition* unwrapped)
    5892           0 :       : MUnaryInstruction(unwrapped)
    5893             :     {
    5894           0 :         setResultType(MIRType::Object);
    5895           0 :     }
    5896             : 
    5897             :   public:
    5898           0 :     INSTRUCTION_HEADER(ToAsyncGen)
    5899           0 :     TRIVIAL_NEW_WRAPPERS
    5900             : };
    5901             : 
    5902             : class MToAsyncIter
    5903             :   : public MUnaryInstruction,
    5904             :     public SingleObjectPolicy::Data
    5905             : {
    5906           0 :     explicit MToAsyncIter(MDefinition* unwrapped)
    5907           0 :       : MUnaryInstruction(unwrapped)
    5908             :     {
    5909           0 :         setResultType(MIRType::Object);
    5910           0 :     }
    5911             : 
    5912             :   public:
    5913           0 :     INSTRUCTION_HEADER(ToAsyncIter)
    5914           0 :     TRIVIAL_NEW_WRAPPERS
    5915             : };
    5916             : 
    5917             : class MToId
    5918             :   : public MUnaryInstruction,
    5919             :     public BoxInputsPolicy::Data
    5920             : {
    5921           0 :     explicit MToId(MDefinition* index)
    5922           0 :       : MUnaryInstruction(index)
    5923             :     {
    5924           0 :         setResultType(MIRType::Value);
    5925           0 :     }
    5926             : 
    5927             :   public:
    5928           0 :     INSTRUCTION_HEADER(ToId)
    5929           0 :     TRIVIAL_NEW_WRAPPERS
    5930             : };
    5931             : 
    5932           0 : class MBinaryBitwiseInstruction
    5933             :   : public MBinaryInstruction,
    5934             :     public BitwisePolicy::Data
    5935             : {
    5936             :   protected:
    5937           2 :     MBinaryBitwiseInstruction(MDefinition* left, MDefinition* right, MIRType type)
    5938           2 :       : MBinaryInstruction(left, right), maskMatchesLeftRange(false),
    5939           2 :         maskMatchesRightRange(false)
    5940             :     {
    5941           2 :         MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
    5942           2 :         setResultType(type);
    5943           2 :         setMovable();
    5944           2 :     }
    5945             : 
    5946             :     void specializeAs(MIRType type);
    5947             :     bool maskMatchesLeftRange;
    5948             :     bool maskMatchesRightRange;
    5949             : 
    5950             :   public:
    5951             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    5952             :     MDefinition* foldUnnecessaryBitop();
    5953             :     virtual MDefinition* foldIfZero(size_t operand) = 0;
    5954             :     virtual MDefinition* foldIfNegOne(size_t operand) = 0;
    5955             :     virtual MDefinition* foldIfEqual()  = 0;
    5956             :     virtual MDefinition* foldIfAllBitsSet(size_t operand)  = 0;
    5957             :     virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
    5958             :     void collectRangeInfoPreTrunc() override;
    5959             : 
    5960           0 :     void setInt32Specialization() {
    5961           0 :         specialization_ = MIRType::Int32;
    5962           0 :         setResultType(MIRType::Int32);
    5963           0 :     }
    5964             : 
    5965           0 :     bool congruentTo(const MDefinition* ins) const override {
    5966           0 :         return binaryCongruentTo(ins);
    5967             :     }
    5968           2 :     AliasSet getAliasSet() const override {
    5969           2 :         if (specialization_ >= MIRType::Object)
    5970           0 :             return AliasSet::Store(AliasSet::Any);
    5971           2 :         return AliasSet::None();
    5972             :     }
    5973             : 
    5974             :     TruncateKind operandTruncateKind(size_t index) const override;
    5975             : };
    5976             : 
    5977           0 : class MBitAnd : public MBinaryBitwiseInstruction
    5978             : {
    5979           0 :     MBitAnd(MDefinition* left, MDefinition* right, MIRType type)
    5980           0 :       : MBinaryBitwiseInstruction(left, right, type)
    5981           0 :     { }
    5982             : 
    5983             :   public:
    5984           0 :     INSTRUCTION_HEADER(BitAnd)
    5985             :     static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    5986             :     static MBitAnd* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    5987             : 
    5988           0 :     MDefinition* foldIfZero(size_t operand) override {
    5989           0 :         return getOperand(operand); // 0 & x => 0;
    5990             :     }
    5991           0 :     MDefinition* foldIfNegOne(size_t operand) override {
    5992           0 :         return getOperand(1 - operand); // x & -1 => x
    5993             :     }
    5994           0 :     MDefinition* foldIfEqual() override {
    5995           0 :         return getOperand(0); // x & x => x;
    5996             :     }
    5997           0 :     MDefinition* foldIfAllBitsSet(size_t operand) override {
    5998             :         // e.g. for uint16: x & 0xffff => x;
    5999           0 :         return getOperand(1 - operand);
    6000             :     }
    6001             :     void computeRange(TempAllocator& alloc) override;
    6002             : 
    6003             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6004           0 :     bool canRecoverOnBailout() const override {
    6005           0 :         return specialization_ != MIRType::None;
    6006             :     }
    6007             : 
    6008           0 :     ALLOW_CLONE(MBitAnd)
    6009             : };
    6010             : 
    6011           0 : class MBitOr : public MBinaryBitwiseInstruction
    6012             : {
    6013           2 :     MBitOr(MDefinition* left, MDefinition* right, MIRType type)
    6014           2 :       : MBinaryBitwiseInstruction(left, right, type)
    6015           2 :     { }
    6016             : 
    6017             :   public:
    6018           4 :     INSTRUCTION_HEADER(BitOr)
    6019             :     static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    6020             :     static MBitOr* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    6021             : 
    6022           0 :     MDefinition* foldIfZero(size_t operand) override {
    6023           0 :         return getOperand(1 - operand); // 0 | x => x, so if ith is 0, return (1-i)th
    6024             :     }
    6025           0 :     MDefinition* foldIfNegOne(size_t operand) override {
    6026           0 :         return getOperand(operand); // x | -1 => -1
    6027             :     }
    6028           0 :     MDefinition* foldIfEqual() override {
    6029           0 :         return getOperand(0); // x | x => x
    6030             :     }
    6031           0 :     MDefinition* foldIfAllBitsSet(size_t operand) override {
    6032           0 :         return this;
    6033             :     }
    6034             :     void computeRange(TempAllocator& alloc) override;
    6035             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6036           0 :     bool canRecoverOnBailout() const override {
    6037           0 :         return specialization_ != MIRType::None;
    6038             :     }
    6039             : 
    6040           0 :     ALLOW_CLONE(MBitOr)
    6041             : };
    6042             : 
    6043           0 : class MBitXor : public MBinaryBitwiseInstruction
    6044             : {
    6045           0 :     MBitXor(MDefinition* left, MDefinition* right, MIRType type)
    6046           0 :       : MBinaryBitwiseInstruction(left, right, type)
    6047           0 :     { }
    6048             : 
    6049             :   public:
    6050           0 :     INSTRUCTION_HEADER(BitXor)
    6051             :     static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    6052             :     static MBitXor* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    6053             : 
    6054           0 :     MDefinition* foldIfZero(size_t operand) override {
    6055           0 :         return getOperand(1 - operand); // 0 ^ x => x
    6056             :     }
    6057           0 :     MDefinition* foldIfNegOne(size_t operand) override {
    6058           0 :         return this;
    6059             :     }
    6060           0 :     MDefinition* foldIfEqual() override {
    6061           0 :         return this;
    6062             :     }
    6063           0 :     MDefinition* foldIfAllBitsSet(size_t operand) override {
    6064           0 :         return this;
    6065             :     }
    6066             :     void computeRange(TempAllocator& alloc) override;
    6067             : 
    6068             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6069           0 :     bool canRecoverOnBailout() const override {
    6070           0 :         return specialization_ < MIRType::Object;
    6071             :     }
    6072             : 
    6073           0 :     ALLOW_CLONE(MBitXor)
    6074             : };
    6075             : 
    6076           0 : class MShiftInstruction
    6077             :   : public MBinaryBitwiseInstruction
    6078             : {
    6079             :   protected:
    6080           0 :     MShiftInstruction(MDefinition* left, MDefinition* right, MIRType type)
    6081           0 :       : MBinaryBitwiseInstruction(left, right, type)
    6082           0 :     { }
    6083             : 
    6084             :   public:
    6085           0 :     MDefinition* foldIfNegOne(size_t operand) override {
    6086           0 :         return this;
    6087             :     }
    6088           0 :     MDefinition* foldIfEqual() override {
    6089           0 :         return this;
    6090             :     }
    6091           0 :     MDefinition* foldIfAllBitsSet(size_t operand) override {
    6092           0 :         return this;
    6093             :     }
    6094             :     virtual void infer(BaselineInspector* inspector, jsbytecode* pc) override;
    6095             : };
    6096             : 
    6097           0 : class MLsh : public MShiftInstruction
    6098             : {
    6099           0 :     MLsh(MDefinition* left, MDefinition* right, MIRType type)
    6100           0 :       : MShiftInstruction(left, right, type)
    6101           0 :     { }
    6102             : 
    6103             :   public:
    6104           0 :     INSTRUCTION_HEADER(Lsh)
    6105             :     static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    6106             :     static MLsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    6107             : 
    6108           0 :     MDefinition* foldIfZero(size_t operand) override {
    6109             :         // 0 << x => 0
    6110             :         // x << 0 => x
    6111           0 :         return getOperand(0);
    6112             :     }
    6113             : 
    6114             :     void computeRange(TempAllocator& alloc) override;
    6115             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6116           0 :     bool canRecoverOnBailout() const override {
    6117           0 :         return specialization_ != MIRType::None;
    6118             :     }
    6119             : 
    6120           0 :     ALLOW_CLONE(MLsh)
    6121             : };
    6122             : 
    6123           0 : class MRsh : public MShiftInstruction
    6124             : {
    6125           0 :     MRsh(MDefinition* left, MDefinition* right, MIRType type)
    6126           0 :       : MShiftInstruction(left, right, type)
    6127           0 :     { }
    6128             : 
    6129             :   public:
    6130           0 :     INSTRUCTION_HEADER(Rsh)
    6131             :     static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    6132             :     static MRsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    6133             : 
    6134           0 :     MDefinition* foldIfZero(size_t operand) override {
    6135             :         // 0 >> x => 0
    6136             :         // x >> 0 => x
    6137           0 :         return getOperand(0);
    6138             :     }
    6139             :     void computeRange(TempAllocator& alloc) override;
    6140             : 
    6141             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6142           0 :     bool canRecoverOnBailout() const override {
    6143           0 :         return specialization_ < MIRType::Object;
    6144             :     }
    6145             : 
    6146             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6147             : 
    6148           0 :     ALLOW_CLONE(MRsh)
    6149             : };
    6150             : 
    6151           0 : class MUrsh : public MShiftInstruction
    6152             : {
    6153             :     bool bailoutsDisabled_;
    6154             : 
    6155           0 :     MUrsh(MDefinition* left, MDefinition* right, MIRType type)
    6156           0 :       : MShiftInstruction(left, right, type),
    6157           0 :         bailoutsDisabled_(false)
    6158           0 :     { }
    6159             : 
    6160             :   public:
    6161           0 :     INSTRUCTION_HEADER(Ursh)
    6162             :     static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right);
    6163             :     static MUrsh* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type);
    6164             : 
    6165           0 :     MDefinition* foldIfZero(size_t operand) override {
    6166             :         // 0 >>> x => 0
    6167           0 :         if (operand == 0)
    6168           0 :             return getOperand(0);
    6169             : 
    6170           0 :         return this;
    6171             :     }
    6172             : 
    6173             :     void infer(BaselineInspector* inspector, jsbytecode* pc) override;
    6174             : 
    6175           0 :     bool bailoutsDisabled() const {
    6176           0 :         return bailoutsDisabled_;
    6177             :     }
    6178             : 
    6179             :     bool fallible() const;
    6180             : 
    6181             :     void computeRange(TempAllocator& alloc) override;
    6182             :     void collectRangeInfoPreTrunc() override;
    6183             : 
    6184             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6185           0 :     bool canRecoverOnBailout() const override {
    6186           0 :         return specialization_ < MIRType::Object;
    6187             :     }
    6188             : 
    6189           0 :     ALLOW_CLONE(MUrsh)
    6190             : };
    6191             : 
    6192           0 : class MSignExtend
    6193             :   : public MUnaryInstruction,
    6194             :     public NoTypePolicy::Data
    6195             : {
    6196             :   public:
    6197             :     enum Mode {
    6198             :         Byte,
    6199             :         Half
    6200             :     };
    6201             : 
    6202             :   private:
    6203             :     Mode mode_;
    6204             : 
    6205           0 :     MSignExtend(MDefinition* op, Mode mode)
    6206           0 :       : MUnaryInstruction(op), mode_(mode)
    6207             :     {
    6208           0 :         setResultType(MIRType::Int32);
    6209           0 :         setMovable();
    6210           0 :     }
    6211             : 
    6212             :   public:
    6213           0 :     INSTRUCTION_HEADER(SignExtend)
    6214           0 :     TRIVIAL_NEW_WRAPPERS
    6215             : 
    6216           0 :     Mode mode() { return mode_; }
    6217             : 
    6218             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6219           0 :     bool canRecoverOnBailout() const override {
    6220           0 :         return true;
    6221             :     }
    6222             : 
    6223           0 :     ALLOW_CLONE(MSignExtend)
    6224             : };
    6225             : 
    6226           0 : class MBinaryArithInstruction
    6227             :   : public MBinaryInstruction,
    6228             :     public ArithPolicy::Data
    6229             : {
    6230             :     // Implicit truncate flag is set by the truncate backward range analysis
    6231             :     // optimization phase, and by wasm pre-processing. It is used in
    6232             :     // NeedNegativeZeroCheck to check if the result of a multiplication needs to
    6233             :     // produce -0 double value, and for avoiding overflow checks.
    6234             : 
    6235             :     // This optimization happens when the multiplication cannot be truncated
    6236             :     // even if all uses are truncating its result, such as when the range
    6237             :     // analysis detect a precision loss in the multiplication.
    6238             :     TruncateKind implicitTruncate_;
    6239             : 
    6240             :     // Whether we must preserve NaN semantics, and in particular not fold
    6241             :     // (x op id) or (id op x) to x, or replace a division by a multiply of the
    6242             :     // exact reciprocal.
    6243             :     bool mustPreserveNaN_;
    6244             : 
    6245             :   public:
    6246         211 :     MBinaryArithInstruction(MDefinition* left, MDefinition* right)
    6247         211 :       : MBinaryInstruction(left, right),
    6248             :         implicitTruncate_(NoTruncate),
    6249         211 :         mustPreserveNaN_(false)
    6250             :     {
    6251         211 :         specialization_ = MIRType::None;
    6252         211 :         setMovable();
    6253         211 :     }
    6254             : 
    6255             :     static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
    6256             :                                         MDefinition* left, MDefinition* right);
    6257             : 
    6258             :     bool constantDoubleResult(TempAllocator& alloc);
    6259             : 
    6260           0 :     void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; }
    6261           0 :     bool mustPreserveNaN() const { return mustPreserveNaN_; }
    6262             : 
    6263             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6264             :     void printOpcode(GenericPrinter& out) const override;
    6265             : 
    6266             :     virtual double getIdentity() = 0;
    6267             : 
    6268         211 :     void setSpecialization(MIRType type) {
    6269         211 :         specialization_ = type;
    6270         211 :         setResultType(type);
    6271         211 :     }
    6272         160 :     void setInt32Specialization() {
    6273         160 :         specialization_ = MIRType::Int32;
    6274         160 :         setResultType(MIRType::Int32);
    6275         160 :     }
    6276             :     void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
    6277             : 
    6278             :     virtual void trySpecializeFloat32(TempAllocator& alloc) override;
    6279             : 
    6280          12 :     bool congruentTo(const MDefinition* ins) const override {
    6281          12 :         if (!binaryCongruentTo(ins))
    6282           0 :             return false;
    6283          12 :         const auto* other = static_cast<const MBinaryArithInstruction*>(ins);
    6284          12 :         return other->mustPreserveNaN_ == mustPreserveNaN_;
    6285             :     }
    6286         302 :     AliasSet getAliasSet() const override {
    6287         302 :         if (specialization_ >= MIRType::Object)
    6288           0 :             return AliasSet::Store(AliasSet::Any);
    6289         302 :         return AliasSet::None();
    6290             :     }
    6291             : 
    6292           9 :     bool isTruncated() const {
    6293           9 :         return implicitTruncate_ == Truncate;
    6294             :     }
    6295          40 :     TruncateKind truncateKind() const {
    6296          40 :         return implicitTruncate_;
    6297             :     }
    6298           2 :     void setTruncateKind(TruncateKind kind) {
    6299           2 :         implicitTruncate_ = Max(implicitTruncate_, kind);
    6300           2 :     }
    6301             : };
    6302             : 
    6303           0 : class MMinMax
    6304             :   : public MBinaryInstruction,
    6305             :     public ArithPolicy::Data
    6306             : {
    6307             :     bool isMax_;
    6308             : 
    6309           8 :     MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax)
    6310           8 :       : MBinaryInstruction(left, right),
    6311           8 :         isMax_(isMax)
    6312             :     {
    6313           8 :         MOZ_ASSERT(IsNumberType(type));
    6314           8 :         setResultType(type);
    6315           8 :         setMovable();
    6316           8 :         specialization_ = type;
    6317           8 :     }
    6318             : 
    6319             :   public:
    6320        1805 :     INSTRUCTION_HEADER(MinMax)
    6321           8 :     TRIVIAL_NEW_WRAPPERS
    6322             : 
    6323           0 :     static MMinMax* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    6324             :                             MIRType type, bool isMax)
    6325             :     {
    6326           0 :         return New(alloc, left, right, type, isMax);
    6327             :     }
    6328             : 
    6329          31 :     bool isMax() const {
    6330          31 :         return isMax_;
    6331             :     }
    6332             : 
    6333           8 :     bool congruentTo(const MDefinition* ins) const override {
    6334           8 :         if (!congruentIfOperandsEqual(ins))
    6335           0 :             return false;
    6336           8 :         const MMinMax* other = ins->toMinMax();
    6337           8 :         return other->isMax() == isMax();
    6338             :     }
    6339             : 
    6340          58 :     AliasSet getAliasSet() const override {
    6341          58 :         return AliasSet::None();
    6342             :     }
    6343             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6344             :     void computeRange(TempAllocator& alloc) override;
    6345             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6346           5 :     bool canRecoverOnBailout() const override {
    6347           5 :         return true;
    6348             :     }
    6349             : 
    6350           0 :     bool isFloat32Commutative() const override { return true; }
    6351             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    6352             : 
    6353           0 :     ALLOW_CLONE(MMinMax)
    6354             : };
    6355             : 
    6356           0 : class MAbs
    6357             :   : public MUnaryInstruction,
    6358             :     public ArithPolicy::Data
    6359             : {
    6360             :     bool implicitTruncate_;
    6361             : 
    6362           0 :     MAbs(MDefinition* num, MIRType type)
    6363           0 :       : MUnaryInstruction(num),
    6364           0 :         implicitTruncate_(false)
    6365             :     {
    6366           0 :         MOZ_ASSERT(IsNumberType(type));
    6367           0 :         setResultType(type);
    6368           0 :         setMovable();
    6369           0 :         specialization_ = type;
    6370           0 :     }
    6371             : 
    6372             :   public:
    6373           0 :     INSTRUCTION_HEADER(Abs)
    6374           0 :     TRIVIAL_NEW_WRAPPERS
    6375             : 
    6376           0 :     static MAbs* NewWasm(TempAllocator& alloc, MDefinition* num, MIRType type) {
    6377           0 :         auto* ins = new(alloc) MAbs(num, type);
    6378           0 :         if (type == MIRType::Int32)
    6379           0 :             ins->implicitTruncate_ = true;
    6380           0 :         return ins;
    6381             :     }
    6382             : 
    6383           0 :     bool congruentTo(const MDefinition* ins) const override {
    6384           0 :         return congruentIfOperandsEqual(ins);
    6385             :     }
    6386             :     bool fallible() const;
    6387             : 
    6388           0 :     AliasSet getAliasSet() const override {
    6389           0 :         return AliasSet::None();
    6390             :     }
    6391             :     void computeRange(TempAllocator& alloc) override;
    6392           0 :     bool isFloat32Commutative() const override { return true; }
    6393             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    6394             : 
    6395             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6396           0 :     bool canRecoverOnBailout() const override {
    6397           0 :         return true;
    6398             :     }
    6399             : 
    6400           0 :     ALLOW_CLONE(MAbs)
    6401             : };
    6402             : 
    6403             : class MClz
    6404             :   : public MUnaryInstruction
    6405             :   , public BitwisePolicy::Data
    6406             : {
    6407             :     bool operandIsNeverZero_;
    6408             : 
    6409           0 :     explicit MClz(MDefinition* num, MIRType type)
    6410           0 :       : MUnaryInstruction(num),
    6411           0 :         operandIsNeverZero_(false)
    6412             :     {
    6413           0 :         MOZ_ASSERT(IsIntType(type));
    6414           0 :         MOZ_ASSERT(IsNumberType(num->type()));
    6415           0 :         specialization_ = type;
    6416           0 :         setResultType(type);
    6417           0 :         setMovable();
    6418           0 :     }
    6419             : 
    6420             :   public:
    6421           0 :     INSTRUCTION_HEADER(Clz)
    6422           0 :     TRIVIAL_NEW_WRAPPERS
    6423           0 :     NAMED_OPERANDS((0, num))
    6424             : 
    6425           0 :     bool congruentTo(const MDefinition* ins) const override {
    6426           0 :         return congruentIfOperandsEqual(ins);
    6427             :     }
    6428             : 
    6429           0 :     AliasSet getAliasSet() const override {
    6430           0 :         return AliasSet::None();
    6431             :     }
    6432             : 
    6433           0 :     bool operandIsNeverZero() const {
    6434           0 :         return operandIsNeverZero_;
    6435             :     }
    6436             : 
    6437             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6438             :     void computeRange(TempAllocator& alloc) override;
    6439             :     void collectRangeInfoPreTrunc() override;
    6440             : };
    6441             : 
    6442             : class MCtz
    6443             :   : public MUnaryInstruction
    6444             :   , public BitwisePolicy::Data
    6445             : {
    6446             :     bool operandIsNeverZero_;
    6447             : 
    6448           0 :     explicit MCtz(MDefinition* num, MIRType type)
    6449           0 :       : MUnaryInstruction(num),
    6450           0 :         operandIsNeverZero_(false)
    6451             :     {
    6452           0 :         MOZ_ASSERT(IsIntType(type));
    6453           0 :         MOZ_ASSERT(IsNumberType(num->type()));
    6454           0 :         specialization_ = type;
    6455           0 :         setResultType(type);
    6456           0 :         setMovable();
    6457           0 :     }
    6458             : 
    6459             :   public:
    6460           0 :     INSTRUCTION_HEADER(Ctz)
    6461           0 :     TRIVIAL_NEW_WRAPPERS
    6462           0 :     NAMED_OPERANDS((0, num))
    6463             : 
    6464           0 :     bool congruentTo(const MDefinition* ins) const override {
    6465           0 :         return congruentIfOperandsEqual(ins);
    6466             :     }
    6467             : 
    6468           0 :     AliasSet getAliasSet() const override {
    6469           0 :         return AliasSet::None();
    6470             :     }
    6471             : 
    6472           0 :     bool operandIsNeverZero() const {
    6473           0 :         return operandIsNeverZero_;
    6474             :     }
    6475             : 
    6476             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6477             :     void computeRange(TempAllocator& alloc) override;
    6478             :     void collectRangeInfoPreTrunc() override;
    6479             : };
    6480             : 
    6481             : class MPopcnt
    6482             :   : public MUnaryInstruction
    6483             :   , public BitwisePolicy::Data
    6484             : {
    6485           0 :     explicit MPopcnt(MDefinition* num, MIRType type)
    6486           0 :       : MUnaryInstruction(num)
    6487             :     {
    6488           0 :         MOZ_ASSERT(IsNumberType(num->type()));
    6489           0 :         MOZ_ASSERT(IsIntType(type));
    6490           0 :         specialization_ = type;
    6491           0 :         setResultType(type);
    6492           0 :         setMovable();
    6493           0 :     }
    6494             : 
    6495             :   public:
    6496           0 :     INSTRUCTION_HEADER(Popcnt)
    6497           0 :     TRIVIAL_NEW_WRAPPERS
    6498           0 :     NAMED_OPERANDS((0, num))
    6499             : 
    6500           0 :     bool congruentTo(const MDefinition* ins) const override {
    6501           0 :         return congruentIfOperandsEqual(ins);
    6502             :     }
    6503             : 
    6504           0 :     AliasSet getAliasSet() const override {
    6505           0 :         return AliasSet::None();
    6506             :     }
    6507             : 
    6508             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6509             :     void computeRange(TempAllocator& alloc) override;
    6510             : };
    6511             : 
    6512             : // Inline implementation of Math.sqrt().
    6513           0 : class MSqrt
    6514             :   : public MUnaryInstruction,
    6515             :     public FloatingPointPolicy<0>::Data
    6516             : {
    6517           0 :     MSqrt(MDefinition* num, MIRType type)
    6518           0 :       : MUnaryInstruction(num)
    6519             :     {
    6520           0 :         setResultType(type);
    6521           0 :         specialization_ = type;
    6522           0 :         setMovable();
    6523           0 :     }
    6524             : 
    6525             :   public:
    6526           0 :     INSTRUCTION_HEADER(Sqrt)
    6527           0 :     TRIVIAL_NEW_WRAPPERS
    6528             : 
    6529           0 :     bool congruentTo(const MDefinition* ins) const override {
    6530           0 :         return congruentIfOperandsEqual(ins);
    6531             :     }
    6532             : 
    6533           0 :     AliasSet getAliasSet() const override {
    6534           0 :         return AliasSet::None();
    6535             :     }
    6536             :     void computeRange(TempAllocator& alloc) override;
    6537             : 
    6538           0 :     bool isFloat32Commutative() const override { return true; }
    6539             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    6540             : 
    6541             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6542           0 :     bool canRecoverOnBailout() const override {
    6543           0 :         return true;
    6544             :     }
    6545             : 
    6546           0 :     ALLOW_CLONE(MSqrt)
    6547             : };
    6548             : 
    6549           0 : class MCopySign
    6550             :   : public MBinaryInstruction,
    6551             :     public NoTypePolicy::Data
    6552             : {
    6553           0 :     MCopySign(MDefinition* lhs, MDefinition* rhs, MIRType type)
    6554           0 :       : MBinaryInstruction(lhs, rhs)
    6555             :     {
    6556           0 :         setResultType(type);
    6557           0 :         setMovable();
    6558           0 :     }
    6559             : 
    6560             :   public:
    6561           0 :     INSTRUCTION_HEADER(CopySign)
    6562           0 :     TRIVIAL_NEW_WRAPPERS
    6563             : 
    6564           0 :     bool congruentTo(const MDefinition* ins) const override {
    6565           0 :         return congruentIfOperandsEqual(ins);
    6566             :     }
    6567           0 :     AliasSet getAliasSet() const override {
    6568           0 :         return AliasSet::None();
    6569             :     }
    6570             : 
    6571           0 :     ALLOW_CLONE(MCopySign)
    6572             : };
    6573             : 
    6574             : // Inline implementation of atan2 (arctangent of y/x).
    6575           0 : class MAtan2
    6576             :   : public MBinaryInstruction,
    6577             :     public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
    6578             : {
    6579           0 :     MAtan2(MDefinition* y, MDefinition* x)
    6580           0 :       : MBinaryInstruction(y, x)
    6581             :     {
    6582           0 :         setResultType(MIRType::Double);
    6583           0 :         setMovable();
    6584           0 :     }
    6585             : 
    6586             :   public:
    6587           0 :     INSTRUCTION_HEADER(Atan2)
    6588           0 :     TRIVIAL_NEW_WRAPPERS
    6589           0 :     NAMED_OPERANDS((0, y), (1, x))
    6590             : 
    6591           0 :     bool congruentTo(const MDefinition* ins) const override {
    6592           0 :         return congruentIfOperandsEqual(ins);
    6593             :     }
    6594             : 
    6595           0 :     AliasSet getAliasSet() const override {
    6596           0 :         return AliasSet::None();
    6597             :     }
    6598             : 
    6599           0 :     bool possiblyCalls() const override {
    6600           0 :         return true;
    6601             :     }
    6602             : 
    6603             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6604           0 :     bool canRecoverOnBailout() const override {
    6605           0 :         return true;
    6606             :     }
    6607             : 
    6608           0 :     ALLOW_CLONE(MAtan2)
    6609             : };
    6610             : 
    6611             : // Inline implementation of Math.hypot().
    6612             : class MHypot
    6613             :   : public MVariadicInstruction,
    6614             :     public AllDoublePolicy::Data
    6615             : {
    6616           0 :     MHypot()
    6617           0 :     {
    6618           0 :         setResultType(MIRType::Double);
    6619           0 :         setMovable();
    6620           0 :     }
    6621             : 
    6622             :   public:
    6623           0 :     INSTRUCTION_HEADER(Hypot)
    6624             :     static MHypot* New(TempAllocator& alloc, const MDefinitionVector& vector);
    6625             : 
    6626           0 :     bool congruentTo(const MDefinition* ins) const override {
    6627           0 :         return congruentIfOperandsEqual(ins);
    6628             :     }
    6629             : 
    6630           0 :     AliasSet getAliasSet() const override {
    6631           0 :         return AliasSet::None();
    6632             :     }
    6633             : 
    6634           0 :     bool possiblyCalls() const override {
    6635           0 :         return true;
    6636             :     }
    6637             : 
    6638             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6639           0 :     bool canRecoverOnBailout() const override {
    6640           0 :         return true;
    6641             :     }
    6642             : 
    6643           0 :     bool canClone() const override {
    6644           0 :         return true;
    6645             :     }
    6646             : 
    6647           0 :     MInstruction* clone(TempAllocator& alloc,
    6648             :                         const MDefinitionVector& inputs) const override {
    6649           0 :        return MHypot::New(alloc, inputs);
    6650             :     }
    6651             : };
    6652             : 
    6653             : // Inline implementation of Math.pow().
    6654           0 : class MPow
    6655             :   : public MBinaryInstruction,
    6656             :     public PowPolicy::Data
    6657             : {
    6658           0 :     MPow(MDefinition* input, MDefinition* power, MIRType powerType)
    6659           0 :       : MBinaryInstruction(input, power)
    6660             :     {
    6661           0 :         MOZ_ASSERT(powerType == MIRType::Double ||
    6662             :                    powerType == MIRType::Int32 ||
    6663             :                    powerType == MIRType::None);
    6664           0 :         specialization_ = powerType;
    6665           0 :         if (powerType == MIRType::None)
    6666           0 :             setResultType(MIRType::Value);
    6667             :         else
    6668           0 :             setResultType(MIRType::Double);
    6669           0 :         setMovable();
    6670           0 :     }
    6671             : 
    6672             :     // Helpers for `foldsTo`
    6673             :     MDefinition* foldsConstant(TempAllocator &alloc);
    6674             :     MDefinition* foldsConstantPower(TempAllocator &alloc);
    6675             : 
    6676             :   public:
    6677           0 :     INSTRUCTION_HEADER(Pow)
    6678           0 :     TRIVIAL_NEW_WRAPPERS
    6679             : 
    6680           0 :     MDefinition* input() const {
    6681           0 :         return lhs();
    6682             :     }
    6683           0 :     MDefinition* power() const {
    6684           0 :         return rhs();
    6685             :     }
    6686           0 :     bool congruentTo(const MDefinition* ins) const override {
    6687           0 :         return congruentIfOperandsEqual(ins);
    6688             :     }
    6689           0 :     AliasSet getAliasSet() const override {
    6690           0 :         if (specialization_ == MIRType::None)
    6691           0 :             return AliasSet::Store(AliasSet::Any);
    6692           0 :         return AliasSet::None();
    6693             :     }
    6694           0 :     bool possiblyCalls() const override {
    6695           0 :         return true;
    6696             :     }
    6697             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6698           0 :     bool canRecoverOnBailout() const override {
    6699           0 :         return specialization_ != MIRType::None;
    6700             :     }
    6701             : 
    6702             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6703             : 
    6704           0 :     ALLOW_CLONE(MPow)
    6705             : };
    6706             : 
    6707             : // Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
    6708           0 : class MPowHalf
    6709             :   : public MUnaryInstruction,
    6710             :     public DoublePolicy<0>::Data
    6711             : {
    6712             :     bool operandIsNeverNegativeInfinity_;
    6713             :     bool operandIsNeverNegativeZero_;
    6714             :     bool operandIsNeverNaN_;
    6715             : 
    6716           0 :     explicit MPowHalf(MDefinition* input)
    6717           0 :       : MUnaryInstruction(input),
    6718             :         operandIsNeverNegativeInfinity_(false),
    6719             :         operandIsNeverNegativeZero_(false),
    6720           0 :         operandIsNeverNaN_(false)
    6721             :     {
    6722           0 :         setResultType(MIRType::Double);
    6723           0 :         setMovable();
    6724           0 :     }
    6725             : 
    6726             :   public:
    6727           0 :     INSTRUCTION_HEADER(PowHalf)
    6728           0 :     TRIVIAL_NEW_WRAPPERS
    6729             : 
    6730           0 :     bool congruentTo(const MDefinition* ins) const override {
    6731           0 :         return congruentIfOperandsEqual(ins);
    6732             :     }
    6733           0 :     bool operandIsNeverNegativeInfinity() const {
    6734           0 :         return operandIsNeverNegativeInfinity_;
    6735             :     }
    6736           0 :     bool operandIsNeverNegativeZero() const {
    6737           0 :         return operandIsNeverNegativeZero_;
    6738             :     }
    6739           0 :     bool operandIsNeverNaN() const {
    6740           0 :         return operandIsNeverNaN_;
    6741             :     }
    6742           0 :     AliasSet getAliasSet() const override {
    6743           0 :         return AliasSet::None();
    6744             :     }
    6745             :     void collectRangeInfoPreTrunc() override;
    6746             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6747           0 :     bool canRecoverOnBailout() const override {
    6748           0 :         return true;
    6749             :     }
    6750             : 
    6751           0 :     ALLOW_CLONE(MPowHalf)
    6752             : };
    6753             : 
    6754             : // Inline implementation of Math.random().
    6755           0 : class MRandom : public MNullaryInstruction
    6756             : {
    6757           0 :     MRandom()
    6758           0 :     {
    6759           0 :         setResultType(MIRType::Double);
    6760           0 :     }
    6761             : 
    6762             :   public:
    6763           0 :     INSTRUCTION_HEADER(Random)
    6764           0 :     TRIVIAL_NEW_WRAPPERS
    6765             : 
    6766           0 :     AliasSet getAliasSet() const override {
    6767           0 :         return AliasSet::None();
    6768             :     }
    6769             : 
    6770           0 :     bool possiblyCalls() const override {
    6771           0 :         return true;
    6772             :     }
    6773             : 
    6774             :     void computeRange(TempAllocator& alloc) override;
    6775             : 
    6776             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6777             : 
    6778           0 :     bool canRecoverOnBailout() const override {
    6779             : #ifdef JS_MORE_DETERMINISTIC
    6780             :         return false;
    6781             : #else
    6782           0 :         return true;
    6783             : #endif
    6784             :     }
    6785             : 
    6786           0 :     ALLOW_CLONE(MRandom)
    6787             : };
    6788             : 
    6789           0 : class MMathFunction
    6790             :   : public MUnaryInstruction,
    6791             :     public FloatingPointPolicy<0>::Data
    6792             : {
    6793             :   public:
    6794             :     enum Function {
    6795             :         Log,
    6796             :         Sin,
    6797             :         Cos,
    6798             :         Exp,
    6799             :         Tan,
    6800             :         ACos,
    6801             :         ASin,
    6802             :         ATan,
    6803             :         Log10,
    6804             :         Log2,
    6805             :         Log1P,
    6806             :         ExpM1,
    6807             :         CosH,
    6808             :         SinH,
    6809             :         TanH,
    6810             :         ACosH,
    6811             :         ASinH,
    6812             :         ATanH,
    6813             :         Sign,
    6814             :         Trunc,
    6815             :         Cbrt,
    6816             :         Floor,
    6817             :         Ceil,
    6818             :         Round
    6819             :     };
    6820             : 
    6821             :   private:
    6822             :     Function function_;
    6823             :     const MathCache* cache_;
    6824             : 
    6825             :     // A nullptr cache means this function will neither access nor update the cache.
    6826           0 :     MMathFunction(MDefinition* input, Function function, const MathCache* cache)
    6827           0 :       : MUnaryInstruction(input), function_(function), cache_(cache)
    6828             :     {
    6829           0 :         setResultType(MIRType::Double);
    6830           0 :         specialization_ = MIRType::Double;
    6831           0 :         setMovable();
    6832           0 :     }
    6833             : 
    6834             :   public:
    6835           0 :     INSTRUCTION_HEADER(MathFunction)
    6836           0 :     TRIVIAL_NEW_WRAPPERS
    6837             : 
    6838           0 :     Function function() const {
    6839           0 :         return function_;
    6840             :     }
    6841           0 :     const MathCache* cache() const {
    6842           0 :         return cache_;
    6843             :     }
    6844           0 :     bool congruentTo(const MDefinition* ins) const override {
    6845           0 :         if (!ins->isMathFunction())
    6846           0 :             return false;
    6847           0 :         if (ins->toMathFunction()->function() != function())
    6848           0 :             return false;
    6849           0 :         return congruentIfOperandsEqual(ins);
    6850             :     }
    6851             : 
    6852           0 :     AliasSet getAliasSet() const override {
    6853           0 :         return AliasSet::None();
    6854             :     }
    6855             : 
    6856           0 :     bool possiblyCalls() const override {
    6857           0 :         return true;
    6858             :     }
    6859             : 
    6860             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    6861             : 
    6862             :     void printOpcode(GenericPrinter& out) const override;
    6863             : 
    6864             :     static const char* FunctionName(Function function);
    6865             : 
    6866           0 :     bool isFloat32Commutative() const override {
    6867           0 :         return function_ == Floor || function_ == Ceil || function_ == Round;
    6868             :     }
    6869             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    6870             :     void computeRange(TempAllocator& alloc) override;
    6871             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6872           0 :     bool canRecoverOnBailout() const override {
    6873           0 :         if (input()->type() == MIRType::SinCosDouble)
    6874           0 :             return false;
    6875           0 :         switch(function_) {
    6876             :           case Sin:
    6877             :           case Log:
    6878             :           case Round:
    6879           0 :             return true;
    6880             :           default:
    6881           0 :             return false;
    6882             :         }
    6883             :     }
    6884             : 
    6885           0 :     ALLOW_CLONE(MMathFunction)
    6886             : };
    6887             : 
    6888           0 : class MAdd : public MBinaryArithInstruction
    6889             : {
    6890         208 :     MAdd(MDefinition* left, MDefinition* right)
    6891         208 :       : MBinaryArithInstruction(left, right)
    6892             :     {
    6893         208 :         setResultType(MIRType::Value);
    6894         208 :     }
    6895             : 
    6896           0 :     MAdd(MDefinition* left, MDefinition* right, MIRType type, TruncateKind truncateKind = Truncate)
    6897           0 :       : MAdd(left, right)
    6898             :     {
    6899           0 :         specialization_ = type;
    6900           0 :         setResultType(type);
    6901           0 :         if (type == MIRType::Int32) {
    6902           0 :             setTruncateKind(truncateKind);
    6903           0 :             setCommutative();
    6904             :         }
    6905           0 :     }
    6906             : 
    6907             :   public:
    6908        3946 :     INSTRUCTION_HEADER(Add)
    6909         208 :     TRIVIAL_NEW_WRAPPERS
    6910             : 
    6911           0 :     bool isFloat32Commutative() const override { return true; }
    6912             : 
    6913          24 :     double getIdentity() override {
    6914          24 :         return 0;
    6915             :     }
    6916             : 
    6917             :     bool fallible() const;
    6918             :     void computeRange(TempAllocator& alloc) override;
    6919             :     bool needTruncation(TruncateKind kind) override;
    6920             :     void truncate() override;
    6921             :     TruncateKind operandTruncateKind(size_t index) const override;
    6922             : 
    6923             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6924           8 :     bool canRecoverOnBailout() const override {
    6925           8 :         return specialization_ < MIRType::Object;
    6926             :     }
    6927             : 
    6928           0 :     ALLOW_CLONE(MAdd)
    6929             : };
    6930             : 
    6931           0 : class MSub : public MBinaryArithInstruction
    6932             : {
    6933           0 :     MSub(MDefinition* left, MDefinition* right)
    6934           0 :       : MBinaryArithInstruction(left, right)
    6935             :     {
    6936           0 :         setResultType(MIRType::Value);
    6937           0 :     }
    6938             : 
    6939           0 :     MSub(MDefinition* left, MDefinition* right, MIRType type, bool mustPreserveNaN = false)
    6940           0 :       : MSub(left, right)
    6941             :     {
    6942           0 :         specialization_ = type;
    6943           0 :         setResultType(type);
    6944           0 :         setMustPreserveNaN(mustPreserveNaN);
    6945           0 :         if (type == MIRType::Int32)
    6946           0 :             setTruncateKind(Truncate);
    6947           0 :     }
    6948             : 
    6949             :   public:
    6950           0 :     INSTRUCTION_HEADER(Sub)
    6951           0 :     TRIVIAL_NEW_WRAPPERS
    6952             : 
    6953           0 :     double getIdentity() override {
    6954           0 :         return 0;
    6955             :     }
    6956             : 
    6957           0 :     bool isFloat32Commutative() const override { return true; }
    6958             : 
    6959             :     bool fallible() const;
    6960             :     void computeRange(TempAllocator& alloc) override;
    6961             :     bool needTruncation(TruncateKind kind) override;
    6962             :     void truncate() override;
    6963             :     TruncateKind operandTruncateKind(size_t index) const override;
    6964             : 
    6965             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    6966           0 :     bool canRecoverOnBailout() const override {
    6967           0 :         return specialization_ < MIRType::Object;
    6968             :     }
    6969             : 
    6970           0 :     ALLOW_CLONE(MSub)
    6971             : };
    6972             : 
    6973           0 : class MMul : public MBinaryArithInstruction
    6974             : {
    6975             :   public:
    6976             :     enum Mode {
    6977             :         Normal,
    6978             :         Integer
    6979             :     };
    6980             : 
    6981             :   private:
    6982             :     // Annotation the result could be a negative zero
    6983             :     // and we need to guard this during execution.
    6984             :     bool canBeNegativeZero_;
    6985             : 
    6986             :     Mode mode_;
    6987             : 
    6988           3 :     MMul(MDefinition* left, MDefinition* right, MIRType type, Mode mode)
    6989           3 :       : MBinaryArithInstruction(left, right),
    6990             :         canBeNegativeZero_(true),
    6991           3 :         mode_(mode)
    6992             :     {
    6993           3 :         if (mode == Integer) {
    6994             :             // This implements the required behavior for Math.imul, which
    6995             :             // can never fail and always truncates its output to int32.
    6996           0 :             canBeNegativeZero_ = false;
    6997           0 :             setTruncateKind(Truncate);
    6998           0 :             setCommutative();
    6999             :         }
    7000           3 :         MOZ_ASSERT_IF(mode != Integer, mode == Normal);
    7001             : 
    7002           3 :         if (type != MIRType::Value)
    7003           0 :             specialization_ = type;
    7004           3 :         setResultType(type);
    7005           3 :     }
    7006             : 
    7007             :   public:
    7008           9 :     INSTRUCTION_HEADER(Mul)
    7009           3 :     static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
    7010           3 :         return new(alloc) MMul(left, right, MIRType::Value, MMul::Normal);
    7011             :     }
    7012           0 :     static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
    7013             :                      Mode mode = Normal)
    7014             :     {
    7015           0 :         return new(alloc) MMul(left, right, type, mode);
    7016             :     }
    7017           0 :     static MMul* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type,
    7018             :                          Mode mode, bool mustPreserveNaN)
    7019             :     {
    7020           0 :         auto* ret = new(alloc) MMul(left, right, type, mode);
    7021           0 :         ret->setMustPreserveNaN(mustPreserveNaN);
    7022           0 :         return ret;
    7023             :     }
    7024             : 
    7025             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    7026             :     void analyzeEdgeCasesForward() override;
    7027             :     void analyzeEdgeCasesBackward() override;
    7028             :     void collectRangeInfoPreTrunc() override;
    7029             : 
    7030           0 :     double getIdentity() override {
    7031           0 :         return 1;
    7032             :     }
    7033             : 
    7034           0 :     bool congruentTo(const MDefinition* ins) const override {
    7035           0 :         if (!ins->isMul())
    7036           0 :             return false;
    7037             : 
    7038           0 :         const MMul* mul = ins->toMul();
    7039           0 :         if (canBeNegativeZero_ != mul->canBeNegativeZero())
    7040           0 :             return false;
    7041             : 
    7042           0 :         if (mode_ != mul->mode())
    7043           0 :             return false;
    7044             : 
    7045           0 :         if (mustPreserveNaN() != mul->mustPreserveNaN())
    7046           0 :             return false;
    7047             : 
    7048           0 :         return binaryCongruentTo(ins);
    7049             :     }
    7050             : 
    7051             :     bool canOverflow() const;
    7052             : 
    7053           0 :     bool canBeNegativeZero() const {
    7054           0 :         return canBeNegativeZero_;
    7055             :     }
    7056           0 :     void setCanBeNegativeZero(bool negativeZero) {
    7057           0 :         canBeNegativeZero_ = negativeZero;
    7058           0 :     }
    7059             : 
    7060             :     MOZ_MUST_USE bool updateForReplacement(MDefinition* ins) override;
    7061             : 
    7062           0 :     bool fallible() const {
    7063           0 :         return canBeNegativeZero_ || canOverflow();
    7064             :     }
    7065             : 
    7066           0 :     void setSpecialization(MIRType type) {
    7067           0 :         specialization_ = type;
    7068           0 :     }
    7069             : 
    7070           0 :     bool isFloat32Commutative() const override { return true; }
    7071             : 
    7072             :     void computeRange(TempAllocator& alloc) override;
    7073             :     bool needTruncation(TruncateKind kind) override;
    7074             :     void truncate() override;
    7075             :     TruncateKind operandTruncateKind(size_t index) const override;
    7076             : 
    7077           0 :     Mode mode() const { return mode_; }
    7078             : 
    7079             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7080           0 :     bool canRecoverOnBailout() const override {
    7081           0 :         return specialization_ < MIRType::Object;
    7082             :     }
    7083             : 
    7084           0 :     ALLOW_CLONE(MMul)
    7085             : };
    7086             : 
    7087           0 : class MDiv : public MBinaryArithInstruction
    7088             : {
    7089             :     bool canBeNegativeZero_;
    7090             :     bool canBeNegativeOverflow_;
    7091             :     bool canBeDivideByZero_;
    7092             :     bool canBeNegativeDividend_;
    7093             :     bool unsigned_;             // If false, signedness will be derived from operands
    7094             :     bool trapOnError_;
    7095             :     wasm::BytecodeOffset bytecodeOffset_;
    7096             : 
    7097           0 :     MDiv(MDefinition* left, MDefinition* right, MIRType type)
    7098           0 :       : MBinaryArithInstruction(left, right),
    7099             :         canBeNegativeZero_(true),
    7100             :         canBeNegativeOverflow_(true),
    7101             :         canBeDivideByZero_(true),
    7102             :         canBeNegativeDividend_(true),
    7103             :         unsigned_(false),
    7104           0 :         trapOnError_(false)
    7105             :     {
    7106           0 :         if (type != MIRType::Value)
    7107           0 :             specialization_ = type;
    7108           0 :         setResultType(type);
    7109           0 :     }
    7110             : 
    7111             :   public:
    7112           0 :     INSTRUCTION_HEADER(Div)
    7113           0 :     static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
    7114           0 :         return new(alloc) MDiv(left, right, MIRType::Value);
    7115             :     }
    7116           0 :     static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type) {
    7117           0 :         return new(alloc) MDiv(left, right, type);
    7118             :     }
    7119           0 :     static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    7120             :                      MIRType type, bool unsignd, bool trapOnError = false,
    7121             :                      wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset(),
    7122             :                      bool mustPreserveNaN = false)
    7123             :     {
    7124           0 :         auto* div = new(alloc) MDiv(left, right, type);
    7125           0 :         div->unsigned_ = unsignd;
    7126           0 :         div->trapOnError_ = trapOnError;
    7127           0 :         div->bytecodeOffset_ = bytecodeOffset;
    7128           0 :         if (trapOnError) {
    7129           0 :             div->setGuard(); // not removable because of possible side-effects.
    7130           0 :             div->setNotMovable();
    7131             :         }
    7132           0 :         div->setMustPreserveNaN(mustPreserveNaN);
    7133           0 :         if (type == MIRType::Int32)
    7134           0 :             div->setTruncateKind(Truncate);
    7135           0 :         return div;
    7136             :     }
    7137             : 
    7138             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    7139             :     void analyzeEdgeCasesForward() override;
    7140             :     void analyzeEdgeCasesBackward() override;
    7141             : 
    7142           0 :     double getIdentity() override {
    7143           0 :         MOZ_CRASH("not used");
    7144             :     }
    7145             : 
    7146           0 :     bool canBeNegativeZero() const {
    7147           0 :         return canBeNegativeZero_;
    7148             :     }
    7149           0 :     void setCanBeNegativeZero(bool negativeZero) {
    7150           0 :         canBeNegativeZero_ = negativeZero;
    7151           0 :     }
    7152             : 
    7153           0 :     bool canBeNegativeOverflow() const {
    7154           0 :         return canBeNegativeOverflow_;
    7155             :     }
    7156             : 
    7157           0 :     bool canBeDivideByZero() const {
    7158           0 :         return canBeDivideByZero_;
    7159             :     }
    7160             : 
    7161           0 :     bool canBeNegativeDividend() const {
    7162             :         // "Dividend" is an ambiguous concept for unsigned truncated
    7163             :         // division, because of the truncation procedure:
    7164             :         // ((x>>>0)/2)|0, for example, gets transformed in
    7165             :         // MDiv::truncate into a node with lhs representing x (not
    7166             :         // x>>>0) and rhs representing the constant 2; in other words,
    7167             :         // the MIR node corresponds to "cast operands to unsigned and
    7168             :         // divide" operation. In this case, is the dividend x or is it
    7169             :         // x>>>0? In order to resolve such ambiguities, we disallow
    7170             :         // the usage of this method for unsigned division.
    7171           0 :         MOZ_ASSERT(!unsigned_);
    7172           0 :         return canBeNegativeDividend_;
    7173             :     }
    7174             : 
    7175           0 :     bool isUnsigned() const {
    7176           0 :         return unsigned_;
    7177             :     }
    7178             : 
    7179           0 :     bool isTruncatedIndirectly() const {
    7180           0 :         return truncateKind() >= IndirectTruncate;
    7181             :     }
    7182             : 
    7183           0 :     bool canTruncateInfinities() const {
    7184           0 :         return isTruncated();
    7185             :     }
    7186           0 :     bool canTruncateRemainder() const {
    7187           0 :         return isTruncated();
    7188             :     }
    7189           0 :     bool canTruncateOverflow() const {
    7190           0 :         return isTruncated() || isTruncatedIndirectly();
    7191             :     }
    7192           0 :     bool canTruncateNegativeZero() const {
    7193           0 :         return isTruncated() || isTruncatedIndirectly();
    7194             :     }
    7195             : 
    7196           0 :     bool trapOnError() const {
    7197           0 :         return trapOnError_;
    7198             :     }
    7199           0 :     wasm::BytecodeOffset bytecodeOffset() const {
    7200           0 :         MOZ_ASSERT(bytecodeOffset_.isValid());
    7201           0 :         return bytecodeOffset_;
    7202             :     }
    7203             : 
    7204           0 :     bool isFloat32Commutative() const override { return true; }
    7205             : 
    7206             :     void computeRange(TempAllocator& alloc) override;
    7207             :     bool fallible() const;
    7208             :     bool needTruncation(TruncateKind kind) override;
    7209             :     void truncate() override;
    7210             :     void collectRangeInfoPreTrunc() override;
    7211             :     TruncateKind operandTruncateKind(size_t index) const override;
    7212             : 
    7213             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7214           0 :     bool canRecoverOnBailout() const override {
    7215           0 :         return specialization_ < MIRType::Object;
    7216             :     }
    7217             : 
    7218           0 :     bool congruentTo(const MDefinition* ins) const override {
    7219           0 :         if (!MBinaryArithInstruction::congruentTo(ins))
    7220           0 :             return false;
    7221           0 :         const MDiv* other = ins->toDiv();
    7222           0 :         MOZ_ASSERT(other->trapOnError() == trapOnError_);
    7223           0 :         return unsigned_ == other->isUnsigned();
    7224             :     }
    7225             : 
    7226           0 :     ALLOW_CLONE(MDiv)
    7227             : };
    7228             : 
    7229           0 : class MMod : public MBinaryArithInstruction
    7230             : {
    7231             :     bool unsigned_;             // If false, signedness will be derived from operands
    7232             :     bool canBeNegativeDividend_;
    7233             :     bool canBePowerOfTwoDivisor_;
    7234             :     bool canBeDivideByZero_;
    7235             :     bool trapOnError_;
    7236             :     wasm::BytecodeOffset bytecodeOffset_;
    7237             : 
    7238           0 :     MMod(MDefinition* left, MDefinition* right, MIRType type)
    7239           0 :       : MBinaryArithInstruction(left, right),
    7240             :         unsigned_(false),
    7241             :         canBeNegativeDividend_(true),
    7242             :         canBePowerOfTwoDivisor_(true),
    7243             :         canBeDivideByZero_(true),
    7244           0 :         trapOnError_(false)
    7245             :     {
    7246           0 :         if (type != MIRType::Value)
    7247           0 :             specialization_ = type;
    7248           0 :         setResultType(type);
    7249           0 :     }
    7250             : 
    7251             :   public:
    7252           0 :     INSTRUCTION_HEADER(Mod)
    7253           0 :     static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right) {
    7254           0 :         return new(alloc) MMod(left, right, MIRType::Value);
    7255             :     }
    7256           0 :     static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
    7257             :                      MIRType type, bool unsignd, bool trapOnError = false,
    7258             :                      wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
    7259             :     {
    7260           0 :         auto* mod = new(alloc) MMod(left, right, type);
    7261           0 :         mod->unsigned_ = unsignd;
    7262           0 :         mod->trapOnError_ = trapOnError;
    7263           0 :         mod->bytecodeOffset_ = bytecodeOffset;
    7264           0 :         if (trapOnError) {
    7265           0 :             mod->setGuard(); // not removable because of possible side-effects.
    7266           0 :             mod->setNotMovable();
    7267             :         }
    7268           0 :         if (type == MIRType::Int32)
    7269           0 :             mod->setTruncateKind(Truncate);
    7270           0 :         return mod;
    7271             :     }
    7272             : 
    7273             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    7274             : 
    7275           0 :     double getIdentity() override {
    7276           0 :         MOZ_CRASH("not used");
    7277             :     }
    7278             : 
    7279           0 :     bool canBeNegativeDividend() const {
    7280           0 :         MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64);
    7281           0 :         MOZ_ASSERT(!unsigned_);
    7282           0 :         return canBeNegativeDividend_;
    7283             :     }
    7284             : 
    7285           0 :     bool canBeDivideByZero() const {
    7286           0 :         MOZ_ASSERT(specialization_ == MIRType::Int32 || specialization_ == MIRType::Int64);
    7287           0 :         return canBeDivideByZero_;
    7288             :     }
    7289             : 
    7290           0 :     bool canBePowerOfTwoDivisor() const {
    7291           0 :         MOZ_ASSERT(specialization_ == MIRType::Int32);
    7292           0 :         return canBePowerOfTwoDivisor_;
    7293             :     }
    7294             : 
    7295             :     void analyzeEdgeCasesForward() override;
    7296             : 
    7297           0 :     bool isUnsigned() const {
    7298           0 :         return unsigned_;
    7299             :     }
    7300             : 
    7301           0 :     bool trapOnError() const {
    7302           0 :         return trapOnError_;
    7303             :     }
    7304           0 :     wasm::BytecodeOffset bytecodeOffset() const {
    7305           0 :         MOZ_ASSERT(bytecodeOffset_.isValid());
    7306           0 :         return bytecodeOffset_;
    7307             :     }
    7308             : 
    7309             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7310           0 :     bool canRecoverOnBailout() const override {
    7311           0 :         return specialization_ < MIRType::Object;
    7312             :     }
    7313             : 
    7314             :     bool fallible() const;
    7315             : 
    7316             :     void computeRange(TempAllocator& alloc) override;
    7317             :     bool needTruncation(TruncateKind kind) override;
    7318             :     void truncate() override;
    7319             :     void collectRangeInfoPreTrunc() override;
    7320             :     TruncateKind operandTruncateKind(size_t index) const override;
    7321             : 
    7322           0 :     bool congruentTo(const MDefinition* ins) const override {
    7323           0 :         return MBinaryArithInstruction::congruentTo(ins) &&
    7324           0 :                unsigned_ == ins->toMod()->isUnsigned();
    7325             :     }
    7326             : 
    7327           0 :     bool possiblyCalls() const override {
    7328           0 :         return type() == MIRType::Double;
    7329             :     }
    7330             : 
    7331           0 :     ALLOW_CLONE(MMod)
    7332             : };
    7333             : 
    7334           0 : class MConcat
    7335             :   : public MBinaryInstruction,
    7336             :     public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
    7337             : {
    7338          38 :     MConcat(MDefinition* left, MDefinition* right)
    7339          38 :       : MBinaryInstruction(left, right)
    7340             :     {
    7341             :         // At least one input should be definitely string
    7342          38 :         MOZ_ASSERT(left->type() == MIRType::String || right->type() == MIRType::String);
    7343             : 
    7344          38 :         setMovable();
    7345          38 :         setResultType(MIRType::String);
    7346          38 :     }
    7347             : 
    7348             :   public:
    7349        3693 :     INSTRUCTION_HEADER(Concat)
    7350          38 :     TRIVIAL_NEW_WRAPPERS
    7351             : 
    7352             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    7353          24 :     bool congruentTo(const MDefinition* ins) const override {
    7354          24 :         return congruentIfOperandsEqual(ins);
    7355             :     }
    7356         274 :     AliasSet getAliasSet() const override {
    7357         274 :         return AliasSet::None();
    7358             :     }
    7359             : 
    7360             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7361          12 :     bool canRecoverOnBailout() const override {
    7362          12 :         return true;
    7363             :     }
    7364             : 
    7365           0 :     ALLOW_CLONE(MConcat)
    7366             : };
    7367             : 
    7368           0 : class MCharCodeAt
    7369             :   : public MBinaryInstruction,
    7370             :     public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
    7371             : {
    7372           6 :     MCharCodeAt(MDefinition* str, MDefinition* index)
    7373           6 :         : MBinaryInstruction(str, index)
    7374             :     {
    7375           6 :         setMovable();
    7376           6 :         setResultType(MIRType::Int32);
    7377           6 :     }
    7378             : 
    7379             :   public:
    7380        2331 :     INSTRUCTION_HEADER(CharCodeAt)
    7381           6 :     TRIVIAL_NEW_WRAPPERS
    7382             : 
    7383          14 :     bool congruentTo(const MDefinition* ins) const override {
    7384          14 :         return congruentIfOperandsEqual(ins);
    7385             :     }
    7386             : 
    7387          66 :     virtual AliasSet getAliasSet() const override {
    7388             :         // Strings are immutable, so there is no implicit dependency.
    7389          66 :         return AliasSet::None();
    7390             :     }
    7391             : 
    7392             :     void computeRange(TempAllocator& alloc) override;
    7393             : 
    7394             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7395           2 :     bool canRecoverOnBailout() const override {
    7396           2 :         return true;
    7397             :     }
    7398             : 
    7399           0 :     ALLOW_CLONE(MCharCodeAt)
    7400             : };
    7401             : 
    7402           0 : class MFromCharCode
    7403             :   : public MUnaryInstruction,
    7404             :     public IntPolicy<0>::Data
    7405             : {
    7406           3 :     explicit MFromCharCode(MDefinition* code)
    7407           3 :       : MUnaryInstruction(code)
    7408             :     {
    7409           3 :         setMovable();
    7410           3 :         setResultType(MIRType::String);
    7411           3 :     }
    7412             : 
    7413             :   public:
    7414        1024 :     INSTRUCTION_HEADER(FromCharCode)
    7415           3 :     TRIVIAL_NEW_WRAPPERS
    7416             : 
    7417          32 :     virtual AliasSet getAliasSet() const override {
    7418          32 :         return AliasSet::None();
    7419             :     }
    7420           4 :     bool congruentTo(const MDefinition* ins) const override {
    7421           4 :         return congruentIfOperandsEqual(ins);
    7422             :     }
    7423             : 
    7424             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7425           2 :     bool canRecoverOnBailout() const override {
    7426           2 :         return true;
    7427             :     }
    7428             : 
    7429           0 :     ALLOW_CLONE(MFromCharCode)
    7430             : };
    7431             : 
    7432             : class MFromCodePoint
    7433             :   : public MUnaryInstruction,
    7434             :     public IntPolicy<0>::Data
    7435             : {
    7436           0 :     explicit MFromCodePoint(MDefinition* codePoint)
    7437           0 :       : MUnaryInstruction(codePoint)
    7438             :     {
    7439           0 :         setGuard(); // throws on invalid code point
    7440           0 :         setMovable();
    7441           0 :         setResultType(MIRType::String);
    7442           0 :     }
    7443             : 
    7444             :   public:
    7445           0 :     INSTRUCTION_HEADER(FromCodePoint)
    7446           0 :     TRIVIAL_NEW_WRAPPERS
    7447             : 
    7448           0 :     AliasSet getAliasSet() const override {
    7449           0 :         return AliasSet::None();
    7450             :     }
    7451           0 :     bool congruentTo(const MDefinition* ins) const override {
    7452           0 :         return congruentIfOperandsEqual(ins);
    7453             :     }
    7454           0 :     bool possiblyCalls() const override {
    7455           0 :         return true;
    7456             :     }
    7457             : };
    7458             : 
    7459             : class MSinCos
    7460             :   : public MUnaryInstruction,
    7461             :     public FloatingPointPolicy<0>::Data
    7462             : {
    7463             :     const MathCache* cache_;
    7464             : 
    7465           0 :     MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache)
    7466             :     {
    7467           0 :         setResultType(MIRType::SinCosDouble);
    7468           0 :         specialization_ = MIRType::Double;
    7469           0 :         setMovable();
    7470           0 :     }
    7471             : 
    7472             :   public:
    7473           0 :     INSTRUCTION_HEADER(SinCos)
    7474             : 
    7475           0 :     static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
    7476             :     {
    7477           0 :         return new (alloc) MSinCos(input, cache);
    7478             :     }
    7479           0 :     AliasSet getAliasSet() const override {
    7480           0 :         return AliasSet::None();
    7481             :     }
    7482           0 :     bool congruentTo(const MDefinition *ins) const override {
    7483           0 :         return congruentIfOperandsEqual(ins);
    7484             :     }
    7485           0 :     bool possiblyCalls() const override {
    7486           0 :         return true;
    7487             :     }
    7488           0 :     const MathCache* cache() const {
    7489           0 :         return cache_;
    7490             :     }
    7491             : };
    7492             : 
    7493             : class MStringSplit
    7494             :   : public MBinaryInstruction,
    7495             :     public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
    7496             : {
    7497             :     CompilerObjectGroup group_;
    7498             : 
    7499           0 :     MStringSplit(CompilerConstraintList* constraints, MDefinition* string, MDefinition* sep,
    7500             :                  ObjectGroup* group)
    7501           0 :       : MBinaryInstruction(string, sep),
    7502           0 :         group_(group)
    7503             :     {
    7504           0 :         setResultType(MIRType::Object);
    7505           0 :         TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, group);
    7506           0 :         setResultTypeSet(types);
    7507           0 :     }
    7508             : 
    7509             :   public:
    7510           0 :     INSTRUCTION_HEADER(StringSplit)
    7511           0 :     TRIVIAL_NEW_WRAPPERS
    7512           0 :     NAMED_OPERANDS((0, string), (1, separator))
    7513             : 
    7514           0 :     ObjectGroup* group() const {
    7515           0 :         return group_;
    7516             :     }
    7517           0 :     bool possiblyCalls() const override {
    7518           0 :         return true;
    7519             :     }
    7520           0 :     virtual AliasSet getAliasSet() const override {
    7521             :         // Although this instruction returns a new array, we don't have to mark
    7522             :         // it as store instruction, see also MNewArray.
    7523           0 :         return AliasSet::None();
    7524             :     }
    7525             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    7526           0 :     bool canRecoverOnBailout() const override {
    7527           0 :         return true;
    7528             :     }
    7529           0 :     bool appendRoots(MRootList& roots) const override {
    7530           0 :         return roots.append(group_);
    7531             :     }
    7532             : };
    7533             : 
    7534             : // Returns the value to use as |this| value. See also ComputeThis and
    7535             : // BoxNonStrictThis in Interpreter.h.
    7536             : class MComputeThis
    7537             :   : public MUnaryInstruction,
    7538             :     public BoxPolicy<0>::Data
    7539             : {
    7540           0 :     explicit MComputeThis(MDefinition* def)
    7541           0 :       : MUnaryInstruction(def)
    7542             :     {
    7543           0 :         setResultType(MIRType::Value);
    7544           0 :     }
    7545             : 
    7546             :   public:
    7547           0 :     INSTRUCTION_HEADER(ComputeThis)
    7548           0 :     TRIVIAL_NEW_WRAPPERS
    7549             : 
    7550           0 :     bool possiblyCalls() const override {
    7551           0 :         return true;
    7552             :     }
    7553             : 
    7554             :     // Note: don't override getAliasSet: the thisValue hook can be effectful.
    7555             : };
    7556             : 
    7557             : // Load an arrow function's |new.target| value.
    7558             : class MArrowNewTarget
    7559             :   : public MUnaryInstruction,
    7560             :     public SingleObjectPolicy::Data
    7561             : {
    7562           0 :     explicit MArrowNewTarget(MDefinition* callee)
    7563           0 :       : MUnaryInstruction(callee)
    7564             :     {
    7565           0 :         setResultType(MIRType::Value);
    7566           0 :         setMovable();
    7567           0 :     }
    7568             : 
    7569             :   public:
    7570           0 :     INSTRUCTION_HEADER(ArrowNewTarget)
    7571           0 :     TRIVIAL_NEW_WRAPPERS
    7572           0 :     NAMED_OPERANDS((0, callee))
    7573             : 
    7574           0 :     bool congruentTo(const MDefinition* ins) const override {
    7575           0 :         return congruentIfOperandsEqual(ins);
    7576             :     }
    7577           0 :     AliasSet getAliasSet() const override {
    7578             :         // An arrow function's lexical |this| value is immutable.
    7579           0 :         return AliasSet::None();
    7580             :     }
    7581             : };
    7582             : 
    7583             : class MPhi final
    7584             :   : public MDefinition,
    7585             :     public InlineListNode<MPhi>,
    7586             :     public NoTypePolicy::Data
    7587             : {
    7588             :     using InputVector = js::Vector<MUse, 2, JitAllocPolicy>;
    7589             :     InputVector inputs_;
    7590             : 
    7591             :     TruncateKind truncateKind_;
    7592             :     bool hasBackedgeType_;
    7593             :     bool triedToSpecialize_;
    7594             :     bool isIterator_;
    7595             :     bool canProduceFloat32_;
    7596             :     bool canConsumeFloat32_;
    7597             : 
    7598             : #if DEBUG
    7599             :     bool specialized_;
    7600             : #endif
    7601             : 
    7602             :   protected:
    7603       17285 :     MUse* getUseFor(size_t index) override {
    7604             :         // Note: after the initial IonBuilder pass, it is OK to change phi
    7605             :         // operands such that they do not include the type sets of their
    7606             :         // operands. This can arise during e.g. value numbering, where
    7607             :         // definitions producing the same value may have different type sets.
    7608       17285 :         MOZ_ASSERT(index < numOperands());
    7609       17285 :         return &inputs_[index];
    7610             :     }
    7611           0 :     const MUse* getUseFor(size_t index) const override {
    7612           0 :         return &inputs_[index];
    7613             :     }
    7614             : 
    7615             :   public:
    7616       76776 :     INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)
    7617             :     virtual TypePolicy* typePolicy();
    7618             :     virtual MIRType typePolicySpecialization();
    7619             : 
    7620        2728 :     MPhi(TempAllocator& alloc, MIRType resultType)
    7621        2728 :       : inputs_(alloc),
    7622             :         truncateKind_(NoTruncate),
    7623             :         hasBackedgeType_(false),
    7624             :         triedToSpecialize_(false),
    7625             :         isIterator_(false),
    7626             :         canProduceFloat32_(false),
    7627             :         canConsumeFloat32_(false)
    7628             : #if DEBUG
    7629        2728 :         , specialized_(false)
    7630             : #endif
    7631             :     {
    7632        2728 :         setResultType(resultType);
    7633        2728 :     }
    7634             : 
    7635         103 :     static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType::Value) {
    7636         103 :         return new(alloc) MPhi(alloc, resultType);
    7637             :     }
    7638        2625 :     static MPhi* New(TempAllocator::Fallible alloc, MIRType resultType = MIRType::Value) {
    7639        2625 :         return new(alloc) MPhi(alloc.alloc, resultType);
    7640             :     }
    7641             : 
    7642             :     void removeOperand(size_t index);
    7643             :     void removeAllOperands();
    7644             : 
    7645       50249 :     MDefinition* getOperand(size_t index) const override {
    7646       50249 :         return inputs_[index].producer();
    7647             :     }
    7648       63440 :     size_t numOperands() const override {
    7649       63440 :         return inputs_.length();
    7650             :     }
    7651       17128 :     size_t indexOf(const MUse* u) const final override {
    7652       17128 :         MOZ_ASSERT(u >= &inputs_[0]);
    7653       17128 :         MOZ_ASSERT(u <= &inputs_[numOperands() - 1]);
    7654       17128 :         return u - &inputs_[0];
    7655             :     }
    7656         375 :     void replaceOperand(size_t index, MDefinition* operand) final override {
    7657         375 :         inputs_[index].replaceProducer(operand);
    7658         375 :     }
    7659           0 :     bool hasBackedgeType() const {
    7660           0 :         return hasBackedgeType_;
    7661             :     }
    7662         645 :     bool triedToSpecialize() const {
    7663         645 :         return triedToSpecialize_;
    7664             :     }
    7665         296 :     void specialize(MIRType type) {
    7666         296 :         triedToSpecialize_ = true;
    7667         296 :         setResultType(type);
    7668         296 :     }
    7669             :     bool specializeType(TempAllocator& alloc);
    7670             : 
    7671             : #ifdef DEBUG
    7672             :     // Assert that this is a phi in a loop header with a unique predecessor and
    7673             :     // a unique backedge.
    7674             :     void assertLoopPhi() const;
    7675             : #else
    7676             :     void assertLoopPhi() const {}
    7677             : #endif
    7678             : 
    7679             :     // Assuming this phi is in a loop header with a unique loop entry, return
    7680             :     // the phi operand along the loop entry.
    7681          23 :     MDefinition* getLoopPredecessorOperand() const {
    7682          23 :         assertLoopPhi();
    7683          23 :         return getOperand(0);
    7684             :     }
    7685             : 
    7686             :     // Assuming this phi is in a loop header with a unique loop entry, return
    7687             :     // the phi operand along the loop backedge.
    7688          23 :     MDefinition* getLoopBackedgeOperand() const {
    7689          23 :         assertLoopPhi();
    7690          23 :         return getOperand(1);
    7691             :     }
    7692             : 
    7693             :     // Whether this phi's type already includes information for def.
    7694             :     bool typeIncludes(MDefinition* def);
    7695             : 
    7696             :     // Add types for this phi which speculate about new inputs that may come in
    7697             :     // via a loop backedge.
    7698             :     MOZ_MUST_USE bool addBackedgeType(TempAllocator& alloc, MIRType type,
    7699             :                                       TemporaryTypeSet* typeSet);
    7700             : 
    7701             :     // Initializes the operands vector to the given capacity,
    7702             :     // permitting use of addInput() instead of addInputSlow().
    7703        1193 :     MOZ_MUST_USE bool reserveLength(size_t length) {
    7704        1193 :         return inputs_.reserve(length);
    7705             :     }
    7706             : 
    7707             :     // Use only if capacity has been reserved by reserveLength
    7708        2485 :     void addInput(MDefinition* ins) {
    7709        2485 :         inputs_.infallibleEmplaceBack(ins, this);
    7710        2485 :     }
    7711             : 
    7712             :     // Appends a new input to the input vector. May perform reallocation.
    7713             :     // Prefer reserveLength() and addInput() instead, where possible.
    7714        3278 :     MOZ_MUST_USE bool addInputSlow(MDefinition* ins) {
    7715        3278 :         return inputs_.emplaceBack(ins, this);
    7716             :     }
    7717             : 
    7718             :     // Appends a new input to the input vector. Infallible because
    7719             :     // we know the inputs fits in the vector's inline storage.
    7720        1535 :     void addInlineInput(MDefinition* ins) {
    7721        1535 :         MOZ_ASSERT(inputs_.length() < InputVector::InlineLength);
    7722        1535 :         MOZ_ALWAYS_TRUE(addInputSlow(ins));
    7723        1535 :     }
    7724             : 
    7725             :     // Update the type of this phi after adding |ins| as an input. Set
    7726             :     // |*ptypeChange| to true if the type changed.
    7727             :     bool checkForTypeChange(TempAllocator& alloc, MDefinition* ins, bool* ptypeChange);
    7728             : 
    7729             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    7730             :     MDefinition* foldsTernary(TempAllocator& alloc);
    7731             :     MDefinition* foldsFilterTypeSet();
    7732             : 
    7733             :     bool congruentTo(const MDefinition* ins) const override;
    7734             : 
    7735          24 :     bool isIterator() const {
    7736          24 :         return isIterator_;
    7737             :     }
    7738          21 :     void setIterator() {
    7739          21 :         isIterator_ = true;
    7740          21 :     }
    7741             : 
    7742        9457 :     AliasSet getAliasSet() const override {
    7743        9457 :         return AliasSet::None();
    7744             :     }
    7745             :     void computeRange(TempAllocator& alloc) override;
    7746             : 
    7747             :     MDefinition* operandIfRedundant();
    7748             : 
    7749          17 :     bool canProduceFloat32() const override {
    7750          17 :         return canProduceFloat32_;
    7751             :     }
    7752             : 
    7753           0 :     void setCanProduceFloat32(bool can) {
    7754           0 :         canProduceFloat32_ = can;
    7755           0 :     }
    7756             : 
    7757           0 :     bool canConsumeFloat32(MUse* use) const override {
    7758           0 :         return canConsumeFloat32_;
    7759             :     }
    7760             : 
    7761           0 :     void setCanConsumeFloat32(bool can) {
    7762           0 :         canConsumeFloat32_ = can;
    7763           0 :     }
    7764             : 
    7765             :     TruncateKind operandTruncateKind(size_t index) const override;
    7766             :     bool needTruncation(TruncateKind kind) override;
    7767             :     void truncate() override;
    7768             : };
    7769             : 
    7770             : // The goal of a Beta node is to split a def at a conditionally taken
    7771             : // branch, so that uses dominated by it have a different name.
    7772             : class MBeta
    7773             :   : public MUnaryInstruction,
    7774             :     public NoTypePolicy::Data
    7775             : {
    7776             :   private:
    7777             :     // This is the range induced by a comparison and branch in a preceding
    7778             :     // block. Note that this does not reflect any range constraints from
    7779             :     // the input value itself, so this value may differ from the range()
    7780             :     // range after it is computed.
    7781             :     const Range* comparison_;
    7782             : 
    7783          50 :     MBeta(MDefinition* val, const Range* comp)
    7784          50 :         : MUnaryInstruction(val),
    7785          50 :           comparison_(comp)
    7786             :     {
    7787          50 :         setResultType(val->type());
    7788          50 :         setResultTypeSet(val->resultTypeSet());
    7789          50 :     }
    7790             : 
    7791             :   public:
    7792        1144 :     INSTRUCTION_HEADER(Beta)
    7793          50 :     TRIVIAL_NEW_WRAPPERS
    7794             : 
    7795             :     void printOpcode(GenericPrinter& out) const override;
    7796             : 
    7797           0 :     AliasSet getAliasSet() const override {
    7798           0 :         return AliasSet::None();
    7799             :     }
    7800             : 
    7801             :     void computeRange(TempAllocator& alloc) override;
    7802             : };
    7803             : 
    7804             : // If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the input is returned
    7805           0 : class MNaNToZero
    7806             :   : public MUnaryInstruction,
    7807             :     public DoublePolicy<0>::Data
    7808             : {
    7809             :     bool operandIsNeverNaN_;
    7810             :     bool operandIsNeverNegativeZero_;
    7811           0 :     explicit MNaNToZero(MDefinition* input)
    7812           0 :       : MUnaryInstruction(input), operandIsNeverNaN_(false), operandIsNeverNegativeZero_(false)
    7813             :     {
    7814           0 :         setResultType(MIRType::Double);
    7815           0 :         setMovable();
    7816           0 :     }
    7817             :   public:
    7818           0 :     INSTRUCTION_HEADER(NaNToZero)
    7819           0 :     TRIVIAL_NEW_WRAPPERS
    7820             : 
    7821           0 :     bool operandIsNeverNaN() const {
    7822           0 :         return operandIsNeverNaN_;
    7823             :     }
    7824             : 
    7825           0 :     bool operandIsNeverNegativeZero() const {
    7826           0 :         return operandIsNeverNegativeZero_;
    7827             :     }
    7828             : 
    7829             :     void collectRangeInfoPreTrunc() override;
    7830             : 
    7831           0 :     AliasSet getAliasSet() const override {
    7832           0 :         return AliasSet::None();
    7833             :     }
    7834             : 
    7835             :     void computeRange(TempAllocator& alloc) override;
    7836             : 
    7837             :     bool writeRecoverData(CompactBufferWriter& writer) const override;
    7838           0 :     bool canRecoverOnBailout() const override {
    7839           0 :         return true;
    7840             :     }
    7841             : 
    7842           0 :     ALLOW_CLONE(MNaNToZero)
    7843             : };
    7844             : 
    7845             : // MIR representation of a Value on the OSR BaselineFrame.
    7846             : // The Value is indexed off of OsrFrameReg.
    7847             : class MOsrValue
    7848             :   : public MUnaryInstruction,
    7849             :     public NoTypePolicy::Data
    7850             : {
    7851             :   private:
    7852             :     ptrdiff_t frameOffset_;
    7853             : 
    7854          58 :     MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset)
    7855          58 :       : MUnaryInstruction(entry),
    7856          58 :         frameOffset_(frameOffset)
    7857             :     {
    7858          58 :         setResultType(MIRType::Value);
    7859          58 :     }
    7860             : 
    7861             :   public:
    7862       14916 :     INSTRUCTION_HEADER(OsrValue)
    7863          58 :     TRIVIAL_NEW_WRAPPERS
    7864             : 
    7865          42 :     ptrdiff_t frameOffset() const {
    7866          42 :         return frameOffset_;
    7867             :     }
    7868             : 
    7869          42 :     MOsrEntry* entry() {
    7870          42 :         return getOperand(0)->toOsrEntry();
    7871             :     }
    7872             : 
    7873         222 :     AliasSet getAliasSet() const override {
    7874         222 :         return AliasSet::None();
    7875             :     }
    7876             : };
    7877             : 
    7878             : // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
    7879             : // The pointer is indexed off of OsrFrameReg.
    7880             : class MOsrEnvironmentChain
    7881             :   : public MUnaryInstruction,
    7882             :     public NoTypePolicy::Data
    7883             : {
    7884             :   private:
    7885           3 :     explicit MOsrEnvironmentChain(MOsrEntry* entry)
    7886           3 :       : MUnaryInstruction(entry)
    7887             :     {
    7888           3 :         setResultType(MIRType::Object);
    7889           3 :     }
    7890             : 
    7891             :   public:
    7892         676 :     INSTRUCTION_HEADER(OsrEnvironmentChain)
    7893           3 :     TRIVIAL_NEW_WRAPPERS
    7894             : 
    7895           2 :     MOsrEntry* entry() {
    7896           2 :         return getOperand(0)->toOsrEntry();
    7897             :     }
    7898             : };
    7899             : 
    7900             : // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
    7901             : // The pointer is indexed off of OsrFrameReg.
    7902             : class MOsrArgumentsObject
    7903             :   : public MUnaryInstruction,
    7904             :     public NoTypePolicy::Data
    7905             : {
    7906             :   private:
    7907           0 :     explicit MOsrArgumentsObject(MOsrEntry* entry)
    7908           0 :       : MUnaryInstruction(entry)
    7909             :     {
    7910           0 :         setResultType(MIRType::Object);
    7911           0 :     }
    7912             : 
    7913             :   public:
    7914           0 :     INSTRUCTION_HEADER(OsrArgumentsObject)
    7915           0 :     TRIVIAL_NEW_WRAPPERS
    7916             : 
    7917           0 :     MOsrEntry* entry() {
    7918           0 :         return getOperand(0)->toOsrEntry();
    7919             :     }
    7920             : };
    7921             : 
    7922             : // MIR representation of the return value on the OSR BaselineFrame.
    7923             : // The Value is indexed off of OsrFrameReg.
    7924             : class MOsrReturnValue
    7925             :   : public MUnaryInstruction,
    7926             :     public NoTypePolicy::Data
    7927             : {
    7928             :   private:
    7929           4 :     explicit MOsrReturnValue(MOsrEntry* entry)
    7930           4 :       : MUnaryInstruction(entry)
    7931             :     {
    7932           4 :         setResultType(MIRType::Value);
    7933           4 :     }
    7934             : 
    7935             :   public:
    7936         948 :     INSTRUCTION_HEADER(OsrReturnValue)
    7937           4 :     TRIVIAL_NEW_WRAPPERS
    7938             : 
    7939           3 :     MOsrEntry* entry() {
    7940           3 :         return getOperand(0)->toOsrEntry();
    7941             :     }
    7942             : };
    7943             : 
    7944             : class MBinarySharedStub
    7945             :   : public MBinaryInstruction,
    7946             :     public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
    7947             : {
    7948             :   protected:
    7949         217 :     explicit MBinarySharedStub(MDefinition* left, MDefinition* right)
    7950         217 :       : MBinaryInstruction(left, right)
    7951             :     {
    7952         217 :         setResultType(MIRType::Value);
    7953         217 :     }
    7954             : 
    7955             :   public:
    7956          44 :     INSTRUCTION_HEADER(BinarySharedStub)
    7957         217 :     TRIVIAL_NEW_WRAPPERS
    7958             : };
    7959             : 
    7960             : class MUnarySharedStub
    7961             :   : public MUnaryInstruction,
    7962             :     public BoxPolicy<0>::Data
    7963             : {
    7964           0 :     explicit MUnarySharedStub(MDefinition* input)
    7965           0 :       : MUnaryInstruction(input)
    7966             :     {
    7967           0 :         setResultType(MIRType::Value);
    7968           0 :     }
    7969             : 
    7970             :   public:
    7971           0 :     INSTRUCTION_HEADER(UnarySharedStub)
    7972           0 :     TRIVIAL_NEW_WRAPPERS
    7973             : };
    7974             : 
    7975             : class MNullarySharedStub
    7976             :   : public MNullaryInstruction
    7977             : {
    7978           3 :     explicit MNullarySharedStub()
    7979           3 :       : MNullaryInstruction()
    7980             :     {
    7981           3 :         setResultType(MIRType::Value);
    7982           3 :     }
    7983             : 
    7984             :   public:
    7985           4 :     INSTRUCTION_HEADER(NullarySharedStub)
    7986           3 :     TRIVIAL_NEW_WRAPPERS
    7987             : };
    7988             : 
    7989             : // Check the current frame for over-recursion past the global stack limit.
    7990         146 : class MCheckOverRecursed
    7991             :   : public MNullaryInstruction
    7992             : {
    7993             :   public:
    7994        1853 :     INSTRUCTION_HEADER(CheckOverRecursed)
    7995         146 :     TRIVIAL_NEW_WRAPPERS
    7996             : 
    7997          60 :     AliasSet getAliasSet() const override {
    7998          60 :         return AliasSet::None();
    7999             :     }
    8000             : };
    8001             : 
    8002             : // Check whether we need to fire the interrupt handler.
    8003             : class MInterruptCheck : public MNullaryInstruction
    8004             : {
    8005         119 :     MInterruptCheck() {
    8006         119 :         setGuard();
    8007         119 :     }
    8008             : 
    8009             :   public:
    8010        1494 :     INSTRUCTION_HEADER(InterruptCheck)
    8011         119 :     TRIVIAL_NEW_WRAPPERS
    8012             : 
    8013          41 :     AliasSet getAliasSet() const override {
    8014          41 :         return AliasSet::None();
    8015             :     }
    8016             : };
    8017             : 
    8018             : // Directly jumps to the indicated trap, leaving Wasm code and reporting a
    8019             : // runtime error.
    8020             : 
    8021             : class MWasmTrap
    8022             :   : public MAryControlInstruction<0, 0>,
    8023             :     public NoTypePolicy::Data
    8024             : {
    8025             :     wasm::Trap trap_;
    8026             :     wasm::BytecodeOffset bytecodeOffset_;
    8027             : 
    8028           0 :     explicit MWasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset)
    8029           0 :       : trap_(trap),
    8030           0 :         bytecodeOffset_(bytecodeOffset)
    8031           0 :     {}
    8032             : 
    8033             :   public:
    8034           0 :     INSTRUCTION_HEADER(WasmTrap)
    8035           0 :     TRIVIAL_NEW_WRAPPERS
    8036             : 
    8037           0 :     AliasSet getAliasSet() const override {
    8038           0 :         return AliasSet::None();
    8039             :     }
    8040             : 
    8041           0 :     wasm::Trap trap() const { return trap_; }
    8042           0 :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
    8043             : };
    8044             : 
    8045             : // Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
    8046             : // it to baseline to throw at the correct pc.
    8047             : class MLexicalCheck
    8048             :   : public MUnaryInstruction,
    8049             :     public BoxPolicy<0>::Data
    8050             : {
    8051             :     BailoutKind kind_;
    8052           2 :     explicit MLexicalCheck(MDefinition* input, BailoutKind kind = Bailout_UninitializedLexical)
    8053           2 :       : MUnaryInstruction(input),
    8054           2 :         kind_(kind)
    8055             :     {
    8056           2 :         setResultType(MIRType::Value);
    8057           2 :         setResultTypeSet(input->resultTypeSet());
    8058           2 :         setMovable();
    8059           2 :         setGuard();
    8060           2 :     }
    8061             : 
    8062             :   public:
    8063           0 :     INSTRUCTION_HEADER(LexicalCheck)
    8064           2 :     TRIVIAL_NEW_WRAPPERS
    8065             : 
    8066           0 :     AliasSet getAliasSet() const override {
    8067           0 :         return AliasSet::None();
    8068             :     }
    8069             : 
    8070           0 :     BailoutKind bailoutKind() const {
    8071           0 :         return kind_;
    8072             :     }
    8073             : 
    8074           0 :     bool congruentTo(const MDefinition* ins) const override {
    8075           0 :         return congruentIfOperandsEqual(ins);
    8076             :     }
    8077             : };
    8078             : 
    8079             : // Unconditionally throw an uninitialized let error.
    8080             : class MThrowRuntimeLexicalError : public MNullaryInstruction
    8081             : {
    8082             :     unsigned errorNumber_;
    8083             : 
    8084           0 :     explicit MThrowRuntimeLexicalError(unsigned errorNumber)
    8085           0 :       : errorNumber_(errorNumber)
    8086             :     {
    8087           0 :         setGuard();
    8088           0 :         setResultType(MIRType::None);
    8089           0 :     }
    8090             : 
    8091             :   public:
    8092           0 :     INSTRUCTION_HEADER(ThrowRuntimeLexicalError)
    8093           0 :     TRIVIAL_NEW_WRAPPERS
    8094             : 
    8095           0 :     unsigned errorNumber() const {
    8096           0 :         return errorNumber_;
    8097             :     }
    8098             : 
    8099           0 :     AliasSet getAliasSet() const override {
    8100           0 :         return AliasSet::None();
    8101             :     }
    8102             : };
    8103             : 
    8104             : // In the prologues of global and eval scripts, check for redeclarations.
    8105             : class MGlobalNameConflictsCheck : public MNullaryInstruction
    8106             : {
    8107           0 :     MGlobalNameConflictsCheck() {
    8108           0 :         setGuard();
    8109           0 :     }
    8110             : 
    8111             :   public:
    8112           0 :     INSTRUCTION_HEADER(GlobalNameConflictsCheck)
    8113           0 :     TRIVIAL_NEW_WRAPPERS
    8114             : };
    8115             : 
    8116             : // If not defined, set a global variable to |undefined|.
    8117             : class MDefVar
    8118             :   : public MUnaryInstruction,
    8119             :     public NoTypePolicy::Data
    8120             : {
    8121             :     CompilerPropertyName name_; // Target name to be defined.
    8122             :     unsigned attrs_; // Attributes to be set.
    8123             : 
    8124             :   private:
    8125           0 :     MDefVar(PropertyName* name, unsigned attrs, MDefinition* envChain)
    8126           0 :       : MUnaryInstruction(envChain),
    8127             :         name_(name),
    8128           0 :         attrs_(attrs)
    8129             :     {
    8130           0 :     }
    8131             : 
    8132             :   public:
    8133           0 :     INSTRUCTION_HEADER(DefVar)
    8134           0 :     TRIVIAL_NEW_WRAPPERS
    8135           0 :     NAMED_OPERANDS((0, environmentChain))
    8136             : 
    8137           0 :     PropertyName* name() const {
    8138           0 :         return name_;
    8139             :     }
    8140           0 :     unsigned attrs() const {
    8141           0 :         return attrs_;
    8142             :     }
    8143             : 
    8144           0 :     bool possiblyCalls() const override {
    8145           0 :         return true;
    8146             :     }
    8147           0 :     bool appendRoots(MRootList& roots) const override {
    8148           0 :         return roots.append(name_);
    8149             :     }
    8150             : };
    8151             : 
    8152             : class MDefLexical
    8153             :   : public MNullaryInstruction
    8154             : {
    8155             :     CompilerPropertyName name_; // Target name to be defined.
    8156             :     unsigned attrs_; // Attributes to be set.
    8157             : 
    8158             :   private:
    8159           0 :     MDefLexical(PropertyName* name, unsigned attrs)
    8160           0 :       : name_(name),
    8161           0 :         attrs_(attrs)
    8162           0 :     { }
    8163             : 
    8164             :   public:
    8165           0 :     INSTRUCTION_HEADER(DefLexical)
    8166           0 :     TRIVIAL_NEW_WRAPPERS
    8167             : 
    8168           0 :     PropertyName* name() const {
    8169           0 :         return name_;
    8170             :     }
    8171           0 :     unsigned attrs() const {
    8172           0 :         return attrs_;
    8173             :     }
    8174           0 :     bool appendRoots(MRootList& roots) const override {
    8175           0 :         return roots.append(name_);
    8176             :     }
    8177             : };
    8178             : 
    8179             : class MDefFun
    8180             :   : public MBinaryInstruction,
    8181             :     public ObjectPolicy<0>::Data
    8182             : {
    8183             :   private:
    8184           0 :     MDefFun(MDefinition* fun, MDefinition* envChain)
    8185           0 :       : MBinaryInstruction(fun, envChain)
    8186           0 :     {}
    8187             : 
    8188             :   public:
    8189           0 :     INSTRUCTION_HEADER(DefFun)
    8190           0 :     TRIVIAL_NEW_WRAPPERS
    8191           0 :     NAMED_OPERANDS((0, fun), (1, environmentChain))
    8192             : 
    8193           0 :     bool possiblyCalls() const override {
    8194           0 :         return true;
    8195             :     }
    8196             : };
    8197             : 
    8198             : class MRegExp : public MNullaryInstruction
    8199             : {
    8200             :     CompilerGCPointer<RegExpObject*> source_;
    8201             :     bool mustClone_;
    8202             :     bool hasShared_;
    8203             : 
    8204           0 :     MRegExp(CompilerConstraintList* constraints, RegExpObject* source, bool hasShared)
    8205           0 :       : source_(source),
    8206             :         mustClone_(true),
    8207           0 :         hasShared_(hasShared)
    8208             :     {
    8209           0 :         setResultType(MIRType::Object);
    8210           0 :         setResultTypeSet(MakeSingletonTypeSet(constraints, source));
    8211           0 :     }
    8212             : 
    8213             :   public:
    8214           0 :     INSTRUCTION_HEADER(RegExp)
    8215           0 :     TRIVIAL_NEW_WRAPPERS
    8216             : 
    8217           0 :     void setDoNotClone() {
    8218           0 :         mustClone_ = false;
    8219           0 :     }
    8220           0 :     bool mustClone() const {
    8221           0 :         return mustClone_;
    8222             :     }
    8223           0 :     bool hasShared() const {
    8224           0 :         return hasShared_;
    8225             :     }
    8226           0 :     RegExpObject* source() const {
    8227           0 :         return source_;
    8228             :     }
    8229           0 :     AliasSet getAliasSet() const override {
    8230           0 :         return AliasSet::None();
    8231             :     }
    8232           0 :     bool possiblyCalls() const override {
    8233           0 :         return true;
    8234             :     }
    8235           0 :     bool appendRoots(MRootList& roots) const override {
    8236           0 :         return roots.append(source_);
    8237             :     }
    8238             : };
    8239             : 
    8240             : class MRegExpMatcher
    8241             :   : public MAryInstruction<3>,
    8242             :     public Mix3Policy<ObjectPolicy<0>,
    8243             :                       StringPolicy<1>,
    8244             :                       IntPolicy<2> >::Data
    8245             : {
    8246             :   private:
    8247             : 
    8248           0 :     MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
    8249           0 :       : MAryInstruction<3>()
    8250             :     {
    8251           0 :         initOperand(0, regexp);
    8252           0 :         initOperand(1, string);
    8253           0 :         initOperand(2, lastIndex);
    8254             : 
    8255           0 :         setMovable();
    8256             :         // May be object or null.
    8257           0 :         setResultType(MIRType::Value);
    8258           0 :     }
    8259             : 
    8260             :   public:
    8261           0 :     INSTRUCTION_HEADER(RegExpMatcher)
    8262           0 :     TRIVIAL_NEW_WRAPPERS
    8263           0 :     NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
    8264             : 
    8265             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8266             : 
    8267           0 :     bool canRecoverOnBailout() const override {
    8268           0 :         return true;
    8269             :     }
    8270             : 
    8271           0 :     bool possiblyCalls() const override {
    8272           0 :         return true;
    8273             :     }
    8274             : };
    8275             : 
    8276             : class MRegExpSearcher
    8277             :   : public MAryInstruction<3>,
    8278             :     public Mix3Policy<ObjectPolicy<0>,
    8279             :                       StringPolicy<1>,
    8280             :                       IntPolicy<2> >::Data
    8281             : {
    8282             :   private:
    8283             : 
    8284           0 :     MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
    8285           0 :       : MAryInstruction<3>()
    8286             :     {
    8287           0 :         initOperand(0, regexp);
    8288           0 :         initOperand(1, string);
    8289           0 :         initOperand(2, lastIndex);
    8290             : 
    8291           0 :         setMovable();
    8292           0 :         setResultType(MIRType::Int32);
    8293           0 :     }
    8294             : 
    8295             :   public:
    8296           0 :     INSTRUCTION_HEADER(RegExpSearcher)
    8297           0 :     TRIVIAL_NEW_WRAPPERS
    8298           0 :     NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
    8299             : 
    8300             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8301             : 
    8302           0 :     bool canRecoverOnBailout() const override {
    8303           0 :         return true;
    8304             :     }
    8305             : 
    8306           0 :     bool possiblyCalls() const override {
    8307           0 :         return true;
    8308             :     }
    8309             : };
    8310             : 
    8311             : class MRegExpTester
    8312             :   : public MAryInstruction<3>,
    8313             :     public Mix3Policy<ObjectPolicy<0>,
    8314             :                       StringPolicy<1>,
    8315             :                       IntPolicy<2> >::Data
    8316             : {
    8317             :   private:
    8318             : 
    8319           0 :     MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
    8320           0 :       : MAryInstruction<3>()
    8321             :     {
    8322           0 :         initOperand(0, regexp);
    8323           0 :         initOperand(1, string);
    8324           0 :         initOperand(2, lastIndex);
    8325             : 
    8326           0 :         setMovable();
    8327           0 :         setResultType(MIRType::Int32);
    8328           0 :     }
    8329             : 
    8330             :   public:
    8331           0 :     INSTRUCTION_HEADER(RegExpTester)
    8332           0 :     TRIVIAL_NEW_WRAPPERS
    8333           0 :     NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
    8334             : 
    8335           0 :     bool possiblyCalls() const override {
    8336           0 :         return true;
    8337             :     }
    8338             : 
    8339             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8340           0 :     bool canRecoverOnBailout() const override {
    8341           0 :         return true;
    8342             :     }
    8343             : };
    8344             : 
    8345             : class MRegExpPrototypeOptimizable
    8346             :   : public MUnaryInstruction,
    8347             :     public SingleObjectPolicy::Data
    8348             : {
    8349           0 :     explicit MRegExpPrototypeOptimizable(MDefinition* object)
    8350           0 :       : MUnaryInstruction(object)
    8351             :     {
    8352           0 :         setResultType(MIRType::Boolean);
    8353           0 :     }
    8354             : 
    8355             :   public:
    8356           0 :     INSTRUCTION_HEADER(RegExpPrototypeOptimizable)
    8357           0 :     TRIVIAL_NEW_WRAPPERS
    8358           0 :     NAMED_OPERANDS((0, object))
    8359             : 
    8360           0 :     AliasSet getAliasSet() const override {
    8361           0 :         return AliasSet::None();
    8362             :     }
    8363             : };
    8364             : 
    8365             : class MRegExpInstanceOptimizable
    8366             :   : public MBinaryInstruction,
    8367             :     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
    8368             : {
    8369           0 :     explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto)
    8370           0 :       : MBinaryInstruction(object, proto)
    8371             :     {
    8372           0 :         setResultType(MIRType::Boolean);
    8373           0 :     }
    8374             : 
    8375             :   public:
    8376           0 :     INSTRUCTION_HEADER(RegExpInstanceOptimizable)
    8377           0 :     TRIVIAL_NEW_WRAPPERS
    8378           0 :     NAMED_OPERANDS((0, object), (1, proto))
    8379             : 
    8380           0 :     AliasSet getAliasSet() const override {
    8381           0 :         return AliasSet::None();
    8382             :     }
    8383             : };
    8384             : 
    8385             : class MGetFirstDollarIndex
    8386             :   : public MUnaryInstruction,
    8387             :     public StringPolicy<0>::Data
    8388             : {
    8389           0 :     explicit MGetFirstDollarIndex(MDefinition* str)
    8390           0 :       : MUnaryInstruction(str)
    8391             :     {
    8392           0 :         setResultType(MIRType::Int32);
    8393           0 :         setMovable();
    8394           0 :     }
    8395             : 
    8396             :   public:
    8397           0 :     INSTRUCTION_HEADER(GetFirstDollarIndex)
    8398           0 :     TRIVIAL_NEW_WRAPPERS
    8399           0 :     NAMED_OPERANDS((0, str))
    8400             : 
    8401           0 :     AliasSet getAliasSet() const override {
    8402           0 :         return AliasSet::None();
    8403             :     }
    8404             : 
    8405             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    8406             : };
    8407             : 
    8408             : class MStringReplace
    8409             :   : public MTernaryInstruction,
    8410             :     public Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >::Data
    8411             : {
    8412             :   private:
    8413             : 
    8414             :     bool isFlatReplacement_;
    8415             : 
    8416           0 :     MStringReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
    8417           0 :       : MTernaryInstruction(string, pattern, replacement), isFlatReplacement_(false)
    8418             :     {
    8419           0 :         setMovable();
    8420           0 :         setResultType(MIRType::String);
    8421           0 :     }
    8422             : 
    8423             :   public:
    8424           0 :     INSTRUCTION_HEADER(StringReplace)
    8425           0 :     TRIVIAL_NEW_WRAPPERS
    8426           0 :     NAMED_OPERANDS((0, string), (1, pattern), (2, replacement))
    8427             : 
    8428           0 :     void setFlatReplacement() {
    8429           0 :         MOZ_ASSERT(!isFlatReplacement_);
    8430           0 :         isFlatReplacement_ = true;
    8431           0 :     }
    8432             : 
    8433           0 :     bool isFlatReplacement() const {
    8434           0 :         return isFlatReplacement_;
    8435             :     }
    8436             : 
    8437           0 :     bool congruentTo(const MDefinition* ins) const override {
    8438           0 :         if (!ins->isStringReplace())
    8439           0 :             return false;
    8440           0 :         if (isFlatReplacement_ != ins->toStringReplace()->isFlatReplacement())
    8441           0 :             return false;
    8442           0 :         return congruentIfOperandsEqual(ins);
    8443             :     }
    8444             : 
    8445           0 :     AliasSet getAliasSet() const override {
    8446           0 :         return AliasSet::None();
    8447             :     }
    8448             : 
    8449             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8450           0 :     bool canRecoverOnBailout() const override {
    8451           0 :         if (isFlatReplacement_) {
    8452           0 :             MOZ_ASSERT(!pattern()->isRegExp());
    8453           0 :             return true;
    8454             :         }
    8455           0 :         return false;
    8456             :     }
    8457             : 
    8458           0 :     bool possiblyCalls() const override {
    8459           0 :         return true;
    8460             :     }
    8461             : };
    8462             : 
    8463             : class MSubstr
    8464             :   : public MTernaryInstruction,
    8465             :     public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
    8466             : {
    8467             :   private:
    8468             : 
    8469           0 :     MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length)
    8470           0 :       : MTernaryInstruction(string, begin, length)
    8471             :     {
    8472           0 :         setResultType(MIRType::String);
    8473           0 :     }
    8474             : 
    8475             :   public:
    8476           0 :     INSTRUCTION_HEADER(Substr)
    8477           0 :     TRIVIAL_NEW_WRAPPERS
    8478           0 :     NAMED_OPERANDS((0, string), (1, begin), (2, length))
    8479             : 
    8480           0 :     bool congruentTo(const MDefinition* ins) const override {
    8481           0 :         return congruentIfOperandsEqual(ins);
    8482             :     }
    8483           0 :     AliasSet getAliasSet() const override {
    8484           0 :         return AliasSet::None();
    8485             :     }
    8486             : };
    8487             : 
    8488             : struct LambdaFunctionInfo
    8489             : {
    8490             :     // The functions used in lambdas are the canonical original function in
    8491             :     // the script, and are immutable except for delazification. Record this
    8492             :     // information while still on the active thread to avoid races.
    8493             :     CompilerFunction fun;
    8494             :     uint16_t flags;
    8495             :     uint16_t nargs;
    8496             :     gc::Cell* scriptOrLazyScript;
    8497             :     bool singletonType;
    8498             :     bool useSingletonForClone;
    8499             : 
    8500          29 :     explicit LambdaFunctionInfo(JSFunction* fun)
    8501          87 :       : fun(fun), flags(fun->flags()), nargs(fun->nargs()),
    8502          29 :         scriptOrLazyScript(fun->hasScript()
    8503          29 :                            ? (gc::Cell*) fun->nonLazyScript()
    8504             :                            : (gc::Cell*) fun->lazyScript()),
    8505          29 :         singletonType(fun->isSingleton()),
    8506         145 :         useSingletonForClone(ObjectGroup::useSingletonForClone(fun))
    8507          29 :     {}
    8508             : 
    8509          12 :     bool appendRoots(MRootList& roots) const {
    8510          12 :         if (!roots.append(fun))
    8511           0 :             return false;
    8512          12 :         if (fun->hasScript())
    8513          12 :             return roots.append(fun->nonLazyScript());
    8514           0 :         return roots.append(fun->lazyScript());
    8515             :     }
    8516             : 
    8517             :   private:
    8518             :     LambdaFunctionInfo(const LambdaFunctionInfo&) = delete;
    8519             :     void operator=(const LambdaFunctionInfo&) = delete;
    8520             : };
    8521             : 
    8522             : class MLambda
    8523             :   : public MBinaryInstruction,
    8524             :     public SingleObjectPolicy::Data
    8525             : {
    8526             :     const LambdaFunctionInfo info_;
    8527             : 
    8528          28 :     MLambda(CompilerConstraintList* constraints, MDefinition* envChain, MConstant* cst)
    8529          28 :       : MBinaryInstruction(envChain, cst), info_(&cst->toObject().as<JSFunction>())
    8530             :     {
    8531          28 :         setResultType(MIRType::Object);
    8532          28 :         if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
    8533          28 :             setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
    8534          28 :     }
    8535             : 
    8536             :   public:
    8537        3280 :     INSTRUCTION_HEADER(Lambda)
    8538          28 :     TRIVIAL_NEW_WRAPPERS
    8539          10 :     NAMED_OPERANDS((0, environmentChain))
    8540             : 
    8541           0 :     MConstant* functionOperand() const {
    8542           0 :         return getOperand(1)->toConstant();
    8543             :     }
    8544         114 :     const LambdaFunctionInfo& info() const {
    8545         114 :         return info_;
    8546             :     }
    8547             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8548          32 :     bool canRecoverOnBailout() const override {
    8549          32 :         return true;
    8550             :     }
    8551          12 :     bool appendRoots(MRootList& roots) const override {
    8552          12 :         return info_.appendRoots(roots);
    8553             :     }
    8554             : };
    8555             : 
    8556             : class MLambdaArrow
    8557             :   : public MTernaryInstruction,
    8558             :     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>::Data
    8559             : {
    8560             :     const LambdaFunctionInfo info_;
    8561             : 
    8562           1 :     MLambdaArrow(CompilerConstraintList* constraints, MDefinition* envChain,
    8563             :                  MDefinition* newTarget, MConstant* cst)
    8564           1 :       : MTernaryInstruction(envChain, newTarget, cst),
    8565           1 :         info_(&cst->toObject().as<JSFunction>())
    8566             :     {
    8567           1 :         setResultType(MIRType::Object);
    8568           1 :         MOZ_ASSERT(!ObjectGroup::useSingletonForClone(info().fun));
    8569           1 :         if (!info().fun->isSingleton())
    8570           1 :             setResultTypeSet(MakeSingletonTypeSet(constraints, info().fun));
    8571           1 :     }
    8572             : 
    8573             :   public:
    8574           1 :     INSTRUCTION_HEADER(LambdaArrow)
    8575           1 :     TRIVIAL_NEW_WRAPPERS
    8576           0 :     NAMED_OPERANDS((0, environmentChain), (1, newTargetDef))
    8577             : 
    8578           0 :     MConstant* functionOperand() const {
    8579           0 :         return getOperand(2)->toConstant();
    8580             :     }
    8581           3 :     const LambdaFunctionInfo& info() const {
    8582           3 :         return info_;
    8583             :     }
    8584             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    8585           0 :     bool canRecoverOnBailout() const override {
    8586           0 :         return true;
    8587             :     }
    8588           0 :     bool appendRoots(MRootList& roots) const override {
    8589           0 :         return info_.appendRoots(roots);
    8590             :     }
    8591             : };
    8592             : 
    8593             : class MSetFunName
    8594             :   : public MAryInstruction<2>,
    8595             :     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
    8596             : {
    8597             :     uint8_t prefixKind_;
    8598             : 
    8599           0 :     explicit MSetFunName(MDefinition* fun, MDefinition* name, uint8_t prefixKind)
    8600           0 :       : prefixKind_(prefixKind)
    8601             :     {
    8602           0 :         initOperand(0, fun);
    8603           0 :         initOperand(1, name);
    8604           0 :         setResultType(MIRType::None);
    8605           0 :     }
    8606             : 
    8607             :   public:
    8608           0 :     INSTRUCTION_HEADER(SetFunName)
    8609           0 :     TRIVIAL_NEW_WRAPPERS
    8610           0 :     NAMED_OPERANDS((0, fun), (1, name))
    8611             : 
    8612           0 :     uint8_t prefixKind() const {
    8613           0 :         return prefixKind_;
    8614             :     }
    8615             : 
    8616           0 :     bool possiblyCalls() const override {
    8617           0 :         return true;
    8618             :     }
    8619             : };
    8620             : 
    8621             : // Returns obj->slots.
    8622           0 : class MSlots
    8623             :   : public MUnaryInstruction,
    8624             :     public SingleObjectPolicy::Data
    8625             : {
    8626           9 :     explicit MSlots(MDefinition* object)
    8627           9 :       : MUnaryInstruction(object)
    8628             :     {
    8629           9 :         setResultType(MIRType::Slots);
    8630           9 :         setMovable();
    8631           9 :     }
    8632             : 
    8633             :   public:
    8634        2166 :     INSTRUCTION_HEADER(Slots)
    8635           9 :     TRIVIAL_NEW_WRAPPERS
    8636          14 :     NAMED_OPERANDS((0, object))
    8637             : 
    8638          16 :     bool congruentTo(const MDefinition* ins) const override {
    8639          16 :         return congruentIfOperandsEqual(ins);
    8640             :     }
    8641         310 :     AliasSet getAliasSet() const override {
    8642         310 :         return AliasSet::Load(AliasSet::ObjectFields);
    8643             :     }
    8644             : 
    8645           0 :     ALLOW_CLONE(MSlots)
    8646             : };
    8647             : 
    8648             : // Returns obj->elements.
    8649           0 : class MElements
    8650             :   : public MUnaryInstruction,
    8651             :     public SingleObjectPolicy::Data
    8652             : {
    8653             :     bool unboxed_;
    8654             : 
    8655          19 :     explicit MElements(MDefinition* object, bool unboxed = false)
    8656          19 :       : MUnaryInstruction(object), unboxed_(unboxed)
    8657             :     {
    8658          19 :         setResultType(MIRType::Elements);
    8659          19 :         setMovable();
    8660          19 :     }
    8661             : 
    8662             :   public:
    8663        2818 :     INSTRUCTION_HEADER(Elements)
    8664          19 :     TRIVIAL_NEW_WRAPPERS
    8665           7 :     NAMED_OPERANDS((0, object))
    8666             : 
    8667          37 :     bool unboxed() const {
    8668          37 :         return unboxed_;
    8669             :     }
    8670          15 :     bool congruentTo(const MDefinition* ins) const override {
    8671          30 :         return congruentIfOperandsEqual(ins) &&
    8672          30 :                ins->toElements()->unboxed() == unboxed();
    8673             :     }
    8674         243 :     AliasSet getAliasSet() const override {
    8675         243 :         return AliasSet::Load(AliasSet::ObjectFields);
    8676             :     }
    8677             : 
    8678           0 :     ALLOW_CLONE(MElements)
    8679             : };
    8680             : 
    8681             : // A constant value for some object's typed array elements.
    8682           0 : class MConstantElements : public MNullaryInstruction
    8683             : {
    8684             :     SharedMem<void*> value_;
    8685             : 
    8686             :   protected:
    8687           0 :     explicit MConstantElements(SharedMem<void*> v)
    8688           0 :       : value_(v)
    8689             :     {
    8690           0 :         setResultType(MIRType::Elements);
    8691           0 :         setMovable();
    8692           0 :     }
    8693             : 
    8694             :   public:
    8695           0 :     INSTRUCTION_HEADER(ConstantElements)
    8696           0 :     TRIVIAL_NEW_WRAPPERS
    8697             : 
    8698           0 :     SharedMem<void*> value() const {
    8699           0 :         return value_;
    8700             :     }
    8701             : 
    8702             :     void printOpcode(GenericPrinter& out) const override;
    8703             : 
    8704           0 :     HashNumber valueHash() const override {
    8705           0 :         return (HashNumber)(size_t) value_.asValue();
    8706             :     }
    8707             : 
    8708           0 :     bool congruentTo(const MDefinition* ins) const override {
    8709           0 :         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
    8710             :     }
    8711             : 
    8712           0 :     AliasSet getAliasSet() const override {
    8713           0 :         return AliasSet::None();
    8714             :     }
    8715             : 
    8716           0 :     ALLOW_CLONE(MConstantElements)
    8717             : };
    8718             : 
    8719             : // Passes through an object's elements, after ensuring it is entirely doubles.
    8720             : class MConvertElementsToDoubles
    8721             :   : public MUnaryInstruction,
    8722             :     public NoTypePolicy::Data
    8723             : {
    8724           0 :     explicit MConvertElementsToDoubles(MDefinition* elements)
    8725           0 :       : MUnaryInstruction(elements)
    8726             :     {
    8727           0 :         setGuard();
    8728           0 :         setMovable();
    8729           0 :         setResultType(MIRType::Elements);
    8730           0 :     }
    8731             : 
    8732             :   public:
    8733           0 :     INSTRUCTION_HEADER(ConvertElementsToDoubles)
    8734           0 :     TRIVIAL_NEW_WRAPPERS
    8735           0 :     NAMED_OPERANDS((0, elements))
    8736             : 
    8737           0 :     bool congruentTo(const MDefinition* ins) const override {
    8738           0 :         return congruentIfOperandsEqual(ins);
    8739             :     }
    8740           0 :     AliasSet getAliasSet() const override {
    8741             :         // This instruction can read and write to the elements' contents.
    8742             :         // However, it is alright to hoist this from loops which explicitly
    8743             :         // read or write to the elements: such reads and writes will use double
    8744             :         // values and can be reordered freely wrt this conversion, except that
    8745             :         // definite double loads must follow the conversion. The latter
    8746             :         // property is ensured by chaining this instruction with the elements
    8747             :         // themselves, in the same manner as MBoundsCheck.
    8748           0 :         return AliasSet::None();
    8749             :     }
    8750             : };
    8751             : 
    8752             : // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
    8753             : // double. Else return the original value.
    8754             : class MMaybeToDoubleElement
    8755             :   : public MBinaryInstruction,
    8756             :     public IntPolicy<1>::Data
    8757             : {
    8758           0 :     MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
    8759           0 :       : MBinaryInstruction(elements, value)
    8760             :     {
    8761           0 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
    8762           0 :         setMovable();
    8763           0 :         setResultType(MIRType::Value);
    8764           0 :     }
    8765             : 
    8766             :   public:
    8767           0 :     INSTRUCTION_HEADER(MaybeToDoubleElement)
    8768           0 :     TRIVIAL_NEW_WRAPPERS
    8769           0 :     NAMED_OPERANDS((0, elements), (1, value))
    8770             : 
    8771           0 :     bool congruentTo(const MDefinition* ins) const override {
    8772           0 :         return congruentIfOperandsEqual(ins);
    8773             :     }
    8774           0 :     AliasSet getAliasSet() const override {
    8775           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    8776             :     }
    8777             : };
    8778             : 
    8779             : // Passes through an object, after ensuring its elements are not copy on write.
    8780             : class MMaybeCopyElementsForWrite
    8781             :   : public MUnaryInstruction,
    8782             :     public SingleObjectPolicy::Data
    8783             : {
    8784             :     bool checkNative_;
    8785             : 
    8786           0 :     explicit MMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
    8787           0 :       : MUnaryInstruction(object), checkNative_(checkNative)
    8788             :     {
    8789           0 :         setGuard();
    8790           0 :         setMovable();
    8791           0 :         setResultType(MIRType::Object);
    8792           0 :         setResultTypeSet(object->resultTypeSet());
    8793           0 :     }
    8794             : 
    8795             :   public:
    8796           0 :     INSTRUCTION_HEADER(MaybeCopyElementsForWrite)
    8797           0 :     TRIVIAL_NEW_WRAPPERS
    8798           0 :     NAMED_OPERANDS((0, object))
    8799             : 
    8800           0 :     bool checkNative() const {
    8801           0 :         return checkNative_;
    8802             :     }
    8803           0 :     bool congruentTo(const MDefinition* ins) const override {
    8804           0 :         return congruentIfOperandsEqual(ins) &&
    8805           0 :                checkNative() == ins->toMaybeCopyElementsForWrite()->checkNative();
    8806             :     }
    8807           0 :     AliasSet getAliasSet() const override {
    8808           0 :         return AliasSet::Store(AliasSet::ObjectFields);
    8809             :     }
    8810             : #ifdef DEBUG
    8811           0 :     bool needsResumePoint() const override {
    8812             :         // This instruction is idempotent and does not change observable
    8813             :         // behavior, so does not need its own resume point.
    8814           0 :         return false;
    8815             :     }
    8816             : #endif
    8817             : 
    8818             : };
    8819             : 
    8820             : // Load the initialized length from an elements header.
    8821           0 : class MInitializedLength
    8822             :   : public MUnaryInstruction,
    8823             :     public NoTypePolicy::Data
    8824             : {
    8825           1 :     explicit MInitializedLength(MDefinition* elements)
    8826           1 :       : MUnaryInstruction(elements)
    8827             :     {
    8828           1 :         setResultType(MIRType::Int32);
    8829           1 :         setMovable();
    8830           1 :     }
    8831             : 
    8832             :   public:
    8833         357 :     INSTRUCTION_HEADER(InitializedLength)
    8834           1 :     TRIVIAL_NEW_WRAPPERS
    8835           2 :     NAMED_OPERANDS((0, elements))
    8836             : 
    8837           1 :     bool congruentTo(const MDefinition* ins) const override {
    8838           1 :         return congruentIfOperandsEqual(ins);
    8839             :     }
    8840          27 :     AliasSet getAliasSet() const override {
    8841          27 :         return AliasSet::Load(AliasSet::ObjectFields);
    8842             :     }
    8843             : 
    8844             :     void computeRange(TempAllocator& alloc) override;
    8845             : 
    8846           0 :     ALLOW_CLONE(MInitializedLength)
    8847             : };
    8848             : 
    8849             : // Store to the initialized length in an elements header. Note the input is an
    8850             : // *index*, one less than the desired length.
    8851           0 : class MSetInitializedLength
    8852             :   : public MAryInstruction<2>,
    8853             :     public NoTypePolicy::Data
    8854             : {
    8855          14 :     MSetInitializedLength(MDefinition* elements, MDefinition* index) {
    8856          14 :         initOperand(0, elements);
    8857          14 :         initOperand(1, index);
    8858          14 :     }
    8859             : 
    8860             :   public:
    8861        1398 :     INSTRUCTION_HEADER(SetInitializedLength)
    8862          14 :     TRIVIAL_NEW_WRAPPERS
    8863          20 :     NAMED_OPERANDS((0, elements), (1, index))
    8864             : 
    8865          62 :     AliasSet getAliasSet() const override {
    8866          62 :         return AliasSet::Store(AliasSet::ObjectFields);
    8867             :     }
    8868             : 
    8869           0 :     ALLOW_CLONE(MSetInitializedLength)
    8870             : };
    8871             : 
    8872             : // Load the length from an unboxed array.
    8873           0 : class MUnboxedArrayLength
    8874             :   : public MUnaryInstruction,
    8875             :     public SingleObjectPolicy::Data
    8876             : {
    8877           0 :     explicit MUnboxedArrayLength(MDefinition* object)
    8878           0 :       : MUnaryInstruction(object)
    8879             :     {
    8880           0 :         setResultType(MIRType::Int32);
    8881           0 :         setMovable();
    8882           0 :     }
    8883             : 
    8884             :   public:
    8885           0 :     INSTRUCTION_HEADER(UnboxedArrayLength)
    8886           0 :     TRIVIAL_NEW_WRAPPERS
    8887           0 :     NAMED_OPERANDS((0, object))
    8888             : 
    8889           0 :     bool congruentTo(const MDefinition* ins) const override {
    8890           0 :         return congruentIfOperandsEqual(ins);
    8891             :     }
    8892           0 :     AliasSet getAliasSet() const override {
    8893           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    8894             :     }
    8895             : 
    8896           0 :     ALLOW_CLONE(MUnboxedArrayLength)
    8897             : };
    8898             : 
    8899             : // Load the initialized length from an unboxed array.
    8900           0 : class MUnboxedArrayInitializedLength
    8901             :   : public MUnaryInstruction,
    8902             :     public SingleObjectPolicy::Data
    8903             : {
    8904           0 :     explicit MUnboxedArrayInitializedLength(MDefinition* object)
    8905           0 :       : MUnaryInstruction(object)
    8906             :     {
    8907           0 :         setResultType(MIRType::Int32);
    8908           0 :         setMovable();
    8909           0 :     }
    8910             : 
    8911             :   public:
    8912           0 :     INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
    8913           0 :     TRIVIAL_NEW_WRAPPERS
    8914           0 :     NAMED_OPERANDS((0, object))
    8915             : 
    8916           0 :     bool congruentTo(const MDefinition* ins) const override {
    8917           0 :         return congruentIfOperandsEqual(ins);
    8918             :     }
    8919           0 :     AliasSet getAliasSet() const override {
    8920           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    8921             :     }
    8922             : 
    8923           0 :     ALLOW_CLONE(MUnboxedArrayInitializedLength)
    8924             : };
    8925             : 
    8926             : // Increment the initialized length of an unboxed array object.
    8927           0 : class MIncrementUnboxedArrayInitializedLength
    8928             :   : public MUnaryInstruction,
    8929             :     public SingleObjectPolicy::Data
    8930             : {
    8931           0 :     explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
    8932           0 :       : MUnaryInstruction(obj)
    8933           0 :     {}
    8934             : 
    8935             :   public:
    8936           0 :     INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
    8937           0 :     TRIVIAL_NEW_WRAPPERS
    8938           0 :     NAMED_OPERANDS((0, object))
    8939             : 
    8940           0 :     AliasSet getAliasSet() const override {
    8941           0 :         return AliasSet::Store(AliasSet::ObjectFields);
    8942             :     }
    8943             : 
    8944           0 :     ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
    8945             : };
    8946             : 
    8947             : // Set the initialized length of an unboxed array object.
    8948           0 : class MSetUnboxedArrayInitializedLength
    8949             :   : public MBinaryInstruction,
    8950             :     public SingleObjectPolicy::Data
    8951             : {
    8952           0 :     explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length)
    8953           0 :       : MBinaryInstruction(obj, length)
    8954           0 :     {}
    8955             : 
    8956             :   public:
    8957           0 :     INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)
    8958           0 :     TRIVIAL_NEW_WRAPPERS
    8959           0 :     NAMED_OPERANDS((0, object), (1, length))
    8960             : 
    8961           0 :     AliasSet getAliasSet() const override {
    8962           0 :         return AliasSet::Store(AliasSet::ObjectFields);
    8963             :     }
    8964             : 
    8965           0 :     ALLOW_CLONE(MSetUnboxedArrayInitializedLength)
    8966             : };
    8967             : 
    8968             : // Load the array length from an elements header.
    8969           0 : class MArrayLength
    8970             :   : public MUnaryInstruction,
    8971             :     public NoTypePolicy::Data
    8972             : {
    8973           3 :     explicit MArrayLength(MDefinition* elements)
    8974           3 :       : MUnaryInstruction(elements)
    8975             :     {
    8976           3 :         setResultType(MIRType::Int32);
    8977           3 :         setMovable();
    8978           3 :     }
    8979             : 
    8980             :   public:
    8981         605 :     INSTRUCTION_HEADER(ArrayLength)
    8982           3 :     TRIVIAL_NEW_WRAPPERS
    8983           4 :     NAMED_OPERANDS((0, elements))
    8984             : 
    8985           3 :     bool congruentTo(const MDefinition* ins) const override {
    8986           3 :         return congruentIfOperandsEqual(ins);
    8987             :     }
    8988          47 :     AliasSet getAliasSet() const override {
    8989          47 :         return AliasSet::Load(AliasSet::ObjectFields);
    8990             :     }
    8991             : 
    8992             :     void computeRange(TempAllocator& alloc) override;
    8993             : 
    8994           0 :     ALLOW_CLONE(MArrayLength)
    8995             : };
    8996             : 
    8997             : // Store to the length in an elements header. Note the input is an *index*, one
    8998             : // less than the desired length.
    8999             : class MSetArrayLength
    9000             :   : public MAryInstruction<2>,
    9001             :     public NoTypePolicy::Data
    9002             : {
    9003           0 :     MSetArrayLength(MDefinition* elements, MDefinition* index) {
    9004           0 :         initOperand(0, elements);
    9005           0 :         initOperand(1, index);
    9006           0 :     }
    9007             : 
    9008             :   public:
    9009           0 :     INSTRUCTION_HEADER(SetArrayLength)
    9010           0 :     TRIVIAL_NEW_WRAPPERS
    9011           0 :     NAMED_OPERANDS((0, elements), (1, index))
    9012             : 
    9013           0 :     AliasSet getAliasSet() const override {
    9014           0 :         return AliasSet::Store(AliasSet::ObjectFields);
    9015             :     }
    9016             : };
    9017             : 
    9018             : class MGetNextEntryForIterator
    9019             :   : public MBinaryInstruction,
    9020             :     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
    9021             : {
    9022             :   public:
    9023             :     enum Mode {
    9024             :         Map,
    9025             :         Set
    9026             :     };
    9027             : 
    9028             :   private:
    9029             :     Mode mode_;
    9030             : 
    9031           0 :     explicit MGetNextEntryForIterator(MDefinition* iter, MDefinition* result, Mode mode)
    9032           0 :       : MBinaryInstruction(iter, result), mode_(mode)
    9033             :     {
    9034           0 :         setResultType(MIRType::Boolean);
    9035           0 :     }
    9036             : 
    9037             :   public:
    9038           0 :     INSTRUCTION_HEADER(GetNextEntryForIterator)
    9039           0 :     TRIVIAL_NEW_WRAPPERS
    9040           0 :     NAMED_OPERANDS((0, iter), (1, result))
    9041             : 
    9042           0 :     Mode mode() const {
    9043           0 :         return mode_;
    9044             :     }
    9045             : };
    9046             : 
    9047             : // Read the length of a typed array.
    9048             : class MTypedArrayLength
    9049             :   : public MUnaryInstruction,
    9050             :     public SingleObjectPolicy::Data
    9051             : {
    9052           0 :     explicit MTypedArrayLength(MDefinition* obj)
    9053           0 :       : MUnaryInstruction(obj)
    9054             :     {
    9055           0 :         setResultType(MIRType::Int32);
    9056           0 :         setMovable();
    9057           0 :     }
    9058             : 
    9059             :   public:
    9060           0 :     INSTRUCTION_HEADER(TypedArrayLength)
    9061           0 :     TRIVIAL_NEW_WRAPPERS
    9062           0 :     NAMED_OPERANDS((0, object))
    9063             : 
    9064           0 :     bool congruentTo(const MDefinition* ins) const override {
    9065           0 :         return congruentIfOperandsEqual(ins);
    9066             :     }
    9067           0 :     AliasSet getAliasSet() const override {
    9068           0 :         return AliasSet::Load(AliasSet::TypedArrayLength);
    9069             :     }
    9070             : 
    9071             :     void computeRange(TempAllocator& alloc) override;
    9072             : };
    9073             : 
    9074             : // Load a typed array's elements vector.
    9075           0 : class MTypedArrayElements
    9076             :   : public MUnaryInstruction,
    9077             :     public SingleObjectPolicy::Data
    9078             : {
    9079           0 :     explicit MTypedArrayElements(MDefinition* object)
    9080           0 :       : MUnaryInstruction(object)
    9081             :     {
    9082           0 :         setResultType(MIRType::Elements);
    9083           0 :         setMovable();
    9084           0 :     }
    9085             : 
    9086             :   public:
    9087           0 :     INSTRUCTION_HEADER(TypedArrayElements)
    9088           0 :     TRIVIAL_NEW_WRAPPERS
    9089           0 :     NAMED_OPERANDS((0, object))
    9090             : 
    9091           0 :     bool congruentTo(const MDefinition* ins) const override {
    9092           0 :         return congruentIfOperandsEqual(ins);
    9093             :     }
    9094           0 :     AliasSet getAliasSet() const override {
    9095           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    9096             :     }
    9097             : 
    9098           0 :     ALLOW_CLONE(MTypedArrayElements)
    9099             : };
    9100             : 
    9101           0 : class MSetDisjointTypedElements
    9102             :   : public MTernaryInstruction,
    9103             :     public NoTypePolicy::Data
    9104             : {
    9105           0 :     explicit MSetDisjointTypedElements(MDefinition* target, MDefinition* targetOffset,
    9106             :                                        MDefinition* source)
    9107           0 :       : MTernaryInstruction(target, targetOffset, source)
    9108             :     {
    9109           0 :         MOZ_ASSERT(target->type() == MIRType::Object);
    9110           0 :         MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
    9111           0 :         MOZ_ASSERT(source->type() == MIRType::Object);
    9112           0 :         setResultType(MIRType::None);
    9113           0 :     }
    9114             : 
    9115             :   public:
    9116           0 :     INSTRUCTION_HEADER(SetDisjointTypedElements)
    9117           0 :     NAMED_OPERANDS((0, target), (1, targetOffset), (2, source))
    9118             : 
    9119             :     static MSetDisjointTypedElements*
    9120           0 :     New(TempAllocator& alloc, MDefinition* target, MDefinition* targetOffset,
    9121             :         MDefinition* source)
    9122             :     {
    9123           0 :         return new(alloc) MSetDisjointTypedElements(target, targetOffset, source);
    9124             :     }
    9125             : 
    9126           0 :     AliasSet getAliasSet() const override {
    9127           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
    9128             :     }
    9129             : 
    9130           0 :     ALLOW_CLONE(MSetDisjointTypedElements)
    9131             : };
    9132             : 
    9133             : // Load a binary data object's "elements", which is just its opaque
    9134             : // binary data space. Eventually this should probably be
    9135             : // unified with `MTypedArrayElements`.
    9136             : class MTypedObjectElements
    9137             :   : public MUnaryInstruction,
    9138             :     public SingleObjectPolicy::Data
    9139             : {
    9140             :     bool definitelyOutline_;
    9141             : 
    9142             :   private:
    9143           0 :     explicit MTypedObjectElements(MDefinition* object, bool definitelyOutline)
    9144           0 :       : MUnaryInstruction(object),
    9145           0 :         definitelyOutline_(definitelyOutline)
    9146             :     {
    9147           0 :         setResultType(MIRType::Elements);
    9148           0 :         setMovable();
    9149           0 :     }
    9150             : 
    9151             :   public:
    9152           0 :     INSTRUCTION_HEADER(TypedObjectElements)
    9153           0 :     TRIVIAL_NEW_WRAPPERS
    9154           0 :     NAMED_OPERANDS((0, object))
    9155             : 
    9156           0 :     bool definitelyOutline() const {
    9157           0 :         return definitelyOutline_;
    9158             :     }
    9159           0 :     bool congruentTo(const MDefinition* ins) const override {
    9160           0 :         if (!ins->isTypedObjectElements())
    9161           0 :             return false;
    9162           0 :         const MTypedObjectElements* other = ins->toTypedObjectElements();
    9163           0 :         if (other->definitelyOutline() != definitelyOutline())
    9164           0 :             return false;
    9165           0 :         return congruentIfOperandsEqual(other);
    9166             :     }
    9167           0 :     AliasSet getAliasSet() const override {
    9168           0 :         return AliasSet::Load(AliasSet::ObjectFields);
    9169             :     }
    9170             : };
    9171             : 
    9172             : // Inlined version of the js::SetTypedObjectOffset() intrinsic.
    9173             : class MSetTypedObjectOffset
    9174             :   : public MBinaryInstruction,
    9175             :     public NoTypePolicy::Data
    9176             : {
    9177             :   private:
    9178           0 :     MSetTypedObjectOffset(MDefinition* object, MDefinition* offset)
    9179           0 :       : MBinaryInstruction(object, offset)
    9180             :     {
    9181           0 :         MOZ_ASSERT(object->type() == MIRType::Object);
    9182           0 :         MOZ_ASSERT(offset->type() == MIRType::Int32);
    9183           0 :         setResultType(MIRType::None);
    9184           0 :     }
    9185             : 
    9186             :   public:
    9187           0 :     INSTRUCTION_HEADER(SetTypedObjectOffset)
    9188           0 :     TRIVIAL_NEW_WRAPPERS
    9189           0 :     NAMED_OPERANDS((0, object), (1, offset))
    9190             : 
    9191           0 :     AliasSet getAliasSet() const override {
    9192             :         // This affects the result of MTypedObjectElements,
    9193             :         // which is described as a load of ObjectFields.
    9194           0 :         return AliasSet::Store(AliasSet::ObjectFields);
    9195             :     }
    9196             : };
    9197             : 
    9198             : class MKeepAliveObject
    9199             :   : public MUnaryInstruction,
    9200             :     public SingleObjectPolicy::Data
    9201             : {
    9202           2 :     explicit MKeepAliveObject(MDefinition* object)
    9203           2 :       : MUnaryInstruction(object)
    9204             :     {
    9205           2 :         setResultType(MIRType::None);
    9206           2 :         setGuard();
    9207           2 :     }
    9208             : 
    9209             :   public:
    9210          26 :     INSTRUCTION_HEADER(KeepAliveObject)
    9211           2 :     TRIVIAL_NEW_WRAPPERS
    9212           2 :     NAMED_OPERANDS((0, object))
    9213             : 
    9214             : };
    9215             : 
    9216             : // Perform !-operation
    9217             : class MNot
    9218             :   : public MUnaryInstruction,
    9219             :     public TestPolicy::Data
    9220             : {
    9221             :     bool operandMightEmulateUndefined_;
    9222             :     bool operandIsNeverNaN_;
    9223             : 
    9224         127 :     explicit MNot(MDefinition* input, CompilerConstraintList* constraints = nullptr)
    9225         127 :       : MUnaryInstruction(input),
    9226             :         operandMightEmulateUndefined_(true),
    9227         127 :         operandIsNeverNaN_(false)
    9228             :     {
    9229         127 :         setResultType(MIRType::Boolean);
    9230         127 :         setMovable();
    9231         127 :         if (constraints)
    9232         127 :             cacheOperandMightEmulateUndefined(constraints);
    9233         127 :     }
    9234             : 
    9235             :     void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
    9236             : 
    9237             :   public:
    9238           0 :     static MNot* NewInt32(TempAllocator& alloc, MDefinition* input) {
    9239           0 :         MOZ_ASSERT(input->type() == MIRType::Int32 || input->type() == MIRType::Int64);
    9240           0 :         auto* ins = new(alloc) MNot(input);
    9241           0 :         ins->setResultType(MIRType::Int32);
    9242           0 :         return ins;
    9243             :     }
    9244             : 
    9245        3819 :     INSTRUCTION_HEADER(Not)
    9246         127 :     TRIVIAL_NEW_WRAPPERS
    9247             : 
    9248             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    9249             : 
    9250         127 :     void markNoOperandEmulatesUndefined() {
    9251         127 :         operandMightEmulateUndefined_ = false;
    9252         127 :     }
    9253         131 :     bool operandMightEmulateUndefined() const {
    9254         131 :         return operandMightEmulateUndefined_;
    9255             :     }
    9256           0 :     bool operandIsNeverNaN() const {
    9257           0 :         return operandIsNeverNaN_;
    9258             :     }
    9259             : 
    9260         260 :     virtual AliasSet getAliasSet() const override {
    9261         260 :         return AliasSet::None();
    9262             :     }
    9263             :     void collectRangeInfoPreTrunc() override;
    9264             : 
    9265             :     void trySpecializeFloat32(TempAllocator& alloc) override;
    9266           0 :     bool isFloat32Commutative() const override { return true; }
    9267             : #ifdef DEBUG
    9268           0 :     bool isConsistentFloat32Use(MUse* use) const override {
    9269           0 :         return true;
    9270             :     }
    9271             : #endif
    9272          22 :     bool congruentTo(const MDefinition* ins) const override {
    9273          22 :         return congruentIfOperandsEqual(ins);
    9274             :     }
    9275             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
    9276           2 :     bool canRecoverOnBailout() const override {
    9277           2 :         return true;
    9278             :     }
    9279             : };
    9280             : 
    9281             : // Bailout if index + minimum < 0 or index + maximum >= length. The length used
    9282             : // in a bounds check must not be negative, or the wrong result may be computed
    9283             : // (unsigned comparisons may be used).
    9284           0 : class MBoundsCheck
    9285             :   : public MBinaryInstruction,
    9286             :     public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
    9287             : {
    9288             :     // Range over which to perform the bounds check, may be modified by GVN.
    9289             :     int32_t minimum_;
    9290             :     int32_t maximum_;
    9291             :     bool fallible_;
    9292             : 
    9293           8 :     MBoundsCheck(MDefinition* index, MDefinition* length)
    9294           8 :       : MBinaryInstruction(index, length), minimum_(0), maximum_(0), fallible_(true)
    9295             :     {
    9296           8 :         setGuard();
    9297           8 :         setMovable();
    9298           8 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9299           8 :         MOZ_ASSERT(length->type() == MIRType::Int32);
    9300             : 
    9301             :         // Returns the checked index.
    9302           8 :         setResultType(MIRType::Int32);
    9303           8 :     }
    9304             : 
    9305             :   public:
    9306        1259 :     INSTRUCTION_HEADER(BoundsCheck)
    9307           8 :     TRIVIAL_NEW_WRAPPERS
    9308          31 :     NAMED_OPERANDS((0, index), (1, length))
    9309             : 
    9310          35 :     int32_t minimum() const {
    9311          35 :         return minimum_;
    9312             :     }
    9313           0 :     void setMinimum(int32_t n) {
    9314           0 :         MOZ_ASSERT(fallible_);
    9315           0 :         minimum_ = n;
    9316           0 :     }
    9317          35 :     int32_t maximum() const {
    9318          35 :         return maximum_;
    9319             :     }
    9320           0 :     void setMaximum(int32_t n) {
    9321           0 :         MOZ_ASSERT(fallible_);
    9322           0 :         maximum_ = n;
    9323           0 :     }
    9324             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    9325          16 :     bool congruentTo(const MDefinition* ins) const override {
    9326          16 :         if (!ins->isBoundsCheck())
    9327           0 :             return false;
    9328          16 :         const MBoundsCheck* other = ins->toBoundsCheck();
    9329          16 :         if (minimum() != other->minimum() || maximum() != other->maximum())
    9330           0 :             return false;
    9331          16 :         if (fallible() != other->fallible())
    9332           0 :             return false;
    9333          16 :         return congruentIfOperandsEqual(other);
    9334             :     }
    9335          77 :     virtual AliasSet getAliasSet() const override {
    9336          77 :         return AliasSet::None();
    9337             :     }
    9338             :     void computeRange(TempAllocator& alloc) override;
    9339          36 :     bool fallible() const {
    9340          36 :         return fallible_;
    9341             :     }
    9342             :     void collectRangeInfoPreTrunc() override;
    9343             : 
    9344           0 :     ALLOW_CLONE(MBoundsCheck)
    9345             : };
    9346             : 
    9347             : // Bailout if index < minimum.
    9348             : class MBoundsCheckLower
    9349             :   : public MUnaryInstruction,
    9350             :     public IntPolicy<0>::Data
    9351             : {
    9352             :     int32_t minimum_;
    9353             :     bool fallible_;
    9354             : 
    9355           2 :     explicit MBoundsCheckLower(MDefinition* index)
    9356           2 :       : MUnaryInstruction(index), minimum_(0), fallible_(true)
    9357             :     {
    9358           2 :         setGuard();
    9359           2 :         setMovable();
    9360           2 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9361           2 :     }
    9362             : 
    9363             :   public:
    9364         220 :     INSTRUCTION_HEADER(BoundsCheckLower)
    9365           2 :     TRIVIAL_NEW_WRAPPERS
    9366           6 :     NAMED_OPERANDS((0, index))
    9367             : 
    9368           2 :     int32_t minimum() const {
    9369           2 :         return minimum_;
    9370             :     }
    9371           2 :     void setMinimum(int32_t n) {
    9372           2 :         minimum_ = n;
    9373           2 :     }
    9374           4 :     AliasSet getAliasSet() const override {
    9375           4 :         return AliasSet::None();
    9376             :     }
    9377           2 :     bool fallible() const {
    9378           2 :         return fallible_;
    9379             :     }
    9380             :     void collectRangeInfoPreTrunc() override;
    9381             : };
    9382             : 
    9383             : // Instructions which access an object's elements can either do so on a
    9384             : // definition accessing that elements pointer, or on the object itself, if its
    9385             : // elements are inline. In the latter case there must be an offset associated
    9386             : // with the access.
    9387             : static inline bool
    9388          20 : IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment)
    9389             : {
    9390          40 :     return elements->type() == MIRType::Elements ||
    9391          20 :            (elements->type() == MIRType::Object && offsetAdjustment != 0);
    9392             : }
    9393             : 
    9394             : // Load a value from a dense array's element vector and does a hole check if the
    9395             : // array is not known to be packed.
    9396           0 : class MLoadElement
    9397             :   : public MBinaryInstruction,
    9398             :     public SingleObjectPolicy::Data
    9399             : {
    9400             :     bool needsHoleCheck_;
    9401             :     bool loadDoubles_;
    9402             :     int32_t offsetAdjustment_;
    9403             : 
    9404           1 :     MLoadElement(MDefinition* elements, MDefinition* index,
    9405             :                  bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment = 0)
    9406           1 :       : MBinaryInstruction(elements, index),
    9407             :         needsHoleCheck_(needsHoleCheck),
    9408             :         loadDoubles_(loadDoubles),
    9409           1 :         offsetAdjustment_(offsetAdjustment)
    9410             :     {
    9411           1 :         if (needsHoleCheck) {
    9412             :             // Uses may be optimized away based on this instruction's result
    9413             :             // type. This means it's invalid to DCE this instruction, as we
    9414             :             // have to invalidate when we read a hole.
    9415           0 :             setGuard();
    9416             :         }
    9417           1 :         setResultType(MIRType::Value);
    9418           1 :         setMovable();
    9419           1 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9420           1 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9421           1 :     }
    9422             : 
    9423             :   public:
    9424         285 :     INSTRUCTION_HEADER(LoadElement)
    9425           1 :     TRIVIAL_NEW_WRAPPERS
    9426           4 :     NAMED_OPERANDS((0, elements), (1, index))
    9427             : 
    9428           5 :     bool needsHoleCheck() const {
    9429           5 :         return needsHoleCheck_;
    9430             :     }
    9431           4 :     bool loadDoubles() const {
    9432           4 :         return loadDoubles_;
    9433             :     }
    9434           4 :     int32_t offsetAdjustment() const {
    9435           4 :         return offsetAdjustment_;
    9436             :     }
    9437           1 :     bool fallible() const {
    9438           1 :         return needsHoleCheck();
    9439             :     }
    9440           1 :     bool congruentTo(const MDefinition* ins) const override {
    9441           1 :         if (!ins->isLoadElement())
    9442           0 :             return false;
    9443           1 :         const MLoadElement* other = ins->toLoadElement();
    9444           1 :         if (needsHoleCheck() != other->needsHoleCheck())
    9445           0 :             return false;
    9446           1 :         if (loadDoubles() != other->loadDoubles())
    9447           0 :             return false;
    9448           1 :         if (offsetAdjustment() != other->offsetAdjustment())
    9449           0 :             return false;
    9450           1 :         return congruentIfOperandsEqual(other);
    9451             :     }
    9452             :     AliasType mightAlias(const MDefinition* store) const override;
    9453             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    9454          22 :     AliasSet getAliasSet() const override {
    9455          22 :         return AliasSet::Load(AliasSet::Element);
    9456             :     }
    9457             : 
    9458           0 :     ALLOW_CLONE(MLoadElement)
    9459             : };
    9460             : 
    9461             : // Load a value from the elements vector for a dense native or unboxed array.
    9462             : // If the index is out-of-bounds, or the indexed slot has a hole, undefined is
    9463             : // returned instead.
    9464           0 : class MLoadElementHole
    9465             :   : public MTernaryInstruction,
    9466             :     public SingleObjectPolicy::Data
    9467             : {
    9468             :     // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
    9469             :     JSValueType unboxedType_;
    9470             : 
    9471             :     bool needsNegativeIntCheck_;
    9472             :     bool needsHoleCheck_;
    9473             : 
    9474           0 :     MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
    9475             :                      JSValueType unboxedType, bool needsHoleCheck)
    9476           0 :       : MTernaryInstruction(elements, index, initLength),
    9477             :         unboxedType_(unboxedType),
    9478             :         needsNegativeIntCheck_(true),
    9479           0 :         needsHoleCheck_(needsHoleCheck)
    9480             :     {
    9481           0 :         setResultType(MIRType::Value);
    9482           0 :         setMovable();
    9483             : 
    9484             :         // Set the guard flag to make sure we bail when we see a negative
    9485             :         // index. We can clear this flag (and needsNegativeIntCheck_) in
    9486             :         // collectRangeInfoPreTrunc.
    9487           0 :         setGuard();
    9488             : 
    9489           0 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
    9490           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9491           0 :         MOZ_ASSERT(initLength->type() == MIRType::Int32);
    9492           0 :     }
    9493             : 
    9494             :   public:
    9495           0 :     INSTRUCTION_HEADER(LoadElementHole)
    9496           0 :     TRIVIAL_NEW_WRAPPERS
    9497           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
    9498             : 
    9499           0 :     JSValueType unboxedType() const {
    9500           0 :         return unboxedType_;
    9501             :     }
    9502           0 :     bool needsNegativeIntCheck() const {
    9503           0 :         return needsNegativeIntCheck_;
    9504             :     }
    9505           0 :     bool needsHoleCheck() const {
    9506           0 :         return needsHoleCheck_;
    9507             :     }
    9508           0 :     bool congruentTo(const MDefinition* ins) const override {
    9509           0 :         if (!ins->isLoadElementHole())
    9510           0 :             return false;
    9511           0 :         const MLoadElementHole* other = ins->toLoadElementHole();
    9512           0 :         if (unboxedType() != other->unboxedType())
    9513           0 :             return false;
    9514           0 :         if (needsHoleCheck() != other->needsHoleCheck())
    9515           0 :             return false;
    9516           0 :         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
    9517           0 :             return false;
    9518           0 :         return congruentIfOperandsEqual(other);
    9519             :     }
    9520           0 :     AliasSet getAliasSet() const override {
    9521           0 :         return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType()));
    9522             :     }
    9523             :     void collectRangeInfoPreTrunc() override;
    9524             : 
    9525           0 :     ALLOW_CLONE(MLoadElementHole)
    9526             : };
    9527             : 
    9528           0 : class MLoadUnboxedObjectOrNull
    9529             :   : public MBinaryInstruction,
    9530             :     public SingleObjectPolicy::Data
    9531             : {
    9532             :   public:
    9533             :     enum NullBehavior {
    9534             :         HandleNull,
    9535             :         BailOnNull,
    9536             :         NullNotPossible
    9537             :     };
    9538             : 
    9539             :   private:
    9540             :     NullBehavior nullBehavior_;
    9541             :     int32_t offsetAdjustment_;
    9542             : 
    9543           0 :     MLoadUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
    9544             :                              NullBehavior nullBehavior, int32_t offsetAdjustment)
    9545           0 :       : MBinaryInstruction(elements, index),
    9546             :         nullBehavior_(nullBehavior),
    9547           0 :         offsetAdjustment_(offsetAdjustment)
    9548             :     {
    9549           0 :         if (nullBehavior == BailOnNull) {
    9550             :             // Don't eliminate loads which bail out on a null pointer, for the
    9551             :             // same reason as MLoadElement.
    9552           0 :             setGuard();
    9553             :         }
    9554           0 :         setResultType(nullBehavior == HandleNull ? MIRType::Value : MIRType::Object);
    9555           0 :         setMovable();
    9556           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9557           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9558           0 :     }
    9559             : 
    9560             :   public:
    9561           0 :     INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
    9562           0 :     TRIVIAL_NEW_WRAPPERS
    9563           0 :     NAMED_OPERANDS((0, elements), (1, index))
    9564             : 
    9565           0 :     NullBehavior nullBehavior() const {
    9566           0 :         return nullBehavior_;
    9567             :     }
    9568           0 :     int32_t offsetAdjustment() const {
    9569           0 :         return offsetAdjustment_;
    9570             :     }
    9571             :     bool fallible() const {
    9572             :         return nullBehavior() == BailOnNull;
    9573             :     }
    9574           0 :     bool congruentTo(const MDefinition* ins) const override {
    9575           0 :         if (!ins->isLoadUnboxedObjectOrNull())
    9576           0 :             return false;
    9577           0 :         const MLoadUnboxedObjectOrNull* other = ins->toLoadUnboxedObjectOrNull();
    9578           0 :         if (nullBehavior() != other->nullBehavior())
    9579           0 :             return false;
    9580           0 :         if (offsetAdjustment() != other->offsetAdjustment())
    9581           0 :             return false;
    9582           0 :         return congruentIfOperandsEqual(other);
    9583             :     }
    9584           0 :     AliasSet getAliasSet() const override {
    9585           0 :         return AliasSet::Load(AliasSet::UnboxedElement);
    9586             :     }
    9587             :     AliasType mightAlias(const MDefinition* store) const override;
    9588             :     MDefinition* foldsTo(TempAllocator& alloc) override;
    9589             : 
    9590           0 :     ALLOW_CLONE(MLoadUnboxedObjectOrNull)
    9591             : };
    9592             : 
    9593           0 : class MLoadUnboxedString
    9594             :   : public MBinaryInstruction,
    9595             :     public SingleObjectPolicy::Data
    9596             : {
    9597             :     int32_t offsetAdjustment_;
    9598             : 
    9599           0 :     MLoadUnboxedString(MDefinition* elements, MDefinition* index, int32_t offsetAdjustment = 0)
    9600           0 :       : MBinaryInstruction(elements, index),
    9601           0 :         offsetAdjustment_(offsetAdjustment)
    9602             :     {
    9603           0 :         setResultType(MIRType::String);
    9604           0 :         setMovable();
    9605           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9606           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9607           0 :     }
    9608             : 
    9609             :   public:
    9610           0 :     INSTRUCTION_HEADER(LoadUnboxedString)
    9611           0 :     TRIVIAL_NEW_WRAPPERS
    9612           0 :     NAMED_OPERANDS((0, elements), (1, index))
    9613             : 
    9614           0 :     int32_t offsetAdjustment() const {
    9615           0 :         return offsetAdjustment_;
    9616             :     }
    9617           0 :     bool congruentTo(const MDefinition* ins) const override {
    9618           0 :         if (!ins->isLoadUnboxedString())
    9619           0 :             return false;
    9620           0 :         const MLoadUnboxedString* other = ins->toLoadUnboxedString();
    9621           0 :         if (offsetAdjustment() != other->offsetAdjustment())
    9622           0 :             return false;
    9623           0 :         return congruentIfOperandsEqual(ins);
    9624             :     }
    9625           0 :     AliasSet getAliasSet() const override {
    9626           0 :         return AliasSet::Load(AliasSet::UnboxedElement);
    9627             :     }
    9628             : 
    9629           0 :     ALLOW_CLONE(MLoadUnboxedString)
    9630             : };
    9631             : 
    9632             : class MStoreElementCommon
    9633             : {
    9634             :     MIRType elementType_;
    9635             :     bool needsBarrier_;
    9636             : 
    9637             :   protected:
    9638          15 :     MStoreElementCommon()
    9639          15 :       : elementType_(MIRType::Value),
    9640          15 :         needsBarrier_(false)
    9641          15 :     { }
    9642             : 
    9643             :   public:
    9644           5 :     MIRType elementType() const {
    9645           5 :         return elementType_;
    9646             :     }
    9647           1 :     void setElementType(MIRType elementType) {
    9648           1 :         MOZ_ASSERT(elementType != MIRType::None);
    9649           1 :         elementType_ = elementType;
    9650           1 :     }
    9651           5 :     bool needsBarrier() const {
    9652           5 :         return needsBarrier_;
    9653             :     }
    9654           1 :     void setNeedsBarrier() {
    9655           1 :         needsBarrier_ = true;
    9656           1 :     }
    9657             : };
    9658             : 
    9659             : // Store a value to a dense array slots vector.
    9660           0 : class MStoreElement
    9661             :   : public MAryInstruction<3>,
    9662             :     public MStoreElementCommon,
    9663             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
    9664             : {
    9665             :     bool needsHoleCheck_;
    9666             :     int32_t offsetAdjustment_;
    9667             : 
    9668          14 :     MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value,
    9669             :                   bool needsHoleCheck, int32_t offsetAdjustment = 0)
    9670          14 :     {
    9671          14 :         initOperand(0, elements);
    9672          14 :         initOperand(1, index);
    9673          14 :         initOperand(2, value);
    9674          14 :         needsHoleCheck_ = needsHoleCheck;
    9675          14 :         offsetAdjustment_ = offsetAdjustment;
    9676          14 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9677          14 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9678          14 :     }
    9679             : 
    9680             :   public:
    9681        1422 :     INSTRUCTION_HEADER(StoreElement)
    9682          14 :     TRIVIAL_NEW_WRAPPERS
    9683          28 :     NAMED_OPERANDS((0, elements), (1, index), (2, value))
    9684             : 
    9685          48 :     AliasSet getAliasSet() const override {
    9686          48 :         return AliasSet::Store(AliasSet::Element);
    9687             :     }
    9688          12 :     bool needsHoleCheck() const {
    9689          12 :         return needsHoleCheck_;
    9690             :     }
    9691           8 :     int32_t offsetAdjustment() const {
    9692           8 :         return offsetAdjustment_;
    9693             :     }
    9694           4 :     bool fallible() const {
    9695           4 :         return needsHoleCheck();
    9696             :     }
    9697             : 
    9698           0 :     ALLOW_CLONE(MStoreElement)
    9699             : };
    9700             : 
    9701             : // Like MStoreElement, but supports indexes >= initialized length, and can
    9702             : // handle unboxed arrays. The downside is that we cannot hoist the elements
    9703             : // vector and bounds check, since this instruction may update the (initialized)
    9704             : // length and reallocate the elements vector.
    9705           0 : class MStoreElementHole
    9706             :   : public MAryInstruction<4>,
    9707             :     public MStoreElementCommon,
    9708             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
    9709             : {
    9710             :     JSValueType unboxedType_;
    9711             : 
    9712           1 :     MStoreElementHole(MDefinition* object, MDefinition* elements,
    9713             :                       MDefinition* index, MDefinition* value, JSValueType unboxedType)
    9714           1 :       : unboxedType_(unboxedType)
    9715             :     {
    9716           1 :         initOperand(0, object);
    9717           1 :         initOperand(1, elements);
    9718           1 :         initOperand(2, index);
    9719           1 :         initOperand(3, value);
    9720           1 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
    9721           1 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9722           1 :     }
    9723             : 
    9724             :   public:
    9725         246 :     INSTRUCTION_HEADER(StoreElementHole)
    9726           1 :     TRIVIAL_NEW_WRAPPERS
    9727          11 :     NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
    9728             : 
    9729          11 :     JSValueType unboxedType() const {
    9730          11 :         return unboxedType_;
    9731             :     }
    9732           8 :     AliasSet getAliasSet() const override {
    9733             :         // StoreElementHole can update the initialized length, the array length
    9734             :         // or reallocate obj->elements.
    9735             :         return AliasSet::Store(AliasSet::ObjectFields |
    9736           8 :                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
    9737             :     }
    9738             : 
    9739           0 :     ALLOW_CLONE(MStoreElementHole)
    9740             : };
    9741             : 
    9742             : // Try to store a value to a dense array slots vector. May fail due to the object being frozen.
    9743             : // Cannot be used on an object that has extra indexed properties.
    9744           0 : class MFallibleStoreElement
    9745             :   : public MAryInstruction<4>,
    9746             :     public MStoreElementCommon,
    9747             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
    9748             : {
    9749             :     JSValueType unboxedType_;
    9750             :     bool strict_;
    9751             : 
    9752           0 :     MFallibleStoreElement(MDefinition* object, MDefinition* elements,
    9753             :                           MDefinition* index, MDefinition* value,
    9754             :                           JSValueType unboxedType, bool strict)
    9755           0 :       : unboxedType_(unboxedType)
    9756             :     {
    9757           0 :         initOperand(0, object);
    9758           0 :         initOperand(1, elements);
    9759           0 :         initOperand(2, index);
    9760           0 :         initOperand(3, value);
    9761           0 :         strict_ = strict;
    9762           0 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
    9763           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9764           0 :     }
    9765             : 
    9766             :   public:
    9767           0 :     INSTRUCTION_HEADER(FallibleStoreElement)
    9768           0 :     TRIVIAL_NEW_WRAPPERS
    9769           0 :     NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
    9770             : 
    9771           0 :     JSValueType unboxedType() const {
    9772           0 :         return unboxedType_;
    9773             :     }
    9774           0 :     AliasSet getAliasSet() const override {
    9775             :         return AliasSet::Store(AliasSet::ObjectFields |
    9776           0 :                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
    9777             :     }
    9778           0 :     bool strict() const {
    9779           0 :         return strict_;
    9780             :     }
    9781             : 
    9782           0 :     ALLOW_CLONE(MFallibleStoreElement)
    9783             : };
    9784             : 
    9785             : 
    9786             : // Store an unboxed object or null pointer to a v\ector.
    9787           0 : class MStoreUnboxedObjectOrNull
    9788             :   : public MAryInstruction<4>,
    9789             :     public StoreUnboxedObjectOrNullPolicy::Data
    9790             : {
    9791             :     int32_t offsetAdjustment_;
    9792             :     bool preBarrier_;
    9793             : 
    9794           0 :     MStoreUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
    9795             :                               MDefinition* value, MDefinition* typedObj,
    9796             :                               int32_t offsetAdjustment = 0, bool preBarrier = true)
    9797           0 :       : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
    9798             :     {
    9799           0 :         initOperand(0, elements);
    9800           0 :         initOperand(1, index);
    9801           0 :         initOperand(2, value);
    9802           0 :         initOperand(3, typedObj);
    9803           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9804           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9805           0 :         MOZ_ASSERT(typedObj->type() == MIRType::Object);
    9806           0 :     }
    9807             : 
    9808             :   public:
    9809           0 :     INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
    9810           0 :     TRIVIAL_NEW_WRAPPERS
    9811           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, value), (3, typedObj))
    9812             : 
    9813           0 :     int32_t offsetAdjustment() const {
    9814           0 :         return offsetAdjustment_;
    9815             :     }
    9816           0 :     bool preBarrier() const {
    9817           0 :         return preBarrier_;
    9818             :     }
    9819           0 :     AliasSet getAliasSet() const override {
    9820           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
    9821             :     }
    9822             : 
    9823             :     // For StoreUnboxedObjectOrNullPolicy.
    9824           0 :     void setValue(MDefinition* def) {
    9825           0 :         replaceOperand(2, def);
    9826           0 :     }
    9827             : 
    9828           0 :     ALLOW_CLONE(MStoreUnboxedObjectOrNull)
    9829             : };
    9830             : 
    9831             : // Store an unboxed object or null pointer to a vector.
    9832           0 : class MStoreUnboxedString
    9833             :   : public MAryInstruction<3>,
    9834             :     public MixPolicy<SingleObjectPolicy, ConvertToStringPolicy<2> >::Data
    9835             : {
    9836             :     int32_t offsetAdjustment_;
    9837             :     bool preBarrier_;
    9838             : 
    9839           0 :     MStoreUnboxedString(MDefinition* elements, MDefinition* index, MDefinition* value,
    9840             :                         int32_t offsetAdjustment = 0, bool preBarrier = true)
    9841           0 :       : offsetAdjustment_(offsetAdjustment), preBarrier_(preBarrier)
    9842             :     {
    9843           0 :         initOperand(0, elements);
    9844           0 :         initOperand(1, index);
    9845           0 :         initOperand(2, value);
    9846           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
    9847           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
    9848           0 :     }
    9849             : 
    9850             :   public:
    9851           0 :     INSTRUCTION_HEADER(StoreUnboxedString)
    9852           0 :     TRIVIAL_NEW_WRAPPERS
    9853           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, value))
    9854             : 
    9855           0 :     int32_t offsetAdjustment() const {
    9856           0 :         return offsetAdjustment_;
    9857             :     }
    9858           0 :     bool preBarrier() const {
    9859           0 :         return preBarrier_;
    9860             :     }
    9861           0 :     AliasSet getAliasSet() const override {
    9862           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
    9863             :     }
    9864             : 
    9865           0 :     ALLOW_CLONE(MStoreUnboxedString)
    9866             : };
    9867             : 
    9868             : // Passes through an object, after ensuring it is converted from an unboxed
    9869             : // object to a native representation.
    9870             : class MConvertUnboxedObjectToNative
    9871             :   : public MUnaryInstruction,
    9872             :     public SingleObjectPolicy::Data
    9873             : {
    9874             :     CompilerObjectGroup group_;
    9875             : 
    9876           0 :     explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
    9877           0 :       : MUnaryInstruction(obj),
    9878           0 :         group_(group)
    9879             :     {
    9880           0 :         setGuard();
    9881           0 :         setMovable();
    9882           0 :         setResultType(MIRType::Object);
    9883           0 :     }
    9884             : 
    9885             :   public:
    9886           0 :     INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
    9887           0 :     NAMED_OPERANDS((0, object))
    9888             : 
    9889             :     static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
    9890             :                                               ObjectGroup* group);
    9891             : 
    9892           0 :     ObjectGroup* group() const {
    9893           0 :         return group_;
    9894             :     }
    9895           0 :     bool congruentTo(const MDefinition* ins) const override {
    9896           0 :         if (!congruentIfOperandsEqual(ins))
    9897           0 :             return false;
    9898           0 :         return ins->toConvertUnboxedObjectToNative()->group() == group();
    9899             :     }
    9900           0 :     AliasSet getAliasSet() const override {
    9901             :         // This instruction can read and write to all parts of the object, but
    9902             :         // is marked as non-effectful so it can be consolidated by LICM and GVN
    9903             :         // and avoid inhibiting other optimizations.
    9904             :         //
    9905             :         // This is valid to do because when unboxed objects might have a native
    9906             :         // group they can be converted to, we do not optimize accesses to the
    9907             :         // unboxed objects and do not guard on their group or shape (other than
    9908             :         // in this opcode).
    9909             :         //
    9910             :         // Later accesses can assume the object has a native representation
    9911             :         // and optimize accordingly. Those accesses cannot be reordered before
    9912             :         // this instruction, however. This is prevented by chaining this
    9913             :         // instruction with the object itself, in the same way as MBoundsCheck.
    9914           0 :         return AliasSet::None();
    9915             :     }
    9916           0 :     bool appendRoots(MRootList& roots) const override {
    9917           0 :         return roots.append(group_);
    9918             :     }
    9919             : };
    9920             : 
    9921             : // Array.prototype.pop or Array.prototype.shift on a dense array.
    9922           0 : class MArrayPopShift
    9923             :   : public MUnaryInstruction,
    9924             :     public SingleObjectPolicy::Data
    9925             : {
    9926             :   public:
    9927             :     enum Mode {
    9928             :         Pop,
    9929             :         Shift
    9930             :     };
    9931             : 
    9932             :   private:
    9933             :     Mode mode_;
    9934             :     JSValueType unboxedType_;
    9935             :     bool needsHoleCheck_;
    9936             :     bool maybeUndefined_;
    9937             : 
    9938           0 :     MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType,
    9939             :                    bool needsHoleCheck, bool maybeUndefined)
    9940           0 :       : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType),
    9941           0 :         needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
    9942           0 :     { }
    9943             : 
    9944             :   public:
    9945           0 :     INSTRUCTION_HEADER(ArrayPopShift)
    9946           0 :     TRIVIAL_NEW_WRAPPERS
    9947           0 :     NAMED_OPERANDS((0, object))
    9948             : 
    9949           0 :     bool needsHoleCheck() const {
    9950           0 :         return needsHoleCheck_;
    9951             :     }
    9952           0 :     bool maybeUndefined() const {
    9953           0 :         return maybeUndefined_;
    9954             :     }
    9955           0 :     bool mode() const {
    9956           0 :         return mode_;
    9957             :     }
    9958           0 :     JSValueType unboxedType() const {
    9959           0 :         return unboxedType_;
    9960             :     }
    9961           0 :     AliasSet getAliasSet() const override {
    9962             :         return AliasSet::Store(AliasSet::ObjectFields |
    9963           0 :                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
    9964             :     }
    9965             : 
    9966           0 :     ALLOW_CLONE(MArrayPopShift)
    9967             : };
    9968             : 
    9969             : // Array.prototype.push on a dense array. Returns the new array length.
    9970           0 : class MArrayPush
    9971             :   : public MBinaryInstruction,
    9972             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
    9973             : {
    9974             :     JSValueType unboxedType_;
    9975             : 
    9976           2 :     MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType)
    9977           2 :       : MBinaryInstruction(object, value), unboxedType_(unboxedType)
    9978             :     {
    9979           2 :         setResultType(MIRType::Int32);
    9980           2 :     }
    9981             : 
    9982             :   public:
    9983         266 :     INSTRUCTION_HEADER(ArrayPush)
    9984           2 :     TRIVIAL_NEW_WRAPPERS
    9985           4 :     NAMED_OPERANDS((0, object), (1, value))
    9986             : 
    9987          11 :     JSValueType unboxedType() const {
    9988          11 :         return unboxedType_;
    9989             :     }
    9990           9 :     AliasSet getAliasSet() const override {
    9991             :         return AliasSet::Store(AliasSet::ObjectFields |
    9992           9 :                                AliasSet::BoxedOrUnboxedElements(unboxedType()));
    9993             :     }
    9994             :     void computeRange(TempAllocator& alloc) override;
    9995             : 
    9996           0 :     ALLOW_CLONE(MArrayPush)
    9997             : };
    9998             : 
    9999             : // Array.prototype.slice on a dense array.
   10000             : class MArraySlice
   10001             :   : public MTernaryInstruction,
   10002             :     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
   10003             : {
   10004             :     CompilerObject templateObj_;
   10005             :     gc::InitialHeap initialHeap_;
   10006             :     JSValueType unboxedType_;
   10007             : 
   10008           0 :     MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
   10009             :                 MDefinition* begin, MDefinition* end,
   10010             :                 JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
   10011           0 :       : MTernaryInstruction(obj, begin, end),
   10012             :         templateObj_(templateObj),
   10013             :         initialHeap_(initialHeap),
   10014           0 :         unboxedType_(unboxedType)
   10015             :     {
   10016           0 :         setResultType(MIRType::Object);
   10017           0 :     }
   10018             : 
   10019             :   public:
   10020           0 :     INSTRUCTION_HEADER(ArraySlice)
   10021           0 :     TRIVIAL_NEW_WRAPPERS
   10022           0 :     NAMED_OPERANDS((0, object), (1, begin), (2, end))
   10023             : 
   10024           0 :     JSObject* templateObj() const {
   10025           0 :         return templateObj_;
   10026             :     }
   10027             : 
   10028           0 :     gc::InitialHeap initialHeap() const {
   10029           0 :         return initialHeap_;
   10030             :     }
   10031             : 
   10032           0 :     JSValueType unboxedType() const {
   10033           0 :         return unboxedType_;
   10034             :     }
   10035             : 
   10036           0 :     AliasSet getAliasSet() const override {
   10037           0 :         return AliasSet::Store(AliasSet::BoxedOrUnboxedElements(unboxedType()) |
   10038           0 :                                AliasSet::ObjectFields);
   10039             :     }
   10040           0 :     bool possiblyCalls() const override {
   10041           0 :         return true;
   10042             :     }
   10043           0 :     bool appendRoots(MRootList& roots) const override {
   10044           0 :         return roots.append(templateObj_);
   10045             :     }
   10046             : };
   10047             : 
   10048             : class MArrayJoin
   10049             :     : public MBinaryInstruction,
   10050             :       public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
   10051             : {
   10052           1 :     MArrayJoin(MDefinition* array, MDefinition* sep)
   10053           1 :         : MBinaryInstruction(array, sep)
   10054             :     {
   10055           1 :         setResultType(MIRType::String);
   10056           1 :     }
   10057             :   public:
   10058         427 :     INSTRUCTION_HEADER(ArrayJoin)
   10059           1 :     TRIVIAL_NEW_WRAPPERS
   10060           6 :     NAMED_OPERANDS((0, array), (1, sep))
   10061             : 
   10062           1 :     bool possiblyCalls() const override {
   10063           1 :         return true;
   10064             :     }
   10065           8 :     virtual AliasSet getAliasSet() const override {
   10066             :         // Array.join might coerce the elements of the Array to strings.  This
   10067             :         // coercion might cause the evaluation of the some JavaScript code.
   10068           8 :         return AliasSet::Store(AliasSet::Any);
   10069             :     }
   10070             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   10071             : };
   10072             : 
   10073             : // All barriered operations - MCompareExchangeTypedArrayElement,
   10074             : // MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as
   10075             : // well as MLoadUnboxedScalar and MStoreUnboxedScalar when they are
   10076             : // marked as requiring a memory barrer - have the following
   10077             : // attributes:
   10078             : //
   10079             : // - Not movable
   10080             : // - Not removable
   10081             : // - Not congruent with any other instruction
   10082             : // - Effectful (they alias every TypedArray store)
   10083             : //
   10084             : // The intended effect of those constraints is to prevent all loads
   10085             : // and stores preceding the barriered operation from being moved to
   10086             : // after the barriered operation, and vice versa, and to prevent the
   10087             : // barriered operation from being removed or hoisted.
   10088             : 
   10089             : enum MemoryBarrierRequirement
   10090             : {
   10091             :     DoesNotRequireMemoryBarrier,
   10092             :     DoesRequireMemoryBarrier
   10093             : };
   10094             : 
   10095             : // Also see comments at MMemoryBarrierRequirement, above.
   10096             : 
   10097             : // Load an unboxed scalar value from a typed array or other object.
   10098           0 : class MLoadUnboxedScalar
   10099             :   : public MBinaryInstruction,
   10100             :     public SingleObjectPolicy::Data
   10101             : {
   10102             :     Scalar::Type storageType_;
   10103             :     Scalar::Type readType_;
   10104             :     unsigned numElems_; // used only for SIMD
   10105             :     bool requiresBarrier_;
   10106             :     int32_t offsetAdjustment_;
   10107             :     bool canonicalizeDoubles_;
   10108             : 
   10109           0 :     MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, Scalar::Type storageType,
   10110             :                        MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
   10111             :                        int32_t offsetAdjustment = 0, bool canonicalizeDoubles = true)
   10112           0 :       : MBinaryInstruction(elements, index),
   10113             :         storageType_(storageType),
   10114             :         readType_(storageType),
   10115             :         numElems_(1),
   10116           0 :         requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
   10117             :         offsetAdjustment_(offsetAdjustment),
   10118           0 :         canonicalizeDoubles_(canonicalizeDoubles)
   10119             :     {
   10120           0 :         setResultType(MIRType::Value);
   10121           0 :         if (requiresBarrier_)
   10122           0 :             setGuard();         // Not removable or movable
   10123             :         else
   10124           0 :             setMovable();
   10125           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
   10126           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   10127           0 :         MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
   10128           0 :     }
   10129             : 
   10130             :   public:
   10131           0 :     INSTRUCTION_HEADER(LoadUnboxedScalar)
   10132           0 :     TRIVIAL_NEW_WRAPPERS
   10133           0 :     NAMED_OPERANDS((0, elements), (1, index))
   10134             : 
   10135           0 :     void setSimdRead(Scalar::Type type, unsigned numElems) {
   10136           0 :         readType_ = type;
   10137           0 :         numElems_ = numElems;
   10138           0 :     }
   10139           0 :     unsigned numElems() const {
   10140           0 :         return numElems_;
   10141             :     }
   10142           0 :     Scalar::Type readType() const {
   10143           0 :         return readType_;
   10144             :     }
   10145             : 
   10146           0 :     Scalar::Type storageType() const {
   10147           0 :         return storageType_;
   10148             :     }
   10149           0 :     bool fallible() const {
   10150             :         // Bailout if the result does not fit in an int32.
   10151           0 :         return readType_ == Scalar::Uint32 && type() == MIRType::Int32;
   10152             :     }
   10153           0 :     bool requiresMemoryBarrier() const {
   10154           0 :         return requiresBarrier_;
   10155             :     }
   10156           0 :     bool canonicalizeDoubles() const {
   10157           0 :         return canonicalizeDoubles_;
   10158             :     }
   10159           0 :     int32_t offsetAdjustment() const {
   10160           0 :         return offsetAdjustment_;
   10161             :     }
   10162           0 :     void setOffsetAdjustment(int32_t offsetAdjustment) {
   10163           0 :         offsetAdjustment_ = offsetAdjustment;
   10164           0 :     }
   10165           0 :     AliasSet getAliasSet() const override {
   10166             :         // When a barrier is needed make the instruction effectful by
   10167             :         // giving it a "store" effect.
   10168           0 :         if (requiresBarrier_)
   10169           0 :             return AliasSet::Store(AliasSet::UnboxedElement);
   10170           0 :         return AliasSet::Load(AliasSet::UnboxedElement);
   10171             :     }
   10172             : 
   10173           0 :     bool congruentTo(const MDefinition* ins) const override {
   10174           0 :         if (requiresBarrier_)
   10175           0 :             return false;
   10176           0 :         if (!ins->isLoadUnboxedScalar())
   10177           0 :             return false;
   10178           0 :         const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
   10179           0 :         if (storageType_ != other->storageType_)
   10180           0 :             return false;
   10181           0 :         if (readType_ != other->readType_)
   10182           0 :             return false;
   10183           0 :         if (numElems_ != other->numElems_)
   10184           0 :             return false;
   10185           0 :         if (offsetAdjustment() != other->offsetAdjustment())
   10186           0 :             return false;
   10187           0 :         if (canonicalizeDoubles() != other->canonicalizeDoubles())
   10188           0 :             return false;
   10189           0 :         return congruentIfOperandsEqual(other);
   10190             :     }
   10191             : 
   10192             :     void printOpcode(GenericPrinter& out) const override;
   10193             : 
   10194             :     void computeRange(TempAllocator& alloc) override;
   10195             : 
   10196           0 :     bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
   10197             : 
   10198           0 :     ALLOW_CLONE(MLoadUnboxedScalar)
   10199             : };
   10200             : 
   10201             : // Load a value from a typed array. Out-of-bounds accesses are handled in-line.
   10202           0 : class MLoadTypedArrayElementHole
   10203             :   : public MBinaryInstruction,
   10204             :     public SingleObjectPolicy::Data
   10205             : {
   10206             :     Scalar::Type arrayType_;
   10207             :     bool allowDouble_;
   10208             : 
   10209           0 :     MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble)
   10210           0 :       : MBinaryInstruction(object, index), arrayType_(arrayType), allowDouble_(allowDouble)
   10211             :     {
   10212           0 :         setResultType(MIRType::Value);
   10213           0 :         setMovable();
   10214           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   10215           0 :         MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
   10216           0 :     }
   10217             : 
   10218             :   public:
   10219           0 :     INSTRUCTION_HEADER(LoadTypedArrayElementHole)
   10220           0 :     TRIVIAL_NEW_WRAPPERS
   10221           0 :     NAMED_OPERANDS((0, object), (1, index))
   10222             : 
   10223           0 :     Scalar::Type arrayType() const {
   10224           0 :         return arrayType_;
   10225             :     }
   10226           0 :     bool allowDouble() const {
   10227           0 :         return allowDouble_;
   10228             :     }
   10229           0 :     bool fallible() const {
   10230           0 :         return arrayType_ == Scalar::Uint32 && !allowDouble_;
   10231             :     }
   10232           0 :     bool congruentTo(const MDefinition* ins) const override {
   10233           0 :         if (!ins->isLoadTypedArrayElementHole())
   10234           0 :             return false;
   10235           0 :         const MLoadTypedArrayElementHole* other = ins->toLoadTypedArrayElementHole();
   10236           0 :         if (arrayType() != other->arrayType())
   10237           0 :             return false;
   10238           0 :         if (allowDouble() != other->allowDouble())
   10239           0 :             return false;
   10240           0 :         return congruentIfOperandsEqual(other);
   10241             :     }
   10242           0 :     AliasSet getAliasSet() const override {
   10243           0 :         return AliasSet::Load(AliasSet::UnboxedElement);
   10244             :     }
   10245           0 :     bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
   10246             : 
   10247           0 :     ALLOW_CLONE(MLoadTypedArrayElementHole)
   10248             : };
   10249             : 
   10250             : // Load a value fallibly or infallibly from a statically known typed array.
   10251             : class MLoadTypedArrayElementStatic
   10252             :   : public MUnaryInstruction,
   10253             :     public ConvertToInt32Policy<0>::Data
   10254             : {
   10255           0 :     MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
   10256             :                                  int32_t offset = 0, bool needsBoundsCheck = true)
   10257           0 :       : MUnaryInstruction(ptr), someTypedArray_(someTypedArray), offset_(offset),
   10258           0 :         needsBoundsCheck_(needsBoundsCheck), fallible_(true)
   10259             :     {
   10260           0 :         int type = accessType();
   10261           0 :         if (type == Scalar::Float32)
   10262           0 :             setResultType(MIRType::Float32);
   10263           0 :         else if (type == Scalar::Float64)
   10264           0 :             setResultType(MIRType::Double);
   10265             :         else
   10266           0 :             setResultType(MIRType::Int32);
   10267           0 :     }
   10268             : 
   10269             :     CompilerObject someTypedArray_;
   10270             : 
   10271             :     // An offset to be encoded in the load instruction - taking advantage of the
   10272             :     // addressing modes. This is only non-zero when the access is proven to be
   10273             :     // within bounds.
   10274             :     int32_t offset_;
   10275             :     bool needsBoundsCheck_;
   10276             :     bool fallible_;
   10277             : 
   10278             :   public:
   10279           0 :     INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
   10280           0 :     TRIVIAL_NEW_WRAPPERS
   10281             : 
   10282           0 :     Scalar::Type accessType() const {
   10283           0 :         return someTypedArray_->as<TypedArrayObject>().type();
   10284             :     }
   10285             :     SharedMem<void*> base() const;
   10286             :     size_t length() const;
   10287             : 
   10288           0 :     MDefinition* ptr() const { return getOperand(0); }
   10289           0 :     int32_t offset() const { return offset_; }
   10290             :     void setOffset(int32_t offset) { offset_ = offset; }
   10291             :     bool congruentTo(const MDefinition* ins) const override;
   10292           0 :     AliasSet getAliasSet() const override {
   10293           0 :         return AliasSet::Load(AliasSet::UnboxedElement);
   10294             :     }
   10295             : 
   10296           0 :     bool needsBoundsCheck() const { return needsBoundsCheck_; }
   10297           0 :     void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
   10298             : 
   10299           0 :     bool fallible() const {
   10300           0 :         return fallible_;
   10301             :     }
   10302             : 
   10303           0 :     void setInfallible() {
   10304           0 :         fallible_ = false;
   10305           0 :     }
   10306             : 
   10307             :     void computeRange(TempAllocator& alloc) override;
   10308             :     bool needTruncation(TruncateKind kind) override;
   10309           0 :     bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
   10310             :     void collectRangeInfoPreTrunc() override;
   10311             : 
   10312           0 :     bool appendRoots(MRootList& roots) const override {
   10313           0 :         return roots.append(someTypedArray_);
   10314             :     }
   10315             : };
   10316             : 
   10317             : // Base class for MIR ops that write unboxed scalar values.
   10318             : class StoreUnboxedScalarBase
   10319             : {
   10320             :     Scalar::Type writeType_;
   10321             : 
   10322             :   protected:
   10323           0 :     explicit StoreUnboxedScalarBase(Scalar::Type writeType)
   10324           0 :       : writeType_(writeType)
   10325             :     {
   10326           0 :         MOZ_ASSERT(isIntegerWrite() || isFloatWrite() || isSimdWrite());
   10327           0 :     }
   10328             : 
   10329             :   public:
   10330           0 :     void setWriteType(Scalar::Type type) {
   10331           0 :         writeType_ = type;
   10332           0 :     }
   10333           0 :     Scalar::Type writeType() const {
   10334           0 :         return writeType_;
   10335             :     }
   10336           0 :     bool isByteWrite() const {
   10337           0 :         return writeType_ == Scalar::Int8 ||
   10338           0 :                writeType_ == Scalar::Uint8 ||
   10339           0 :                writeType_ == Scalar::Uint8Clamped;
   10340             :     }
   10341           0 :     bool isIntegerWrite() const {
   10342           0 :         return isByteWrite () ||
   10343           0 :                writeType_ == Scalar::Int16 ||
   10344           0 :                writeType_ == Scalar::Uint16 ||
   10345           0 :                writeType_ == Scalar::Int32 ||
   10346           0 :                writeType_ == Scalar::Uint32;
   10347             :     }
   10348           0 :     bool isFloatWrite() const {
   10349           0 :         return writeType_ == Scalar::Float32 ||
   10350           0 :                writeType_ == Scalar::Float64;
   10351             :     }
   10352           0 :     bool isSimdWrite() const {
   10353           0 :         return Scalar::isSimdType(writeType());
   10354             :     }
   10355             : };
   10356             : 
   10357             : // Store an unboxed scalar value to a typed array or other object.
   10358           0 : class MStoreUnboxedScalar
   10359             :   : public MTernaryInstruction,
   10360             :     public StoreUnboxedScalarBase,
   10361             :     public StoreUnboxedScalarPolicy::Data
   10362             : {
   10363             :   public:
   10364             :     enum TruncateInputKind {
   10365             :         DontTruncateInput,
   10366             :         TruncateInput
   10367             :     };
   10368             : 
   10369             :   private:
   10370             :     Scalar::Type storageType_;
   10371             : 
   10372             :     // Whether this store truncates out of range inputs, for use by range analysis.
   10373             :     TruncateInputKind truncateInput_;
   10374             : 
   10375             :     bool requiresBarrier_;
   10376             :     int32_t offsetAdjustment_;
   10377             :     unsigned numElems_; // used only for SIMD
   10378             : 
   10379           0 :     MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
   10380             :                         Scalar::Type storageType, TruncateInputKind truncateInput,
   10381             :                         MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
   10382             :                         int32_t offsetAdjustment = 0)
   10383           0 :       : MTernaryInstruction(elements, index, value),
   10384             :         StoreUnboxedScalarBase(storageType),
   10385             :         storageType_(storageType),
   10386             :         truncateInput_(truncateInput),
   10387           0 :         requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
   10388             :         offsetAdjustment_(offsetAdjustment),
   10389           0 :         numElems_(1)
   10390             :     {
   10391           0 :         if (requiresBarrier_)
   10392           0 :             setGuard();         // Not removable or movable
   10393             :         else
   10394           0 :             setMovable();
   10395           0 :         MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
   10396           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   10397           0 :         MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
   10398           0 :     }
   10399             : 
   10400             :   public:
   10401           0 :     INSTRUCTION_HEADER(StoreUnboxedScalar)
   10402           0 :     TRIVIAL_NEW_WRAPPERS
   10403           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, value))
   10404             : 
   10405           0 :     void setSimdWrite(Scalar::Type writeType, unsigned numElems) {
   10406           0 :         MOZ_ASSERT(Scalar::isSimdType(writeType));
   10407           0 :         setWriteType(writeType);
   10408           0 :         numElems_ = numElems;
   10409           0 :     }
   10410           0 :     unsigned numElems() const {
   10411           0 :         return numElems_;
   10412             :     }
   10413           0 :     Scalar::Type storageType() const {
   10414           0 :         return storageType_;
   10415             :     }
   10416           0 :     AliasSet getAliasSet() const override {
   10417           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   10418             :     }
   10419           0 :     TruncateInputKind truncateInput() const {
   10420           0 :         return truncateInput_;
   10421             :     }
   10422           0 :     bool requiresMemoryBarrier() const {
   10423           0 :         return requiresBarrier_;
   10424             :     }
   10425           0 :     int32_t offsetAdjustment() const {
   10426           0 :         return offsetAdjustment_;
   10427             :     }
   10428             :     TruncateKind operandTruncateKind(size_t index) const override;
   10429             : 
   10430           0 :     bool canConsumeFloat32(MUse* use) const override {
   10431           0 :         return use == getUseFor(2) && writeType() == Scalar::Float32;
   10432             :     }
   10433             : 
   10434           0 :     ALLOW_CLONE(MStoreUnboxedScalar)
   10435             : };
   10436             : 
   10437           0 : class MStoreTypedArrayElementHole
   10438             :   : public MAryInstruction<4>,
   10439             :     public StoreUnboxedScalarBase,
   10440             :     public StoreTypedArrayHolePolicy::Data
   10441             : {
   10442           0 :     MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, MDefinition* index,
   10443             :                                 MDefinition* value, Scalar::Type arrayType)
   10444           0 :       : MAryInstruction<4>(),
   10445           0 :         StoreUnboxedScalarBase(arrayType)
   10446             :     {
   10447           0 :         initOperand(0, elements);
   10448           0 :         initOperand(1, length);
   10449           0 :         initOperand(2, index);
   10450           0 :         initOperand(3, value);
   10451           0 :         setMovable();
   10452           0 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
   10453           0 :         MOZ_ASSERT(length->type() == MIRType::Int32);
   10454           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   10455           0 :         MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
   10456           0 :     }
   10457             : 
   10458             :   public:
   10459           0 :     INSTRUCTION_HEADER(StoreTypedArrayElementHole)
   10460           0 :     TRIVIAL_NEW_WRAPPERS
   10461           0 :     NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value))
   10462             : 
   10463           0 :     Scalar::Type arrayType() const {
   10464           0 :         MOZ_ASSERT(!Scalar::isSimdType(writeType()),
   10465             :                    "arrayType == writeType iff the write type isn't SIMD");
   10466           0 :         return writeType();
   10467             :     }
   10468           0 :     AliasSet getAliasSet() const override {
   10469           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   10470             :     }
   10471             :     TruncateKind operandTruncateKind(size_t index) const override;
   10472             : 
   10473           0 :     bool canConsumeFloat32(MUse* use) const override {
   10474           0 :         return use == getUseFor(3) && arrayType() == Scalar::Float32;
   10475             :     }
   10476             : 
   10477           0 :     ALLOW_CLONE(MStoreTypedArrayElementHole)
   10478             : };
   10479             : 
   10480             : // Store a value infallibly to a statically known typed array.
   10481             : class MStoreTypedArrayElementStatic :
   10482             :     public MBinaryInstruction,
   10483             :     public StoreUnboxedScalarBase,
   10484             :     public StoreTypedArrayElementStaticPolicy::Data
   10485             : {
   10486           0 :     MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
   10487             :                                   int32_t offset = 0, bool needsBoundsCheck = true)
   10488           0 :         : MBinaryInstruction(ptr, v),
   10489           0 :           StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
   10490             :           someTypedArray_(someTypedArray),
   10491           0 :           offset_(offset), needsBoundsCheck_(needsBoundsCheck)
   10492           0 :     {}
   10493             : 
   10494             :     CompilerObject someTypedArray_;
   10495             : 
   10496             :     // An offset to be encoded in the store instruction - taking advantage of the
   10497             :     // addressing modes. This is only non-zero when the access is proven to be
   10498             :     // within bounds.
   10499             :     int32_t offset_;
   10500             :     bool needsBoundsCheck_;
   10501             : 
   10502             :   public:
   10503           0 :     INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
   10504           0 :     TRIVIAL_NEW_WRAPPERS
   10505             : 
   10506           0 :     Scalar::Type accessType() const {
   10507           0 :         return writeType();
   10508             :     }
   10509             : 
   10510             :     SharedMem<void*> base() const;
   10511             :     size_t length() const;
   10512             : 
   10513           0 :     MDefinition* ptr() const { return getOperand(0); }
   10514           0 :     MDefinition* value() const { return getOperand(1); }
   10515             :     bool needsBoundsCheck() const { return needsBoundsCheck_; }
   10516           0 :     void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
   10517           0 :     int32_t offset() const { return offset_; }
   10518             :     void setOffset(int32_t offset) { offset_ = offset; }
   10519           0 :     AliasSet getAliasSet() const override {
   10520           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   10521             :     }
   10522             :     TruncateKind operandTruncateKind(size_t index) const override;
   10523             : 
   10524           0 :     bool canConsumeFloat32(MUse* use) const override {
   10525           0 :         return use == getUseFor(1) && accessType() == Scalar::Float32;
   10526             :     }
   10527             :     void collectRangeInfoPreTrunc() override;
   10528             : 
   10529           0 :     bool appendRoots(MRootList& roots) const override {
   10530           0 :         return roots.append(someTypedArray_);
   10531             :     }
   10532             : };
   10533             : 
   10534             : // Compute an "effective address", i.e., a compound computation of the form:
   10535             : //   base + index * scale + displacement
   10536           0 : class MEffectiveAddress
   10537             :   : public MBinaryInstruction,
   10538             :     public NoTypePolicy::Data
   10539             : {
   10540           0 :     MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
   10541           0 :       : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
   10542             :     {
   10543           0 :         MOZ_ASSERT(base->type() == MIRType::Int32);
   10544           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   10545           0 :         setMovable();
   10546           0 :         setResultType(MIRType::Int32);
   10547           0 :     }
   10548             : 
   10549             :     Scale scale_;
   10550             :     int32_t displacement_;
   10551             : 
   10552             :   public:
   10553           0 :     INSTRUCTION_HEADER(EffectiveAddress)
   10554           0 :     TRIVIAL_NEW_WRAPPERS
   10555             : 
   10556           0 :     MDefinition* base() const {
   10557           0 :         return lhs();
   10558             :     }
   10559           0 :     MDefinition* index() const {
   10560           0 :         return rhs();
   10561             :     }
   10562           0 :     Scale scale() const {
   10563           0 :         return scale_;
   10564             :     }
   10565           0 :     int32_t displacement() const {
   10566           0 :         return displacement_;
   10567             :     }
   10568             : 
   10569           0 :     ALLOW_CLONE(MEffectiveAddress)
   10570             : };
   10571             : 
   10572             : // Clamp input to range [0, 255] for Uint8ClampedArray.
   10573           0 : class MClampToUint8
   10574             :   : public MUnaryInstruction,
   10575             :     public ClampPolicy::Data
   10576             : {
   10577           0 :     explicit MClampToUint8(MDefinition* input)
   10578           0 :       : MUnaryInstruction(input)
   10579             :     {
   10580           0 :         setResultType(MIRType::Int32);
   10581           0 :         setMovable();
   10582           0 :     }
   10583             : 
   10584             :   public:
   10585           0 :     INSTRUCTION_HEADER(ClampToUint8)
   10586           0 :     TRIVIAL_NEW_WRAPPERS
   10587             : 
   10588             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   10589             : 
   10590           0 :     bool congruentTo(const MDefinition* ins) const override {
   10591           0 :         return congruentIfOperandsEqual(ins);
   10592             :     }
   10593           0 :     AliasSet getAliasSet() const override {
   10594           0 :         return AliasSet::None();
   10595             :     }
   10596             :     void computeRange(TempAllocator& alloc) override;
   10597             : 
   10598           0 :     ALLOW_CLONE(MClampToUint8)
   10599             : };
   10600             : 
   10601           0 : class MLoadFixedSlot
   10602             :   : public MUnaryInstruction,
   10603             :     public SingleObjectPolicy::Data
   10604             : {
   10605             :     size_t slot_;
   10606             : 
   10607             :   protected:
   10608         675 :     MLoadFixedSlot(MDefinition* obj, size_t slot)
   10609         675 :       : MUnaryInstruction(obj), slot_(slot)
   10610             :     {
   10611         675 :         setResultType(MIRType::Value);
   10612         675 :         setMovable();
   10613         675 :     }
   10614             : 
   10615             :   public:
   10616       17426 :     INSTRUCTION_HEADER(LoadFixedSlot)
   10617         672 :     TRIVIAL_NEW_WRAPPERS
   10618          99 :     NAMED_OPERANDS((0, object))
   10619             : 
   10620         742 :     size_t slot() const {
   10621         742 :         return slot_;
   10622             :     }
   10623         278 :     bool congruentTo(const MDefinition* ins) const override {
   10624         278 :         if (!ins->isLoadFixedSlot())
   10625           0 :             return false;
   10626         278 :         if (slot() != ins->toLoadFixedSlot()->slot())
   10627         134 :             return false;
   10628         144 :         return congruentIfOperandsEqual(ins);
   10629             :     }
   10630             : 
   10631             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   10632             : 
   10633        2320 :     AliasSet getAliasSet() const override {
   10634        2320 :         return AliasSet::Load(AliasSet::FixedSlot);
   10635             :     }
   10636             : 
   10637             :     AliasType mightAlias(const MDefinition* store) const override;
   10638             : 
   10639           0 :     ALLOW_CLONE(MLoadFixedSlot)
   10640             : };
   10641             : 
   10642           0 : class MLoadFixedSlotAndUnbox
   10643             :   : public MUnaryInstruction,
   10644             :     public SingleObjectPolicy::Data
   10645             : {
   10646             :     size_t slot_;
   10647             :     MUnbox::Mode mode_;
   10648             :     BailoutKind bailoutKind_;
   10649             :   protected:
   10650           1 :     MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, MIRType type,
   10651             :                            BailoutKind kind)
   10652           1 :       : MUnaryInstruction(obj), slot_(slot), mode_(mode), bailoutKind_(kind)
   10653             :     {
   10654           1 :         setResultType(type);
   10655           1 :         setMovable();
   10656           1 :         if (mode_ == MUnbox::TypeBarrier || mode_ == MUnbox::Fallible)
   10657           1 :             setGuard();
   10658           1 :     }
   10659             : 
   10660             :   public:
   10661         266 :     INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)
   10662           1 :     TRIVIAL_NEW_WRAPPERS
   10663           1 :     NAMED_OPERANDS((0, object))
   10664             : 
   10665           3 :     size_t slot() const {
   10666           3 :         return slot_;
   10667             :     }
   10668           2 :     MUnbox::Mode mode() const {
   10669           2 :         return mode_;
   10670             :     }
   10671           1 :     BailoutKind bailoutKind() const {
   10672           1 :         return bailoutKind_;
   10673             :     }
   10674           2 :     bool fallible() const {
   10675           2 :         return mode_ != MUnbox::Infallible;
   10676             :     }
   10677           1 :     bool congruentTo(const MDefinition* ins) const override {
   10678           3 :         if (!ins->isLoadFixedSlotAndUnbox() ||
   10679           2 :             slot() != ins->toLoadFixedSlotAndUnbox()->slot() ||
   10680           1 :             mode() != ins->toLoadFixedSlotAndUnbox()->mode())
   10681             :         {
   10682           0 :             return false;
   10683             :         }
   10684           1 :         return congruentIfOperandsEqual(ins);
   10685             :     }
   10686             : 
   10687             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   10688             : 
   10689           6 :     AliasSet getAliasSet() const override {
   10690           6 :         return AliasSet::Load(AliasSet::FixedSlot);
   10691             :     }
   10692             : 
   10693             :     AliasType mightAlias(const MDefinition* store) const override;
   10694             : 
   10695           0 :     ALLOW_CLONE(MLoadFixedSlotAndUnbox);
   10696             : };
   10697             : 
   10698           0 : class MStoreFixedSlot
   10699             :   : public MBinaryInstruction,
   10700             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
   10701             : {
   10702             :     bool needsBarrier_;
   10703             :     size_t slot_;
   10704             : 
   10705         146 :     MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, bool barrier)
   10706         146 :       : MBinaryInstruction(obj, rval),
   10707             :         needsBarrier_(barrier),
   10708         146 :         slot_(slot)
   10709         146 :     { }
   10710             : 
   10711             :   public:
   10712       11196 :     INSTRUCTION_HEADER(StoreFixedSlot)
   10713         290 :     NAMED_OPERANDS((0, object), (1, value))
   10714             : 
   10715          62 :     static MStoreFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
   10716             :                                 MDefinition* rval)
   10717             :     {
   10718          62 :         return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
   10719             :     }
   10720          84 :     static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, size_t slot,
   10721             :                                          MDefinition* rval)
   10722             :     {
   10723          84 :         return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
   10724             :     }
   10725             : 
   10726         209 :     size_t slot() const {
   10727         209 :         return slot_;
   10728             :     }
   10729             : 
   10730         972 :     AliasSet getAliasSet() const override {
   10731         972 :         return AliasSet::Store(AliasSet::FixedSlot);
   10732             :     }
   10733          32 :     bool needsBarrier() const {
   10734          32 :         return needsBarrier_;
   10735             :     }
   10736          30 :     void setNeedsBarrier(bool needsBarrier = true) {
   10737          30 :         needsBarrier_ = needsBarrier;
   10738          30 :     }
   10739             : 
   10740           0 :     ALLOW_CLONE(MStoreFixedSlot)
   10741             : };
   10742             : 
   10743             : struct InliningTarget
   10744             : {
   10745             :     JSObject* target;
   10746             : 
   10747             :     // If target is a singleton, group is nullptr. If target is not a singleton,
   10748             :     // this is the group we need to guard on when doing a polymorphic inlining
   10749             :     // dispatch. Note that this can be different from target->group() due to
   10750             :     // proto mutation.
   10751             :     ObjectGroup* group;
   10752             : 
   10753         363 :     InliningTarget(JSObject* target, ObjectGroup* group)
   10754         363 :       : target(target), group(group)
   10755             :     {
   10756         363 :         MOZ_ASSERT(target->isSingleton() == !group);
   10757         363 :     }
   10758             : };
   10759             : 
   10760             : using InliningTargets = Vector<InliningTarget, 4, JitAllocPolicy>;
   10761             : using BoolVector = Vector<bool, 8, JitAllocPolicy>;
   10762             : 
   10763             : class InlinePropertyTable : public TempObject
   10764             : {
   10765             :     struct Entry : public TempObject {
   10766             :         CompilerObjectGroup group;
   10767             :         CompilerFunction func;
   10768             : 
   10769           0 :         Entry(ObjectGroup* group, JSFunction* func)
   10770           0 :           : group(group), func(func)
   10771           0 :         { }
   10772           0 :         bool appendRoots(MRootList& roots) const {
   10773           0 :             return roots.append(group) && roots.append(func);
   10774             :         }
   10775             :     };
   10776             : 
   10777             :     jsbytecode* pc_;
   10778             :     MResumePoint* priorResumePoint_;
   10779             :     Vector<Entry*, 4, JitAllocPolicy> entries_;
   10780             : 
   10781             :   public:
   10782           3 :     InlinePropertyTable(TempAllocator& alloc, jsbytecode* pc)
   10783           3 :       : pc_(pc), priorResumePoint_(nullptr), entries_(alloc)
   10784           3 :     { }
   10785             : 
   10786           0 :     void setPriorResumePoint(MResumePoint* resumePoint) {
   10787           0 :         MOZ_ASSERT(priorResumePoint_ == nullptr);
   10788           0 :         priorResumePoint_ = resumePoint;
   10789           0 :     }
   10790           0 :     bool hasPriorResumePoint() { return bool(priorResumePoint_); }
   10791           0 :     MResumePoint* takePriorResumePoint() {
   10792           0 :         MResumePoint* rp = priorResumePoint_;
   10793           0 :         priorResumePoint_ = nullptr;
   10794           0 :         return rp;
   10795             :     }
   10796             : 
   10797           0 :     jsbytecode* pc() const {
   10798           0 :         return pc_;
   10799             :     }
   10800             : 
   10801           0 :     MOZ_MUST_USE bool addEntry(TempAllocator& alloc, ObjectGroup* group, JSFunction* func) {
   10802           0 :         return entries_.append(new(alloc) Entry(group, func));
   10803             :     }
   10804             : 
   10805           3 :     size_t numEntries() const {
   10806           3 :         return entries_.length();
   10807             :     }
   10808             : 
   10809           0 :     ObjectGroup* getObjectGroup(size_t i) const {
   10810           0 :         MOZ_ASSERT(i < numEntries());
   10811           0 :         return entries_[i]->group;
   10812             :     }
   10813             : 
   10814           0 :     JSFunction* getFunction(size_t i) const {
   10815           0 :         MOZ_ASSERT(i < numEntries());
   10816           0 :         return entries_[i]->func;
   10817             :     }
   10818             : 
   10819             :     bool hasFunction(JSFunction* func) const;
   10820             :     bool hasObjectGroup(ObjectGroup* group) const;
   10821             : 
   10822             :     TemporaryTypeSet* buildTypeSetForFunction(JSFunction* func) const;
   10823             : 
   10824             :     // Remove targets that vetoed inlining from the InlinePropertyTable.
   10825             :     void trimTo(const InliningTargets& targets, const BoolVector& choiceSet);
   10826             : 
   10827             :     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
   10828             :     void trimToTargets(const InliningTargets& targets);
   10829             : 
   10830             :     bool appendRoots(MRootList& roots) const;
   10831             : };
   10832             : 
   10833             : class MGetPropertyCache
   10834             :   : public MBinaryInstruction,
   10835             :     public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
   10836             : {
   10837             :     bool idempotent_ : 1;
   10838             :     bool monitoredResult_ : 1;
   10839             : 
   10840             :     InlinePropertyTable* inlinePropertyTable_;
   10841             : 
   10842          37 :     MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
   10843          37 :       : MBinaryInstruction(obj, id),
   10844             :         idempotent_(false),
   10845             :         monitoredResult_(monitoredResult),
   10846          37 :         inlinePropertyTable_(nullptr)
   10847             :     {
   10848          37 :         setResultType(MIRType::Value);
   10849             : 
   10850             :         // The cache will invalidate if there are objects with e.g. lookup or
   10851             :         // resolve hooks on the proto chain. setGuard ensures this check is not
   10852             :         // eliminated.
   10853          37 :         setGuard();
   10854          37 :     }
   10855             : 
   10856             :   public:
   10857        8587 :     INSTRUCTION_HEADER(GetPropertyCache)
   10858          37 :     TRIVIAL_NEW_WRAPPERS
   10859          94 :     NAMED_OPERANDS((0, value), (1, idval))
   10860             : 
   10861           3 :     InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
   10862           3 :         MOZ_ASSERT(inlinePropertyTable_ == nullptr);
   10863           3 :         inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
   10864           3 :         return inlinePropertyTable_;
   10865             :     }
   10866             : 
   10867           3 :     void clearInlinePropertyTable() {
   10868           3 :         inlinePropertyTable_ = nullptr;
   10869           3 :     }
   10870             : 
   10871           4 :     InlinePropertyTable* propTable() const {
   10872           4 :         return inlinePropertyTable_;
   10873             :     }
   10874             : 
   10875           3 :     bool idempotent() const {
   10876           3 :         return idempotent_;
   10877             :     }
   10878           3 :     void setIdempotent() {
   10879           3 :         idempotent_ = true;
   10880           3 :         setMovable();
   10881           3 :     }
   10882          46 :     bool monitoredResult() const {
   10883          46 :         return monitoredResult_;
   10884             :     }
   10885             : 
   10886           3 :     bool congruentTo(const MDefinition* ins) const override {
   10887           3 :         if (!idempotent_)
   10888           0 :             return false;
   10889           3 :         if (!ins->isGetPropertyCache())
   10890           0 :             return false;
   10891           3 :         return congruentIfOperandsEqual(ins);
   10892             :     }
   10893             : 
   10894         319 :     AliasSet getAliasSet() const override {
   10895         319 :         if (idempotent_) {
   10896             :             return AliasSet::Load(AliasSet::ObjectFields |
   10897             :                                   AliasSet::FixedSlot |
   10898          68 :                                   AliasSet::DynamicSlot);
   10899             :         }
   10900         251 :         return AliasSet::Store(AliasSet::Any);
   10901             :     }
   10902             : 
   10903             :     bool allowDoubleResult() const;
   10904             : 
   10905          26 :     bool appendRoots(MRootList& roots) const override {
   10906          26 :         if (inlinePropertyTable_)
   10907           0 :             return inlinePropertyTable_->appendRoots(roots);
   10908          26 :         return true;
   10909             :     }
   10910             : };
   10911             : 
   10912           0 : struct PolymorphicEntry {
   10913             :     // The group and/or shape to guard against.
   10914             :     ReceiverGuard receiver;
   10915             : 
   10916             :     // The property to load, null for loads from unboxed properties.
   10917             :     Shape* shape;
   10918             : 
   10919           0 :     bool appendRoots(MRootList& roots) const {
   10920           0 :         return roots.append(receiver) && roots.append(shape);
   10921             :     }
   10922             : };
   10923             : 
   10924             : // Emit code to load a value from an object if it matches one of the receivers
   10925             : // observed by the baseline IC, else bails out.
   10926             : class MGetPropertyPolymorphic
   10927             :   : public MUnaryInstruction,
   10928             :     public SingleObjectPolicy::Data
   10929             : {
   10930             :     Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
   10931             :     CompilerPropertyName name_;
   10932             : 
   10933           0 :     MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
   10934           0 :       : MUnaryInstruction(obj),
   10935             :         receivers_(alloc),
   10936           0 :         name_(name)
   10937             :     {
   10938           0 :         setGuard();
   10939           0 :         setMovable();
   10940           0 :         setResultType(MIRType::Value);
   10941           0 :     }
   10942             : 
   10943             :   public:
   10944           0 :     INSTRUCTION_HEADER(GetPropertyPolymorphic)
   10945           0 :     NAMED_OPERANDS((0, object))
   10946             : 
   10947           0 :     static MGetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name) {
   10948           0 :         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
   10949             :     }
   10950             : 
   10951           0 :     bool congruentTo(const MDefinition* ins) const override {
   10952           0 :         if (!ins->isGetPropertyPolymorphic())
   10953           0 :             return false;
   10954           0 :         if (name() != ins->toGetPropertyPolymorphic()->name())
   10955           0 :             return false;
   10956           0 :         return congruentIfOperandsEqual(ins);
   10957             :     }
   10958             : 
   10959           0 :     MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
   10960           0 :         PolymorphicEntry entry;
   10961           0 :         entry.receiver = receiver;
   10962           0 :         entry.shape = shape;
   10963           0 :         return receivers_.append(entry);
   10964             :     }
   10965           0 :     size_t numReceivers() const {
   10966           0 :         return receivers_.length();
   10967             :     }
   10968           0 :     const ReceiverGuard receiver(size_t i) const {
   10969           0 :         return receivers_[i].receiver;
   10970             :     }
   10971           0 :     Shape* shape(size_t i) const {
   10972           0 :         return receivers_[i].shape;
   10973             :     }
   10974           0 :     PropertyName* name() const {
   10975           0 :         return name_;
   10976             :     }
   10977           0 :     AliasSet getAliasSet() const override {
   10978           0 :         bool hasUnboxedLoad = false;
   10979           0 :         for (size_t i = 0; i < numReceivers(); i++) {
   10980           0 :             if (!shape(i)) {
   10981           0 :                 hasUnboxedLoad = true;
   10982           0 :                 break;
   10983             :             }
   10984             :         }
   10985             :         return AliasSet::Load(AliasSet::ObjectFields |
   10986             :                               AliasSet::FixedSlot |
   10987             :                               AliasSet::DynamicSlot |
   10988           0 :                               (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
   10989             :     }
   10990             : 
   10991             :     AliasType mightAlias(const MDefinition* store) const override;
   10992             : 
   10993             :     bool appendRoots(MRootList& roots) const override;
   10994             : };
   10995             : 
   10996             : // Emit code to store a value to an object's slots if its shape/group matches
   10997             : // one of the shapes/groups observed by the baseline IC, else bails out.
   10998             : class MSetPropertyPolymorphic
   10999             :   : public MBinaryInstruction,
   11000             :     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
   11001             : {
   11002             :     Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
   11003             :     CompilerPropertyName name_;
   11004             :     bool needsBarrier_;
   11005             : 
   11006           0 :     MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
   11007             :                             PropertyName* name)
   11008           0 :       : MBinaryInstruction(obj, value),
   11009             :         receivers_(alloc),
   11010             :         name_(name),
   11011           0 :         needsBarrier_(false)
   11012             :     {
   11013           0 :     }
   11014             : 
   11015             :   public:
   11016           0 :     INSTRUCTION_HEADER(SetPropertyPolymorphic)
   11017           0 :     NAMED_OPERANDS((0, object), (1, value))
   11018             : 
   11019           0 :     static MSetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
   11020             :                                         PropertyName* name) {
   11021           0 :         return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
   11022             :     }
   11023             : 
   11024           0 :     MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
   11025           0 :         PolymorphicEntry entry;
   11026           0 :         entry.receiver = receiver;
   11027           0 :         entry.shape = shape;
   11028           0 :         return receivers_.append(entry);
   11029             :     }
   11030           0 :     size_t numReceivers() const {
   11031           0 :         return receivers_.length();
   11032             :     }
   11033           0 :     const ReceiverGuard& receiver(size_t i) const {
   11034           0 :         return receivers_[i].receiver;
   11035             :     }
   11036           0 :     Shape* shape(size_t i) const {
   11037           0 :         return receivers_[i].shape;
   11038             :     }
   11039           0 :     PropertyName* name() const {
   11040           0 :         return name_;
   11041             :     }
   11042           0 :     bool needsBarrier() const {
   11043           0 :         return needsBarrier_;
   11044             :     }
   11045           0 :     void setNeedsBarrier() {
   11046           0 :         needsBarrier_ = true;
   11047           0 :     }
   11048           0 :     AliasSet getAliasSet() const override {
   11049           0 :         bool hasUnboxedStore = false;
   11050           0 :         for (size_t i = 0; i < numReceivers(); i++) {
   11051           0 :             if (!shape(i)) {
   11052           0 :                 hasUnboxedStore = true;
   11053           0 :                 break;
   11054             :             }
   11055             :         }
   11056             :         return AliasSet::Store(AliasSet::ObjectFields |
   11057             :                                AliasSet::FixedSlot |
   11058             :                                AliasSet::DynamicSlot |
   11059           0 :                                (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
   11060             :     }
   11061             :     bool appendRoots(MRootList& roots) const override;
   11062             : };
   11063             : 
   11064             : class MDispatchInstruction
   11065             :   : public MControlInstruction,
   11066             :     public SingleObjectPolicy::Data
   11067             : {
   11068             :     // Map from JSFunction* -> MBasicBlock.
   11069             :     struct Entry {
   11070             :         JSFunction* func;
   11071             :         // If |func| has a singleton group, |funcGroup| is null. Otherwise,
   11072             :         // |funcGroup| holds the ObjectGroup for |func|, and dispatch guards
   11073             :         // on the group instead of directly on the function.
   11074             :         ObjectGroup* funcGroup;
   11075             :         MBasicBlock* block;
   11076             : 
   11077           4 :         Entry(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block)
   11078           4 :           : func(func), funcGroup(funcGroup), block(block)
   11079           4 :         { }
   11080           3 :         bool appendRoots(MRootList& roots) const {
   11081           3 :             return roots.append(func) && roots.append(funcGroup);
   11082             :         }
   11083             :     };
   11084             :     Vector<Entry, 4, JitAllocPolicy> map_;
   11085             : 
   11086             :     // An optional fallback path that uses MCall.
   11087             :     MBasicBlock* fallback_;
   11088             :     MUse operand_;
   11089             : 
   11090           4 :     void initOperand(size_t index, MDefinition* operand) {
   11091           4 :         MOZ_ASSERT(index == 0);
   11092           4 :         operand_.init(operand, this);
   11093           4 :     }
   11094             : 
   11095             :   public:
   11096           3 :     NAMED_OPERANDS((0, input))
   11097           4 :     MDispatchInstruction(TempAllocator& alloc, MDefinition* input)
   11098           4 :       : map_(alloc), fallback_(nullptr)
   11099             :     {
   11100           4 :         initOperand(0, input);
   11101           4 :     }
   11102             : 
   11103             :   protected:
   11104          99 :     MUse* getUseFor(size_t index) final override {
   11105          99 :         MOZ_ASSERT(index == 0);
   11106          99 :         return &operand_;
   11107             :     }
   11108          99 :     const MUse* getUseFor(size_t index) const final override {
   11109          99 :         MOZ_ASSERT(index == 0);
   11110          99 :         return &operand_;
   11111             :     }
   11112         159 :     MDefinition* getOperand(size_t index) const final override {
   11113         159 :         MOZ_ASSERT(index == 0);
   11114         159 :         return operand_.producer();
   11115             :     }
   11116         153 :     size_t numOperands() const final override {
   11117         153 :         return 1;
   11118             :     }
   11119          99 :     size_t indexOf(const MUse* u) const final override {
   11120          99 :         MOZ_ASSERT(u == getUseFor(0));
   11121          99 :         return 0;
   11122             :     }
   11123           0 :     void replaceOperand(size_t index, MDefinition* operand) final override {
   11124           0 :         MOZ_ASSERT(index == 0);
   11125           0 :         operand_.replaceProducer(operand);
   11126           0 :     }
   11127             : 
   11128             :   public:
   11129           0 :     void setSuccessor(size_t i, MBasicBlock* successor) {
   11130           0 :         MOZ_ASSERT(i < numSuccessors());
   11131           0 :         if (i == map_.length())
   11132           0 :             fallback_ = successor;
   11133             :         else
   11134           0 :             map_[i].block = successor;
   11135           0 :     }
   11136        2325 :     size_t numSuccessors() const final override {
   11137        2325 :         return map_.length() + (fallback_ ? 1 : 0);
   11138             :     }
   11139           0 :     void replaceSuccessor(size_t i, MBasicBlock* successor) final override {
   11140           0 :         setSuccessor(i, successor);
   11141           0 :     }
   11142         936 :     MBasicBlock* getSuccessor(size_t i) const final override {
   11143         936 :         MOZ_ASSERT(i < numSuccessors());
   11144         936 :         if (i == map_.length())
   11145         426 :             return fallback_;
   11146         510 :         return map_[i].block;
   11147             :     }
   11148             : 
   11149             :   public:
   11150           4 :     MOZ_MUST_USE bool addCase(JSFunction* func, ObjectGroup* funcGroup, MBasicBlock* block) {
   11151           4 :         return map_.append(Entry(func, funcGroup, block));
   11152             :     }
   11153          14 :     uint32_t numCases() const {
   11154          14 :         return map_.length();
   11155             :     }
   11156           0 :     JSFunction* getCase(uint32_t i) const {
   11157           0 :         return map_[i].func;
   11158             :     }
   11159           3 :     ObjectGroup* getCaseObjectGroup(uint32_t i) const {
   11160           3 :         return map_[i].funcGroup;
   11161             :     }
   11162           3 :     MBasicBlock* getCaseBlock(uint32_t i) const {
   11163           3 :         return map_[i].block;
   11164             :     }
   11165             : 
   11166          10 :     bool hasFallback() const {
   11167          10 :         return bool(fallback_);
   11168             :     }
   11169           4 :     void addFallback(MBasicBlock* block) {
   11170           4 :         MOZ_ASSERT(!hasFallback());
   11171           4 :         fallback_ = block;
   11172           4 :     }
   11173           3 :     MBasicBlock* getFallback() const {
   11174           3 :         MOZ_ASSERT(hasFallback());
   11175           3 :         return fallback_;
   11176             :     }
   11177             :     bool appendRoots(MRootList& roots) const override;
   11178             : };
   11179             : 
   11180             : // Polymorphic dispatch for inlining, keyed off incoming ObjectGroup.
   11181             : class MObjectGroupDispatch : public MDispatchInstruction
   11182             : {
   11183             :     // Map ObjectGroup (of CallProp's Target Object) -> JSFunction (yielded by the CallProp).
   11184             :     InlinePropertyTable* inlinePropertyTable_;
   11185             : 
   11186           0 :     MObjectGroupDispatch(TempAllocator& alloc, MDefinition* input, InlinePropertyTable* table)
   11187           0 :       : MDispatchInstruction(alloc, input),
   11188           0 :         inlinePropertyTable_(table)
   11189           0 :     { }
   11190             : 
   11191             :   public:
   11192           0 :     INSTRUCTION_HEADER(ObjectGroupDispatch)
   11193             : 
   11194           0 :     static MObjectGroupDispatch* New(TempAllocator& alloc, MDefinition* ins,
   11195             :                                      InlinePropertyTable* table)
   11196             :     {
   11197           0 :         return new(alloc) MObjectGroupDispatch(alloc, ins, table);
   11198             :     }
   11199             : 
   11200           0 :     InlinePropertyTable* propTable() const {
   11201           0 :         return inlinePropertyTable_;
   11202             :     }
   11203             :     bool appendRoots(MRootList& roots) const override;
   11204             : };
   11205             : 
   11206             : // Polymorphic dispatch for inlining, keyed off incoming JSFunction*.
   11207             : class MFunctionDispatch : public MDispatchInstruction
   11208             : {
   11209           4 :     MFunctionDispatch(TempAllocator& alloc, MDefinition* input)
   11210           4 :       : MDispatchInstruction(alloc, input)
   11211           4 :     { }
   11212             : 
   11213             :   public:
   11214          87 :     INSTRUCTION_HEADER(FunctionDispatch)
   11215             : 
   11216           4 :     static MFunctionDispatch* New(TempAllocator& alloc, MDefinition* ins) {
   11217           4 :         return new(alloc) MFunctionDispatch(alloc, ins);
   11218             :     }
   11219             :     bool appendRoots(MRootList& roots) const override;
   11220             : };
   11221             : 
   11222             : class MBindNameCache
   11223             :   : public MUnaryInstruction,
   11224             :     public SingleObjectPolicy::Data
   11225             : {
   11226             :     CompilerPropertyName name_;
   11227             :     CompilerScript script_;
   11228             :     jsbytecode* pc_;
   11229             : 
   11230           0 :     MBindNameCache(MDefinition* envChain, PropertyName* name, JSScript* script, jsbytecode* pc)
   11231           0 :       : MUnaryInstruction(envChain), name_(name), script_(script), pc_(pc)
   11232             :     {
   11233           0 :         setResultType(MIRType::Object);
   11234           0 :     }
   11235             : 
   11236             :   public:
   11237           0 :     INSTRUCTION_HEADER(BindNameCache)
   11238           0 :     TRIVIAL_NEW_WRAPPERS
   11239           0 :     NAMED_OPERANDS((0, environmentChain))
   11240             : 
   11241             :     PropertyName* name() const {
   11242             :         return name_;
   11243             :     }
   11244             :     JSScript* script() const {
   11245             :         return script_;
   11246             :     }
   11247             :     jsbytecode* pc() const {
   11248             :         return pc_;
   11249             :     }
   11250           0 :     bool appendRoots(MRootList& roots) const override {
   11251             :         // Don't append the script, all scripts are added anyway.
   11252           0 :         return roots.append(name_);
   11253             :     }
   11254             : };
   11255             : 
   11256             : class MCallBindVar
   11257             :   : public MUnaryInstruction,
   11258             :     public SingleObjectPolicy::Data
   11259             : {
   11260           0 :     explicit MCallBindVar(MDefinition* envChain)
   11261           0 :       : MUnaryInstruction(envChain)
   11262             :     {
   11263           0 :         setResultType(MIRType::Object);
   11264           0 :         setMovable();
   11265           0 :     }
   11266             : 
   11267             :   public:
   11268           0 :     INSTRUCTION_HEADER(CallBindVar)
   11269           0 :     TRIVIAL_NEW_WRAPPERS
   11270           0 :     NAMED_OPERANDS((0, environmentChain))
   11271             : 
   11272           0 :     bool congruentTo(const MDefinition* ins) const override {
   11273           0 :         if (!ins->isCallBindVar())
   11274           0 :             return false;
   11275           0 :         return congruentIfOperandsEqual(ins);
   11276             :     }
   11277             : 
   11278           0 :     AliasSet getAliasSet() const override {
   11279           0 :         return AliasSet::None();
   11280             :     }
   11281             : };
   11282             : 
   11283             : // Guard on an object's shape.
   11284             : class MGuardShape
   11285             :   : public MUnaryInstruction,
   11286             :     public SingleObjectPolicy::Data
   11287             : {
   11288             :     CompilerShape shape_;
   11289             :     BailoutKind bailoutKind_;
   11290             : 
   11291           9 :     MGuardShape(MDefinition* obj, Shape* shape, BailoutKind bailoutKind)
   11292           9 :       : MUnaryInstruction(obj),
   11293             :         shape_(shape),
   11294           9 :         bailoutKind_(bailoutKind)
   11295             :     {
   11296           9 :         setGuard();
   11297           9 :         setMovable();
   11298           9 :         setResultType(MIRType::Object);
   11299           9 :         setResultTypeSet(obj->resultTypeSet());
   11300             : 
   11301             :         // Disallow guarding on unboxed object shapes. The group is better to
   11302             :         // guard on, and guarding on the shape can interact badly with
   11303             :         // MConvertUnboxedObjectToNative.
   11304           9 :         MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
   11305           9 :     }
   11306             : 
   11307             :   public:
   11308        3077 :     INSTRUCTION_HEADER(GuardShape)
   11309           9 :     TRIVIAL_NEW_WRAPPERS
   11310          24 :     NAMED_OPERANDS((0, object))
   11311             : 
   11312          38 :     const Shape* shape() const {
   11313          38 :         return shape_;
   11314             :     }
   11315          38 :     BailoutKind bailoutKind() const {
   11316          38 :         return bailoutKind_;
   11317             :     }
   11318          15 :     bool congruentTo(const MDefinition* ins) const override {
   11319          15 :         if (!ins->isGuardShape())
   11320           0 :             return false;
   11321          15 :         if (shape() != ins->toGuardShape()->shape())
   11322           0 :             return false;
   11323          15 :         if (bailoutKind() != ins->toGuardShape()->bailoutKind())
   11324           0 :             return false;
   11325          15 :         return congruentIfOperandsEqual(ins);
   11326             :     }
   11327         324 :     AliasSet getAliasSet() const override {
   11328         324 :         return AliasSet::Load(AliasSet::ObjectFields);
   11329             :     }
   11330           8 :     bool appendRoots(MRootList& roots) const override {
   11331           8 :         return roots.append(shape_);
   11332             :     }
   11333             : };
   11334             : 
   11335             : // Bail if the object's shape or unboxed group is not in the input list.
   11336             : class MGuardReceiverPolymorphic
   11337             :   : public MUnaryInstruction,
   11338             :     public SingleObjectPolicy::Data
   11339             : {
   11340             :     Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
   11341             : 
   11342           0 :     MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
   11343           0 :       : MUnaryInstruction(obj),
   11344           0 :         receivers_(alloc)
   11345             :     {
   11346           0 :         setGuard();
   11347           0 :         setMovable();
   11348           0 :         setResultType(MIRType::Object);
   11349           0 :         setResultTypeSet(obj->resultTypeSet());
   11350           0 :     }
   11351             : 
   11352             :   public:
   11353           0 :     INSTRUCTION_HEADER(GuardReceiverPolymorphic)
   11354           0 :     NAMED_OPERANDS((0, object))
   11355             : 
   11356           0 :     static MGuardReceiverPolymorphic* New(TempAllocator& alloc, MDefinition* obj) {
   11357           0 :         return new(alloc) MGuardReceiverPolymorphic(alloc, obj);
   11358             :     }
   11359             : 
   11360           0 :     MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver) {
   11361           0 :         return receivers_.append(receiver);
   11362             :     }
   11363           0 :     size_t numReceivers() const {
   11364           0 :         return receivers_.length();
   11365             :     }
   11366           0 :     const ReceiverGuard& receiver(size_t i) const {
   11367           0 :         return receivers_[i];
   11368             :     }
   11369             : 
   11370             :     bool congruentTo(const MDefinition* ins) const override;
   11371             : 
   11372           0 :     AliasSet getAliasSet() const override {
   11373           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11374             :     }
   11375             : 
   11376             :     bool appendRoots(MRootList& roots) const override;
   11377             : 
   11378             : };
   11379             : 
   11380             : // Guard on an object's group, inclusively or exclusively.
   11381             : class MGuardObjectGroup
   11382             :   : public MUnaryInstruction,
   11383             :     public SingleObjectPolicy::Data
   11384             : {
   11385             :     CompilerObjectGroup group_;
   11386             :     bool bailOnEquality_;
   11387             :     BailoutKind bailoutKind_;
   11388             : 
   11389           0 :     MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
   11390             :                       BailoutKind bailoutKind)
   11391           0 :       : MUnaryInstruction(obj),
   11392             :         group_(group),
   11393             :         bailOnEquality_(bailOnEquality),
   11394           0 :         bailoutKind_(bailoutKind)
   11395             :     {
   11396           0 :         setGuard();
   11397           0 :         setMovable();
   11398           0 :         setResultType(MIRType::Object);
   11399             : 
   11400             :         // Unboxed groups which might be converted to natives can't be guarded
   11401             :         // on, due to MConvertUnboxedObjectToNative.
   11402           0 :         MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
   11403             :                       !group->unboxedLayoutDontCheckGeneration().nativeGroup());
   11404           0 :     }
   11405             : 
   11406             :   public:
   11407           0 :     INSTRUCTION_HEADER(GuardObjectGroup)
   11408           0 :     TRIVIAL_NEW_WRAPPERS
   11409           0 :     NAMED_OPERANDS((0, object))
   11410             : 
   11411           0 :     const ObjectGroup* group() const {
   11412           0 :         return group_;
   11413             :     }
   11414           0 :     bool bailOnEquality() const {
   11415           0 :         return bailOnEquality_;
   11416             :     }
   11417           0 :     BailoutKind bailoutKind() const {
   11418           0 :         return bailoutKind_;
   11419             :     }
   11420           0 :     bool congruentTo(const MDefinition* ins) const override {
   11421           0 :         if (!ins->isGuardObjectGroup())
   11422           0 :             return false;
   11423           0 :         if (group() != ins->toGuardObjectGroup()->group())
   11424           0 :             return false;
   11425           0 :         if (bailOnEquality() != ins->toGuardObjectGroup()->bailOnEquality())
   11426           0 :             return false;
   11427           0 :         if (bailoutKind() != ins->toGuardObjectGroup()->bailoutKind())
   11428           0 :             return false;
   11429           0 :         return congruentIfOperandsEqual(ins);
   11430             :     }
   11431           0 :     AliasSet getAliasSet() const override {
   11432           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11433             :     }
   11434           0 :     bool appendRoots(MRootList& roots) const override {
   11435           0 :         return roots.append(group_);
   11436             :     }
   11437             : };
   11438             : 
   11439             : // Guard on an object's identity, inclusively or exclusively.
   11440             : class MGuardObjectIdentity
   11441             :   : public MBinaryInstruction,
   11442             :     public SingleObjectPolicy::Data
   11443             : {
   11444             :     bool bailOnEquality_;
   11445             : 
   11446           0 :     MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
   11447           0 :       : MBinaryInstruction(obj, expected),
   11448           0 :         bailOnEquality_(bailOnEquality)
   11449             :     {
   11450           0 :         setGuard();
   11451           0 :         setMovable();
   11452           0 :         setResultType(MIRType::Object);
   11453           0 :     }
   11454             : 
   11455             :   public:
   11456           0 :     INSTRUCTION_HEADER(GuardObjectIdentity)
   11457           0 :     TRIVIAL_NEW_WRAPPERS
   11458           0 :     NAMED_OPERANDS((0, object), (1, expected))
   11459             : 
   11460           0 :     bool bailOnEquality() const {
   11461           0 :         return bailOnEquality_;
   11462             :     }
   11463           0 :     bool congruentTo(const MDefinition* ins) const override {
   11464           0 :         if (!ins->isGuardObjectIdentity())
   11465           0 :             return false;
   11466           0 :         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
   11467           0 :             return false;
   11468           0 :         return congruentIfOperandsEqual(ins);
   11469             :     }
   11470           0 :     AliasSet getAliasSet() const override {
   11471           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11472             :     }
   11473             : };
   11474             : 
   11475             : // Guard on an object's class.
   11476           0 : class MGuardClass
   11477             :   : public MUnaryInstruction,
   11478             :     public SingleObjectPolicy::Data
   11479             : {
   11480             :     const Class* class_;
   11481             : 
   11482             :     MGuardClass(MDefinition* obj, const Class* clasp)
   11483             :       : MUnaryInstruction(obj),
   11484             :         class_(clasp)
   11485             :     {
   11486             :         setGuard();
   11487             :         setMovable();
   11488             :     }
   11489             : 
   11490             :   public:
   11491           0 :     INSTRUCTION_HEADER(GuardClass)
   11492             :     TRIVIAL_NEW_WRAPPERS
   11493           0 :     NAMED_OPERANDS((0, object))
   11494             : 
   11495           0 :     const Class* getClass() const {
   11496           0 :         return class_;
   11497             :     }
   11498           0 :     bool congruentTo(const MDefinition* ins) const override {
   11499           0 :         if (!ins->isGuardClass())
   11500           0 :             return false;
   11501           0 :         if (getClass() != ins->toGuardClass()->getClass())
   11502           0 :             return false;
   11503           0 :         return congruentIfOperandsEqual(ins);
   11504             :     }
   11505           0 :     AliasSet getAliasSet() const override {
   11506           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11507             :     }
   11508             : 
   11509           0 :     ALLOW_CLONE(MGuardClass)
   11510             : };
   11511             : 
   11512             : // Guard on the presence or absence of an unboxed object's expando.
   11513             : class MGuardUnboxedExpando
   11514             :   : public MUnaryInstruction,
   11515             :     public SingleObjectPolicy::Data
   11516             : {
   11517             :     bool requireExpando_;
   11518             :     BailoutKind bailoutKind_;
   11519             : 
   11520           0 :     MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
   11521           0 :       : MUnaryInstruction(obj),
   11522             :         requireExpando_(requireExpando),
   11523           0 :         bailoutKind_(bailoutKind)
   11524             :     {
   11525           0 :         setGuard();
   11526           0 :         setMovable();
   11527           0 :         setResultType(MIRType::Object);
   11528           0 :     }
   11529             : 
   11530             :   public:
   11531           0 :     INSTRUCTION_HEADER(GuardUnboxedExpando)
   11532           0 :     TRIVIAL_NEW_WRAPPERS
   11533           0 :     NAMED_OPERANDS((0, object))
   11534             : 
   11535           0 :     bool requireExpando() const {
   11536           0 :         return requireExpando_;
   11537             :     }
   11538           0 :     BailoutKind bailoutKind() const {
   11539           0 :         return bailoutKind_;
   11540             :     }
   11541           0 :     bool congruentTo(const MDefinition* ins) const override {
   11542           0 :         if (!congruentIfOperandsEqual(ins))
   11543           0 :             return false;
   11544           0 :         if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
   11545           0 :             return false;
   11546           0 :         return true;
   11547             :     }
   11548           0 :     AliasSet getAliasSet() const override {
   11549           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11550             :     }
   11551             : };
   11552             : 
   11553             : // Load an unboxed plain object's expando.
   11554             : class MLoadUnboxedExpando
   11555             :   : public MUnaryInstruction,
   11556             :     public SingleObjectPolicy::Data
   11557             : {
   11558             :   private:
   11559           0 :     explicit MLoadUnboxedExpando(MDefinition* object)
   11560           0 :       : MUnaryInstruction(object)
   11561             :     {
   11562           0 :         setResultType(MIRType::Object);
   11563           0 :         setMovable();
   11564           0 :     }
   11565             : 
   11566             :   public:
   11567           0 :     INSTRUCTION_HEADER(LoadUnboxedExpando)
   11568           0 :     TRIVIAL_NEW_WRAPPERS
   11569           0 :     NAMED_OPERANDS((0, object))
   11570             : 
   11571           0 :     bool congruentTo(const MDefinition* ins) const override {
   11572           0 :         return congruentIfOperandsEqual(ins);
   11573             :     }
   11574           0 :     AliasSet getAliasSet() const override {
   11575           0 :         return AliasSet::Load(AliasSet::ObjectFields);
   11576             :     }
   11577             : };
   11578             : 
   11579             : // Load from vp[slot] (slots that are not inline in an object).
   11580           0 : class MLoadSlot
   11581             :   : public MUnaryInstruction,
   11582             :     public SingleObjectPolicy::Data
   11583             : {
   11584             :     uint32_t slot_;
   11585             : 
   11586           9 :     MLoadSlot(MDefinition* slots, uint32_t slot)
   11587           9 :       : MUnaryInstruction(slots),
   11588           9 :         slot_(slot)
   11589             :     {
   11590           9 :         setResultType(MIRType::Value);
   11591           9 :         setMovable();
   11592           9 :         MOZ_ASSERT(slots->type() == MIRType::Slots);
   11593           9 :     }
   11594             : 
   11595             :   public:
   11596        2133 :     INSTRUCTION_HEADER(LoadSlot)
   11597           9 :     TRIVIAL_NEW_WRAPPERS
   11598         267 :     NAMED_OPERANDS((0, slots))
   11599             : 
   11600          33 :     uint32_t slot() const {
   11601          33 :         return slot_;
   11602             :     }
   11603             : 
   11604             :     HashNumber valueHash() const override;
   11605          13 :     bool congruentTo(const MDefinition* ins) const override {
   11606          13 :         if (!ins->isLoadSlot())
   11607           0 :             return false;
   11608          13 :         if (slot() != ins->toLoadSlot()->slot())
   11609           0 :             return false;
   11610          13 :         return congruentIfOperandsEqual(ins);
   11611             :     }
   11612             : 
   11613             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   11614             : 
   11615         260 :     AliasSet getAliasSet() const override {
   11616         260 :         MOZ_ASSERT(slots()->type() == MIRType::Slots);
   11617         260 :         return AliasSet::Load(AliasSet::DynamicSlot);
   11618             :     }
   11619             :     AliasType mightAlias(const MDefinition* store) const override;
   11620             : 
   11621             :     void printOpcode(GenericPrinter& out) const override;
   11622             : 
   11623           0 :     ALLOW_CLONE(MLoadSlot)
   11624             : };
   11625             : 
   11626             : // Inline call to access a function's environment (scope chain).
   11627             : class MFunctionEnvironment
   11628             :   : public MUnaryInstruction,
   11629             :     public SingleObjectPolicy::Data
   11630             : {
   11631         143 :     explicit MFunctionEnvironment(MDefinition* function)
   11632         143 :         : MUnaryInstruction(function)
   11633             :     {
   11634         143 :         setResultType(MIRType::Object);
   11635         143 :         setMovable();
   11636         143 :     }
   11637             : 
   11638             :   public:
   11639        3266 :     INSTRUCTION_HEADER(FunctionEnvironment)
   11640         143 :     TRIVIAL_NEW_WRAPPERS
   11641           6 :     NAMED_OPERANDS((0, function))
   11642             : 
   11643             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   11644             : 
   11645             :     // A function's environment is fixed.
   11646          48 :     AliasSet getAliasSet() const override {
   11647          48 :         return AliasSet::None();
   11648             :     }
   11649             : };
   11650             : 
   11651             : // Allocate a new LexicalEnvironmentObject.
   11652             : class MNewLexicalEnvironmentObject
   11653             :   : public MUnaryInstruction,
   11654             :     public SingleObjectPolicy::Data
   11655             : {
   11656             :     CompilerGCPointer<LexicalScope*> scope_;
   11657             : 
   11658           4 :     MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
   11659           4 :       : MUnaryInstruction(enclosing),
   11660           4 :         scope_(scope)
   11661             :     {
   11662           4 :         setResultType(MIRType::Object);
   11663           4 :     }
   11664             : 
   11665             :   public:
   11666           0 :     INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
   11667           4 :     TRIVIAL_NEW_WRAPPERS
   11668           0 :     NAMED_OPERANDS((0, enclosing))
   11669             : 
   11670           0 :     LexicalScope* scope() const {
   11671           0 :         return scope_;
   11672             :     }
   11673           0 :     bool possiblyCalls() const override {
   11674           0 :         return true;
   11675             :     }
   11676           0 :     bool appendRoots(MRootList& roots) const override {
   11677           0 :         return roots.append(scope_);
   11678             :     }
   11679           0 :     AliasSet getAliasSet() const override {
   11680           0 :         return AliasSet::None();
   11681             :     }
   11682             : };
   11683             : 
   11684             : // Allocate a new LexicalEnvironmentObject from existing one
   11685             : class MCopyLexicalEnvironmentObject
   11686             :   : public MUnaryInstruction,
   11687             :     public SingleObjectPolicy::Data
   11688             : {
   11689             :     bool copySlots_;
   11690             : 
   11691           1 :     MCopyLexicalEnvironmentObject(MDefinition* env, bool copySlots)
   11692           1 :       : MUnaryInstruction(env),
   11693           1 :         copySlots_(copySlots)
   11694             :     {
   11695           1 :         setResultType(MIRType::Object);
   11696           1 :     }
   11697             : 
   11698             :   public:
   11699           0 :     INSTRUCTION_HEADER(CopyLexicalEnvironmentObject)
   11700           1 :     TRIVIAL_NEW_WRAPPERS
   11701           0 :     NAMED_OPERANDS((0, env))
   11702             : 
   11703           0 :     bool copySlots() const {
   11704           0 :         return copySlots_;
   11705             :     }
   11706           0 :     bool possiblyCalls() const override {
   11707           0 :         return true;
   11708             :     }
   11709           0 :     AliasSet getAliasSet() const override {
   11710             :         return AliasSet::Load(AliasSet::ObjectFields |
   11711             :                               AliasSet::FixedSlot |
   11712           0 :                               AliasSet::DynamicSlot);
   11713             :     }
   11714             : };
   11715             : 
   11716             : // Store to vp[slot] (slots that are not inline in an object).
   11717           0 : class MStoreSlot
   11718             :   : public MBinaryInstruction,
   11719             :     public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
   11720             : {
   11721             :     uint32_t slot_;
   11722             :     MIRType slotType_;
   11723             :     bool needsBarrier_;
   11724             : 
   11725           0 :     MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier)
   11726           0 :         : MBinaryInstruction(slots, value),
   11727             :           slot_(slot),
   11728             :           slotType_(MIRType::Value),
   11729           0 :           needsBarrier_(barrier)
   11730             :     {
   11731           0 :         MOZ_ASSERT(slots->type() == MIRType::Slots);
   11732           0 :     }
   11733             : 
   11734             :   public:
   11735           0 :     INSTRUCTION_HEADER(StoreSlot)
   11736           0 :     NAMED_OPERANDS((0, slots), (1, value))
   11737             : 
   11738           0 :     static MStoreSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
   11739             :                            MDefinition* value)
   11740             :     {
   11741           0 :         return new(alloc) MStoreSlot(slots, slot, value, false);
   11742             :     }
   11743           0 :     static MStoreSlot* NewBarriered(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
   11744             :                                     MDefinition* value)
   11745             :     {
   11746           0 :         return new(alloc) MStoreSlot(slots, slot, value, true);
   11747             :     }
   11748             : 
   11749           0 :     uint32_t slot() const {
   11750           0 :         return slot_;
   11751             :     }
   11752           0 :     MIRType slotType() const {
   11753           0 :         return slotType_;
   11754             :     }
   11755           0 :     void setSlotType(MIRType slotType) {
   11756           0 :         MOZ_ASSERT(slotType != MIRType::None);
   11757           0 :         slotType_ = slotType;
   11758           0 :     }
   11759           0 :     bool needsBarrier() const {
   11760           0 :         return needsBarrier_;
   11761             :     }
   11762           0 :     void setNeedsBarrier() {
   11763           0 :         needsBarrier_ = true;
   11764           0 :     }
   11765           0 :     AliasSet getAliasSet() const override {
   11766           0 :         return AliasSet::Store(AliasSet::DynamicSlot);
   11767             :     }
   11768             :     void printOpcode(GenericPrinter& out) const override;
   11769             : 
   11770           0 :     ALLOW_CLONE(MStoreSlot)
   11771             : };
   11772             : 
   11773             : class MGetNameCache
   11774             :   : public MUnaryInstruction,
   11775             :     public SingleObjectPolicy::Data
   11776             : {
   11777             :   private:
   11778          42 :     explicit MGetNameCache(MDefinition* obj)
   11779          42 :       : MUnaryInstruction(obj)
   11780             :     {
   11781          42 :         setResultType(MIRType::Value);
   11782          42 :     }
   11783             : 
   11784             :   public:
   11785        1820 :     INSTRUCTION_HEADER(GetNameCache)
   11786          42 :     TRIVIAL_NEW_WRAPPERS
   11787           8 :     NAMED_OPERANDS((0, envObj))
   11788             : };
   11789             : 
   11790             : class MCallGetIntrinsicValue : public MNullaryInstruction
   11791             : {
   11792             :     CompilerPropertyName name_;
   11793             : 
   11794         506 :     explicit MCallGetIntrinsicValue(PropertyName* name)
   11795         506 :       : name_(name)
   11796             :     {
   11797         506 :         setResultType(MIRType::Value);
   11798         506 :     }
   11799             : 
   11800             :   public:
   11801        1173 :     INSTRUCTION_HEADER(CallGetIntrinsicValue)
   11802         506 :     TRIVIAL_NEW_WRAPPERS
   11803             : 
   11804           1 :     PropertyName* name() const {
   11805           1 :         return name_;
   11806             :     }
   11807         569 :     AliasSet getAliasSet() const override {
   11808         569 :         return AliasSet::None();
   11809             :     }
   11810           1 :     bool possiblyCalls() const override {
   11811           1 :         return true;
   11812             :     }
   11813          23 :     bool appendRoots(MRootList& roots) const override {
   11814          23 :         return roots.append(name_);
   11815             :     }
   11816             : };
   11817             : 
   11818             : class MSetPropertyInstruction : public MBinaryInstruction
   11819             : {
   11820             :     CompilerPropertyName name_;
   11821             :     bool strict_;
   11822             : 
   11823             :   protected:
   11824          23 :     MSetPropertyInstruction(MDefinition* obj, MDefinition* value, PropertyName* name,
   11825             :                             bool strict)
   11826          23 :       : MBinaryInstruction(obj, value),
   11827          23 :         name_(name), strict_(strict)
   11828          23 :     {}
   11829             : 
   11830             :   public:
   11831           0 :     NAMED_OPERANDS((0, object), (1, value))
   11832           0 :     PropertyName* name() const {
   11833           0 :         return name_;
   11834             :     }
   11835           0 :     bool strict() const {
   11836           0 :         return strict_;
   11837             :     }
   11838           0 :     bool appendRoots(MRootList& roots) const override {
   11839           0 :         return roots.append(name_);
   11840             :     }
   11841             : };
   11842             : 
   11843             : class MSetElementInstruction
   11844             :   : public MTernaryInstruction
   11845             : {
   11846             :     bool strict_;
   11847             :   protected:
   11848           0 :     MSetElementInstruction(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
   11849           0 :         : MTernaryInstruction(object, index, value),
   11850           0 :           strict_(strict)
   11851             :     {
   11852           0 :     }
   11853             : 
   11854             :   public:
   11855           0 :     NAMED_OPERANDS((0, object), (1, index), (2, value))
   11856           0 :     bool strict() const {
   11857           0 :         return strict_;
   11858             :     }
   11859             : };
   11860             : 
   11861             : class MDeleteProperty
   11862             :   : public MUnaryInstruction,
   11863             :     public BoxInputsPolicy::Data
   11864             : {
   11865             :     CompilerPropertyName name_;
   11866             :     bool strict_;
   11867             : 
   11868             :   protected:
   11869           0 :     MDeleteProperty(MDefinition* val, PropertyName* name, bool strict)
   11870           0 :       : MUnaryInstruction(val),
   11871             :         name_(name),
   11872           0 :         strict_(strict)
   11873             :     {
   11874           0 :         setResultType(MIRType::Boolean);
   11875           0 :     }
   11876             : 
   11877             :   public:
   11878           0 :     INSTRUCTION_HEADER(DeleteProperty)
   11879           0 :     TRIVIAL_NEW_WRAPPERS
   11880           0 :     NAMED_OPERANDS((0, value))
   11881             : 
   11882           0 :     PropertyName* name() const {
   11883           0 :         return name_;
   11884             :     }
   11885           0 :     bool strict() const {
   11886           0 :         return strict_;
   11887             :     }
   11888           0 :     bool appendRoots(MRootList& roots) const override {
   11889           0 :         return roots.append(name_);
   11890             :     }
   11891             : };
   11892             : 
   11893             : class MDeleteElement
   11894             :   : public MBinaryInstruction,
   11895             :     public BoxInputsPolicy::Data
   11896             : {
   11897             :     bool strict_;
   11898             : 
   11899           0 :     MDeleteElement(MDefinition* value, MDefinition* index, bool strict)
   11900           0 :       : MBinaryInstruction(value, index),
   11901           0 :         strict_(strict)
   11902             :     {
   11903           0 :         setResultType(MIRType::Boolean);
   11904           0 :     }
   11905             : 
   11906             :   public:
   11907           0 :     INSTRUCTION_HEADER(DeleteElement)
   11908           0 :     TRIVIAL_NEW_WRAPPERS
   11909           0 :     NAMED_OPERANDS((0, value), (1, index))
   11910             : 
   11911           0 :     bool strict() const {
   11912           0 :         return strict_;
   11913             :     }
   11914             : };
   11915             : 
   11916             : // Note: This uses CallSetElementPolicy to always box its second input,
   11917             : // ensuring we don't need two LIR instructions to lower this.
   11918             : class MCallSetProperty
   11919             :   : public MSetPropertyInstruction,
   11920             :     public CallSetElementPolicy::Data
   11921             : {
   11922          23 :     MCallSetProperty(MDefinition* obj, MDefinition* value, PropertyName* name, bool strict)
   11923          23 :       : MSetPropertyInstruction(obj, value, name, strict)
   11924             :     {
   11925          23 :     }
   11926             : 
   11927             :   public:
   11928          18 :     INSTRUCTION_HEADER(CallSetProperty)
   11929          23 :     TRIVIAL_NEW_WRAPPERS
   11930             : 
   11931           0 :     bool possiblyCalls() const override {
   11932           0 :         return true;
   11933             :     }
   11934             : };
   11935             : 
   11936             : class MSetPropertyCache
   11937             :   : public MTernaryInstruction,
   11938             :     public Mix3Policy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
   11939             : {
   11940             :     bool strict_ : 1;
   11941             :     bool needsPostBarrier_ : 1;
   11942             :     bool needsTypeBarrier_ : 1;
   11943             :     bool guardHoles_ : 1;
   11944             : 
   11945           8 :     MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
   11946             :                       bool needsPostBarrier, bool typeBarrier, bool guardHoles)
   11947           8 :       : MTernaryInstruction(obj, id, value),
   11948             :         strict_(strict),
   11949             :         needsPostBarrier_(needsPostBarrier),
   11950             :         needsTypeBarrier_(typeBarrier),
   11951           8 :         guardHoles_(guardHoles)
   11952             :     {
   11953           8 :     }
   11954             : 
   11955             :   public:
   11956        1865 :     INSTRUCTION_HEADER(SetPropertyCache)
   11957           8 :     TRIVIAL_NEW_WRAPPERS
   11958          42 :     NAMED_OPERANDS((0, object), (1, idval), (2, value))
   11959             : 
   11960           6 :     bool needsPostBarrier() const {
   11961           6 :         return needsPostBarrier_;
   11962             :     }
   11963           6 :     bool needsTypeBarrier() const {
   11964           6 :         return needsTypeBarrier_;
   11965             :     }
   11966             : 
   11967           6 :     bool guardHoles() const {
   11968           6 :         return guardHoles_;
   11969             :     }
   11970             : 
   11971           6 :     bool strict() const {
   11972           6 :         return strict_;
   11973             :     }
   11974             : };
   11975             : 
   11976             : class MCallGetProperty
   11977             :   : public MUnaryInstruction,
   11978             :     public BoxInputsPolicy::Data
   11979             : {
   11980             :     CompilerPropertyName name_;
   11981             :     bool idempotent_;
   11982             : 
   11983         418 :     MCallGetProperty(MDefinition* value, PropertyName* name)
   11984         418 :       : MUnaryInstruction(value), name_(name),
   11985         418 :         idempotent_(false)
   11986             :     {
   11987         418 :         setResultType(MIRType::Value);
   11988         418 :     }
   11989             : 
   11990             :   public:
   11991        2653 :     INSTRUCTION_HEADER(CallGetProperty)
   11992         418 :     TRIVIAL_NEW_WRAPPERS
   11993           3 :     NAMED_OPERANDS((0, value))
   11994             : 
   11995         218 :     PropertyName* name() const {
   11996         218 :         return name_;
   11997             :     }
   11998             : 
   11999             :     // Constructors need to perform a GetProp on the function prototype.
   12000             :     // Since getters cannot be set on the prototype, fetching is non-effectful.
   12001             :     // The operation may be safely repeated in case of bailout.
   12002           0 :     void setIdempotent() {
   12003           0 :         idempotent_ = true;
   12004           0 :     }
   12005         480 :     AliasSet getAliasSet() const override {
   12006         480 :         if (!idempotent_)
   12007         480 :             return AliasSet::Store(AliasSet::Any);
   12008           0 :         return AliasSet::None();
   12009             :     }
   12010           3 :     bool possiblyCalls() const override {
   12011           3 :         return true;
   12012             :     }
   12013           5 :     bool appendRoots(MRootList& roots) const override {
   12014           5 :         return roots.append(name_);
   12015             :     }
   12016             : };
   12017             : 
   12018             : // Inline call to handle lhs[rhs]. The first input is a Value so that this
   12019             : // instruction can handle both objects and strings.
   12020             : class MCallGetElement
   12021             :   : public MBinaryInstruction,
   12022             :     public BoxInputsPolicy::Data
   12023             : {
   12024         867 :     MCallGetElement(MDefinition* lhs, MDefinition* rhs)
   12025         867 :       : MBinaryInstruction(lhs, rhs)
   12026             :     {
   12027         867 :         setResultType(MIRType::Value);
   12028         867 :     }
   12029             : 
   12030             :   public:
   12031        3073 :     INSTRUCTION_HEADER(CallGetElement)
   12032         867 :     TRIVIAL_NEW_WRAPPERS
   12033             : 
   12034           0 :     bool possiblyCalls() const override {
   12035           0 :         return true;
   12036             :     }
   12037             : };
   12038             : 
   12039             : class MCallSetElement
   12040             :   : public MSetElementInstruction,
   12041             :     public CallSetElementPolicy::Data
   12042             : {
   12043           0 :     MCallSetElement(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
   12044           0 :       : MSetElementInstruction(object, index, value, strict)
   12045             :     {
   12046           0 :     }
   12047             : 
   12048             :   public:
   12049           0 :     INSTRUCTION_HEADER(CallSetElement)
   12050           0 :     TRIVIAL_NEW_WRAPPERS
   12051             : 
   12052           0 :     bool possiblyCalls() const override {
   12053           0 :         return true;
   12054             :     }
   12055             : };
   12056             : 
   12057             : class MCallInitElementArray
   12058             :   : public MTernaryInstruction,
   12059             :     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
   12060             : {
   12061           0 :     MCallInitElementArray(MDefinition* obj, MDefinition* index, MDefinition* val)
   12062           0 :       : MTernaryInstruction(obj, index, val)
   12063             :     {
   12064           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   12065           0 :     }
   12066             : 
   12067             :   public:
   12068           0 :     INSTRUCTION_HEADER(CallInitElementArray)
   12069           0 :     TRIVIAL_NEW_WRAPPERS
   12070           0 :     NAMED_OPERANDS((0, object), (1, index), (2, value))
   12071             : 
   12072           0 :     bool possiblyCalls() const override {
   12073           0 :         return true;
   12074             :     }
   12075             : };
   12076             : 
   12077             : class MSetDOMProperty
   12078             :   : public MAryInstruction<2>,
   12079             :     public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
   12080             : {
   12081             :     const JSJitSetterOp func_;
   12082             : 
   12083           0 :     MSetDOMProperty(const JSJitSetterOp func, MDefinition* obj, MDefinition* val)
   12084           0 :       : func_(func)
   12085             :     {
   12086           0 :         initOperand(0, obj);
   12087           0 :         initOperand(1, val);
   12088           0 :     }
   12089             : 
   12090             :   public:
   12091           0 :     INSTRUCTION_HEADER(SetDOMProperty)
   12092           0 :     TRIVIAL_NEW_WRAPPERS
   12093           0 :     NAMED_OPERANDS((0, object), (1, value))
   12094             : 
   12095           0 :     JSJitSetterOp fun() const {
   12096           0 :         return func_;
   12097             :     }
   12098             : 
   12099           0 :     bool possiblyCalls() const override {
   12100           0 :         return true;
   12101             :     }
   12102             : };
   12103             : 
   12104             : class MGetDOMProperty
   12105             :   : public MVariadicInstruction,
   12106             :     public ObjectPolicy<0>::Data
   12107             : {
   12108             :     const JSJitInfo* info_;
   12109             : 
   12110             :   protected:
   12111           0 :     explicit MGetDOMProperty(const JSJitInfo* jitinfo)
   12112           0 :       : info_(jitinfo)
   12113             :     {
   12114           0 :         MOZ_ASSERT(jitinfo);
   12115           0 :         MOZ_ASSERT(jitinfo->type() == JSJitInfo::Getter);
   12116             : 
   12117             :         // We are movable iff the jitinfo says we can be.
   12118           0 :         if (isDomMovable()) {
   12119           0 :             MOZ_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything);
   12120           0 :             setMovable();
   12121             :         } else {
   12122             :             // If we're not movable, that means we shouldn't be DCEd either,
   12123             :             // because we might throw an exception when called, and getting rid
   12124             :             // of that is observable.
   12125           0 :             setGuard();
   12126             :         }
   12127             : 
   12128           0 :         setResultType(MIRType::Value);
   12129           0 :     }
   12130             : 
   12131           0 :     const JSJitInfo* info() const {
   12132           0 :         return info_;
   12133             :     }
   12134             : 
   12135           0 :     MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* guard,
   12136             :                            MDefinition* globalGuard) {
   12137           0 :         MOZ_ASSERT(obj);
   12138             :         // guard can be null.
   12139             :         // globalGuard can be null.
   12140           0 :         size_t operandCount = 1;
   12141           0 :         if (guard)
   12142           0 :             ++operandCount;
   12143           0 :         if (globalGuard)
   12144           0 :             ++operandCount;
   12145           0 :         if (!MVariadicInstruction::init(alloc, operandCount))
   12146           0 :             return false;
   12147           0 :         initOperand(0, obj);
   12148             : 
   12149           0 :         size_t operandIndex = 1;
   12150             :         // Pin the guard, if we have one as an operand if we want to hoist later.
   12151           0 :         if (guard)
   12152           0 :             initOperand(operandIndex++, guard);
   12153             : 
   12154             :         // And the same for the global guard, if we have one.
   12155           0 :         if (globalGuard)
   12156           0 :             initOperand(operandIndex, globalGuard);
   12157             : 
   12158           0 :         return true;
   12159             :     }
   12160             : 
   12161             :   public:
   12162           0 :     INSTRUCTION_HEADER(GetDOMProperty)
   12163           0 :     NAMED_OPERANDS((0, object))
   12164             : 
   12165           0 :     static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
   12166             :                                 MDefinition* guard, MDefinition* globalGuard)
   12167             :     {
   12168           0 :         auto* res = new(alloc) MGetDOMProperty(info);
   12169           0 :         if (!res || !res->init(alloc, obj, guard, globalGuard))
   12170           0 :             return nullptr;
   12171           0 :         return res;
   12172             :     }
   12173             : 
   12174           0 :     JSJitGetterOp fun() const {
   12175           0 :         return info_->getter;
   12176             :     }
   12177           0 :     bool isInfallible() const {
   12178           0 :         return info_->isInfallible;
   12179             :     }
   12180           0 :     bool isDomMovable() const {
   12181           0 :         return info_->isMovable;
   12182             :     }
   12183           0 :     JSJitInfo::AliasSet domAliasSet() const {
   12184           0 :         return info_->aliasSet();
   12185             :     }
   12186           0 :     size_t domMemberSlotIndex() const {
   12187           0 :         MOZ_ASSERT(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot);
   12188           0 :         return info_->slotIndex;
   12189             :     }
   12190           0 :     bool valueMayBeInSlot() const {
   12191           0 :         return info_->isLazilyCachedInSlot;
   12192             :     }
   12193           0 :     bool congruentTo(const MDefinition* ins) const override {
   12194           0 :         if (!ins->isGetDOMProperty())
   12195           0 :             return false;
   12196             : 
   12197           0 :         return congruentTo(ins->toGetDOMProperty());
   12198             :     }
   12199             : 
   12200           0 :     bool congruentTo(const MGetDOMProperty* ins) const {
   12201           0 :         if (!isDomMovable())
   12202           0 :             return false;
   12203             : 
   12204             :         // Checking the jitinfo is the same as checking the constant function
   12205           0 :         if (!(info() == ins->info()))
   12206           0 :             return false;
   12207             : 
   12208           0 :         return congruentIfOperandsEqual(ins);
   12209             :     }
   12210             : 
   12211           0 :     AliasSet getAliasSet() const override {
   12212           0 :         JSJitInfo::AliasSet aliasSet = domAliasSet();
   12213           0 :         if (aliasSet == JSJitInfo::AliasNone)
   12214           0 :             return AliasSet::None();
   12215           0 :         if (aliasSet == JSJitInfo::AliasDOMSets)
   12216           0 :             return AliasSet::Load(AliasSet::DOMProperty);
   12217           0 :         MOZ_ASSERT(aliasSet == JSJitInfo::AliasEverything);
   12218           0 :         return AliasSet::Store(AliasSet::Any);
   12219             :     }
   12220             : 
   12221           0 :     bool possiblyCalls() const override {
   12222           0 :         return true;
   12223             :     }
   12224             : };
   12225             : 
   12226             : class MGetDOMMember : public MGetDOMProperty
   12227             : {
   12228             :     // We inherit everything from MGetDOMProperty except our
   12229             :     // possiblyCalls value and the congruentTo behavior.
   12230           0 :     explicit MGetDOMMember(const JSJitInfo* jitinfo)
   12231           0 :         : MGetDOMProperty(jitinfo)
   12232             :     {
   12233           0 :         setResultType(MIRTypeFromValueType(jitinfo->returnType()));
   12234           0 :     }
   12235             : 
   12236             :   public:
   12237           0 :     INSTRUCTION_HEADER(GetDOMMember)
   12238             : 
   12239           0 :     static MGetDOMMember* New(TempAllocator& alloc, const JSJitInfo* info, MDefinition* obj,
   12240             :                               MDefinition* guard, MDefinition* globalGuard)
   12241             :     {
   12242           0 :         auto* res = new(alloc) MGetDOMMember(info);
   12243           0 :         if (!res || !res->init(alloc, obj, guard, globalGuard))
   12244           0 :             return nullptr;
   12245           0 :         return res;
   12246             :     }
   12247             : 
   12248           0 :     bool possiblyCalls() const override {
   12249           0 :         return false;
   12250             :     }
   12251             : 
   12252           0 :     bool congruentTo(const MDefinition* ins) const override {
   12253           0 :         if (!ins->isGetDOMMember())
   12254           0 :             return false;
   12255             : 
   12256           0 :         return MGetDOMProperty::congruentTo(ins->toGetDOMMember());
   12257             :     }
   12258             : };
   12259             : 
   12260           0 : class MStringLength
   12261             :   : public MUnaryInstruction,
   12262             :     public StringPolicy<0>::Data
   12263             : {
   12264          15 :     explicit MStringLength(MDefinition* string)
   12265          15 :       : MUnaryInstruction(string)
   12266             :     {
   12267          15 :         setResultType(MIRType::Int32);
   12268          15 :         setMovable();
   12269          15 :     }
   12270             :   public:
   12271        2647 :     INSTRUCTION_HEADER(StringLength)
   12272          15 :     TRIVIAL_NEW_WRAPPERS
   12273          36 :     NAMED_OPERANDS((0, string))
   12274             : 
   12275             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   12276             : 
   12277          36 :     bool congruentTo(const MDefinition* ins) const override {
   12278          36 :         return congruentIfOperandsEqual(ins);
   12279             :     }
   12280         200 :     AliasSet getAliasSet() const override {
   12281             :         // The string |length| property is immutable, so there is no
   12282             :         // implicit dependency.
   12283         200 :         return AliasSet::None();
   12284             :     }
   12285             : 
   12286             :     void computeRange(TempAllocator& alloc) override;
   12287             : 
   12288             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   12289           8 :     bool canRecoverOnBailout() const override {
   12290           8 :         return true;
   12291             :     }
   12292             : 
   12293           0 :     ALLOW_CLONE(MStringLength)
   12294             : };
   12295             : 
   12296             : // Inlined assembly for Math.floor(double | float32) -> int32.
   12297           0 : class MFloor
   12298             :   : public MUnaryInstruction,
   12299             :     public FloatingPointPolicy<0>::Data
   12300             : {
   12301           0 :     explicit MFloor(MDefinition* num)
   12302           0 :       : MUnaryInstruction(num)
   12303             :     {
   12304           0 :         setResultType(MIRType::Int32);
   12305           0 :         specialization_ = MIRType::Double;
   12306           0 :         setMovable();
   12307           0 :     }
   12308             : 
   12309             :   public:
   12310           0 :     INSTRUCTION_HEADER(Floor)
   12311           0 :     TRIVIAL_NEW_WRAPPERS
   12312             : 
   12313           0 :     AliasSet getAliasSet() const override {
   12314           0 :         return AliasSet::None();
   12315             :     }
   12316           0 :     bool isFloat32Commutative() const override {
   12317           0 :         return true;
   12318             :     }
   12319             :     void trySpecializeFloat32(TempAllocator& alloc) override;
   12320             : #ifdef DEBUG
   12321           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   12322           0 :         return true;
   12323             :     }
   12324             : #endif
   12325           0 :     bool congruentTo(const MDefinition* ins) const override {
   12326           0 :         return congruentIfOperandsEqual(ins);
   12327             :     }
   12328             :     void computeRange(TempAllocator& alloc) override;
   12329             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   12330           0 :     bool canRecoverOnBailout() const override {
   12331           0 :         return true;
   12332             :     }
   12333             : 
   12334           0 :     ALLOW_CLONE(MFloor)
   12335             : };
   12336             : 
   12337             : // Inlined assembly version for Math.ceil(double | float32) -> int32.
   12338           0 : class MCeil
   12339             :   : public MUnaryInstruction,
   12340             :     public FloatingPointPolicy<0>::Data
   12341             : {
   12342           0 :     explicit MCeil(MDefinition* num)
   12343           0 :       : MUnaryInstruction(num)
   12344             :     {
   12345           0 :         setResultType(MIRType::Int32);
   12346           0 :         specialization_ = MIRType::Double;
   12347           0 :         setMovable();
   12348           0 :     }
   12349             : 
   12350             :   public:
   12351           0 :     INSTRUCTION_HEADER(Ceil)
   12352           0 :     TRIVIAL_NEW_WRAPPERS
   12353             : 
   12354           0 :     AliasSet getAliasSet() const override {
   12355           0 :         return AliasSet::None();
   12356             :     }
   12357           0 :     bool isFloat32Commutative() const override {
   12358           0 :         return true;
   12359             :     }
   12360             :     void trySpecializeFloat32(TempAllocator& alloc) override;
   12361             : #ifdef DEBUG
   12362           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   12363           0 :         return true;
   12364             :     }
   12365             : #endif
   12366           0 :     bool congruentTo(const MDefinition* ins) const override {
   12367           0 :         return congruentIfOperandsEqual(ins);
   12368             :     }
   12369             :     void computeRange(TempAllocator& alloc) override;
   12370             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   12371           0 :     bool canRecoverOnBailout() const override {
   12372           0 :         return true;
   12373             :     }
   12374             : 
   12375           0 :     ALLOW_CLONE(MCeil)
   12376             : };
   12377             : 
   12378             : // Inlined version of Math.round(double | float32) -> int32.
   12379           0 : class MRound
   12380             :   : public MUnaryInstruction,
   12381             :     public FloatingPointPolicy<0>::Data
   12382             : {
   12383           0 :     explicit MRound(MDefinition* num)
   12384           0 :       : MUnaryInstruction(num)
   12385             :     {
   12386           0 :         setResultType(MIRType::Int32);
   12387           0 :         specialization_ = MIRType::Double;
   12388           0 :         setMovable();
   12389           0 :     }
   12390             : 
   12391             :   public:
   12392           0 :     INSTRUCTION_HEADER(Round)
   12393           0 :     TRIVIAL_NEW_WRAPPERS
   12394             : 
   12395           0 :     AliasSet getAliasSet() const override {
   12396           0 :         return AliasSet::None();
   12397             :     }
   12398             : 
   12399           0 :     bool isFloat32Commutative() const override {
   12400           0 :         return true;
   12401             :     }
   12402             :     void trySpecializeFloat32(TempAllocator& alloc) override;
   12403             : #ifdef DEBUG
   12404           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   12405           0 :         return true;
   12406             :     }
   12407             : #endif
   12408           0 :     bool congruentTo(const MDefinition* ins) const override {
   12409           0 :         return congruentIfOperandsEqual(ins);
   12410             :     }
   12411             : 
   12412             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   12413           0 :     bool canRecoverOnBailout() const override {
   12414           0 :         return true;
   12415             :     }
   12416             : 
   12417           0 :     ALLOW_CLONE(MRound)
   12418             : };
   12419             : 
   12420             : // NearbyInt rounds the floating-point input to the nearest integer, according
   12421             : // to the RoundingMode.
   12422           0 : class MNearbyInt
   12423             :   : public MUnaryInstruction,
   12424             :     public FloatingPointPolicy<0>::Data
   12425             : {
   12426             :     RoundingMode roundingMode_;
   12427             : 
   12428           0 :     explicit MNearbyInt(MDefinition* num, MIRType resultType, RoundingMode roundingMode)
   12429           0 :       : MUnaryInstruction(num),
   12430           0 :         roundingMode_(roundingMode)
   12431             :     {
   12432           0 :         MOZ_ASSERT(HasAssemblerSupport(roundingMode));
   12433             : 
   12434           0 :         MOZ_ASSERT(IsFloatingPointType(resultType));
   12435           0 :         setResultType(resultType);
   12436           0 :         specialization_ = resultType;
   12437             : 
   12438           0 :         setMovable();
   12439           0 :     }
   12440             : 
   12441             :   public:
   12442           0 :     INSTRUCTION_HEADER(NearbyInt)
   12443           0 :     TRIVIAL_NEW_WRAPPERS
   12444             : 
   12445           0 :     static bool HasAssemblerSupport(RoundingMode mode) {
   12446           0 :         return Assembler::HasRoundInstruction(mode);
   12447             :     }
   12448             : 
   12449           0 :     RoundingMode roundingMode() const { return roundingMode_; }
   12450             : 
   12451           0 :     AliasSet getAliasSet() const override {
   12452           0 :         return AliasSet::None();
   12453             :     }
   12454             : 
   12455           0 :     bool isFloat32Commutative() const override {
   12456           0 :         return true;
   12457             :     }
   12458             :     void trySpecializeFloat32(TempAllocator& alloc) override;
   12459             : #ifdef DEBUG
   12460           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   12461           0 :         return true;
   12462             :     }
   12463             : #endif
   12464             : 
   12465           0 :     bool congruentTo(const MDefinition* ins) const override {
   12466           0 :         return congruentIfOperandsEqual(ins) &&
   12467           0 :                ins->toNearbyInt()->roundingMode() == roundingMode_;
   12468             :     }
   12469             : 
   12470             :     void printOpcode(GenericPrinter& out) const override;
   12471             : 
   12472           0 :     ALLOW_CLONE(MNearbyInt)
   12473             : };
   12474             : 
   12475             : class MIteratorStart
   12476             :   : public MUnaryInstruction,
   12477             :     public BoxExceptPolicy<0, MIRType::Object>::Data
   12478             : {
   12479             :     uint8_t flags_;
   12480             : 
   12481           0 :     MIteratorStart(MDefinition* obj, uint8_t flags)
   12482           0 :       : MUnaryInstruction(obj), flags_(flags)
   12483             :     {
   12484           0 :         setResultType(MIRType::Object);
   12485           0 :     }
   12486             : 
   12487             :   public:
   12488           0 :     INSTRUCTION_HEADER(IteratorStart)
   12489           0 :     TRIVIAL_NEW_WRAPPERS
   12490           0 :     NAMED_OPERANDS((0, object))
   12491             : 
   12492           0 :     uint8_t flags() const {
   12493           0 :         return flags_;
   12494             :     }
   12495             : };
   12496             : 
   12497             : class MIteratorMore
   12498             :   : public MUnaryInstruction,
   12499             :     public SingleObjectPolicy::Data
   12500             : {
   12501           0 :     explicit MIteratorMore(MDefinition* iter)
   12502           0 :       : MUnaryInstruction(iter)
   12503             :     {
   12504           0 :         setResultType(MIRType::Value);
   12505           0 :     }
   12506             : 
   12507             :   public:
   12508           0 :     INSTRUCTION_HEADER(IteratorMore)
   12509           0 :     TRIVIAL_NEW_WRAPPERS
   12510           0 :     NAMED_OPERANDS((0, iterator))
   12511             : 
   12512             : };
   12513             : 
   12514             : class MIsNoIter
   12515             :   : public MUnaryInstruction,
   12516             :     public NoTypePolicy::Data
   12517             : {
   12518           0 :     explicit MIsNoIter(MDefinition* def)
   12519           0 :       : MUnaryInstruction(def)
   12520             :     {
   12521           0 :         setResultType(MIRType::Boolean);
   12522           0 :         setMovable();
   12523           0 :     }
   12524             : 
   12525             :   public:
   12526           0 :     INSTRUCTION_HEADER(IsNoIter)
   12527           0 :     TRIVIAL_NEW_WRAPPERS
   12528             : 
   12529           0 :     AliasSet getAliasSet() const override {
   12530           0 :         return AliasSet::None();
   12531             :     }
   12532             : };
   12533             : 
   12534             : class MIteratorEnd
   12535             :   : public MUnaryInstruction,
   12536             :     public SingleObjectPolicy::Data
   12537             : {
   12538           0 :     explicit MIteratorEnd(MDefinition* iter)
   12539           0 :       : MUnaryInstruction(iter)
   12540           0 :     { }
   12541             : 
   12542             :   public:
   12543           0 :     INSTRUCTION_HEADER(IteratorEnd)
   12544           0 :     TRIVIAL_NEW_WRAPPERS
   12545           0 :     NAMED_OPERANDS((0, iterator))
   12546             : 
   12547             : };
   12548             : 
   12549             : // Implementation for 'in' operator using instruction cache
   12550             : class MInCache
   12551             :   : public MBinaryInstruction,
   12552             :     public MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >::Data
   12553             : {
   12554          91 :     MInCache(MDefinition* key, MDefinition* obj)
   12555          91 :       : MBinaryInstruction(key, obj)
   12556             :     {
   12557          91 :         setResultType(MIRType::Boolean);
   12558          91 :     }
   12559             : 
   12560             :   public:
   12561        1065 :     INSTRUCTION_HEADER(InCache)
   12562          91 :     TRIVIAL_NEW_WRAPPERS
   12563           2 :     NAMED_OPERANDS((0, key), (1, object))
   12564             : };
   12565             : 
   12566             : 
   12567             : // Test whether the index is in the array bounds or a hole.
   12568             : class MInArray
   12569             :   : public MQuaternaryInstruction,
   12570             :     public ObjectPolicy<3>::Data
   12571             : {
   12572             :     bool needsHoleCheck_;
   12573             :     bool needsNegativeIntCheck_;
   12574             :     JSValueType unboxedType_;
   12575             : 
   12576           0 :     MInArray(MDefinition* elements, MDefinition* index,
   12577             :              MDefinition* initLength, MDefinition* object,
   12578             :              bool needsHoleCheck, JSValueType unboxedType)
   12579           0 :       : MQuaternaryInstruction(elements, index, initLength, object),
   12580             :         needsHoleCheck_(needsHoleCheck),
   12581             :         needsNegativeIntCheck_(true),
   12582           0 :         unboxedType_(unboxedType)
   12583             :     {
   12584           0 :         setResultType(MIRType::Boolean);
   12585           0 :         setMovable();
   12586           0 :         MOZ_ASSERT(elements->type() == MIRType::Elements);
   12587           0 :         MOZ_ASSERT(index->type() == MIRType::Int32);
   12588           0 :         MOZ_ASSERT(initLength->type() == MIRType::Int32);
   12589           0 :     }
   12590             : 
   12591             :   public:
   12592           0 :     INSTRUCTION_HEADER(InArray)
   12593           0 :     TRIVIAL_NEW_WRAPPERS
   12594           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, initLength), (3, object))
   12595             : 
   12596           0 :     bool needsHoleCheck() const {
   12597           0 :         return needsHoleCheck_;
   12598             :     }
   12599           0 :     bool needsNegativeIntCheck() const {
   12600           0 :         return needsNegativeIntCheck_;
   12601             :     }
   12602           0 :     JSValueType unboxedType() const {
   12603           0 :         return unboxedType_;
   12604             :     }
   12605             :     void collectRangeInfoPreTrunc() override;
   12606           0 :     AliasSet getAliasSet() const override {
   12607           0 :         return AliasSet::Load(AliasSet::Element);
   12608             :     }
   12609           0 :     bool congruentTo(const MDefinition* ins) const override {
   12610           0 :         if (!ins->isInArray())
   12611           0 :             return false;
   12612           0 :         const MInArray* other = ins->toInArray();
   12613           0 :         if (needsHoleCheck() != other->needsHoleCheck())
   12614           0 :             return false;
   12615           0 :         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
   12616           0 :             return false;
   12617           0 :         if (unboxedType() != other->unboxedType())
   12618           0 :             return false;
   12619           0 :         return congruentIfOperandsEqual(other);
   12620             :     }
   12621             : };
   12622             : 
   12623             : class MHasOwnCache
   12624             :   : public MBinaryInstruction,
   12625             :     public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
   12626             : {
   12627           0 :     MHasOwnCache(MDefinition* obj, MDefinition* id)
   12628           0 :       : MBinaryInstruction(obj, id)
   12629             :     {
   12630           0 :         setResultType(MIRType::Boolean);
   12631           0 :     }
   12632             : 
   12633             :   public:
   12634           0 :     INSTRUCTION_HEADER(HasOwnCache)
   12635           0 :     TRIVIAL_NEW_WRAPPERS
   12636           0 :     NAMED_OPERANDS((0, value), (1, idval))
   12637             : };
   12638             : 
   12639             : // Implementation for instanceof operator with specific rhs.
   12640             : class MInstanceOf
   12641             :   : public MUnaryInstruction,
   12642             :     public InstanceOfPolicy::Data
   12643             : {
   12644             :     CompilerObject protoObj_;
   12645             : 
   12646           0 :     MInstanceOf(MDefinition* obj, JSObject* proto)
   12647           0 :       : MUnaryInstruction(obj),
   12648           0 :         protoObj_(proto)
   12649             :     {
   12650           0 :         setResultType(MIRType::Boolean);
   12651           0 :     }
   12652             : 
   12653             :   public:
   12654           0 :     INSTRUCTION_HEADER(InstanceOf)
   12655           0 :     TRIVIAL_NEW_WRAPPERS
   12656             : 
   12657           0 :     JSObject* prototypeObject() {
   12658           0 :         return protoObj_;
   12659             :     }
   12660             : 
   12661           0 :     bool appendRoots(MRootList& roots) const override {
   12662           0 :         return roots.append(protoObj_);
   12663             :     }
   12664             : };
   12665             : 
   12666             : // Implementation for instanceof operator with unknown rhs.
   12667             : class MCallInstanceOf
   12668             :   : public MBinaryInstruction,
   12669             :     public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
   12670             : {
   12671           0 :     MCallInstanceOf(MDefinition* obj, MDefinition* proto)
   12672           0 :       : MBinaryInstruction(obj, proto)
   12673             :     {
   12674           0 :         setResultType(MIRType::Boolean);
   12675           0 :     }
   12676             : 
   12677             :   public:
   12678           0 :     INSTRUCTION_HEADER(CallInstanceOf)
   12679           0 :     TRIVIAL_NEW_WRAPPERS
   12680             : };
   12681             : 
   12682             : class MArgumentsLength : public MNullaryInstruction
   12683             : {
   12684           5 :     MArgumentsLength()
   12685           5 :     {
   12686           5 :         setResultType(MIRType::Int32);
   12687           5 :         setMovable();
   12688           5 :     }
   12689             : 
   12690             :   public:
   12691         937 :     INSTRUCTION_HEADER(ArgumentsLength)
   12692           5 :     TRIVIAL_NEW_WRAPPERS
   12693             : 
   12694          13 :     bool congruentTo(const MDefinition* ins) const override {
   12695          13 :         return congruentIfOperandsEqual(ins);
   12696             :     }
   12697          62 :     AliasSet getAliasSet() const override {
   12698             :         // Arguments |length| cannot be mutated by Ion Code.
   12699          62 :         return AliasSet::None();
   12700             :    }
   12701             : 
   12702             :     void computeRange(TempAllocator& alloc) override;
   12703             : 
   12704             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   12705             : 
   12706           2 :     bool canRecoverOnBailout() const override {
   12707           2 :         return true;
   12708             :     }
   12709             : };
   12710             : 
   12711             : // This MIR instruction is used to get an argument from the actual arguments.
   12712             : class MGetFrameArgument
   12713             :   : public MUnaryInstruction,
   12714             :     public IntPolicy<0>::Data
   12715             : {
   12716             :     bool scriptHasSetArg_;
   12717             : 
   12718           1 :     MGetFrameArgument(MDefinition* idx, bool scriptHasSetArg)
   12719           1 :       : MUnaryInstruction(idx),
   12720           1 :         scriptHasSetArg_(scriptHasSetArg)
   12721             :     {
   12722           1 :         setResultType(MIRType::Value);
   12723           1 :         setMovable();
   12724           1 :     }
   12725             : 
   12726             :   public:
   12727         274 :     INSTRUCTION_HEADER(GetFrameArgument)
   12728           1 :     TRIVIAL_NEW_WRAPPERS
   12729           1 :     NAMED_OPERANDS((0, index))
   12730             : 
   12731           1 :     bool congruentTo(const MDefinition* ins) const override {
   12732           1 :         return congruentIfOperandsEqual(ins);
   12733             :     }
   12734           8 :     AliasSet getAliasSet() const override {
   12735             :         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
   12736             :         // aliased.
   12737           8 :         if (scriptHasSetArg_)
   12738           0 :             return AliasSet::Load(AliasSet::FrameArgument);
   12739           8 :         return AliasSet::None();
   12740             :     }
   12741             : };
   12742             : 
   12743             : class MNewTarget : public MNullaryInstruction
   12744             : {
   12745          23 :     MNewTarget() : MNullaryInstruction() {
   12746          23 :         setResultType(MIRType::Value);
   12747          23 :         setMovable();
   12748          23 :     }
   12749             : 
   12750             :   public:
   12751         155 :     INSTRUCTION_HEADER(NewTarget)
   12752          23 :     TRIVIAL_NEW_WRAPPERS
   12753             : 
   12754           0 :     bool congruentTo(const MDefinition* ins) const override {
   12755           0 :         return congruentIfOperandsEqual(ins);
   12756             :     }
   12757           0 :     AliasSet getAliasSet() const override {
   12758           0 :         return AliasSet::None();
   12759             :     }
   12760             : };
   12761             : 
   12762             : // This MIR instruction is used to set an argument value in the frame.
   12763             : class MSetFrameArgument
   12764             :   : public MUnaryInstruction,
   12765             :     public NoFloatPolicy<0>::Data
   12766             : {
   12767             :     uint32_t argno_;
   12768             : 
   12769           0 :     MSetFrameArgument(uint32_t argno, MDefinition* value)
   12770           0 :       : MUnaryInstruction(value),
   12771           0 :         argno_(argno)
   12772             :     {
   12773           0 :         setMovable();
   12774           0 :     }
   12775             : 
   12776             :   public:
   12777           0 :     INSTRUCTION_HEADER(SetFrameArgument)
   12778           0 :     TRIVIAL_NEW_WRAPPERS
   12779           0 :     NAMED_OPERANDS((0, value))
   12780             : 
   12781           0 :     uint32_t argno() const {
   12782           0 :         return argno_;
   12783             :     }
   12784             : 
   12785           0 :     bool congruentTo(const MDefinition* ins) const override {
   12786           0 :         return false;
   12787             :     }
   12788           0 :     AliasSet getAliasSet() const override {
   12789           0 :         return AliasSet::Store(AliasSet::FrameArgument);
   12790             :     }
   12791             : };
   12792             : 
   12793             : class MRestCommon
   12794             : {
   12795             :     unsigned numFormals_;
   12796             :     CompilerGCPointer<ArrayObject*> templateObject_;
   12797             : 
   12798             :   protected:
   12799           2 :     MRestCommon(unsigned numFormals, ArrayObject* templateObject)
   12800           2 :       : numFormals_(numFormals),
   12801           2 :         templateObject_(templateObject)
   12802           2 :    { }
   12803             : 
   12804             :   public:
   12805           1 :     unsigned numFormals() const {
   12806           1 :         return numFormals_;
   12807             :     }
   12808           2 :     ArrayObject* templateObject() const {
   12809           2 :         return templateObject_;
   12810             :     }
   12811             : };
   12812             : 
   12813             : class MRest
   12814             :   : public MUnaryInstruction,
   12815             :     public MRestCommon,
   12816             :     public IntPolicy<0>::Data
   12817             : {
   12818           2 :     MRest(CompilerConstraintList* constraints, MDefinition* numActuals, unsigned numFormals,
   12819             :           ArrayObject* templateObject)
   12820           2 :       : MUnaryInstruction(numActuals),
   12821           2 :         MRestCommon(numFormals, templateObject)
   12822             :     {
   12823           2 :         setResultType(MIRType::Object);
   12824           2 :         setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
   12825           2 :     }
   12826             : 
   12827             :   public:
   12828         418 :     INSTRUCTION_HEADER(Rest)
   12829           2 :     TRIVIAL_NEW_WRAPPERS
   12830           2 :     NAMED_OPERANDS((0, numActuals))
   12831             : 
   12832           8 :     AliasSet getAliasSet() const override {
   12833           8 :         return AliasSet::None();
   12834             :     }
   12835           1 :     bool possiblyCalls() const override {
   12836           1 :         return true;
   12837             :     }
   12838           1 :     bool appendRoots(MRootList& roots) const override {
   12839           1 :         return roots.append(templateObject());
   12840             :     }
   12841             : };
   12842             : 
   12843             : class MFilterTypeSet
   12844             :   : public MUnaryInstruction,
   12845             :     public FilterTypeSetPolicy::Data
   12846             : {
   12847          47 :     MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types)
   12848          47 :       : MUnaryInstruction(def)
   12849             :     {
   12850          47 :         MOZ_ASSERT(!types->unknown());
   12851          47 :         setResultType(types->getKnownMIRType());
   12852          47 :         setResultTypeSet(types);
   12853          47 :     }
   12854             : 
   12855             :   public:
   12856        4350 :     INSTRUCTION_HEADER(FilterTypeSet)
   12857          47 :     TRIVIAL_NEW_WRAPPERS
   12858             : 
   12859          20 :     bool congruentTo(const MDefinition* def) const override {
   12860          20 :         return false;
   12861             :     }
   12862         296 :     AliasSet getAliasSet() const override {
   12863         296 :         return AliasSet::None();
   12864             :     }
   12865           0 :     virtual bool neverHoist() const override {
   12866           0 :         return resultTypeSet()->empty();
   12867             :     }
   12868             :     void computeRange(TempAllocator& alloc) override;
   12869             : 
   12870           0 :     bool isFloat32Commutative() const override {
   12871           0 :         return IsFloatingPointType(type());
   12872             :     }
   12873             : 
   12874             :     bool canProduceFloat32() const override;
   12875             :     bool canConsumeFloat32(MUse* operand) const override;
   12876             :     void trySpecializeFloat32(TempAllocator& alloc) override;
   12877             : };
   12878             : 
   12879             : // Given a value, guard that the value is in a particular TypeSet, then returns
   12880             : // that value.
   12881           0 : class MTypeBarrier
   12882             :   : public MUnaryInstruction,
   12883             :     public TypeBarrierPolicy::Data
   12884             : {
   12885             :     BarrierKind barrierKind_;
   12886             : 
   12887        3494 :     MTypeBarrier(MDefinition* def, TemporaryTypeSet* types,
   12888             :                  BarrierKind kind = BarrierKind::TypeSet)
   12889        3494 :       : MUnaryInstruction(def),
   12890        3494 :         barrierKind_(kind)
   12891             :     {
   12892        3494 :         MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
   12893             : 
   12894        3494 :         MOZ_ASSERT(!types->unknown());
   12895        3494 :         setResultType(types->getKnownMIRType());
   12896        3494 :         setResultTypeSet(types);
   12897             : 
   12898        3494 :         setGuard();
   12899        3494 :         setMovable();
   12900        3494 :     }
   12901             : 
   12902             :   public:
   12903       43769 :     INSTRUCTION_HEADER(TypeBarrier)
   12904        3494 :     TRIVIAL_NEW_WRAPPERS
   12905             : 
   12906             :     void printOpcode(GenericPrinter& out) const override;
   12907             :     bool congruentTo(const MDefinition* def) const override;
   12908             : 
   12909        2184 :     AliasSet getAliasSet() const override {
   12910        2184 :         return AliasSet::None();
   12911             :     }
   12912         106 :     virtual bool neverHoist() const override {
   12913         106 :         return resultTypeSet()->empty();
   12914             :     }
   12915         602 :     BarrierKind barrierKind() const {
   12916         602 :         return barrierKind_;
   12917             :     }
   12918             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   12919             : 
   12920         127 :     bool alwaysBails() const {
   12921             :         // If mirtype of input doesn't agree with mirtype of barrier,
   12922             :         // we will definitely bail.
   12923         127 :         MIRType type = resultTypeSet()->getKnownMIRType();
   12924         127 :         if (type == MIRType::Value)
   12925          35 :             return false;
   12926          92 :         if (input()->type() == MIRType::Value)
   12927          12 :             return false;
   12928          80 :         if (input()->type() == MIRType::ObjectOrNull) {
   12929             :             // The ObjectOrNull optimization is only performed when the
   12930             :             // barrier's type is MIRType::Null.
   12931           0 :             MOZ_ASSERT(type == MIRType::Null);
   12932           0 :             return false;
   12933             :         }
   12934          80 :         return input()->type() != type;
   12935             :     }
   12936             : 
   12937           0 :     ALLOW_CLONE(MTypeBarrier)
   12938             : };
   12939             : 
   12940             : // Like MTypeBarrier, guard that the value is in the given type set. This is
   12941             : // used before property writes to ensure the value being written is represented
   12942             : // in the property types for the object.
   12943             : class MMonitorTypes
   12944             :   : public MUnaryInstruction,
   12945             :     public BoxInputsPolicy::Data
   12946             : {
   12947             :     const TemporaryTypeSet* typeSet_;
   12948             :     BarrierKind barrierKind_;
   12949             : 
   12950           0 :     MMonitorTypes(MDefinition* def, const TemporaryTypeSet* types, BarrierKind kind)
   12951           0 :       : MUnaryInstruction(def),
   12952             :         typeSet_(types),
   12953           0 :         barrierKind_(kind)
   12954             :     {
   12955           0 :         MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
   12956             : 
   12957           0 :         setGuard();
   12958           0 :         MOZ_ASSERT(!types->unknown());
   12959           0 :     }
   12960             : 
   12961             :   public:
   12962           0 :     INSTRUCTION_HEADER(MonitorTypes)
   12963           0 :     TRIVIAL_NEW_WRAPPERS
   12964             : 
   12965           0 :     const TemporaryTypeSet* typeSet() const {
   12966           0 :         return typeSet_;
   12967             :     }
   12968           0 :     BarrierKind barrierKind() const {
   12969           0 :         return barrierKind_;
   12970             :     }
   12971             : 
   12972           0 :     AliasSet getAliasSet() const override {
   12973           0 :         return AliasSet::None();
   12974             :     }
   12975             : };
   12976             : 
   12977             : // Given a value being written to another object, update the generational store
   12978             : // buffer if the value is in the nursery and object is in the tenured heap.
   12979           0 : class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
   12980             : {
   12981          24 :     MPostWriteBarrier(MDefinition* obj, MDefinition* value)
   12982          24 :       : MBinaryInstruction(obj, value)
   12983             :     {
   12984          24 :         setGuard();
   12985          24 :     }
   12986             : 
   12987             :   public:
   12988        1007 :     INSTRUCTION_HEADER(PostWriteBarrier)
   12989          24 :     TRIVIAL_NEW_WRAPPERS
   12990          38 :     NAMED_OPERANDS((0, object), (1, value))
   12991             : 
   12992          26 :     AliasSet getAliasSet() const override {
   12993          26 :         return AliasSet::None();
   12994             :     }
   12995             : 
   12996             : #ifdef DEBUG
   12997           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   12998             :         // During lowering, values that neither have object nor value MIR type
   12999             :         // are ignored, thus Float32 can show up at this point without any issue.
   13000           0 :         return use == getUseFor(1);
   13001             :     }
   13002             : #endif
   13003             : 
   13004           0 :     ALLOW_CLONE(MPostWriteBarrier)
   13005             : };
   13006             : 
   13007             : // Given a value being written to another object's elements at the specified
   13008             : // index, update the generational store buffer if the value is in the nursery
   13009             : // and object is in the tenured heap.
   13010           0 : class MPostWriteElementBarrier : public MTernaryInstruction
   13011             :                                , public MixPolicy<ObjectPolicy<0>, IntPolicy<2>>::Data
   13012             : {
   13013           0 :     MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, MDefinition* index)
   13014           0 :       : MTernaryInstruction(obj, value, index)
   13015             :     {
   13016           0 :         setGuard();
   13017           0 :     }
   13018             : 
   13019             :   public:
   13020           0 :     INSTRUCTION_HEADER(PostWriteElementBarrier)
   13021           0 :     TRIVIAL_NEW_WRAPPERS
   13022           0 :     NAMED_OPERANDS((0, object), (1, value), (2, index))
   13023             : 
   13024           0 :     AliasSet getAliasSet() const override {
   13025           0 :         return AliasSet::None();
   13026             :     }
   13027             : 
   13028             : #ifdef DEBUG
   13029           0 :     bool isConsistentFloat32Use(MUse* use) const override {
   13030             :         // During lowering, values that neither have object nor value MIR type
   13031             :         // are ignored, thus Float32 can show up at this point without any issue.
   13032           0 :         return use == getUseFor(1);
   13033             :     }
   13034             : #endif
   13035             : 
   13036           0 :     ALLOW_CLONE(MPostWriteElementBarrier)
   13037             : };
   13038             : 
   13039             : class MNewNamedLambdaObject : public MNullaryInstruction
   13040             : {
   13041             :     CompilerGCPointer<LexicalEnvironmentObject*> templateObj_;
   13042             : 
   13043           0 :     explicit MNewNamedLambdaObject(LexicalEnvironmentObject* templateObj)
   13044           0 :       : MNullaryInstruction(),
   13045           0 :         templateObj_(templateObj)
   13046             :     {
   13047           0 :         setResultType(MIRType::Object);
   13048           0 :     }
   13049             : 
   13050             :   public:
   13051           0 :     INSTRUCTION_HEADER(NewNamedLambdaObject)
   13052           0 :     TRIVIAL_NEW_WRAPPERS
   13053             : 
   13054           0 :     LexicalEnvironmentObject* templateObj() {
   13055           0 :         return templateObj_;
   13056             :     }
   13057           0 :     AliasSet getAliasSet() const override {
   13058           0 :         return AliasSet::None();
   13059             :     }
   13060           0 :     bool appendRoots(MRootList& roots) const override {
   13061           0 :         return roots.append(templateObj_);
   13062             :     }
   13063             : };
   13064             : 
   13065             : class MNewCallObjectBase : public MNullaryInstruction
   13066             : {
   13067             :     CompilerGCPointer<CallObject*> templateObj_;
   13068             : 
   13069             :   protected:
   13070           4 :     explicit MNewCallObjectBase(CallObject* templateObj)
   13071           4 :       : MNullaryInstruction(),
   13072           4 :         templateObj_(templateObj)
   13073             :     {
   13074           4 :         setResultType(MIRType::Object);
   13075           4 :     }
   13076             : 
   13077             :   public:
   13078           4 :     CallObject* templateObject() {
   13079           4 :         return templateObj_;
   13080             :     }
   13081          14 :     AliasSet getAliasSet() const override {
   13082          14 :         return AliasSet::None();
   13083             :     }
   13084           2 :     bool appendRoots(MRootList& roots) const override {
   13085           2 :         return roots.append(templateObj_);
   13086             :     }
   13087             : };
   13088             : 
   13089             : class MNewCallObject : public MNewCallObjectBase
   13090             : {
   13091             :   public:
   13092        1066 :     INSTRUCTION_HEADER(NewCallObject)
   13093             : 
   13094           4 :     explicit MNewCallObject(CallObject* templateObj)
   13095           4 :       : MNewCallObjectBase(templateObj)
   13096             :     {
   13097           4 :         MOZ_ASSERT(!templateObj->isSingleton());
   13098           4 :     }
   13099             : 
   13100             :     static MNewCallObject*
   13101           4 :     New(TempAllocator& alloc, CallObject* templateObj)
   13102             :     {
   13103           4 :         return new(alloc) MNewCallObject(templateObj);
   13104             :     }
   13105             : };
   13106             : 
   13107             : class MNewSingletonCallObject : public MNewCallObjectBase
   13108             : {
   13109             :   public:
   13110           0 :     INSTRUCTION_HEADER(NewSingletonCallObject)
   13111             : 
   13112           0 :     explicit MNewSingletonCallObject(CallObject* templateObj)
   13113           0 :       : MNewCallObjectBase(templateObj)
   13114           0 :     {}
   13115             : 
   13116             :     static MNewSingletonCallObject*
   13117           0 :     New(TempAllocator& alloc, CallObject* templateObj)
   13118             :     {
   13119           0 :         return new(alloc) MNewSingletonCallObject(templateObj);
   13120             :     }
   13121             : };
   13122             : 
   13123             : class MNewStringObject :
   13124             :   public MUnaryInstruction,
   13125             :   public ConvertToStringPolicy<0>::Data
   13126             : {
   13127             :     CompilerObject templateObj_;
   13128             : 
   13129           0 :     MNewStringObject(MDefinition* input, JSObject* templateObj)
   13130           0 :       : MUnaryInstruction(input),
   13131           0 :         templateObj_(templateObj)
   13132             :     {
   13133           0 :         setResultType(MIRType::Object);
   13134           0 :     }
   13135             : 
   13136             :   public:
   13137           0 :     INSTRUCTION_HEADER(NewStringObject)
   13138           0 :     TRIVIAL_NEW_WRAPPERS
   13139             : 
   13140             :     StringObject* templateObj() const;
   13141             : 
   13142           0 :     bool appendRoots(MRootList& roots) const override {
   13143           0 :         return roots.append(templateObj_);
   13144             :     }
   13145             : };
   13146             : 
   13147             : // This is an alias for MLoadFixedSlot.
   13148             : class MEnclosingEnvironment : public MLoadFixedSlot
   13149             : {
   13150           3 :     explicit MEnclosingEnvironment(MDefinition* obj)
   13151           3 :       : MLoadFixedSlot(obj, EnvironmentObject::enclosingEnvironmentSlot())
   13152             :     {
   13153           3 :         setResultType(MIRType::Object);
   13154           3 :     }
   13155             : 
   13156             :   public:
   13157           3 :     static MEnclosingEnvironment* New(TempAllocator& alloc, MDefinition* obj) {
   13158           3 :         return new(alloc) MEnclosingEnvironment(obj);
   13159             :     }
   13160             : 
   13161           0 :     AliasSet getAliasSet() const override {
   13162             :         // EnvironmentObject reserved slots are immutable.
   13163           0 :         return AliasSet::None();
   13164             :     }
   13165             : };
   13166             : 
   13167             : // This is an element of a spaghetti stack which is used to represent the memory
   13168             : // context which has to be restored in case of a bailout.
   13169             : struct MStoreToRecover : public TempObject, public InlineSpaghettiStackNode<MStoreToRecover>
   13170             : {
   13171             :     MDefinition* operand;
   13172             : 
   13173          87 :     explicit MStoreToRecover(MDefinition* operand)
   13174          87 :       : operand(operand)
   13175          87 :     { }
   13176             : };
   13177             : 
   13178             : typedef InlineSpaghettiStack<MStoreToRecover> MStoresToRecoverList;
   13179             : 
   13180             : // A resume point contains the information needed to reconstruct the Baseline
   13181             : // state from a position in the JIT. See the big comment near resumeAfter() in
   13182             : // IonBuilder.cpp.
   13183             : class MResumePoint final :
   13184             :   public MNode
   13185             : #ifdef DEBUG
   13186             :   , public InlineForwardListNode<MResumePoint>
   13187             : #endif
   13188             : {
   13189             :   public:
   13190             :     enum Mode {
   13191             :         ResumeAt,    // Resume until before the current instruction
   13192             :         ResumeAfter, // Resume after the current instruction
   13193             :         Outer        // State before inlining.
   13194             :     };
   13195             : 
   13196             :   private:
   13197             :     friend class MBasicBlock;
   13198             :     friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force);
   13199             : 
   13200             :     // List of stack slots needed to reconstruct the frame corresponding to the
   13201             :     // function which is compiled by IonBuilder.
   13202             :     FixedList<MUse> operands_;
   13203             : 
   13204             :     // List of stores needed to reconstruct the content of objects which are
   13205             :     // emulated by EmulateStateOf variants.
   13206             :     MStoresToRecoverList stores_;
   13207             : 
   13208             :     jsbytecode* pc_;
   13209             :     MInstruction* instruction_;
   13210             :     Mode mode_;
   13211             : 
   13212             :     MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode);
   13213             :     void inherit(MBasicBlock* state);
   13214             : 
   13215             :   protected:
   13216             :     // Initializes operands_ to an empty array of a fixed length.
   13217             :     // The array may then be filled in by inherit().
   13218             :     MOZ_MUST_USE bool init(TempAllocator& alloc);
   13219             : 
   13220        2354 :     void clearOperand(size_t index) {
   13221             :         // FixedList doesn't initialize its elements, so do an unchecked init.
   13222        2354 :         operands_[index].initUncheckedWithoutProducer(this);
   13223        2354 :     }
   13224             : 
   13225      419523 :     MUse* getUseFor(size_t index) override {
   13226      419523 :         return &operands_[index];
   13227             :     }
   13228        1736 :     const MUse* getUseFor(size_t index) const override {
   13229        1736 :         return &operands_[index];
   13230             :     }
   13231             : 
   13232             :   public:
   13233             :     static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, jsbytecode* pc,
   13234             :                              Mode mode);
   13235             :     static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, MResumePoint* model,
   13236             :                              const MDefinitionVector& operands);
   13237             :     static MResumePoint* Copy(TempAllocator& alloc, MResumePoint* src);
   13238             : 
   13239      781259 :     MNode::Kind kind() const override {
   13240      781259 :         return MNode::ResumePoint;
   13241             :     }
   13242      612064 :     size_t numAllocatedOperands() const {
   13243      612064 :         return operands_.length();
   13244             :     }
   13245       64000 :     uint32_t stackDepth() const {
   13246       64000 :         return numAllocatedOperands();
   13247             :     }
   13248      547532 :     size_t numOperands() const override {
   13249      547532 :         return numAllocatedOperands();
   13250             :     }
   13251      431719 :     size_t indexOf(const MUse* u) const final override {
   13252      431719 :         MOZ_ASSERT(u >= &operands_[0]);
   13253      431719 :         MOZ_ASSERT(u <= &operands_[numOperands() - 1]);
   13254      431719 :         return u - &operands_[0];
   13255             :     }
   13256      114429 :     void initOperand(size_t index, MDefinition* operand) {
   13257             :         // FixedList doesn't initialize its elements, so do an unchecked init.
   13258      114429 :         operands_[index].initUnchecked(operand, this);
   13259      114429 :     }
   13260        1108 :     void replaceOperand(size_t index, MDefinition* operand) final override {
   13261        1108 :         operands_[index].replaceProducer(operand);
   13262        1108 :     }
   13263             : 
   13264             :     bool isObservableOperand(MUse* u) const;
   13265             :     bool isObservableOperand(size_t index) const;
   13266             :     bool isRecoverableOperand(MUse* u) const;
   13267             : 
   13268     1128653 :     MDefinition* getOperand(size_t index) const override {
   13269     1128653 :         return operands_[index].producer();
   13270             :     }
   13271        1319 :     jsbytecode* pc() const {
   13272        1319 :         return pc_;
   13273             :     }
   13274             :     MResumePoint* caller() const;
   13275         174 :     uint32_t frameCount() const {
   13276         174 :         uint32_t count = 1;
   13277         210 :         for (MResumePoint* it = caller(); it; it = it->caller())
   13278          36 :             count++;
   13279         174 :         return count;
   13280             :     }
   13281       61322 :     MInstruction* instruction() {
   13282       61322 :         return instruction_;
   13283             :     }
   13284        4969 :     void setInstruction(MInstruction* ins) {
   13285        4969 :         MOZ_ASSERT(!instruction_);
   13286        4969 :         instruction_ = ins;
   13287        4969 :     }
   13288             :     // Only to be used by stealResumePoint.
   13289           0 :     void replaceInstruction(MInstruction* ins) {
   13290           0 :         MOZ_ASSERT(instruction_);
   13291           0 :         instruction_ = ins;
   13292           0 :     }
   13293          49 :     void resetInstruction() {
   13294          49 :         MOZ_ASSERT(instruction_);
   13295          49 :         instruction_ = nullptr;
   13296          49 :     }
   13297        1335 :     Mode mode() const {
   13298        1335 :         return mode_;
   13299             :     }
   13300             : 
   13301         811 :     void releaseUses() {
   13302       12088 :         for (size_t i = 0, e = numOperands(); i < e; i++) {
   13303       11277 :             if (operands_[i].hasProducer())
   13304        9520 :                 operands_[i].releaseProducer();
   13305             :         }
   13306         811 :     }
   13307             : 
   13308             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   13309             : 
   13310             :     // Register a store instruction on the current resume point. This
   13311             :     // instruction would be recovered when we are bailing out. The |cache|
   13312             :     // argument can be any resume point, it is used to share memory if we are
   13313             :     // doing the same modification.
   13314             :     void addStore(TempAllocator& alloc, MDefinition* store, const MResumePoint* cache = nullptr);
   13315             : 
   13316         213 :     MStoresToRecoverList::iterator storesBegin() const {
   13317         213 :         return stores_.begin();
   13318             :     }
   13319         213 :     MStoresToRecoverList::iterator storesEnd() const {
   13320         213 :         return stores_.end();
   13321             :     }
   13322             : 
   13323             :     virtual void dump(GenericPrinter& out) const override;
   13324             :     virtual void dump() const override;
   13325             : };
   13326             : 
   13327             : class MIsCallable
   13328             :   : public MUnaryInstruction,
   13329             :     public SingleObjectPolicy::Data
   13330             : {
   13331           0 :     explicit MIsCallable(MDefinition* object)
   13332           0 :       : MUnaryInstruction(object)
   13333             :     {
   13334           0 :         setResultType(MIRType::Boolean);
   13335           0 :         setMovable();
   13336           0 :     }
   13337             : 
   13338             :   public:
   13339           0 :     INSTRUCTION_HEADER(IsCallable)
   13340           0 :     TRIVIAL_NEW_WRAPPERS
   13341           0 :     NAMED_OPERANDS((0, object))
   13342             : 
   13343           0 :     AliasSet getAliasSet() const override {
   13344           0 :         return AliasSet::None();
   13345             :     }
   13346             : };
   13347             : 
   13348             : class MIsConstructor
   13349             :   : public MUnaryInstruction,
   13350             :     public SingleObjectPolicy::Data
   13351             : {
   13352             :   public:
   13353           0 :     explicit MIsConstructor(MDefinition* object)
   13354           0 :       : MUnaryInstruction(object)
   13355             :     {
   13356           0 :         setResultType(MIRType::Boolean);
   13357           0 :         setMovable();
   13358           0 :     }
   13359             : 
   13360             :   public:
   13361           0 :     INSTRUCTION_HEADER(IsConstructor)
   13362           0 :     TRIVIAL_NEW_WRAPPERS
   13363           0 :     NAMED_OPERANDS((0, object))
   13364             : 
   13365           0 :     AliasSet getAliasSet() const override {
   13366           0 :         return AliasSet::None();
   13367             :     }
   13368             : };
   13369             : 
   13370             : class MIsObject
   13371             :   : public MUnaryInstruction,
   13372             :     public BoxInputsPolicy::Data
   13373             : {
   13374           0 :     explicit MIsObject(MDefinition* object)
   13375           0 :     : MUnaryInstruction(object)
   13376             :     {
   13377           0 :         setResultType(MIRType::Boolean);
   13378           0 :         setMovable();
   13379           0 :     }
   13380             :   public:
   13381           0 :     INSTRUCTION_HEADER(IsObject)
   13382           0 :     TRIVIAL_NEW_WRAPPERS
   13383             :     NAMED_OPERANDS((0, object))
   13384             : 
   13385           0 :     bool congruentTo(const MDefinition* ins) const override {
   13386           0 :         return congruentIfOperandsEqual(ins);
   13387             :     }
   13388           0 :     AliasSet getAliasSet() const override {
   13389           0 :         return AliasSet::None();
   13390             :     }
   13391             : };
   13392             : 
   13393             : class MHasClass
   13394             :     : public MUnaryInstruction,
   13395             :       public SingleObjectPolicy::Data
   13396             : {
   13397             :     const Class* class_;
   13398             : 
   13399           0 :     MHasClass(MDefinition* object, const Class* clasp)
   13400           0 :       : MUnaryInstruction(object)
   13401           0 :       , class_(clasp)
   13402             :     {
   13403           0 :         MOZ_ASSERT(object->type() == MIRType::Object);
   13404           0 :         setResultType(MIRType::Boolean);
   13405           0 :         setMovable();
   13406           0 :     }
   13407             : 
   13408             :   public:
   13409           0 :     INSTRUCTION_HEADER(HasClass)
   13410           0 :     TRIVIAL_NEW_WRAPPERS
   13411           0 :     NAMED_OPERANDS((0, object))
   13412             : 
   13413           0 :     const Class* getClass() const {
   13414           0 :         return class_;
   13415             :     }
   13416           0 :     AliasSet getAliasSet() const override {
   13417           0 :         return AliasSet::None();
   13418             :     }
   13419           0 :     bool congruentTo(const MDefinition* ins) const override {
   13420           0 :         if (!ins->isHasClass())
   13421           0 :             return false;
   13422           0 :         if (getClass() != ins->toHasClass()->getClass())
   13423           0 :             return false;
   13424           0 :         return congruentIfOperandsEqual(ins);
   13425             :     }
   13426             : };
   13427             : 
   13428             : // Note: we might call a proxy trap, so this instruction is effectful.
   13429             : class MIsArray
   13430             :   : public MUnaryInstruction,
   13431             :     public BoxExceptPolicy<0, MIRType::Object>::Data
   13432             : {
   13433           0 :     explicit MIsArray(MDefinition* value)
   13434           0 :       : MUnaryInstruction(value)
   13435             :     {
   13436           0 :         setResultType(MIRType::Boolean);
   13437           0 :     }
   13438             : 
   13439             :   public:
   13440           0 :     INSTRUCTION_HEADER(IsArray)
   13441           0 :     TRIVIAL_NEW_WRAPPERS
   13442           0 :     NAMED_OPERANDS((0, value))
   13443             : };
   13444             : 
   13445             : class MCheckReturn
   13446             :   : public MBinaryInstruction,
   13447             :     public BoxInputsPolicy::Data
   13448             : {
   13449             :     explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
   13450             :       : MBinaryInstruction(retVal, thisVal)
   13451             :     {
   13452             :         setGuard();
   13453             :         setResultType(MIRType::Value);
   13454             :         setResultTypeSet(retVal->resultTypeSet());
   13455             :     }
   13456             : 
   13457             :   public:
   13458           0 :     INSTRUCTION_HEADER(CheckReturn)
   13459             :     TRIVIAL_NEW_WRAPPERS
   13460           0 :     NAMED_OPERANDS((0, returnValue), (1, thisValue))
   13461             : 
   13462             : };
   13463             : 
   13464             : // Increase the warm-up counter of the provided script upon execution and test if
   13465             : // the warm-up counter surpasses the threshold. Upon hit it will recompile the
   13466             : // outermost script (i.e. not the inlined script).
   13467             : class MRecompileCheck : public MNullaryInstruction
   13468             : {
   13469             :   public:
   13470             :     enum RecompileCheckType {
   13471             :         RecompileCheck_OptimizationLevel,
   13472             :         RecompileCheck_Inlining
   13473             :     };
   13474             : 
   13475             :   private:
   13476             :     JSScript* script_;
   13477             :     uint32_t recompileThreshold_;
   13478             :     bool forceRecompilation_;
   13479             :     bool increaseWarmUpCounter_;
   13480             : 
   13481           9 :     MRecompileCheck(JSScript* script, uint32_t recompileThreshold, RecompileCheckType type)
   13482           9 :       : script_(script),
   13483           9 :         recompileThreshold_(recompileThreshold)
   13484             :     {
   13485           9 :         switch (type) {
   13486             :           case RecompileCheck_OptimizationLevel:
   13487           0 :             forceRecompilation_ = false;
   13488           0 :             increaseWarmUpCounter_ = true;
   13489           0 :             break;
   13490             :           case RecompileCheck_Inlining:
   13491           9 :             forceRecompilation_ = true;
   13492           9 :             increaseWarmUpCounter_ = false;
   13493           9 :             break;
   13494             :           default:
   13495           0 :             MOZ_CRASH("Unexpected recompile check type");
   13496             :         }
   13497             : 
   13498           9 :         setGuard();
   13499           9 :     }
   13500             : 
   13501             :   public:
   13502        1822 :     INSTRUCTION_HEADER(RecompileCheck)
   13503           9 :     TRIVIAL_NEW_WRAPPERS
   13504             : 
   13505           6 :     JSScript* script() const {
   13506           6 :         return script_;
   13507             :     }
   13508             : 
   13509           6 :     uint32_t recompileThreshold() const {
   13510           6 :         return recompileThreshold_;
   13511             :     }
   13512             : 
   13513           6 :     bool forceRecompilation() const {
   13514           6 :         return forceRecompilation_;
   13515             :     }
   13516             : 
   13517           6 :     bool increaseWarmUpCounter() const {
   13518           6 :         return increaseWarmUpCounter_;
   13519             :     }
   13520             : 
   13521          89 :     AliasSet getAliasSet() const override {
   13522          89 :         return AliasSet::None();
   13523             :     }
   13524             : };
   13525             : 
   13526           0 : class MAtomicIsLockFree
   13527             :   : public MUnaryInstruction,
   13528             :     public ConvertToInt32Policy<0>::Data
   13529             : {
   13530           0 :     explicit MAtomicIsLockFree(MDefinition* value)
   13531           0 :       : MUnaryInstruction(value)
   13532             :     {
   13533           0 :         setResultType(MIRType::Boolean);
   13534           0 :         setMovable();
   13535           0 :     }
   13536             : 
   13537             :   public:
   13538           0 :     INSTRUCTION_HEADER(AtomicIsLockFree)
   13539           0 :     TRIVIAL_NEW_WRAPPERS
   13540             : 
   13541             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   13542             : 
   13543           0 :     AliasSet getAliasSet() const override {
   13544           0 :         return AliasSet::None();
   13545             :     }
   13546             : 
   13547           0 :     bool congruentTo(const MDefinition* ins) const override {
   13548           0 :         return congruentIfOperandsEqual(ins);
   13549             :     }
   13550             : 
   13551             :     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
   13552           0 :     bool canRecoverOnBailout() const override {
   13553           0 :         return true;
   13554             :     }
   13555             : 
   13556           0 :     ALLOW_CLONE(MAtomicIsLockFree)
   13557             : };
   13558             : 
   13559             : // This applies to an object that is known to be a TypedArray, it bails out
   13560             : // if the obj does not map a SharedArrayBuffer.
   13561             : 
   13562             : class MGuardSharedTypedArray
   13563             :   : public MUnaryInstruction,
   13564             :     public SingleObjectPolicy::Data
   13565             : {
   13566           0 :     explicit MGuardSharedTypedArray(MDefinition* obj)
   13567           0 :       : MUnaryInstruction(obj)
   13568             :     {
   13569           0 :         setGuard();
   13570           0 :         setMovable();
   13571           0 :     }
   13572             : 
   13573             : public:
   13574           0 :     INSTRUCTION_HEADER(GuardSharedTypedArray)
   13575           0 :     TRIVIAL_NEW_WRAPPERS
   13576           0 :     NAMED_OPERANDS((0, object))
   13577             : 
   13578           0 :     AliasSet getAliasSet() const override {
   13579           0 :         return AliasSet::None();
   13580             :     }
   13581             : };
   13582             : 
   13583             : class MCompareExchangeTypedArrayElement
   13584             :   : public MAryInstruction<4>,
   13585             :     public Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
   13586             : {
   13587             :     Scalar::Type arrayType_;
   13588             : 
   13589           0 :     explicit MCompareExchangeTypedArrayElement(MDefinition* elements, MDefinition* index,
   13590             :                                                Scalar::Type arrayType, MDefinition* oldval,
   13591             :                                                MDefinition* newval)
   13592           0 :       : arrayType_(arrayType)
   13593             :     {
   13594           0 :         initOperand(0, elements);
   13595           0 :         initOperand(1, index);
   13596           0 :         initOperand(2, oldval);
   13597           0 :         initOperand(3, newval);
   13598           0 :         setGuard();             // Not removable
   13599           0 :     }
   13600             : 
   13601             :   public:
   13602           0 :     INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)
   13603           0 :     TRIVIAL_NEW_WRAPPERS
   13604           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, oldval), (3, newval))
   13605             : 
   13606           0 :     bool isByteArray() const {
   13607           0 :         return (arrayType_ == Scalar::Int8 ||
   13608           0 :                 arrayType_ == Scalar::Uint8);
   13609             :     }
   13610             :     int oldvalOperand() {
   13611             :         return 2;
   13612             :     }
   13613           0 :     Scalar::Type arrayType() const {
   13614           0 :         return arrayType_;
   13615             :     }
   13616           0 :     AliasSet getAliasSet() const override {
   13617           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   13618             :     }
   13619             : };
   13620             : 
   13621             : class MAtomicExchangeTypedArrayElement
   13622             :   : public MAryInstruction<3>,
   13623             :     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
   13624             : {
   13625             :     Scalar::Type arrayType_;
   13626             : 
   13627           0 :     MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, MDefinition* value,
   13628             :                                      Scalar::Type arrayType)
   13629           0 :       : arrayType_(arrayType)
   13630             :     {
   13631           0 :         MOZ_ASSERT(arrayType <= Scalar::Uint32);
   13632           0 :         initOperand(0, elements);
   13633           0 :         initOperand(1, index);
   13634           0 :         initOperand(2, value);
   13635           0 :         setGuard();             // Not removable
   13636           0 :     }
   13637             : 
   13638             :   public:
   13639           0 :     INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)
   13640           0 :     TRIVIAL_NEW_WRAPPERS
   13641           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, value))
   13642             : 
   13643           0 :     bool isByteArray() const {
   13644           0 :         return (arrayType_ == Scalar::Int8 ||
   13645           0 :                 arrayType_ == Scalar::Uint8);
   13646             :     }
   13647           0 :     Scalar::Type arrayType() const {
   13648           0 :         return arrayType_;
   13649             :     }
   13650           0 :     AliasSet getAliasSet() const override {
   13651           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   13652             :     }
   13653             : };
   13654             : 
   13655             : class MAtomicTypedArrayElementBinop
   13656             :     : public MAryInstruction<3>,
   13657             :       public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
   13658             : {
   13659             :   private:
   13660             :     AtomicOp op_;
   13661             :     Scalar::Type arrayType_;
   13662             : 
   13663             :   protected:
   13664           0 :     explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, MDefinition* index,
   13665             :                                            Scalar::Type arrayType, MDefinition* value)
   13666           0 :       : op_(op),
   13667           0 :         arrayType_(arrayType)
   13668             :     {
   13669           0 :         initOperand(0, elements);
   13670           0 :         initOperand(1, index);
   13671           0 :         initOperand(2, value);
   13672           0 :         setGuard();             // Not removable
   13673           0 :     }
   13674             : 
   13675             :   public:
   13676           0 :     INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)
   13677           0 :     TRIVIAL_NEW_WRAPPERS
   13678           0 :     NAMED_OPERANDS((0, elements), (1, index), (2, value))
   13679             : 
   13680           0 :     bool isByteArray() const {
   13681           0 :         return (arrayType_ == Scalar::Int8 ||
   13682           0 :                 arrayType_ == Scalar::Uint8);
   13683             :     }
   13684           0 :     AtomicOp operation() const {
   13685           0 :         return op_;
   13686             :     }
   13687           0 :     Scalar::Type arrayType() const {
   13688           0 :         return arrayType_;
   13689             :     }
   13690           0 :     AliasSet getAliasSet() const override {
   13691           0 :         return AliasSet::Store(AliasSet::UnboxedElement);
   13692             :     }
   13693             : };
   13694             : 
   13695           0 : class MDebugger : public MNullaryInstruction
   13696             : {
   13697             :   public:
   13698           0 :     INSTRUCTION_HEADER(Debugger)
   13699           0 :     TRIVIAL_NEW_WRAPPERS
   13700             : };
   13701             : 
   13702             : class MCheckIsObj
   13703             :   : public MUnaryInstruction,
   13704             :     public BoxInputsPolicy::Data
   13705             : {
   13706             :     uint8_t checkKind_;
   13707             : 
   13708           6 :     MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
   13709           6 :       : MUnaryInstruction(toCheck),
   13710           6 :         checkKind_(checkKind)
   13711             :     {
   13712           6 :         setResultType(MIRType::Value);
   13713           6 :         setResultTypeSet(toCheck->resultTypeSet());
   13714           6 :         setGuard();
   13715           6 :     }
   13716             : 
   13717             :   public:
   13718          23 :     INSTRUCTION_HEADER(CheckIsObj)
   13719           6 :     TRIVIAL_NEW_WRAPPERS
   13720           0 :     NAMED_OPERANDS((0, checkValue))
   13721             : 
   13722           0 :     uint8_t checkKind() const { return checkKind_; }
   13723             : 
   13724           2 :     AliasSet getAliasSet() const override {
   13725           2 :         return AliasSet::None();
   13726             :     }
   13727             : };
   13728             : 
   13729             : class MCheckIsCallable
   13730             :   : public MUnaryInstruction,
   13731             :     public BoxInputsPolicy::Data
   13732             : {
   13733             :     uint8_t checkKind_;
   13734             : 
   13735           0 :     MCheckIsCallable(MDefinition* toCheck, uint8_t checkKind)
   13736           0 :       : MUnaryInstruction(toCheck),
   13737           0 :         checkKind_(checkKind)
   13738             :     {
   13739           0 :         setResultType(MIRType::Value);
   13740           0 :         setResultTypeSet(toCheck->resultTypeSet());
   13741           0 :         setGuard();
   13742           0 :     }
   13743             : 
   13744             :   public:
   13745           0 :     INSTRUCTION_HEADER(CheckIsCallable)
   13746           0 :     TRIVIAL_NEW_WRAPPERS
   13747           0 :     NAMED_OPERANDS((0, checkValue))
   13748             : 
   13749           0 :     uint8_t checkKind() const { return checkKind_; }
   13750             : 
   13751           0 :     AliasSet getAliasSet() const override {
   13752           0 :         return AliasSet::None();
   13753             :     }
   13754             : };
   13755             : 
   13756             : class MCheckObjCoercible
   13757             :   : public MUnaryInstruction,
   13758             :     public BoxInputsPolicy::Data
   13759             : {
   13760           0 :     explicit MCheckObjCoercible(MDefinition* toCheck)
   13761           0 :       : MUnaryInstruction(toCheck)
   13762             :     {
   13763           0 :         setGuard();
   13764           0 :         setResultType(MIRType::Value);
   13765           0 :         setResultTypeSet(toCheck->resultTypeSet());
   13766           0 :     }
   13767             : 
   13768             :   public:
   13769           0 :     INSTRUCTION_HEADER(CheckObjCoercible)
   13770           0 :     TRIVIAL_NEW_WRAPPERS
   13771           0 :     NAMED_OPERANDS((0, checkValue))
   13772             : };
   13773             : 
   13774             : class MDebugCheckSelfHosted
   13775             :   : public MUnaryInstruction,
   13776             :     public BoxInputsPolicy::Data
   13777             : {
   13778          59 :     explicit MDebugCheckSelfHosted(MDefinition* toCheck)
   13779          59 :       : MUnaryInstruction(toCheck)
   13780             :     {
   13781          59 :         setGuard();
   13782          59 :         setResultType(MIRType::Value);
   13783          59 :         setResultTypeSet(toCheck->resultTypeSet());
   13784          59 :     }
   13785             : 
   13786             :   public:
   13787         111 :     INSTRUCTION_HEADER(DebugCheckSelfHosted)
   13788          59 :     TRIVIAL_NEW_WRAPPERS
   13789           0 :     NAMED_OPERANDS((0, checkValue))
   13790             : 
   13791             : };
   13792             : 
   13793             : class MFinishBoundFunctionInit
   13794             :   : public MTernaryInstruction,
   13795             :     public Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2>>::Data
   13796             : {
   13797           0 :     MFinishBoundFunctionInit(MDefinition* bound, MDefinition* target, MDefinition* argCount)
   13798           0 :       : MTernaryInstruction(bound, target, argCount)
   13799           0 :     { }
   13800             : 
   13801             :   public:
   13802           0 :     INSTRUCTION_HEADER(FinishBoundFunctionInit)
   13803           0 :     TRIVIAL_NEW_WRAPPERS
   13804           0 :     NAMED_OPERANDS((0, bound), (1, target), (2, argCount))
   13805             : };
   13806             : 
   13807             : // Flips the input's sign bit, independently of the rest of the number's
   13808             : // payload. Note this is different from multiplying by minus-one, which has
   13809             : // side-effects for e.g. NaNs.
   13810             : class MWasmNeg
   13811             :   : public MUnaryInstruction,
   13812             :     public NoTypePolicy::Data
   13813             : {
   13814           0 :     MWasmNeg(MDefinition* op, MIRType type)
   13815           0 :       : MUnaryInstruction(op)
   13816             :     {
   13817           0 :         setResultType(type);
   13818           0 :         setMovable();
   13819           0 :     }
   13820             : 
   13821             :   public:
   13822           0 :     INSTRUCTION_HEADER(WasmNeg)
   13823           0 :     TRIVIAL_NEW_WRAPPERS
   13824             : };
   13825             : 
   13826             : class MWasmLoadTls
   13827             :   : public MUnaryInstruction,
   13828             :     public NoTypePolicy::Data
   13829             : {
   13830             :     uint32_t offset_;
   13831             :     AliasSet aliases_;
   13832             : 
   13833             :     explicit MWasmLoadTls(MDefinition* tlsPointer, uint32_t offset, MIRType type, AliasSet aliases)
   13834             :       : MUnaryInstruction(tlsPointer),
   13835             :         offset_(offset),
   13836             :         aliases_(aliases)
   13837             :     {
   13838             :         // Different Tls data have different alias classes and only those classes are allowed.
   13839             :         MOZ_ASSERT(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
   13840             :                    aliases_.flags() == AliasSet::None().flags());
   13841             : 
   13842             :         // The only types supported at the moment.
   13843             :         MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32);
   13844             : 
   13845             :         setMovable();
   13846             :         setResultType(type);
   13847             :     }
   13848             : 
   13849             :   public:
   13850           0 :     INSTRUCTION_HEADER(WasmLoadTls)
   13851             :     TRIVIAL_NEW_WRAPPERS
   13852             :     NAMED_OPERANDS((0, tlsPtr))
   13853             : 
   13854           0 :     uint32_t offset() const {
   13855           0 :         return offset_;
   13856             :     }
   13857             : 
   13858           0 :     bool congruentTo(const MDefinition* ins) const override {
   13859           0 :         return op() == ins->op() &&
   13860           0 :                offset() == ins->toWasmLoadTls()->offset() &&
   13861           0 :                type() == ins->type();
   13862             :     }
   13863             : 
   13864           0 :     HashNumber valueHash() const override {
   13865           0 :         return op() + offset();
   13866             :     }
   13867             : 
   13868           0 :     AliasSet getAliasSet() const override {
   13869           0 :         return aliases_;
   13870             :     }
   13871             : };
   13872             : 
   13873             : class MWasmBoundsCheck
   13874             :   : public MBinaryInstruction,
   13875             :     public NoTypePolicy::Data
   13876             : {
   13877             :     wasm::BytecodeOffset bytecodeOffset_;
   13878             : 
   13879           0 :     explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
   13880             :                               wasm::BytecodeOffset bytecodeOffset)
   13881           0 :       : MBinaryInstruction(index, boundsCheckLimit),
   13882           0 :         bytecodeOffset_(bytecodeOffset)
   13883             :     {
   13884             :         // Bounds check is effectful: it throws for OOB.
   13885           0 :         setGuard();
   13886           0 :     }
   13887             : 
   13888             :   public:
   13889           0 :     INSTRUCTION_HEADER(WasmBoundsCheck)
   13890           0 :     TRIVIAL_NEW_WRAPPERS
   13891           0 :     NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
   13892             : 
   13893           0 :     AliasSet getAliasSet() const override {
   13894           0 :         return AliasSet::None();
   13895             :     }
   13896             : 
   13897             :     bool isRedundant() const {
   13898             :         return !isGuard();
   13899             :     }
   13900             : 
   13901           0 :     void setRedundant() {
   13902           0 :         setNotGuard();
   13903           0 :     }
   13904             : 
   13905             :     wasm::BytecodeOffset bytecodeOffset() const {
   13906             :         return bytecodeOffset_;
   13907             :     }
   13908             : };
   13909             : 
   13910             : class MWasmAddOffset
   13911             :   : public MUnaryInstruction,
   13912             :     public NoTypePolicy::Data
   13913             : {
   13914             :     uint32_t offset_;
   13915             :     wasm::BytecodeOffset bytecodeOffset_;
   13916             : 
   13917           0 :     MWasmAddOffset(MDefinition* base, uint32_t offset, wasm::BytecodeOffset bytecodeOffset)
   13918           0 :       : MUnaryInstruction(base),
   13919             :         offset_(offset),
   13920           0 :         bytecodeOffset_(bytecodeOffset)
   13921             :     {
   13922           0 :         setGuard();
   13923           0 :         setResultType(MIRType::Int32);
   13924           0 :     }
   13925             : 
   13926             :   public:
   13927           0 :     INSTRUCTION_HEADER(WasmAddOffset)
   13928           0 :     TRIVIAL_NEW_WRAPPERS
   13929           0 :     NAMED_OPERANDS((0, base))
   13930             : 
   13931             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   13932             : 
   13933           0 :     AliasSet getAliasSet() const override {
   13934           0 :         return AliasSet::None();
   13935             :     }
   13936             : 
   13937           0 :     uint32_t offset() const {
   13938           0 :         return offset_;
   13939             :     }
   13940           0 :     wasm::BytecodeOffset bytecodeOffset() const {
   13941           0 :         return bytecodeOffset_;
   13942             :     }
   13943             : };
   13944             : 
   13945             : class MWasmLoad
   13946             :   : public MVariadicInstruction, // memoryBase is nullptr on some platforms
   13947             :     public NoTypePolicy::Data
   13948             : {
   13949             :     wasm::MemoryAccessDesc access_;
   13950             : 
   13951           0 :     explicit MWasmLoad(const wasm::MemoryAccessDesc& access, MIRType resultType)
   13952           0 :       : access_(access)
   13953             :     {
   13954           0 :         setGuard();
   13955           0 :         setResultType(resultType);
   13956           0 :     }
   13957             : 
   13958             :   public:
   13959           0 :     INSTRUCTION_HEADER(WasmLoad)
   13960           0 :     NAMED_OPERANDS((0, base), (1, memoryBase));
   13961             : 
   13962           0 :     static MWasmLoad* New(TempAllocator& alloc,
   13963             :                           MDefinition* memoryBase,
   13964             :                           MDefinition* base,
   13965             :                           const wasm::MemoryAccessDesc& access,
   13966             :                           MIRType resultType)
   13967             :     {
   13968           0 :         MWasmLoad* load = new(alloc) MWasmLoad(access, resultType);
   13969           0 :         if (!load->init(alloc, 1 + !!memoryBase))
   13970           0 :             return nullptr;
   13971             : 
   13972           0 :         load->initOperand(0, base);
   13973           0 :         if (memoryBase)
   13974           0 :             load->initOperand(1, memoryBase);
   13975             : 
   13976           0 :         return load;
   13977             :     }
   13978             : 
   13979           0 :     const wasm::MemoryAccessDesc& access() const {
   13980           0 :         return access_;
   13981             :     }
   13982             : 
   13983           0 :     AliasSet getAliasSet() const override {
   13984             :         // When a barrier is needed, make the instruction effectful by giving
   13985             :         // it a "store" effect.
   13986           0 :         if (access_.isAtomic())
   13987           0 :             return AliasSet::Store(AliasSet::WasmHeap);
   13988           0 :         return AliasSet::Load(AliasSet::WasmHeap);
   13989             :     }
   13990             : };
   13991             : 
   13992             : class MWasmStore
   13993             :   : public MVariadicInstruction,
   13994             :     public NoTypePolicy::Data
   13995             : {
   13996             :     wasm::MemoryAccessDesc access_;
   13997             : 
   13998           0 :     explicit MWasmStore(const wasm::MemoryAccessDesc& access)
   13999           0 :       : access_(access)
   14000             :     {
   14001           0 :         setGuard();
   14002           0 :     }
   14003             : 
   14004             :   public:
   14005           0 :     INSTRUCTION_HEADER(WasmStore)
   14006           0 :     NAMED_OPERANDS((0, base), (1, value), (2, memoryBase))
   14007             : 
   14008           0 :     static MWasmStore* New(TempAllocator& alloc,
   14009             :                            MDefinition* memoryBase,
   14010             :                            MDefinition* base,
   14011             :                            const wasm::MemoryAccessDesc& access,
   14012             :                            MDefinition* value)
   14013             :     {
   14014           0 :         MWasmStore* store = new(alloc) MWasmStore(access);
   14015           0 :         if (!store->init(alloc, 2 + !!memoryBase))
   14016           0 :             return nullptr;
   14017             : 
   14018           0 :         store->initOperand(0, base);
   14019           0 :         store->initOperand(1, value);
   14020           0 :         if (memoryBase)
   14021           0 :             store->initOperand(2, memoryBase);
   14022             : 
   14023           0 :         return store;
   14024             :     }
   14025             : 
   14026           0 :     const wasm::MemoryAccessDesc& access() const {
   14027           0 :         return access_;
   14028             :     }
   14029             : 
   14030           0 :     AliasSet getAliasSet() const override {
   14031           0 :         return AliasSet::Store(AliasSet::WasmHeap);
   14032             :     }
   14033             : };
   14034             : 
   14035             : class MAsmJSMemoryAccess
   14036             : {
   14037             :     uint32_t offset_;
   14038             :     Scalar::Type accessType_;
   14039             :     bool needsBoundsCheck_;
   14040             : 
   14041             :   public:
   14042           0 :     explicit MAsmJSMemoryAccess(Scalar::Type accessType)
   14043           0 :       : offset_(0),
   14044             :         accessType_(accessType),
   14045           0 :         needsBoundsCheck_(true)
   14046             :     {
   14047           0 :         MOZ_ASSERT(accessType != Scalar::Uint8Clamped);
   14048           0 :         MOZ_ASSERT(!Scalar::isSimdType(accessType));
   14049           0 :     }
   14050             : 
   14051           0 :     uint32_t offset() const { return offset_; }
   14052             :     uint32_t endOffset() const { return offset() + byteSize(); }
   14053           0 :     Scalar::Type accessType() const { return accessType_; }
   14054           0 :     unsigned byteSize() const { return TypedArrayElemSize(accessType()); }
   14055             :     bool needsBoundsCheck() const { return needsBoundsCheck_; }
   14056             : 
   14057           0 :     wasm::MemoryAccessDesc access() const {
   14058           0 :         return wasm::MemoryAccessDesc(accessType_, Scalar::byteSize(accessType_), offset_,
   14059           0 :                                       mozilla::Nothing());
   14060             :     }
   14061             : 
   14062           0 :     void removeBoundsCheck() { needsBoundsCheck_ = false; }
   14063           0 :     void setOffset(uint32_t o) { offset_ = o; }
   14064             : };
   14065             : 
   14066             : class MAsmJSLoadHeap
   14067             :   : public MVariadicInstruction, // 1 plus optional memoryBase and boundsCheckLimit
   14068             :     public MAsmJSMemoryAccess,
   14069             :     public NoTypePolicy::Data
   14070             : {
   14071             :     uint32_t memoryBaseIndex_;
   14072             :     uint32_t boundsCheckIndex_;
   14073             : 
   14074           0 :     explicit MAsmJSLoadHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
   14075             :                             Scalar::Type accessType)
   14076           0 :       : MAsmJSMemoryAccess(accessType),
   14077             :         memoryBaseIndex_(memoryBaseIndex),
   14078           0 :         boundsCheckIndex_(boundsCheckIndex)
   14079             :     {
   14080           0 :         setResultType(ScalarTypeToMIRType(accessType));
   14081           0 :     }
   14082             : 
   14083             :   public:
   14084           0 :     INSTRUCTION_HEADER(AsmJSLoadHeap)
   14085             : 
   14086           0 :     static MAsmJSLoadHeap* New(TempAllocator& alloc,
   14087             :                                MDefinition* memoryBase,
   14088             :                                MDefinition* base,
   14089             :                                MDefinition* boundsCheckLimit,
   14090             :                                Scalar::Type accessType)
   14091             :     {
   14092           0 :         uint32_t nextIndex = 1;
   14093           0 :         uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
   14094           0 :         uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
   14095             : 
   14096             :         MAsmJSLoadHeap* load = new(alloc) MAsmJSLoadHeap(memoryBaseIndex, boundsCheckIndex,
   14097           0 :                                                          accessType);
   14098           0 :         if (!load->init(alloc, nextIndex))
   14099           0 :             return nullptr;
   14100             : 
   14101           0 :         load->initOperand(0, base);
   14102           0 :         if (memoryBase)
   14103           0 :             load->initOperand(memoryBaseIndex, memoryBase);
   14104           0 :         if (boundsCheckLimit)
   14105           0 :             load->initOperand(boundsCheckIndex, boundsCheckLimit);
   14106             : 
   14107           0 :         return load;
   14108             :     }
   14109             : 
   14110           0 :     MDefinition* base() const { return getOperand(0); }
   14111           0 :     void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
   14112             :     MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
   14113             :     MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
   14114             : 
   14115             :     bool congruentTo(const MDefinition* ins) const override;
   14116           0 :     AliasSet getAliasSet() const override {
   14117           0 :         return AliasSet::Load(AliasSet::WasmHeap);
   14118             :     }
   14119             :     AliasType mightAlias(const MDefinition* def) const override;
   14120             : };
   14121             : 
   14122             : class MAsmJSStoreHeap
   14123             :   : public MVariadicInstruction, // 2 plus optional memoryBase and boundsCheckLimit
   14124             :     public MAsmJSMemoryAccess,
   14125             :     public NoTypePolicy::Data
   14126             : {
   14127             :     uint32_t memoryBaseIndex_;
   14128             :     uint32_t boundsCheckIndex_;
   14129             : 
   14130           0 :     explicit MAsmJSStoreHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
   14131             :                              Scalar::Type accessType)
   14132           0 :       : MAsmJSMemoryAccess(accessType),
   14133             :         memoryBaseIndex_(memoryBaseIndex),
   14134           0 :         boundsCheckIndex_(boundsCheckIndex)
   14135             :     {
   14136           0 :     }
   14137             : 
   14138             :   public:
   14139           0 :     INSTRUCTION_HEADER(AsmJSStoreHeap)
   14140             : 
   14141           0 :     static MAsmJSStoreHeap* New(TempAllocator& alloc,
   14142             :                                 MDefinition* memoryBase,
   14143             :                                 MDefinition* base,
   14144             :                                 MDefinition* boundsCheckLimit,
   14145             :                                 Scalar::Type accessType,
   14146             :                                 MDefinition* v)
   14147             :     {
   14148           0 :         uint32_t nextIndex = 2;
   14149           0 :         uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
   14150           0 :         uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
   14151             : 
   14152             :         MAsmJSStoreHeap* store = new(alloc) MAsmJSStoreHeap(memoryBaseIndex, boundsCheckIndex,
   14153           0 :                                                             accessType);
   14154           0 :         if (!store->init(alloc, nextIndex))
   14155           0 :             return nullptr;
   14156             : 
   14157           0 :         store->initOperand(0, base);
   14158           0 :         store->initOperand(1, v);
   14159           0 :         if (memoryBase)
   14160           0 :             store->initOperand(memoryBaseIndex, memoryBase);
   14161           0 :         if (boundsCheckLimit)
   14162           0 :             store->initOperand(boundsCheckIndex, boundsCheckLimit);
   14163             : 
   14164           0 :         return store;
   14165             :     }
   14166             : 
   14167           0 :     MDefinition* base() const { return getOperand(0); }
   14168           0 :     void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
   14169           0 :     MDefinition* value() const { return getOperand(1); }
   14170             :     MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
   14171             :     MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
   14172             : 
   14173           0 :     AliasSet getAliasSet() const override {
   14174           0 :         return AliasSet::Store(AliasSet::WasmHeap);
   14175             :     }
   14176             : };
   14177             : 
   14178             : class MAsmJSCompareExchangeHeap
   14179             :   : public MVariadicInstruction,
   14180             :     public NoTypePolicy::Data
   14181             : {
   14182             :     wasm::MemoryAccessDesc access_;
   14183             :     wasm::BytecodeOffset bytecodeOffset_;
   14184             : 
   14185           0 :     explicit MAsmJSCompareExchangeHeap(const wasm::MemoryAccessDesc& access,
   14186             :                                        wasm::BytecodeOffset bytecodeOffset)
   14187           0 :       : access_(access),
   14188           0 :         bytecodeOffset_(bytecodeOffset)
   14189             :     {
   14190           0 :         setGuard(); // Not removable
   14191           0 :         setResultType(MIRType::Int32);
   14192           0 :     }
   14193             : 
   14194             :   public:
   14195           0 :     INSTRUCTION_HEADER(AsmJSCompareExchangeHeap)
   14196             : 
   14197           0 :     static MAsmJSCompareExchangeHeap* New(TempAllocator& alloc,
   14198             :                                           wasm::BytecodeOffset bytecodeOffset,
   14199             :                                           MDefinition* memoryBase,
   14200             :                                           MDefinition* base,
   14201             :                                           const wasm::MemoryAccessDesc& access,
   14202             :                                           MDefinition* oldv,
   14203             :                                           MDefinition* newv,
   14204             :                                           MDefinition* tls)
   14205             :     {
   14206           0 :         MAsmJSCompareExchangeHeap* cas = new(alloc) MAsmJSCompareExchangeHeap(access, bytecodeOffset);
   14207           0 :         if (!cas->init(alloc, 4 + !!memoryBase))
   14208           0 :             return nullptr;
   14209           0 :         cas->initOperand(0, base);
   14210           0 :         cas->initOperand(1, oldv);
   14211           0 :         cas->initOperand(2, newv);
   14212           0 :         cas->initOperand(3, tls);
   14213           0 :         if (memoryBase)
   14214           0 :             cas->initOperand(4, memoryBase);
   14215           0 :         return cas;
   14216             :     }
   14217             : 
   14218           0 :     const wasm::MemoryAccessDesc& access() const { return access_; }
   14219             :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
   14220             : 
   14221           0 :     MDefinition* base() const { return getOperand(0); }
   14222           0 :     MDefinition* oldValue() const { return getOperand(1); }
   14223           0 :     MDefinition* newValue() const { return getOperand(2); }
   14224             :     MDefinition* tls() const { return getOperand(3); }
   14225             :     MDefinition* memoryBase() const { return getOperand(4); }
   14226             : 
   14227           0 :     AliasSet getAliasSet() const override {
   14228           0 :         return AliasSet::Store(AliasSet::WasmHeap);
   14229             :     }
   14230             : };
   14231             : 
   14232             : class MAsmJSAtomicExchangeHeap
   14233             :   : public MVariadicInstruction,
   14234             :     public NoTypePolicy::Data
   14235             : {
   14236             :     wasm::MemoryAccessDesc access_;
   14237             :     wasm::BytecodeOffset bytecodeOffset_;
   14238             : 
   14239           0 :     explicit MAsmJSAtomicExchangeHeap(const wasm::MemoryAccessDesc& access,
   14240             :                                       wasm::BytecodeOffset bytecodeOffset)
   14241           0 :         : access_(access),
   14242           0 :           bytecodeOffset_(bytecodeOffset)
   14243             :     {
   14244           0 :         setGuard();             // Not removable
   14245           0 :         setResultType(MIRType::Int32);
   14246           0 :     }
   14247             : 
   14248             :   public:
   14249           0 :     INSTRUCTION_HEADER(AsmJSAtomicExchangeHeap)
   14250             : 
   14251           0 :     static MAsmJSAtomicExchangeHeap* New(TempAllocator& alloc,
   14252             :                                          wasm::BytecodeOffset bytecodeOffset,
   14253             :                                          MDefinition* memoryBase,
   14254             :                                          MDefinition* base,
   14255             :                                          const wasm::MemoryAccessDesc& access,
   14256             :                                          MDefinition* value,
   14257             :                                          MDefinition* tls)
   14258             :     {
   14259           0 :         MAsmJSAtomicExchangeHeap* xchg = new(alloc) MAsmJSAtomicExchangeHeap(access, bytecodeOffset);
   14260           0 :         if (!xchg->init(alloc, 3 + !!memoryBase))
   14261           0 :             return nullptr;
   14262             : 
   14263           0 :         xchg->initOperand(0, base);
   14264           0 :         xchg->initOperand(1, value);
   14265           0 :         xchg->initOperand(2, tls);
   14266           0 :         if (memoryBase)
   14267           0 :             xchg->initOperand(3, memoryBase);
   14268             : 
   14269           0 :         return xchg;
   14270             :     }
   14271             : 
   14272           0 :     const wasm::MemoryAccessDesc& access() const { return access_; }
   14273             :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
   14274             : 
   14275           0 :     MDefinition* base() const { return getOperand(0); }
   14276           0 :     MDefinition* value() const { return getOperand(1); }
   14277             :     MDefinition* tls() const { return getOperand(2); }
   14278             :     MDefinition* memoryBase() const { return getOperand(3); }
   14279             : 
   14280           0 :     AliasSet getAliasSet() const override {
   14281           0 :         return AliasSet::Store(AliasSet::WasmHeap);
   14282             :     }
   14283             : };
   14284             : 
   14285             : class MAsmJSAtomicBinopHeap
   14286             :   : public MVariadicInstruction,
   14287             :     public NoTypePolicy::Data
   14288             : {
   14289             :     AtomicOp op_;
   14290             :     wasm::MemoryAccessDesc access_;
   14291             :     wasm::BytecodeOffset bytecodeOffset_;
   14292             : 
   14293           0 :     explicit MAsmJSAtomicBinopHeap(AtomicOp op, const wasm::MemoryAccessDesc& access,
   14294             :                                    wasm::BytecodeOffset bytecodeOffset)
   14295           0 :       : op_(op),
   14296             :         access_(access),
   14297           0 :         bytecodeOffset_(bytecodeOffset)
   14298             :     {
   14299           0 :         setGuard();         // Not removable
   14300           0 :         setResultType(MIRType::Int32);
   14301           0 :     }
   14302             : 
   14303             :   public:
   14304           0 :     INSTRUCTION_HEADER(AsmJSAtomicBinopHeap)
   14305             : 
   14306           0 :     static MAsmJSAtomicBinopHeap* New(TempAllocator& alloc,
   14307             :                                       wasm::BytecodeOffset bytecodeOffset,
   14308             :                                       AtomicOp op,
   14309             :                                       MDefinition* memoryBase,
   14310             :                                       MDefinition* base,
   14311             :                                       const wasm::MemoryAccessDesc& access,
   14312             :                                       MDefinition* v,
   14313             :                                       MDefinition* tls)
   14314             :     {
   14315           0 :         MAsmJSAtomicBinopHeap* binop = new(alloc) MAsmJSAtomicBinopHeap(op, access, bytecodeOffset);
   14316           0 :         if (!binop->init(alloc, 3 + !!memoryBase))
   14317           0 :             return nullptr;
   14318             : 
   14319           0 :         binop->initOperand(0, base);
   14320           0 :         binop->initOperand(1, v);
   14321           0 :         binop->initOperand(2, tls);
   14322           0 :         if (memoryBase)
   14323           0 :             binop->initOperand(3, memoryBase);
   14324             : 
   14325           0 :         return binop;
   14326             :     }
   14327             : 
   14328           0 :     AtomicOp operation() const { return op_; }
   14329           0 :     const wasm::MemoryAccessDesc& access() const { return access_; }
   14330             :     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
   14331             : 
   14332           0 :     MDefinition* base() const { return getOperand(0); }
   14333           0 :     MDefinition* value() const { return getOperand(1); }
   14334             :     MDefinition* tls() const { return getOperand(2); }
   14335             :     MDefinition* memoryBase() const { return getOperand(3); }
   14336             : 
   14337           0 :     AliasSet getAliasSet() const override {
   14338           0 :         return AliasSet::Store(AliasSet::WasmHeap);
   14339             :     }
   14340             : };
   14341             : 
   14342             : class MWasmLoadGlobalVar
   14343             :   : public MAryInstruction<1>,
   14344             :     public NoTypePolicy::Data
   14345             : {
   14346           0 :     MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant, MDefinition* tlsPtr)
   14347           0 :       : globalDataOffset_(globalDataOffset), isConstant_(isConstant)
   14348             :     {
   14349           0 :         MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
   14350           0 :         setResultType(type);
   14351           0 :         setMovable();
   14352           0 :         initOperand(0, tlsPtr);
   14353           0 :     }
   14354             : 
   14355             :     unsigned globalDataOffset_;
   14356             :     bool isConstant_;
   14357             : 
   14358             :   public:
   14359           0 :     INSTRUCTION_HEADER(WasmLoadGlobalVar)
   14360           0 :     TRIVIAL_NEW_WRAPPERS
   14361           0 :     NAMED_OPERANDS((0, tlsPtr))
   14362             : 
   14363           0 :     unsigned globalDataOffset() const { return globalDataOffset_; }
   14364             : 
   14365             :     HashNumber valueHash() const override;
   14366             :     bool congruentTo(const MDefinition* ins) const override;
   14367             :     MDefinition* foldsTo(TempAllocator& alloc) override;
   14368             : 
   14369           0 :     AliasSet getAliasSet() const override {
   14370           0 :         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::WasmGlobalVar);
   14371             :     }
   14372             : 
   14373             :     AliasType mightAlias(const MDefinition* def) const override;
   14374             : };
   14375             : 
   14376             : class MWasmStoreGlobalVar
   14377             :   : public MAryInstruction<2>,
   14378             :     public NoTypePolicy::Data
   14379             : {
   14380           0 :     MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value, MDefinition* tlsPtr)
   14381           0 :       : globalDataOffset_(globalDataOffset)
   14382             :     {
   14383           0 :         initOperand(0, value);
   14384           0 :         initOperand(1, tlsPtr);
   14385           0 :     }
   14386             : 
   14387             :     unsigned globalDataOffset_;
   14388             : 
   14389             :   public:
   14390           0 :     INSTRUCTION_HEADER(WasmStoreGlobalVar)
   14391           0 :     TRIVIAL_NEW_WRAPPERS
   14392           0 :     NAMED_OPERANDS((0, value), (1, tlsPtr))
   14393             : 
   14394           0 :     unsigned globalDataOffset() const { return globalDataOffset_; }
   14395             : 
   14396           0 :     AliasSet getAliasSet() const override {
   14397           0 :         return AliasSet::Store(AliasSet::WasmGlobalVar);
   14398             :     }
   14399             : };
   14400             : 
   14401             : class MWasmParameter : public MNullaryInstruction
   14402             : {
   14403             :     ABIArg abi_;
   14404             : 
   14405           0 :     MWasmParameter(ABIArg abi, MIRType mirType)
   14406           0 :       : abi_(abi)
   14407             :     {
   14408           0 :         setResultType(mirType);
   14409           0 :     }
   14410             : 
   14411             :   public:
   14412           0 :     INSTRUCTION_HEADER(WasmParameter)
   14413           0 :     TRIVIAL_NEW_WRAPPERS
   14414             : 
   14415           0 :     ABIArg abi() const { return abi_; }
   14416             : };
   14417             : 
   14418             : class MWasmReturn
   14419             :   : public MAryControlInstruction<1, 0>,
   14420             :     public NoTypePolicy::Data
   14421             : {
   14422           0 :     explicit MWasmReturn(MDefinition* ins) {
   14423           0 :         initOperand(0, ins);
   14424           0 :     }
   14425             : 
   14426             :   public:
   14427           0 :     INSTRUCTION_HEADER(WasmReturn)
   14428           0 :     TRIVIAL_NEW_WRAPPERS
   14429             : };
   14430             : 
   14431           0 : class MWasmReturnVoid
   14432             :   : public MAryControlInstruction<0, 0>,
   14433             :     public NoTypePolicy::Data
   14434             : {
   14435             :   public:
   14436           0 :     INSTRUCTION_HEADER(WasmReturnVoid)
   14437           0 :     TRIVIAL_NEW_WRAPPERS
   14438             : };
   14439             : 
   14440             : class MWasmStackArg
   14441             :   : public MUnaryInstruction,
   14442             :     public NoTypePolicy::Data
   14443             : {
   14444           0 :     MWasmStackArg(uint32_t spOffset, MDefinition* ins)
   14445           0 :       : MUnaryInstruction(ins),
   14446           0 :         spOffset_(spOffset)
   14447           0 :     {}
   14448             : 
   14449             :     uint32_t spOffset_;
   14450             : 
   14451             :   public:
   14452           0 :     INSTRUCTION_HEADER(WasmStackArg)
   14453           0 :     TRIVIAL_NEW_WRAPPERS
   14454           0 :     NAMED_OPERANDS((0, arg))
   14455             : 
   14456           0 :     uint32_t spOffset() const {
   14457           0 :         return spOffset_;
   14458             :     }
   14459           0 :     void incrementOffset(uint32_t inc) {
   14460           0 :         spOffset_ += inc;
   14461           0 :     }
   14462             : };
   14463             : 
   14464             : class MWasmCall final
   14465             :   : public MVariadicInstruction,
   14466             :     public NoTypePolicy::Data
   14467             : {
   14468             :     wasm::CallSiteDesc desc_;
   14469             :     wasm::CalleeDesc callee_;
   14470             :     FixedList<AnyRegister> argRegs_;
   14471             :     uint32_t spIncrement_;
   14472             :     ABIArg instanceArg_;
   14473             : 
   14474           0 :     MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement)
   14475           0 :       : desc_(desc),
   14476             :         callee_(callee),
   14477           0 :         spIncrement_(spIncrement)
   14478           0 :     { }
   14479             : 
   14480             :   public:
   14481           0 :     INSTRUCTION_HEADER(WasmCall)
   14482             : 
   14483             :     struct Arg {
   14484             :         AnyRegister reg;
   14485             :         MDefinition* def;
   14486           0 :         Arg(AnyRegister reg, MDefinition* def) : reg(reg), def(def) {}
   14487             :     };
   14488             :     typedef Vector<Arg, 8, SystemAllocPolicy> Args;
   14489             : 
   14490             :     static MWasmCall* New(TempAllocator& alloc,
   14491             :                           const wasm::CallSiteDesc& desc,
   14492             :                           const wasm::CalleeDesc& callee,
   14493             :                           const Args& args,
   14494             :                           MIRType resultType,
   14495             :                           uint32_t spIncrement,
   14496             :                           MDefinition* tableIndex = nullptr);
   14497             : 
   14498             :     static MWasmCall* NewBuiltinInstanceMethodCall(TempAllocator& alloc,
   14499             :                                                    const wasm::CallSiteDesc& desc,
   14500             :                                                    const wasm::SymbolicAddress builtin,
   14501             :                                                    const ABIArg& instanceArg,
   14502             :                                                    const Args& args,
   14503             :                                                    MIRType resultType,
   14504             :                                                    uint32_t spIncrement);
   14505             : 
   14506           0 :     size_t numArgs() const {
   14507           0 :         return argRegs_.length();
   14508             :     }
   14509           0 :     AnyRegister registerForArg(size_t index) const {
   14510           0 :         MOZ_ASSERT(index < numArgs());
   14511           0 :         return argRegs_[index];
   14512             :     }
   14513           0 :     const wasm::CallSiteDesc& desc() const {
   14514           0 :         return desc_;
   14515             :     }
   14516           0 :     const wasm::CalleeDesc &callee() const {
   14517           0 :         return callee_;
   14518             :     }
   14519           0 :     uint32_t spIncrement() const {
   14520           0 :         return spIncrement_;
   14521             :     }
   14522             : 
   14523           0 :     bool possiblyCalls() const override {
   14524           0 :         return true;
   14525             :     }
   14526             : 
   14527           0 :     const ABIArg& instanceArg() const {
   14528           0 :         return instanceArg_;
   14529             :     }
   14530             : };
   14531             : 
   14532           0 : class MWasmSelect
   14533             :   : public MTernaryInstruction,
   14534             :     public NoTypePolicy::Data
   14535             : {
   14536           0 :     MWasmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr)
   14537           0 :       : MTernaryInstruction(trueExpr, falseExpr, condExpr)
   14538             :     {
   14539           0 :         MOZ_ASSERT(condExpr->type() == MIRType::Int32);
   14540           0 :         MOZ_ASSERT(trueExpr->type() == falseExpr->type());
   14541           0 :         setResultType(trueExpr->type());
   14542           0 :         setMovable();
   14543           0 :     }
   14544             : 
   14545             :   public:
   14546           0 :     INSTRUCTION_HEADER(WasmSelect)
   14547           0 :     TRIVIAL_NEW_WRAPPERS
   14548           0 :     NAMED_OPERANDS((0, trueExpr), (1, falseExpr), (2, condExpr))
   14549             : 
   14550           0 :     AliasSet getAliasSet() const override {
   14551           0 :         return AliasSet::None();
   14552             :     }
   14553             : 
   14554           0 :     bool congruentTo(const MDefinition* ins) const override {
   14555           0 :         return congruentIfOperandsEqual(ins);
   14556             :     }
   14557             : 
   14558           0 :     ALLOW_CLONE(MWasmSelect)
   14559             : };
   14560             : 
   14561           0 : class MWasmReinterpret
   14562             :   : public MUnaryInstruction,
   14563             :     public NoTypePolicy::Data
   14564             : {
   14565           0 :     MWasmReinterpret(MDefinition* val, MIRType toType)
   14566           0 :       : MUnaryInstruction(val)
   14567             :     {
   14568           0 :         switch (val->type()) {
   14569           0 :           case MIRType::Int32:   MOZ_ASSERT(toType == MIRType::Float32); break;
   14570           0 :           case MIRType::Float32: MOZ_ASSERT(toType == MIRType::Int32);   break;
   14571           0 :           case MIRType::Double:  MOZ_ASSERT(toType == MIRType::Int64);   break;
   14572           0 :           case MIRType::Int64:   MOZ_ASSERT(toType == MIRType::Double);  break;
   14573           0 :           default:              MOZ_CRASH("unexpected reinterpret conversion");
   14574             :         }
   14575           0 :         setMovable();
   14576           0 :         setResultType(toType);
   14577           0 :     }
   14578             : 
   14579             :   public:
   14580           0 :     INSTRUCTION_HEADER(WasmReinterpret)
   14581           0 :     TRIVIAL_NEW_WRAPPERS
   14582             : 
   14583           0 :     AliasSet getAliasSet() const override {
   14584           0 :         return AliasSet::None();
   14585             :     }
   14586           0 :     bool congruentTo(const MDefinition* ins) const override {
   14587           0 :         return congruentIfOperandsEqual(ins);
   14588             :     }
   14589             : 
   14590           0 :     ALLOW_CLONE(MWasmReinterpret)
   14591             : };
   14592             : 
   14593           0 : class MRotate
   14594             :   : public MBinaryInstruction,
   14595             :     public NoTypePolicy::Data
   14596             : {
   14597             :     bool isLeftRotate_;
   14598             : 
   14599           0 :     MRotate(MDefinition* input, MDefinition* count, MIRType type, bool isLeftRotate)
   14600           0 :       : MBinaryInstruction(input, count), isLeftRotate_(isLeftRotate)
   14601             :     {
   14602           0 :         setMovable();
   14603           0 :         setResultType(type);
   14604           0 :     }
   14605             : 
   14606             :   public:
   14607           0 :     INSTRUCTION_HEADER(Rotate)
   14608           0 :     TRIVIAL_NEW_WRAPPERS
   14609           0 :     NAMED_OPERANDS((0, input), (1, count))
   14610             : 
   14611           0 :     AliasSet getAliasSet() const override {
   14612           0 :         return AliasSet::None();
   14613             :     }
   14614           0 :     bool congruentTo(const MDefinition* ins) const override {
   14615           0 :         return congruentIfOperandsEqual(ins) && ins->toRotate()->isLeftRotate() == isLeftRotate_;
   14616             :     }
   14617             : 
   14618           0 :     bool isLeftRotate() const {
   14619           0 :         return isLeftRotate_;
   14620             :     }
   14621             : 
   14622           0 :     ALLOW_CLONE(MRotate)
   14623             : };
   14624             : 
   14625             : class MUnknownValue : public MNullaryInstruction
   14626             : {
   14627             :   protected:
   14628           0 :     MUnknownValue() {
   14629           0 :         setResultType(MIRType::Value);
   14630           0 :     }
   14631             : 
   14632             :   public:
   14633           0 :     INSTRUCTION_HEADER(UnknownValue)
   14634           0 :     TRIVIAL_NEW_WRAPPERS
   14635             : };
   14636             : 
   14637             : #undef INSTRUCTION_HEADER
   14638             : 
   14639       11936 : void MUse::init(MDefinition* producer, MNode* consumer)
   14640             : {
   14641       11936 :     MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
   14642       11936 :     MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer");
   14643       11936 :     initUnchecked(producer, consumer);
   14644       11936 : }
   14645             : 
   14646      137005 : void MUse::initUnchecked(MDefinition* producer, MNode* consumer)
   14647             : {
   14648      137005 :     MOZ_ASSERT(consumer, "Initializing to null consumer");
   14649      137005 :     consumer_ = consumer;
   14650      137005 :     producer_ = producer;
   14651      137005 :     producer_->addUseUnchecked(this);
   14652      137005 : }
   14653             : 
   14654        2354 : void MUse::initUncheckedWithoutProducer(MNode* consumer)
   14655             : {
   14656        2354 :     MOZ_ASSERT(consumer, "Initializing to null consumer");
   14657        2354 :     consumer_ = consumer;
   14658        2354 :     producer_ = nullptr;
   14659        2354 : }
   14660             : 
   14661        2170 : void MUse::replaceProducer(MDefinition* producer)
   14662             : {
   14663        2170 :     MOZ_ASSERT(consumer_, "Resetting MUse without a consumer");
   14664        2170 :     producer_->removeUse(this);
   14665        2170 :     producer_ = producer;
   14666        2170 :     producer_->addUse(this);
   14667        2170 : }
   14668             : 
   14669       12005 : void MUse::releaseProducer()
   14670             : {
   14671       12005 :     MOZ_ASSERT(consumer_, "Clearing MUse without a consumer");
   14672       12005 :     producer_->removeUse(this);
   14673       12005 :     producer_ = nullptr;
   14674       12005 : }
   14675             : 
   14676             : // Implement cast functions now that the compiler can see the inheritance.
   14677             : 
   14678             : MDefinition*
   14679       70111 : MNode::toDefinition()
   14680             : {
   14681       70111 :     MOZ_ASSERT(isDefinition());
   14682       70111 :     return (MDefinition*)this;
   14683             : }
   14684             : 
   14685             : MResumePoint*
   14686       15656 : MNode::toResumePoint()
   14687             : {
   14688       15656 :     MOZ_ASSERT(isResumePoint());
   14689       15656 :     return (MResumePoint*)this;
   14690             : }
   14691             : 
   14692             : MInstruction*
   14693       66290 : MDefinition::toInstruction()
   14694             : {
   14695       66290 :     MOZ_ASSERT(!isPhi());
   14696       66290 :     return (MInstruction*)this;
   14697             : }
   14698             : 
   14699             : const MInstruction*
   14700        2007 : MDefinition::toInstruction() const
   14701             : {
   14702        2007 :     MOZ_ASSERT(!isPhi());
   14703        2007 :     return (const MInstruction*)this;
   14704             : }
   14705             : 
   14706             : MControlInstruction*
   14707      514071 : MDefinition::toControlInstruction()
   14708             : {
   14709      514071 :     MOZ_ASSERT(isControlInstruction());
   14710      514070 :     return (MControlInstruction*)this;
   14711             : }
   14712             : 
   14713             : MConstant*
   14714        1182 : MDefinition::maybeConstantValue()
   14715             : {
   14716        1182 :     MDefinition* op = this;
   14717        1182 :     if (op->isBox())
   14718           0 :         op = op->toBox()->input();
   14719        1182 :     if (op->isConstant())
   14720         112 :         return op->toConstant();
   14721        1070 :     return nullptr;
   14722             : }
   14723             : 
   14724             : // Helper functions used to decide how to build MIR.
   14725             : 
   14726             : bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
   14727             :                                 MDefinition* obj, MDefinition* id);
   14728             : JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
   14729             :                                     MDefinition* id);
   14730             : bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
   14731             :                                MDefinition* obj, MDefinition* id,
   14732             :                                Scalar::Type* arrayType);
   14733             : bool ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj);
   14734             : bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj);
   14735             : bool ElementAccessMightBeFrozen(CompilerConstraintList* constraints, MDefinition* obj);
   14736             : AbortReasonOr<bool>
   14737             : ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj);
   14738             : MIRType DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj);
   14739             : BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
   14740             :                                          CompilerConstraintList* constraints,
   14741             :                                          TypeSet::ObjectKey* key, PropertyName* name,
   14742             :                                          TemporaryTypeSet* observed, bool updateObserved);
   14743             : BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx,
   14744             :                                          CompilerConstraintList* constraints,
   14745             :                                          MDefinition* obj, PropertyName* name,
   14746             :                                          TemporaryTypeSet* observed);
   14747             : AbortReasonOr<BarrierKind>
   14748             : PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
   14749             :                                         MDefinition* obj, PropertyName* name,
   14750             :                                         TemporaryTypeSet* observed);
   14751             : bool PropertyReadIsIdempotent(CompilerConstraintList* constraints,
   14752             :                               MDefinition* obj, PropertyName* name);
   14753             : void AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
   14754             :                                TemporaryTypeSet* observed);
   14755             : bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
   14756             :                       HeapTypeSetKey property, MDefinition* value,
   14757             :                       MIRType implicitType = MIRType::None);
   14758             : bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
   14759             :                                    MBasicBlock* current, MDefinition** pobj,
   14760             :                                    PropertyName* name, MDefinition** pvalue,
   14761             :                                    bool canModify, MIRType implicitType = MIRType::None);
   14762             : AbortReasonOr<bool>
   14763             : ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script);
   14764             : AbortReasonOr<bool>
   14765             : TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types);
   14766             : 
   14767             : } // namespace jit
   14768             : } // namespace js
   14769             : 
   14770             : // Specialize the AlignmentFinder class to make Result<V, E> works with abstract
   14771             : // classes such as MDefinition*, and MInstruction*
   14772             : namespace mozilla
   14773             : {
   14774             : 
   14775             : template <>
   14776             : class AlignmentFinder<js::jit::MDefinition> : public AlignmentFinder<js::jit::MStart>
   14777             : {
   14778             : };
   14779             : 
   14780             : template <>
   14781             : class AlignmentFinder<js::jit::MInstruction> : public AlignmentFinder<js::jit::MStart>
   14782             : {
   14783             : };
   14784             : 
   14785             : } // namespace mozilla
   14786             : 
   14787             : #endif /* jit_MIR_h */

Generated by: LCOV version 1.13