Bug 1004116 - Moved 'MNullaryInstruction', 'MUnaryInstrction', 'MBinaryInstruction', 'MTernaryInstruction' and 'MQuaternaryInstruction' subclasses into 'MIRInstruction.h'. Dependencies of these children by other files requires investigation. draft
authorChris Mander <mandercs3@gmail.com>
Thu, 23 Nov 2017 14:58:21 +0100
changeset 702645 fa542beb66353e1d6ce8bd27c3b368ee4527de8e
parent 700921 b974a43921b945375b29278f70c95201dbc16cbf
child 741543 e6196b01f0f011188ce9b0d2465951ea60415aba
push id90566
push userbmo:mandercs3@gmail.com
push dateThu, 23 Nov 2017 14:25:40 +0000
bugs1004116
milestone59.0a1
Bug 1004116 - Moved 'MNullaryInstruction', 'MUnaryInstrction', 'MBinaryInstruction', 'MTernaryInstruction' and 'MQuaternaryInstruction' subclasses into 'MIRInstruction.h'. Dependencies of these children by other files requires investigation. MozReview-Commit-ID: Di5aT8AM25a
js/src/jit/MIR.h
js/src/jit/MIRInstruction.h
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1425,33 +1425,16 @@ class MTernaryInstruction : public MAryI
         initOperand(0, first);
         initOperand(1, second);
         initOperand(2, third);
     }
 
     HashNumber valueHash() const override;
 };
 
-class MQuaternaryInstruction : public MAryInstruction<4>
-{
-  protected:
-    MQuaternaryInstruction(Opcode op,
-                           MDefinition* first, MDefinition* second,
-                           MDefinition* third, MDefinition* fourth)
-      : MAryInstruction(op)
-    {
-        initOperand(0, first);
-        initOperand(1, second);
-        initOperand(2, third);
-        initOperand(3, fourth);
-    }
-
-    HashNumber valueHash() const override;
-};
-
 template <class T>
 class MVariadicT : public T
 {
     FixedList<MUse> operands_;
 
   protected:
     explicit MVariadicT(typename T::Opcode op)
       : T(op)
@@ -1485,687 +1468,16 @@ class MVariadicT : public T
     }
     void replaceOperand(size_t index, MDefinition* operand) final override {
         operands_[index].replaceProducer(operand);
     }
 };
 
 typedef MVariadicT<MInstruction> MVariadicInstruction;
 
-// Generates an LSnapshot without further effect.
-class MStart : public MNullaryInstruction
-{
-    MStart()
-      : MNullaryInstruction(classOpcode)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(Start)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-// Instruction marking on entrypoint for on-stack replacement.
-// OSR may occur at loop headers (at JSOP_TRACE).
-// There is at most one MOsrEntry per MIRGraph.
-class MOsrEntry : public MNullaryInstruction
-{
-  protected:
-    MOsrEntry()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Pointer);
-    }
-
-  public:
-    INSTRUCTION_HEADER(OsrEntry)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-// No-op instruction. This cannot be moved or eliminated, and is intended for
-// anchoring resume points at arbitrary points in a block.
-class MNop : public MNullaryInstruction
-{
-  protected:
-    MNop()
-      : MNullaryInstruction(classOpcode)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(Nop)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MNop)
-};
-
-// Truncation barrier. This is intended for protecting its input against
-// follow-up truncation optimizations.
-class MLimitedTruncate
-  : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>::Data
-{
-  public:
-    TruncateKind truncate_;
-    TruncateKind truncateLimit_;
-
-  protected:
-    MLimitedTruncate(MDefinition* input, TruncateKind limit)
-      : MUnaryInstruction(classOpcode, input),
-        truncate_(NoTruncate),
-        truncateLimit_(limit)
-    {
-        setResultType(MIRType::Int32);
-        setResultTypeSet(input->resultTypeSet());
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LimitedTruncate)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-    bool needTruncation(TruncateKind kind) override;
-    TruncateKind operandTruncateKind(size_t index) const override;
-    TruncateKind truncateKind() const {
-        return truncate_;
-    }
-    void setTruncateKind(TruncateKind kind) {
-        truncate_ = kind;
-    }
-};
-
-// A constant js::Value.
-class MConstant : public MNullaryInstruction
-{
-    struct Payload {
-        union {
-            bool b;
-            int32_t i32;
-            int64_t i64;
-            float f;
-            double d;
-            JSString* str;
-            JS::Symbol* sym;
-            JSObject* obj;
-            uint64_t asBits;
-        };
-        Payload() : asBits(0) {}
-    };
-
-    Payload payload_;
-
-    static_assert(sizeof(Payload) == sizeof(uint64_t),
-                  "asBits must be big enough for all payload bits");
-
-#ifdef DEBUG
-    void assertInitializedPayload() const;
-#else
-    void assertInitializedPayload() const {}
-#endif
-
-  protected:
-    MConstant(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints);
-    explicit MConstant(JSObject* obj);
-    explicit MConstant(float f);
-    explicit MConstant(int64_t i);
-
-  public:
-    INSTRUCTION_HEADER(Constant)
-    static MConstant* New(TempAllocator& alloc, const Value& v,
-                          CompilerConstraintList* constraints = nullptr);
-    static MConstant* New(TempAllocator::Fallible alloc, const Value& v,
-                          CompilerConstraintList* constraints = nullptr);
-    static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type);
-    static MConstant* NewFloat32(TempAllocator& alloc, double d);
-    static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
-    static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
-    static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
-        return new(alloc) MConstant(*src);
-    }
-
-    // Try to convert this constant to boolean, similar to js::ToBoolean.
-    // Returns false if the type is MIRType::Magic*.
-    bool MOZ_MUST_USE valueToBoolean(bool* res) const;
-
-    // Like valueToBoolean, but returns the result directly instead of using
-    // an outparam. Should not be used if this constant might be a magic value.
-    bool valueToBooleanInfallible() const {
-        bool res;
-        MOZ_ALWAYS_TRUE(valueToBoolean(&res));
-        return res;
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    HashNumber valueHash() const override;
-    bool congruentTo(const MDefinition* ins) const override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool updateForReplacement(MDefinition* def) override {
-        MConstant* c = def->toConstant();
-        // During constant folding, we don't want to replace a float32
-        // value by a double value.
-        if (type() == MIRType::Float32)
-            return c->type() == MIRType::Float32;
-        if (type() == MIRType::Double)
-            return c->type() != MIRType::Float32;
-        return true;
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-    bool needTruncation(TruncateKind kind) override;
-    void truncate() override;
-
-    bool canProduceFloat32() const override;
-
-    ALLOW_CLONE(MConstant)
-
-    bool equals(const MConstant* other) const {
-        assertInitializedPayload();
-        return type() == other->type() && payload_.asBits == other->payload_.asBits;
-    }
-
-    bool toBoolean() const {
-        MOZ_ASSERT(type() == MIRType::Boolean);
-        return payload_.b;
-    }
-    int32_t toInt32() const {
-        MOZ_ASSERT(type() == MIRType::Int32);
-        return payload_.i32;
-    }
-    int64_t toInt64() const {
-        MOZ_ASSERT(type() == MIRType::Int64);
-        return payload_.i64;
-    }
-    bool isInt32(int32_t i) const {
-        return type() == MIRType::Int32 && payload_.i32 == i;
-    }
-    const double& toDouble() const {
-        MOZ_ASSERT(type() == MIRType::Double);
-        return payload_.d;
-    }
-    const float& toFloat32() const {
-        MOZ_ASSERT(type() == MIRType::Float32);
-        return payload_.f;
-    }
-    JSString* toString() const {
-        MOZ_ASSERT(type() == MIRType::String);
-        return payload_.str;
-    }
-    JS::Symbol* toSymbol() const {
-        MOZ_ASSERT(type() == MIRType::Symbol);
-        return payload_.sym;
-    }
-    JSObject& toObject() const {
-        MOZ_ASSERT(type() == MIRType::Object);
-        return *payload_.obj;
-    }
-    JSObject* toObjectOrNull() const {
-        if (type() == MIRType::Object)
-            return payload_.obj;
-        MOZ_ASSERT(type() == MIRType::Null);
-        return nullptr;
-    }
-
-    bool isTypeRepresentableAsDouble() const {
-        return IsTypeRepresentableAsDouble(type());
-    }
-    double numberToDouble() const {
-        MOZ_ASSERT(isTypeRepresentableAsDouble());
-        if (type() == MIRType::Int32)
-            return toInt32();
-        if (type() == MIRType::Double)
-            return toDouble();
-        return toFloat32();
-    }
-
-    // Convert this constant to a js::Value. Float32 constants will be stored
-    // as DoubleValue and NaNs are canonicalized. Callers must be careful: not
-    // all constants can be represented by js::Value (wasm supports int64).
-    Value toJSValue() const;
-
-    bool appendRoots(MRootList& roots) const override;
-};
-
-// Floating-point value as created by wasm. Just a constant value, used to
-// effectively inhibite all the MIR optimizations. This uses the same LIR nodes
-// as a MConstant of the same type would.
-class MWasmFloatConstant : public MNullaryInstruction
-{
-    union {
-        float f32_;
-        double f64_;
-        uint64_t bits_;
-    } u;
-
-    explicit MWasmFloatConstant(MIRType type)
-      : MNullaryInstruction(classOpcode)
-    {
-        u.bits_ = 0;
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmFloatConstant)
-
-    static MWasmFloatConstant* NewDouble(TempAllocator& alloc, double d) {
-        auto* ret = new(alloc) MWasmFloatConstant(MIRType::Double);
-        ret->u.f64_ = d;
-        return ret;
-    }
-
-    static MWasmFloatConstant* NewFloat32(TempAllocator& alloc, float f) {
-        auto* ret = new(alloc) MWasmFloatConstant(MIRType::Float32);
-        ret->u.f32_ = f;
-        return ret;
-    }
-
-    HashNumber valueHash() const override;
-    bool congruentTo(const MDefinition* ins) const override;
-    AliasSet getAliasSet() const override { return AliasSet::None(); }
-
-    const double& toDouble() const {
-        MOZ_ASSERT(type() == MIRType::Double);
-        return u.f64_;
-    }
-    const float& toFloat32() const {
-        MOZ_ASSERT(type() == MIRType::Float32);
-        return u.f32_;
-    }
-};
-
-// Generic constructor of SIMD valuesX4.
-class MSimdValueX4
-  : public MQuaternaryInstruction,
-    public MixPolicy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
-                     SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
-{
-  protected:
-    MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w)
-      : MQuaternaryInstruction(classOpcode, x, y, z, w)
-    {
-        MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT(SimdTypeToLength(type) == 4);
-
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdValueX4)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return SimdTypeToLaneType(type()) == MIRType::Float32;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MSimdValueX4)
-};
-
-// Generic constructor of SIMD values with identical lanes.
-class MSimdSplat
-  : public MUnaryInstruction,
-    public SimdScalarPolicy<0>::Data
-{
-  protected:
-    MSimdSplat(MDefinition* v, MIRType type)
-      : MUnaryInstruction(classOpcode, v)
-    {
-        MOZ_ASSERT(IsSimdType(type));
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdSplat)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return SimdTypeToLaneType(type()) == MIRType::Float32;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MSimdSplat)
-};
-
-// A constant SIMD value.
-class MSimdConstant
-  : public MNullaryInstruction
-{
-    SimdConstant value_;
-
-  protected:
-    MSimdConstant(const SimdConstant& v, MIRType type)
-      : MNullaryInstruction(classOpcode),
-        value_(v)
-    {
-        MOZ_ASSERT(IsSimdType(type));
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdConstant)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isSimdConstant())
-            return false;
-        // Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
-        if (type() != ins->type())
-            return false;
-        return value() == ins->toSimdConstant()->value();
-    }
-
-    const SimdConstant& value() const {
-        return value_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MSimdConstant)
-};
-
-// Converts all lanes of a given vector into the type of another vector
-class MSimdConvert
-  : public MUnaryInstruction,
-    public SimdPolicy<0>::Data
-{
-    // When either fromType or toType is an integer vector, should it be treated
-    // as signed or unsigned. Note that we don't support int-int conversions -
-    // use MSimdReinterpretCast for that.
-    SimdSign sign_;
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    MSimdConvert(MDefinition* obj, MIRType toType, SimdSign sign,
-                 wasm::BytecodeOffset bytecodeOffset)
-      : MUnaryInstruction(classOpcode, obj), sign_(sign), bytecodeOffset_(bytecodeOffset)
-    {
-        MIRType fromType = obj->type();
-        MOZ_ASSERT(IsSimdType(fromType));
-        MOZ_ASSERT(IsSimdType(toType));
-        // All conversions are int <-> float, so signedness is required.
-        MOZ_ASSERT(sign != SimdSign::NotApplicable);
-
-        setResultType(toType);
-        specialization_ = fromType; // expects fromType as input
-
-        setMovable();
-        if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
-            // Does the extra range check => do not remove
-            setGuard();
-        }
-    }
-
-    static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign,
-                             wasm::BytecodeOffset bytecodeOffset)
-    {
-        return new (alloc) MSimdConvert(obj, toType, sign, bytecodeOffset);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdConvert)
-
-    // Create a MSimdConvert instruction and add it to the basic block.
-    // Possibly create and add an equivalent sequence of instructions instead if
-    // the current target doesn't support the requested conversion directly.
-    // Return the inserted MInstruction that computes the converted value.
-    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
-                                      MIRType toType, SimdSign sign,
-                                      wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset());
-
-    SimdSign signedness() const {
-        return sign_;
-    }
-    wasm::BytecodeOffset bytecodeOffset() const {
-        return bytecodeOffset_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        const MSimdConvert* other = ins->toSimdConvert();
-        return sign_ == other->sign_;
-    }
-    ALLOW_CLONE(MSimdConvert)
-};
-
-// Casts bits of a vector input to another SIMD type (doesn't generate code).
-class MSimdReinterpretCast
-  : public MUnaryInstruction,
-    public SimdPolicy<0>::Data
-{
-    MSimdReinterpretCast(MDefinition* obj, MIRType toType)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        MIRType fromType = obj->type();
-        MOZ_ASSERT(IsSimdType(fromType));
-        MOZ_ASSERT(IsSimdType(toType));
-        setMovable();
-        setResultType(toType);
-        specialization_ = fromType; // expects fromType as input
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdReinterpretCast)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    ALLOW_CLONE(MSimdReinterpretCast)
-};
-
-// Extracts a lane element from a given vector type, given by its lane symbol.
-//
-// For integer SIMD types, a SimdSign must be provided so the lane value can be
-// converted to a scalar correctly.
-class MSimdExtractElement
-  : public MUnaryInstruction,
-    public SimdPolicy<0>::Data
-{
-  protected:
-    unsigned lane_;
-    SimdSign sign_;
-
-    MSimdExtractElement(MDefinition* obj, MIRType laneType, unsigned lane, SimdSign sign)
-      : MUnaryInstruction(classOpcode, obj), lane_(lane), sign_(sign)
-    {
-        MIRType vecType = obj->type();
-        MOZ_ASSERT(IsSimdType(vecType));
-        MOZ_ASSERT(lane < SimdTypeToLength(vecType));
-        MOZ_ASSERT(!IsSimdType(laneType));
-        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType),
-                   "Signedness must be specified for integer SIMD extractLanes");
-        // The resulting type should match the lane type.
-        // Allow extracting boolean lanes directly into an Int32 (for wasm).
-        // Allow extracting Uint32 lanes into a double.
-        //
-        // We also allow extracting Uint32 lanes into a MIRType::Int32. This is
-        // equivalent to extracting the Uint32 lane to a double and then
-        // applying MTruncateToInt32, but it bypasses the conversion to/from
-        // double.
-        MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
-                   (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) ||
-                   (vecType == MIRType::Int32x4 && laneType == MIRType::Double &&
-                    sign == SimdSign::Unsigned));
-
-        setMovable();
-        specialization_ = vecType;
-        setResultType(laneType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdExtractElement)
-    TRIVIAL_NEW_WRAPPERS
-
-    unsigned lane() const {
-        return lane_;
-    }
-
-    SimdSign signedness() const {
-        return sign_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isSimdExtractElement())
-            return false;
-        const MSimdExtractElement* other = ins->toSimdExtractElement();
-        if (other->lane_ != lane_ || other->sign_ != sign_)
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    ALLOW_CLONE(MSimdExtractElement)
-};
-
-// Replaces the datum in the given lane by a scalar value of the same type.
-class MSimdInsertElement
-  : public MBinaryInstruction,
-    public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
-{
-  private:
-    unsigned lane_;
-
-    MSimdInsertElement(MDefinition* vec, MDefinition* val, unsigned lane)
-      : MBinaryInstruction(classOpcode, vec, val), lane_(lane)
-    {
-        MIRType type = vec->type();
-        MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT(lane < SimdTypeToLength(type));
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdInsertElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, vector), (1, value))
-
-    unsigned lane() const {
-        return lane_;
-    }
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdInsertElement)
-};
-
-// Returns true if all lanes are true.
-class MSimdAllTrue
-  : public MUnaryInstruction,
-    public SimdPolicy<0>::Data
-{
-  protected:
-    explicit MSimdAllTrue(MDefinition* obj, MIRType result)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        MIRType simdType = obj->type();
-        MOZ_ASSERT(IsBooleanSimdType(simdType));
-        MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
-        setResultType(result);
-        specialization_ = simdType;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdAllTrue)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    ALLOW_CLONE(MSimdAllTrue)
-};
-
-// Returns true if any lane is true.
-class MSimdAnyTrue
-  : public MUnaryInstruction,
-    public SimdPolicy<0>::Data
-{
-  protected:
-    explicit MSimdAnyTrue(MDefinition* obj, MIRType result)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        MIRType simdType = obj->type();
-        MOZ_ASSERT(IsBooleanSimdType(simdType));
-        MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
-        setResultType(result);
-        specialization_ = simdType;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdAnyTrue)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    ALLOW_CLONE(MSimdAnyTrue)
-};
-
 // Base for the MSimdSwizzle and MSimdShuffle classes.
 class MSimdShuffleBase
 {
   protected:
     // As of now, there are at most 16 lanes. For each lane, we need to know
     // which input we choose and which of the lanes we choose.
     mozilla::Array<uint8_t, 16> lane_;
     uint32_t arity_;
@@ -2193,54 +1505,16 @@ class MSimdShuffleBase
     }
 
     bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
         return arity_ == 4 && lane(0) == x && lane(1) == y && lane(2) == z &&
                lane(3) == w;
     }
 };
 
-// Applies a swizzle operation to the input, putting the input lanes as
-// indicated in the output register's lanes. This implements the SIMD.js
-// "swizzle" function, that takes one vector and an array of lane indexes.
-class MSimdSwizzle
-  : public MUnaryInstruction,
-    public MSimdShuffleBase,
-    public NoTypePolicy::Data
-{
-  protected:
-    MSimdSwizzle(MDefinition* obj, const uint8_t lanes[])
-      : MUnaryInstruction(classOpcode, obj), MSimdShuffleBase(lanes, obj->type())
-    {
-        for (unsigned i = 0; i < arity_; i++)
-            MOZ_ASSERT(lane(i) < arity_);
-        setResultType(obj->type());
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdSwizzle)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isSimdSwizzle())
-            return false;
-        const MSimdSwizzle* other = ins->toSimdSwizzle();
-        return sameLanes(other) && congruentIfOperandsEqual(other);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MSimdSwizzle)
-};
-
 // A "general shuffle" is a swizzle or a shuffle with non-constant lane
 // indices.  This is the one that Ion inlines and it can be folded into a
 // MSimdSwizzle/MSimdShuffle if lane indices are constant.  Performance of
 // general swizzle/shuffle does not really matter, as we expect to get
 // constant indices most of the time.
 class MSimdGeneralShuffle :
     public MVariadicInstruction,
     public SimdShufflePolicy::Data
@@ -2303,612 +1577,16 @@ class MSimdGeneralShuffle :
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
-// Applies a shuffle operation to the inputs. The lane indexes select a source
-// lane from the concatenation of the two input vectors.
-class MSimdShuffle
-  : public MBinaryInstruction,
-    public MSimdShuffleBase,
-    public NoTypePolicy::Data
-{
-    MSimdShuffle(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[])
-      : MBinaryInstruction(classOpcode, lhs, rhs), MSimdShuffleBase(lanes, lhs->type())
-    {
-        MOZ_ASSERT(IsSimdType(lhs->type()));
-        MOZ_ASSERT(IsSimdType(rhs->type()));
-        MOZ_ASSERT(lhs->type() == rhs->type());
-        for (unsigned i = 0; i < arity_; i++)
-            MOZ_ASSERT(lane(i) < 2 * arity_);
-        setResultType(lhs->type());
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdShuffle)
-
-    static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs,
-                             const uint8_t lanes[])
-    {
-        unsigned arity = SimdTypeToLength(lhs->type());
-
-        // Swap operands so that new lanes come from LHS in majority.
-        // In the balanced case, swap operands if needs be, in order to be able
-        // to do only one vshufps on x86.
-        unsigned lanesFromLHS = 0;
-        for (unsigned i = 0; i < arity; i++) {
-            if (lanes[i] < arity)
-                lanesFromLHS++;
-        }
-
-        if (lanesFromLHS < arity / 2 ||
-            (arity == 4 && lanesFromLHS == 2 && lanes[0] >= 4 && lanes[1] >= 4)) {
-            mozilla::Array<uint8_t, 16> newLanes;
-            for (unsigned i = 0; i < arity; i++)
-                newLanes[i] = (lanes[i] + arity) % (2 * arity);
-            return New(alloc, rhs, lhs, &newLanes[0]);
-        }
-
-        // If all lanes come from the same vector, just use swizzle instead.
-        if (lanesFromLHS == arity)
-            return MSimdSwizzle::New(alloc, lhs, lanes);
-
-        return new(alloc) MSimdShuffle(lhs, rhs, lanes);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isSimdShuffle())
-            return false;
-        const MSimdShuffle* other = ins->toSimdShuffle();
-        return sameLanes(other) && binaryCongruentTo(other);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MSimdShuffle)
-};
-
-class MSimdUnaryArith
-  : public MUnaryInstruction,
-    public SimdSameAsReturnedTypePolicy<0>::Data
-{
-  public:
-    enum Operation {
-#define OP_LIST_(OP) OP,
-        FOREACH_FLOAT_SIMD_UNOP(OP_LIST_)
-        neg,
-        not_
-#undef OP_LIST_
-    };
-
-    static const char* OperationName(Operation op) {
-        switch (op) {
-          case abs:                         return "abs";
-          case neg:                         return "neg";
-          case not_:                        return "not";
-          case reciprocalApproximation:     return "reciprocalApproximation";
-          case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation";
-          case sqrt:                        return "sqrt";
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-  private:
-    Operation operation_;
-
-    MSimdUnaryArith(MDefinition* def, Operation op)
-      : MUnaryInstruction(classOpcode, def), operation_(op)
-    {
-        MIRType type = def->type();
-        MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT_IF(IsIntegerSimdType(type), op == neg || op == not_);
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdUnaryArith)
-    TRIVIAL_NEW_WRAPPERS
-
-    Operation operation() const { return operation_; }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdUnaryArith);
-};
-
-// Compares each value of a SIMD vector to each corresponding lane's value of
-// another SIMD vector, and returns a boolean vector containing the results of
-// the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
-// When comparing integer vectors, a SimdSign must be provided to request signed
-// or unsigned comparison.
-class MSimdBinaryComp
-  : public MBinaryInstruction,
-    public SimdAllPolicy::Data
-{
-  public:
-    enum Operation {
-#define NAME_(x) x,
-        FOREACH_COMP_SIMD_OP(NAME_)
-#undef NAME_
-    };
-
-    static const char* OperationName(Operation op) {
-        switch (op) {
-#define NAME_(x) case x: return #x;
-        FOREACH_COMP_SIMD_OP(NAME_)
-#undef NAME_
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-  private:
-    Operation operation_;
-    SimdSign sign_;
-
-    MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
-      : MBinaryInstruction(classOpcode, left, right), operation_(op), sign_(sign)
-    {
-        MOZ_ASSERT(left->type() == right->type());
-        MIRType opType = left->type();
-        MOZ_ASSERT(IsSimdType(opType));
-        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType),
-                   "Signedness must be specified for integer SIMD compares");
-        setResultType(MIRTypeToBooleanSimdType(opType));
-        specialization_ = opType;
-        setMovable();
-        if (op == equal || op == notEqual)
-            setCommutative();
-    }
-
-    static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
-                                Operation op, SimdSign sign)
-    {
-        return new (alloc) MSimdBinaryComp(left, right, op, sign);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdBinaryComp)
-
-    // Create a MSimdBinaryComp or an equivalent sequence of instructions
-    // supported by the current target.
-    // Add all instructions to the basic block |addTo|.
-    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
-                                      MDefinition* right, Operation op, SimdSign sign);
-
-    AliasSet getAliasSet() const override
-    {
-        return AliasSet::None();
-    }
-
-    Operation operation() const { return operation_; }
-    SimdSign signedness() const { return sign_; }
-    MIRType specialization() const { return specialization_; }
-
-    // Swap the operands and reverse the comparison predicate.
-    void reverse() {
-        switch (operation()) {
-          case greaterThan:        operation_ = lessThan; break;
-          case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
-          case lessThan:           operation_ = greaterThan; break;
-          case lessThanOrEqual:    operation_ = greaterThanOrEqual; break;
-          case equal:
-          case notEqual:
-            break;
-          default: MOZ_CRASH("Unexpected compare operation");
-        }
-        swapOperands();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        const MSimdBinaryComp* other = ins->toSimdBinaryComp();
-        return specialization_ == other->specialization() &&
-               operation_ == other->operation() &&
-               sign_ == other->signedness();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdBinaryComp)
-};
-
-class MSimdBinaryArith
-  : public MBinaryInstruction,
-    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
-{
-  public:
-    enum Operation {
-#define OP_LIST_(OP) Op_##OP,
-        FOREACH_NUMERIC_SIMD_BINOP(OP_LIST_)
-        FOREACH_FLOAT_SIMD_BINOP(OP_LIST_)
-#undef OP_LIST_
-    };
-
-    static const char* OperationName(Operation op) {
-        switch (op) {
-#define OP_CASE_LIST_(OP) case Op_##OP: return #OP;
-          FOREACH_NUMERIC_SIMD_BINOP(OP_CASE_LIST_)
-          FOREACH_FLOAT_SIMD_BINOP(OP_CASE_LIST_)
-#undef OP_CASE_LIST_
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-  private:
-    Operation operation_;
-
-    MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op)
-      : MBinaryInstruction(classOpcode, left, right), operation_(op)
-    {
-        MOZ_ASSERT(left->type() == right->type());
-        MIRType type = left->type();
-        MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT_IF(IsIntegerSimdType(type), op == Op_add || op == Op_sub || op == Op_mul);
-        setResultType(type);
-        setMovable();
-        if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max)
-            setCommutative();
-    }
-
-    static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
-                                 Operation op)
-    {
-        return new (alloc) MSimdBinaryArith(left, right, op);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdBinaryArith)
-
-    // Create an MSimdBinaryArith instruction and add it to the basic block. Possibly
-    // create and add an equivalent sequence of instructions instead if the
-    // current target doesn't support the requested shift operation directly.
-    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
-                                      MDefinition* right, Operation op);
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    Operation operation() const { return operation_; }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        return operation_ == ins->toSimdBinaryArith()->operation();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdBinaryArith)
-};
-
-class MSimdBinarySaturating
-  : public MBinaryInstruction,
-    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data
-{
-  public:
-    enum Operation
-    {
-        add,
-        sub,
-    };
-
-    static const char* OperationName(Operation op)
-    {
-        switch (op) {
-          case add:
-            return "add";
-          case sub:
-            return "sub";
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-  private:
-    Operation operation_;
-    SimdSign sign_;
-
-    MSimdBinarySaturating(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
-      : MBinaryInstruction(classOpcode, left, right)
-      , operation_(op)
-      , sign_(sign)
-    {
-        MOZ_ASSERT(left->type() == right->type());
-        MIRType type = left->type();
-        MOZ_ASSERT(type == MIRType::Int8x16 || type == MIRType::Int16x8);
-        setResultType(type);
-        setMovable();
-        if (op == add)
-            setCommutative();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdBinarySaturating)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override { return AliasSet::None(); }
-
-    Operation operation() const { return operation_; }
-    SimdSign signedness() const { return sign_; }
-
-    bool congruentTo(const MDefinition* ins) const override
-    {
-        if (!binaryCongruentTo(ins))
-            return false;
-        return operation_ == ins->toSimdBinarySaturating()->operation() &&
-               sign_ == ins->toSimdBinarySaturating()->signedness();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdBinarySaturating)
-};
-
-class MSimdBinaryBitwise
-  : public MBinaryInstruction,
-    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
-{
-  public:
-    enum Operation {
-        and_,
-        or_,
-        xor_
-    };
-
-    static const char* OperationName(Operation op) {
-        switch (op) {
-          case and_: return "and";
-          case or_:  return "or";
-          case xor_: return "xor";
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-  private:
-    Operation operation_;
-
-    MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op)
-      : MBinaryInstruction(classOpcode, left, right), operation_(op)
-    {
-        MOZ_ASSERT(left->type() == right->type());
-        MIRType type = left->type();
-        MOZ_ASSERT(IsSimdType(type));
-        setResultType(type);
-        setMovable();
-        setCommutative();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdBinaryBitwise)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    Operation operation() const { return operation_; }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        return operation_ == ins->toSimdBinaryBitwise()->operation();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MSimdBinaryBitwise)
-};
-
-class MSimdShift
-  : public MBinaryInstruction,
-    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
-{
-  public:
-    enum Operation {
-        lsh,
-        rsh,
-        ursh
-    };
-
-  private:
-    Operation operation_;
-
-    MSimdShift(MDefinition* left, MDefinition* right, Operation op)
-      : MBinaryInstruction(classOpcode, left, right), operation_(op)
-    {
-        MIRType type = left->type();
-        MOZ_ASSERT(IsIntegerSimdType(type));
-        setResultType(type);
-        setMovable();
-    }
-
-    static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
-                           Operation op)
-    {
-        return new (alloc) MSimdShift(left, right, op);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdShift)
-
-    // Create an MSimdShift instruction and add it to the basic block. Possibly
-    // create and add an equivalent sequence of instructions instead if the
-    // current target doesn't support the requested shift operation directly.
-    // Return the inserted MInstruction that computes the shifted value.
-    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
-                                      MDefinition* right, Operation op);
-
-    // Get the relevant right shift operation given the signedness of a type.
-    static Operation rshForSign(SimdSign sign) {
-        return sign == SimdSign::Unsigned ? ursh : rsh;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    Operation operation() const { return operation_; }
-
-    static const char* OperationName(Operation op) {
-        switch (op) {
-          case lsh:  return "lsh";
-          case rsh:  return "rsh-arithmetic";
-          case ursh: return "rsh-logical";
-        }
-        MOZ_CRASH("unexpected operation");
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        return operation_ == ins->toSimdShift()->operation();
-    }
-
-    ALLOW_CLONE(MSimdShift)
-};
-
-class MSimdSelect
-  : public MTernaryInstruction,
-    public SimdSelectPolicy::Data
-{
-    MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs)
-      : MTernaryInstruction(classOpcode, mask, lhs, rhs)
-    {
-        MOZ_ASSERT(IsBooleanSimdType(mask->type()));
-        MOZ_ASSERT(lhs->type() == lhs->type());
-        MIRType type = lhs->type();
-        MOZ_ASSERT(IsSimdType(type));
-        setResultType(type);
-        specialization_ = type;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdSelect)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, mask))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    ALLOW_CLONE(MSimdSelect)
-};
-
-// Deep clone a constant JSObject.
-class MCloneLiteral
-  : public MUnaryInstruction,
-    public ObjectPolicy<0>::Data
-{
-  protected:
-    explicit MCloneLiteral(MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CloneLiteral)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MParameter : public MNullaryInstruction
-{
-    int32_t index_;
-
-    MParameter(int32_t index, TemporaryTypeSet* types)
-      : MNullaryInstruction(classOpcode),
-        index_(index)
-    {
-        setResultType(MIRType::Value);
-        setResultTypeSet(types);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Parameter)
-    TRIVIAL_NEW_WRAPPERS
-
-    static const int32_t THIS_SLOT = -1;
-    int32_t index() const {
-        return index_;
-    }
-    void printOpcode(GenericPrinter& out) const override;
-
-    HashNumber valueHash() const override;
-    bool congruentTo(const MDefinition* ins) const override;
-};
-
-class MCallee : public MNullaryInstruction
-{
-  public:
-    MCallee()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Callee)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MIsConstructing : public MNullaryInstruction
-{
-  public:
-    MIsConstructing()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsConstructing)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
 class MControlInstruction : public MInstruction
 {
   protected:
     explicit MControlInstruction(Opcode op)
       : MInstruction(op)
     { }
 
   public:
@@ -3290,592 +1968,16 @@ TypeSetIncludes(TypeSet* types, MIRType 
 bool
 EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
            MIRType type2, TemporaryTypeSet* typeset2);
 
 bool
 CanStoreUnboxedType(TempAllocator& alloc,
                     JSValueType unboxedType, MIRType input, TypeSet* inputTypes);
 
-class MNewArray
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    // Number of elements to allocate for the array.
-    uint32_t length_;
-
-    // Heap where the array should be allocated.
-    gc::InitialHeap initialHeap_;
-
-    // Whether values written to this array should be converted to double first.
-    bool convertDoubleElements_;
-
-    jsbytecode* pc_;
-
-    bool vmCall_;
-
-    MNewArray(TempAllocator& alloc, CompilerConstraintList* constraints, uint32_t length,
-              MConstant* templateConst, gc::InitialHeap initialHeap, jsbytecode* pc,
-              bool vmCall = false);
-
-  public:
-    INSTRUCTION_HEADER(NewArray)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    static MNewArray* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
-                            uint32_t length, MConstant* templateConst,
-                            gc::InitialHeap initialHeap, jsbytecode* pc)
-    {
-        return new(alloc) MNewArray(alloc, constraints, length, templateConst, initialHeap, pc,
-                                    true);
-    }
-
-    uint32_t length() const {
-        return length_;
-    }
-
-    JSObject* templateObject() const {
-        return getOperand(0)->toConstant()->toObjectOrNull();
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    jsbytecode* pc() const {
-        return pc_;
-    }
-
-    bool isVMCall() const {
-        return vmCall_;
-    }
-
-    bool convertDoubleElements() const {
-        return convertDoubleElements_;
-    }
-
-    // NewArray is marked as non-effectful because all our allocations are
-    // either lazy when we are using "new Array(length)" or bounded by the
-    // script or the stack size when we are using "new Array(...)" or "[...]"
-    // notations.  So we might have to allocate the array twice if we bail
-    // during the computation of the first element of the square braket
-    // notation.
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        // The template object can safely be used in the recover instruction
-        // because it can never be mutated by any other function execution.
-        return templateObject() != nullptr;
-    }
-};
-
-class MNewArrayCopyOnWrite : public MNullaryInstruction
-{
-    CompilerGCPointer<ArrayObject*> templateObject_;
-    gc::InitialHeap initialHeap_;
-
-    MNewArrayCopyOnWrite(TempAllocator& alloc, CompilerConstraintList* constraints,
-                         ArrayObject* templateObject, gc::InitialHeap initialHeap)
-      : MNullaryInstruction(classOpcode),
-        templateObject_(templateObject),
-        initialHeap_(initialHeap)
-    {
-        MOZ_ASSERT(!templateObject->isSingleton());
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewArrayCopyOnWrite)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    ArrayObject* templateObject() const {
-        return templateObject_;
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject_);
-    }
-};
-
-class MNewArrayDynamicLength
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    CompilerObject templateObject_;
-    gc::InitialHeap initialHeap_;
-
-    MNewArrayDynamicLength(TempAllocator& alloc, CompilerConstraintList* constraints,
-                           JSObject* templateObject, gc::InitialHeap initialHeap,
-                           MDefinition* length)
-      : MUnaryInstruction(classOpcode, length),
-        templateObject_(templateObject),
-        initialHeap_(initialHeap)
-    {
-        setGuard(); // Need to throw if length is negative.
-        setResultType(MIRType::Object);
-        if (!templateObject->isSingleton())
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewArrayDynamicLength)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-    NAMED_OPERANDS((0, length))
-
-    JSObject* templateObject() const {
-        return templateObject_;
-    }
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject_);
-    }
-};
-
-class MNewTypedArray
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    gc::InitialHeap initialHeap_;
-
-    MNewTypedArray(TempAllocator& alloc, CompilerConstraintList* constraints,
-                   MConstant* templateConst, gc::InitialHeap initialHeap)
-      : MUnaryInstruction(classOpcode, templateConst),
-        initialHeap_(initialHeap)
-    {
-        MOZ_ASSERT(!templateObject()->isSingleton());
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewTypedArray)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    TypedArrayObject* templateObject() const {
-        return &getOperand(0)->toConstant()->toObject().as<TypedArrayObject>();
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-class MNewTypedArrayDynamicLength
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    CompilerObject templateObject_;
-    gc::InitialHeap initialHeap_;
-
-    MNewTypedArrayDynamicLength(TempAllocator& alloc, CompilerConstraintList* constraints,
-                                JSObject* templateObject, gc::InitialHeap initialHeap,
-                                MDefinition* length)
-      : MUnaryInstruction(classOpcode, length),
-        templateObject_(templateObject),
-        initialHeap_(initialHeap)
-    {
-        setGuard(); // Need to throw if length is negative.
-        setResultType(MIRType::Object);
-        if (!templateObject->isSingleton())
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewTypedArrayDynamicLength)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    MDefinition* length() const {
-        return getOperand(0);
-    }
-    JSObject* templateObject() const {
-        return templateObject_;
-    }
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject_);
-    }
-};
-
-class MNewObject
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  public:
-    enum Mode { ObjectLiteral, ObjectCreate };
-
-  private:
-    gc::InitialHeap initialHeap_;
-    Mode mode_;
-    bool vmCall_;
-
-    MNewObject(TempAllocator& alloc, CompilerConstraintList* constraints, MConstant* templateConst,
-               gc::InitialHeap initialHeap, Mode mode, bool vmCall = false)
-      : MUnaryInstruction(classOpcode, templateConst),
-        initialHeap_(initialHeap),
-        mode_(mode),
-        vmCall_(vmCall)
-    {
-        MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
-        setResultType(MIRType::Object);
-
-        if (JSObject* obj = templateObject())
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, obj));
-
-        // The constant is kept separated in a MConstant, this way we can safely
-        // mark it during GC if we recover the object allocation.  Otherwise, by
-        // making it emittedAtUses, we do not produce register allocations for
-        // it and inline its content inside the code produced by the
-        // CodeGenerator.
-        if (templateConst->toConstant()->type() == MIRType::Object)
-            templateConst->setEmittedAtUses();
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewObject)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    static MNewObject* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
-                             MConstant* templateConst, gc::InitialHeap initialHeap,
-                             Mode mode)
-    {
-        return new(alloc) MNewObject(alloc, constraints, templateConst, initialHeap, mode, true);
-    }
-
-    Mode mode() const {
-        return mode_;
-    }
-
-    JSObject* templateObject() const {
-        return getOperand(0)->toConstant()->toObjectOrNull();
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    bool isVMCall() const {
-        return vmCall_;
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        // The template object can safely be used in the recover instruction
-        // because it can never be mutated by any other function execution.
-        return templateObject() != nullptr;
-    }
-};
-
-
-class MNewIterator
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  public:
-    enum Type {
-        ArrayIterator,
-        StringIterator,
-    };
-
-private:
-    Type type_;
-
-    MNewIterator(TempAllocator& alloc, CompilerConstraintList* constraints,
-                 MConstant* templateConst, Type type)
-      : MUnaryInstruction(classOpcode, templateConst),
-        type_(type)
-    {
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
-        templateConst->setEmittedAtUses();
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewIterator)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    Type type() const {
-        return type_;
-    }
-
-    JSObject* templateObject() {
-        return getOperand(0)->toConstant()->toObjectOrNull();
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-
-class MNewTypedObject : public MNullaryInstruction
-{
-    CompilerGCPointer<InlineTypedObject*> templateObject_;
-    gc::InitialHeap initialHeap_;
-
-    MNewTypedObject(TempAllocator& alloc, CompilerConstraintList* constraints,
-                    InlineTypedObject* templateObject,
-                    gc::InitialHeap initialHeap)
-      : MNullaryInstruction(classOpcode),
-        templateObject_(templateObject),
-        initialHeap_(initialHeap)
-    {
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewTypedObject)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    InlineTypedObject* templateObject() const {
-        return templateObject_;
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject_);
-    }
-};
-
-class MTypedObjectDescr
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  private:
-    explicit MTypedObjectDescr(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypedObjectDescr)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Generic way for constructing a SIMD object in IonMonkey, this instruction
-// takes as argument a SIMD instruction and returns a new SIMD object which
-// corresponds to the MIRType of its operand.
-class MSimdBox
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  protected:
-    CompilerGCPointer<InlineTypedObject*> templateObject_;
-    SimdType simdType_;
-    gc::InitialHeap initialHeap_;
-
-    MSimdBox(TempAllocator& alloc,
-             CompilerConstraintList* constraints,
-             MDefinition* op,
-             InlineTypedObject* templateObject,
-             SimdType simdType,
-             gc::InitialHeap initialHeap)
-      : MUnaryInstruction(classOpcode, op),
-        templateObject_(templateObject),
-        simdType_(simdType),
-        initialHeap_(initialHeap)
-    {
-        MOZ_ASSERT(IsSimdType(op->type()));
-        setMovable();
-        setResultType(MIRType::Object);
-        if (constraints)
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdBox)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    InlineTypedObject* templateObject() const {
-        return templateObject_;
-    }
-
-    SimdType simdType() const {
-        return simdType_;
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        const MSimdBox* box = ins->toSimdBox();
-        if (box->simdType() != simdType())
-            return false;
-        MOZ_ASSERT(box->templateObject() == templateObject());
-        if (box->initialHeap() != initialHeap())
-            return false;
-        return true;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject_);
-    }
-};
-
-class MSimdUnbox
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  protected:
-    SimdType simdType_;
-
-    MSimdUnbox(MDefinition* op, SimdType simdType)
-      : MUnaryInstruction(classOpcode, op),
-        simdType_(simdType)
-    {
-        MIRType type = SimdTypeToMIRType(simdType);
-        MOZ_ASSERT(IsSimdType(type));
-        setGuard();
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SimdUnbox)
-    TRIVIAL_NEW_WRAPPERS
-    ALLOW_CLONE(MSimdUnbox)
-
-    SimdType simdType() const { return simdType_; }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        return ins->toSimdUnbox()->simdType() == simdType();
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-};
-
-// Creates a new derived type object. At runtime, this is just a call
-// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
-// compile to particularly optimized code. However, using a distinct
-// MIR for creating derived type objects allows the compiler to
-// optimize ephemeral typed objects as would be created for a
-// reference like `a.b.c` -- here, the `a.b` will create an ephemeral
-// derived type object that aliases the memory of `a` itself. The
-// specific nature of `a.b` is revealed by using
-// `MNewDerivedTypedObject` rather than `MGetProperty` or what have
-// you. Moreover, the compiler knows that there are no side-effects,
-// so `MNewDerivedTypedObject` instructions can be reordered or pruned
-// as dead code.
-class MNewDerivedTypedObject
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>,
-                     ObjectPolicy<1>,
-                     IntPolicy<2> >::Data
-{
-  private:
-    TypedObjectPrediction prediction_;
-
-    MNewDerivedTypedObject(TypedObjectPrediction prediction,
-                           MDefinition* type,
-                           MDefinition* owner,
-                           MDefinition* offset)
-      : MTernaryInstruction(classOpcode, type, owner, offset),
-        prediction_(prediction)
-    {
-        setMovable();
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewDerivedTypedObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, type), (1, owner), (2, offset))
-
-    TypedObjectPrediction prediction() const {
-        return prediction_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
 // This vector is used when the recovered object is kept unboxed. We map the
 // offset of each property to the index of the corresponding operands in the
 // object state.
 struct OperandIndexMap : public TempObject
 {
     // The number of properties is limited by scalar replacement. Thus we cannot
     // have any large number of properties.
     FixedList<uint8_t> map;
@@ -4056,98 +2158,16 @@ class MArgumentState
     bool congruentTo(const MDefinition* ins) const override {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
-// Setting __proto__ in an object literal.
-class MMutateProto
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
-{
-  protected:
-    MMutateProto(MDefinition* obj, MDefinition* value)
-      : MBinaryInstruction(classOpcode, obj, value)
-    {
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(MutateProto)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getObject), (1, getValue))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MInitPropGetterSetter
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
-{
-    CompilerPropertyName name_;
-
-    MInitPropGetterSetter(MDefinition* obj, PropertyName* name, MDefinition* value)
-      : MBinaryInstruction(classOpcode, obj, value),
-        name_(name)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(InitPropGetterSetter)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, value))
-
-    PropertyName* name() const {
-        return name_;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MInitElem
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
-{
-    MInitElem(MDefinition* obj, MDefinition* id, MDefinition* value)
-      : MTernaryInstruction(classOpcode, obj, id, value)
-    {
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(InitElem)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getObject), (1, getId), (2, getValue))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MInitElemGetterSetter
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
-{
-    MInitElemGetterSetter(MDefinition* obj, MDefinition* id, MDefinition* value)
-      : MTernaryInstruction(classOpcode, obj, id, value)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(InitElemGetterSetter)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, idValue), (2, value))
-
-};
-
 // WrappedFunction wraps a JSFunction so it can safely be used off-thread.
 // In particular, a function's flags can be modified on the active thread as
 // functions are relazified and delazified, so we must be careful not to access
 // these flags off-thread.
 class WrappedFunction : public TempObject
 {
     CompilerFunction fun_;
     uint16_t nargs_;
@@ -4333,124 +2353,16 @@ class MCallDOMNative : public MCall
 
     virtual bool isCallDOMNative() const override {
         return true;
     }
 
     virtual void computeMovable() override;
 };
 
-// fun.apply(self, arguments)
-class MApplyArgs
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
-{
-  protected:
-    // Monomorphic cache of single target from TI, or nullptr.
-    WrappedFunction* target_;
-
-    MApplyArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, MDefinition* self)
-      : MTernaryInstruction(classOpcode, fun, argc, self),
-        target_(target)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ApplyArgs)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis))
-
-    // For TI-informed monomorphic callsites.
-    WrappedFunction* getSingleTarget() const {
-        return target_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        if (target_)
-            return target_->appendRoots(roots);
-        return true;
-    }
-};
-
-// fun.apply(fn, array)
-class MApplyArray
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >::Data
-{
-  protected:
-    // Monomorphic cache of single target from TI, or nullptr.
-    WrappedFunction* target_;
-
-    MApplyArray(WrappedFunction* target, MDefinition* fun, MDefinition* elements, MDefinition* self)
-      : MTernaryInstruction(classOpcode, fun, elements, self),
-        target_(target)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ApplyArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis))
-
-    // For TI-informed monomorphic callsites.
-    WrappedFunction* getSingleTarget() const {
-        return target_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        if (target_)
-            return target_->appendRoots(roots);
-        return true;
-    }
-};
-
-class MBail : public MNullaryInstruction
-{
-  protected:
-    explicit MBail(BailoutKind kind)
-      : MNullaryInstruction(classOpcode)
-    {
-        bailoutKind_ = kind;
-        setGuard();
-    }
-
-  private:
-    BailoutKind bailoutKind_;
-
-  public:
-    INSTRUCTION_HEADER(Bail)
-
-    static MBail*
-    New(TempAllocator& alloc, BailoutKind kind) {
-        return new(alloc) MBail(kind);
-    }
-    static MBail*
-    New(TempAllocator& alloc) {
-        return new(alloc) MBail(Bailout_Inevitable);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-};
-
 class MUnreachable
   : public MAryControlInstruction<0, 0>,
     public NoTypePolicy::Data
 {
     MUnreachable()
       : MAryControlInstruction(classOpcode)
     { }
 
@@ -4458,858 +2370,28 @@ class MUnreachable
     INSTRUCTION_HEADER(Unreachable)
     TRIVIAL_NEW_WRAPPERS
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
-// This class serve as a way to force the encoding of a snapshot, even if there
-// is no resume point using it.  This is useful to run MAssertRecoveredOnBailout
-// assertions.
-class MEncodeSnapshot : public MNullaryInstruction
-{
-  protected:
-    MEncodeSnapshot()
-      : MNullaryInstruction(classOpcode)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(EncodeSnapshot)
-
-    static MEncodeSnapshot*
-    New(TempAllocator& alloc) {
-        return new(alloc) MEncodeSnapshot();
-    }
-};
-
-class MAssertRecoveredOnBailout
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  protected:
-    bool mustBeRecovered_;
-
-    MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered)
-      : MUnaryInstruction(classOpcode, ins), mustBeRecovered_(mustBeRecovered)
-    {
-        setResultType(MIRType::Value);
-        setRecoveredOnBailout();
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(AssertRecoveredOnBailout)
-    TRIVIAL_NEW_WRAPPERS
-
-    // Needed to assert that float32 instructions are correctly recovered.
-    bool canConsumeFloat32(MUse* use) const override { return true; }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-class MAssertFloat32
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  protected:
-    bool mustBeFloat32_;
-
-    MAssertFloat32(MDefinition* value, bool mustBeFloat32)
-      : MUnaryInstruction(classOpcode, value), mustBeFloat32_(mustBeFloat32)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(AssertFloat32)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool canConsumeFloat32(MUse* use) const override { return true; }
-
-    bool mustBeFloat32() const { return mustBeFloat32_; }
-};
-
-class MGetDynamicName
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
-{
-  protected:
-    MGetDynamicName(MDefinition* envChain, MDefinition* name)
-      : MBinaryInstruction(classOpcode, envChain, name)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetDynamicName)
-    NAMED_OPERANDS((0, getEnvironmentChain), (1, getName))
-
-    static MGetDynamicName*
-    New(TempAllocator& alloc, MDefinition* envChain, MDefinition* name) {
-        return new(alloc) MGetDynamicName(envChain, name);
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MCallDirectEval
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>,
-                     StringPolicy<1>,
-                     BoxPolicy<2> >::Data
-{
-  protected:
-    MCallDirectEval(MDefinition* envChain, MDefinition* string,
-                    MDefinition* newTargetValue, jsbytecode* pc)
-      : MTernaryInstruction(classOpcode, envChain, string, newTargetValue),
-        pc_(pc)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallDirectEval)
-    NAMED_OPERANDS((0, getEnvironmentChain), (1, getString), (2, getNewTargetValue))
-
-    static MCallDirectEval*
-    New(TempAllocator& alloc, MDefinition* envChain, MDefinition* string,
-        MDefinition* newTargetValue, jsbytecode* pc)
-    {
-        return new(alloc) MCallDirectEval(envChain, string, newTargetValue, pc);
-    }
-
-    jsbytecode* pc() const {
-        return pc_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-  private:
-    jsbytecode* pc_;
-};
-
-class MCompare
-  : public MBinaryInstruction,
-    public ComparePolicy::Data
-{
-  public:
-    enum CompareType {
-
-        // Anything compared to Undefined
-        Compare_Undefined,
-
-        // Anything compared to Null
-        Compare_Null,
-
-        // Undefined compared to Boolean
-        // Null      compared to Boolean
-        // Double    compared to Boolean
-        // String    compared to Boolean
-        // Symbol    compared to Boolean
-        // Object    compared to Boolean
-        // Value     compared to Boolean
-        Compare_Boolean,
-
-        // Int32   compared to Int32
-        // Boolean compared to Boolean
-        Compare_Int32,
-        Compare_Int32MaybeCoerceBoth,
-        Compare_Int32MaybeCoerceLHS,
-        Compare_Int32MaybeCoerceRHS,
-
-        // Int32 compared as unsigneds
-        Compare_UInt32,
-
-        // Int64 compared to Int64.
-        Compare_Int64,
-
-        // Int64 compared as unsigneds.
-        Compare_UInt64,
-
-        // Double compared to Double
-        Compare_Double,
-
-        Compare_DoubleMaybeCoerceLHS,
-        Compare_DoubleMaybeCoerceRHS,
-
-        // Float compared to Float
-        Compare_Float32,
-
-        // String compared to String
-        Compare_String,
-
-        // Symbol compared to Symbol
-        Compare_Symbol,
-
-        // Undefined compared to String
-        // Null      compared to String
-        // Boolean   compared to String
-        // Int32     compared to String
-        // Double    compared to String
-        // Object    compared to String
-        // Value     compared to String
-        Compare_StrictString,
-
-        // Object compared to Object
-        Compare_Object,
-
-        // Compare 2 values bitwise
-        Compare_Bitwise,
-
-        // All other possible compares
-        Compare_Unknown
-    };
-
-  private:
-    CompareType compareType_;
-    JSOp jsop_;
-    bool operandMightEmulateUndefined_;
-    bool operandsAreNeverNaN_;
-
-    // When a floating-point comparison is converted to an integer comparison
-    // (when range analysis proves it safe), we need to convert the operands
-    // to integer as well.
-    bool truncateOperands_;
-
-    MCompare(MDefinition* left, MDefinition* right, JSOp jsop)
-      : MBinaryInstruction(classOpcode, left, right),
-        compareType_(Compare_Unknown),
-        jsop_(jsop),
-        operandMightEmulateUndefined_(true),
-        operandsAreNeverNaN_(false),
-        truncateOperands_(false)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-    MCompare(MDefinition* left, MDefinition* right, JSOp jsop, CompareType compareType)
-      : MCompare(left, right, jsop)
-    {
-        MOZ_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||
-                   compareType == Compare_Int64 || compareType == Compare_UInt64 ||
-                   compareType == Compare_Double || compareType == Compare_Float32);
-        compareType_ = compareType;
-        operandMightEmulateUndefined_ = false;
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Compare)
-    TRIVIAL_NEW_WRAPPERS
-
-    MOZ_MUST_USE bool tryFold(bool* result);
-    MOZ_MUST_USE bool evaluateConstantOperands(TempAllocator& alloc, bool* result);
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
-                                bool* filtersNull);
-
-    CompareType compareType() const {
-        return compareType_;
-    }
-    bool isInt32Comparison() const {
-        return compareType() == Compare_Int32 ||
-               compareType() == Compare_Int32MaybeCoerceBoth ||
-               compareType() == Compare_Int32MaybeCoerceLHS ||
-               compareType() == Compare_Int32MaybeCoerceRHS;
-    }
-    bool isDoubleComparison() const {
-        return compareType() == Compare_Double ||
-               compareType() == Compare_DoubleMaybeCoerceLHS ||
-               compareType() == Compare_DoubleMaybeCoerceRHS;
-    }
-    bool isFloat32Comparison() const {
-        return compareType() == Compare_Float32;
-    }
-    bool isNumericComparison() const {
-        return isInt32Comparison() ||
-               isDoubleComparison() ||
-               isFloat32Comparison();
-    }
-    void setCompareType(CompareType type) {
-        compareType_ = type;
-    }
-    MIRType inputType();
-
-    JSOp jsop() const {
-        return jsop_;
-    }
-    void markNoOperandEmulatesUndefined() {
-        operandMightEmulateUndefined_ = false;
-    }
-    bool operandMightEmulateUndefined() const {
-        return operandMightEmulateUndefined_;
-    }
-    bool operandsAreNeverNaN() const {
-        return operandsAreNeverNaN_;
-    }
-    AliasSet getAliasSet() const override {
-        // Strict equality is never effectful.
-        if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
-            return AliasSet::None();
-        if (compareType_ == Compare_Unknown)
-            return AliasSet::Store(AliasSet::Any);
-        MOZ_ASSERT(compareType_ <= Compare_Bitwise);
-        return AliasSet::None();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-    void collectRangeInfoPreTrunc() override;
-
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-    bool isFloat32Commutative() const override { return true; }
-    bool needTruncation(TruncateKind kind) override;
-    void truncate() override;
-    TruncateKind operandTruncateKind(size_t index) const override;
-
-    static CompareType determineCompareType(JSOp op, MDefinition* left, MDefinition* right);
-    void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
-
-# ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        // Both sides of the compare can be Float32
-        return compareType_ == Compare_Float32;
-    }
-# endif
-
-    ALLOW_CLONE(MCompare)
-
-  protected:
-    MOZ_MUST_USE bool tryFoldEqualOperands(bool* result);
-    MOZ_MUST_USE bool tryFoldTypeOf(bool* result);
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        return compareType() == ins->toCompare()->compareType() &&
-               jsop() == ins->toCompare()->jsop();
-    }
-};
-
-// Takes a typed value and returns an untyped value.
-class MBox
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    MBox(TempAllocator& alloc, MDefinition* ins)
-      : MUnaryInstruction(classOpcode, ins)
-    {
-        setResultType(MIRType::Value);
-        if (ins->resultTypeSet()) {
-            setResultTypeSet(ins->resultTypeSet());
-        } else if (ins->type() != MIRType::Value) {
-            TypeSet::Type ntype = ins->type() == MIRType::Object
-                                  ? TypeSet::AnyObjectType()
-                                  : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type()));
-            setResultTypeSet(alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype));
-        }
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Box)
-    static MBox* New(TempAllocator& alloc, MDefinition* ins)
-    {
-        // Cannot box a box.
-        MOZ_ASSERT(ins->type() != MIRType::Value);
-
-        return new(alloc) MBox(alloc, ins);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MBox)
-};
+
 
 // Note: the op may have been inverted during lowering (to put constants in a
 // position where they can be immediates), so it is important to use the
 // lir->jsop() instead of the mir->jsop() when it is present.
 static inline Assembler::Condition
 JSOpToCondition(MCompare::CompareType compareType, JSOp op)
 {
     bool isSigned = (compareType != MCompare::Compare_UInt32);
     return JSOpToCondition(op, isSigned);
 }
 
-// Takes a typed value and checks if it is a certain type. If so, the payload
-// is unpacked and returned as that type. Otherwise, it is considered a
-// deoptimization.
-class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
-{
-  public:
-    enum Mode {
-        Fallible,       // Check the type, and deoptimize if unexpected.
-        Infallible,     // Type guard is not necessary.
-        TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
-    };
-
-  private:
-    Mode mode_;
-    BailoutKind bailoutKind_;
-
-    MUnbox(MDefinition* ins, MIRType type, Mode mode, BailoutKind kind, TempAllocator& alloc)
-      : MUnaryInstruction(classOpcode, ins),
-        mode_(mode)
-    {
-        // Only allow unboxing a non MIRType::Value when input and output types
-        // don't match. This is often used to force a bailout. Boxing happens
-        // during type analysis.
-        MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type());
-
-        MOZ_ASSERT(type == MIRType::Boolean ||
-                   type == MIRType::Int32   ||
-                   type == MIRType::Double  ||
-                   type == MIRType::String  ||
-                   type == MIRType::Symbol  ||
-                   type == MIRType::Object);
-
-        TemporaryTypeSet* resultSet = ins->resultTypeSet();
-        if (resultSet && type == MIRType::Object)
-            resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc());
-
-        setResultType(type);
-        setResultTypeSet(resultSet);
-        setMovable();
-
-        if (mode_ == TypeBarrier || mode_ == Fallible)
-            setGuard();
-
-        bailoutKind_ = kind;
-    }
-  public:
-    INSTRUCTION_HEADER(Unbox)
-    static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode)
-    {
-        // Unless we were given a specific BailoutKind, pick a default based on
-        // the type we expect.
-        BailoutKind kind;
-        switch (type) {
-          case MIRType::Boolean:
-            kind = Bailout_NonBooleanInput;
-            break;
-          case MIRType::Int32:
-            kind = Bailout_NonInt32Input;
-            break;
-          case MIRType::Double:
-            kind = Bailout_NonNumericInput; // Int32s are fine too
-            break;
-          case MIRType::String:
-            kind = Bailout_NonStringInput;
-            break;
-          case MIRType::Symbol:
-            kind = Bailout_NonSymbolInput;
-            break;
-          case MIRType::Object:
-            kind = Bailout_NonObjectInput;
-            break;
-          default:
-            MOZ_CRASH("Given MIRType cannot be unboxed.");
-        }
-
-        return new(alloc) MUnbox(ins, type, mode, kind, alloc);
-    }
-
-    static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode,
-                       BailoutKind kind)
-    {
-        return new(alloc) MUnbox(ins, type, mode, kind, alloc);
-    }
-
-    Mode mode() const {
-        return mode_;
-    }
-    BailoutKind bailoutKind() const {
-        // If infallible, no bailout should be generated.
-        MOZ_ASSERT(fallible());
-        return bailoutKind_;
-    }
-    bool fallible() const {
-        return mode() != Infallible;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void printOpcode(GenericPrinter& out) const override;
-    void makeInfallible() {
-        // Should only be called if we're already Infallible or TypeBarrier
-        MOZ_ASSERT(mode() != Fallible);
-        mode_ = Infallible;
-    }
-
-    ALLOW_CLONE(MUnbox)
-};
-
-class MGuardObject
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MGuardObject(MDefinition* ins)
-      : MUnaryInstruction(classOpcode, ins)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-        setResultTypeSet(ins->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardObject)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MGuardString
-  : public MUnaryInstruction,
-    public StringPolicy<0>::Data
-{
-    explicit MGuardString(MDefinition* ins)
-      : MUnaryInstruction(classOpcode, ins)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardString)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MPolyInlineGuard
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MPolyInlineGuard(MDefinition* ins)
-      : MUnaryInstruction(classOpcode, ins)
-    {
-        setGuard();
-        setResultType(MIRType::Object);
-        setResultTypeSet(ins->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(PolyInlineGuard)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MAssertRange
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    // This is the range checked by the assertion. Don't confuse this with the
-    // range_ member or the range() accessor. Since MAssertRange doesn't return
-    // a value, it doesn't use those.
-    const Range* assertedRange_;
-
-    MAssertRange(MDefinition* ins, const Range* assertedRange)
-      : MUnaryInstruction(classOpcode, ins), assertedRange_(assertedRange)
-    {
-        setGuard();
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(AssertRange)
-    TRIVIAL_NEW_WRAPPERS
-
-    const Range* assertedRange() const {
-        return assertedRange_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-};
-
-// Caller-side allocation of |this| for |new|:
-// Given a templateobject, construct |this| for JSOP_NEW
-class MCreateThisWithTemplate
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    gc::InitialHeap initialHeap_;
-
-    MCreateThisWithTemplate(TempAllocator& alloc, CompilerConstraintList* constraints,
-                            MConstant* templateConst, gc::InitialHeap initialHeap)
-      : MUnaryInstruction(classOpcode, templateConst),
-        initialHeap_(initialHeap)
-    {
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
-    }
-
-  public:
-    INSTRUCTION_HEADER(CreateThisWithTemplate)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    // Template for |this|, provided by TI.
-    JSObject* templateObject() const {
-        return &getOperand(0)->toConstant()->toObject();
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    // Although creation of |this| modifies global state, it is safely repeatable.
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override;
-};
-
-// Caller-side allocation of |this| for |new|:
-// Given a prototype operand, construct |this| for JSOP_NEW.
-class MCreateThisWithProto
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
-{
-    MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
-      : MTernaryInstruction(classOpcode, callee, newTarget, prototype)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CreateThisWithProto)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getCallee), (1, getNewTarget), (2, getPrototype))
-
-    // Although creation of |this| modifies global state, it is safely repeatable.
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-// Caller-side allocation of |this| for |new|:
-// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
-class MCreateThis
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
-{
-    explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
-      : MBinaryInstruction(classOpcode, callee, newTarget)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CreateThis)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getCallee), (1, getNewTarget))
-
-    // Although creation of |this| modifies global state, it is safely repeatable.
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-// Eager initialization of arguments object.
-class MCreateArgumentsObject
-  : public MUnaryInstruction,
-    public ObjectPolicy<0>::Data
-{
-    CompilerGCPointer<ArgumentsObject*> templateObj_;
-
-    MCreateArgumentsObject(MDefinition* callObj, ArgumentsObject* templateObj)
-      : MUnaryInstruction(classOpcode, callObj),
-        templateObj_(templateObj)
-    {
-        setResultType(MIRType::Object);
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CreateArgumentsObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getCallObject))
-
-    ArgumentsObject* templateObject() const {
-        return templateObj_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObj_);
-    }
-};
-
-class MGetArgumentsObjectArg
-  : public MUnaryInstruction,
-    public ObjectPolicy<0>::Data
-{
-    size_t argno_;
-
-    MGetArgumentsObjectArg(MDefinition* argsObject, size_t argno)
-      : MUnaryInstruction(classOpcode, argsObject),
-        argno_(argno)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetArgumentsObjectArg)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getArgsObject))
-
-    size_t argno() const {
-        return argno_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::Any);
-    }
-};
-
-class MSetArgumentsObjectArg
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
-{
-    size_t argno_;
-
-    MSetArgumentsObjectArg(MDefinition* argsObj, size_t argno, MDefinition* value)
-      : MBinaryInstruction(classOpcode, argsObj, value),
-        argno_(argno)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetArgumentsObjectArg)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getArgsObject), (1, getValue))
-
-    size_t argno() const {
-        return argno_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::Any);
-    }
-};
-
-class MRunOncePrologue
-  : public MNullaryInstruction
-{
-  protected:
-    MRunOncePrologue()
-      : MNullaryInstruction(classOpcode)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(RunOncePrologue)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-// Given a MIRType::Value A and a MIRType::Object B:
-// If the Value may be safely unboxed to an Object, return Object(A).
-// Otherwise, return B.
-// Used to implement return behavior for inlined constructors.
-class MReturnFromCtor
-  : public MBinaryInstruction,
-    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
-{
-    MReturnFromCtor(MDefinition* value, MDefinition* object)
-      : MBinaryInstruction(classOpcode, value, object)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ReturnFromCtor)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, getValue), (1, getObject))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MToFPInstruction
-  : public MUnaryInstruction,
-    public ToDoublePolicy::Data
-{
-  public:
-    // Types of values which can be converted.
-    enum ConversionKind {
-        NonStringPrimitives,
-        NonNullNonStringPrimitives,
-        NumbersOnly
-    };
-
-  private:
-    ConversionKind conversion_;
-
-  protected:
-    MToFPInstruction(Opcode op, MDefinition* def, ConversionKind conversion = NonStringPrimitives)
-      : MUnaryInstruction(op, def), conversion_(conversion)
-    { }
-
-  public:
-    ConversionKind conversion() const {
-        return conversion_;
-    }
-};
-
 // Converts a primitive (either typed or untyped) to a double. If the input is
 // not primitive at runtime, a bailout occurs.
 class MToDouble
   : public MToFPInstruction
 {
   private:
     TruncateKind implicitTruncate_;
 
@@ -5419,656 +2501,16 @@ class MToFloat32
     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
     }
 
     ALLOW_CLONE(MToFloat32)
 };
 
-// Converts a uint32 to a double (coming from wasm).
-class MWasmUnsignedToDouble
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MWasmUnsignedToDouble(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::Double);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmUnsignedToDouble)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Converts a uint32 to a float32 (coming from wasm).
-class MWasmUnsignedToFloat32
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MWasmUnsignedToFloat32(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::Float32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmUnsignedToFloat32)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool canProduceFloat32() const override { return true; }
-};
-
-class MWrapInt64ToInt32
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool bottomHalf_;
-
-    explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf = true)
-      : MUnaryInstruction(classOpcode, def),
-        bottomHalf_(bottomHalf)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WrapInt64ToInt32)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isWrapInt64ToInt32())
-            return false;
-        if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool bottomHalf() const {
-        return bottomHalf_;
-    }
-};
-
-class MExtendInt32ToInt64
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool isUnsigned_;
-
-    MExtendInt32ToInt64(MDefinition* def, bool isUnsigned)
-      : MUnaryInstruction(classOpcode, def),
-        isUnsigned_(isUnsigned)
-    {
-        setResultType(MIRType::Int64);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ExtendInt32ToInt64)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool isUnsigned() const { return isUnsigned_; }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isExtendInt32ToInt64())
-            return false;
-        if (ins->toExtendInt32ToInt64()->isUnsigned_ != isUnsigned_)
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MWasmTruncateToInt64
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool isUnsigned_;
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    MWasmTruncateToInt64(MDefinition* def, bool isUnsigned, wasm::BytecodeOffset bytecodeOffset)
-      : MUnaryInstruction(classOpcode, def),
-        isUnsigned_(isUnsigned),
-        bytecodeOffset_(bytecodeOffset)
-    {
-        setResultType(MIRType::Int64);
-        setGuard(); // neither removable nor movable because of possible side-effects.
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmTruncateToInt64)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool isUnsigned() const { return isUnsigned_; }
-    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) &&
-               ins->toWasmTruncateToInt64()->isUnsigned() == isUnsigned_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Truncate a value to an int32, with wasm semantics: this will trap when the
-// value is out of range.
-class MWasmTruncateToInt32
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool isUnsigned_;
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    explicit MWasmTruncateToInt32(MDefinition* def, bool isUnsigned,
-                                  wasm::BytecodeOffset bytecodeOffset)
-      : MUnaryInstruction(classOpcode, def),
-        isUnsigned_(isUnsigned), bytecodeOffset_(bytecodeOffset)
-    {
-        setResultType(MIRType::Int32);
-        setGuard(); // neither removable nor movable because of possible side-effects.
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmTruncateToInt32)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool isUnsigned() const {
-        return isUnsigned_;
-    }
-    wasm::BytecodeOffset bytecodeOffset() const {
-        return bytecodeOffset_;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) &&
-               ins->toWasmTruncateToInt32()->isUnsigned() == isUnsigned_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MInt64ToFloatingPoint
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool isUnsigned_;
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    MInt64ToFloatingPoint(MDefinition* def, MIRType type, wasm::BytecodeOffset bytecodeOffset,
-                          bool isUnsigned)
-      : MUnaryInstruction(classOpcode, def),
-        isUnsigned_(isUnsigned),
-        bytecodeOffset_(bytecodeOffset)
-    {
-        MOZ_ASSERT(IsFloatingPointType(type));
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Int64ToFloatingPoint)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool isUnsigned() const { return isUnsigned_; }
-    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isInt64ToFloatingPoint())
-            return false;
-        if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_)
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Converts a primitive (either typed or untyped) to an int32. If the input is
-// not primitive at runtime, a bailout occurs. If the input cannot be converted
-// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
-class MToInt32
-  : public MUnaryInstruction,
-    public ToInt32Policy::Data
-{
-    bool canBeNegativeZero_;
-    MacroAssembler::IntConversionInputKind conversion_;
-
-    explicit MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion =
-                                            MacroAssembler::IntConversion_Any)
-      : MUnaryInstruction(classOpcode, def),
-        canBeNegativeZero_(true),
-        conversion_(conversion)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-
-        // An object might have "valueOf", which means it is effectful.
-        // ToNumber(symbol) throws.
-        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
-            setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToInt32)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    // this only has backwards information flow.
-    void analyzeEdgeCasesBackward() override;
-
-    bool canBeNegativeZero() const {
-        return canBeNegativeZero_;
-    }
-    void setCanBeNegativeZero(bool negativeZero) {
-        canBeNegativeZero_ = negativeZero;
-    }
-
-    MacroAssembler::IntConversionInputKind conversion() const {
-        return conversion_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-    void collectRangeInfoPreTrunc() override;
-
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override { return true; }
-#endif
-
-    ALLOW_CLONE(MToInt32)
-};
-
-// Converts a value or typed input to a truncated int32, for use with bitwise
-// operations. This is an infallible ValueToECMAInt32.
-class MTruncateToInt32
-  : public MUnaryInstruction,
-    public ToInt32Policy::Data
-{
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    explicit MTruncateToInt32(MDefinition* def,
-                              wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
-      : MUnaryInstruction(classOpcode, def),
-        bytecodeOffset_(bytecodeOffset)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-
-        // An object might have "valueOf", which means it is effectful.
-        // ToInt32(symbol) throws.
-        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
-            setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TruncateToInt32)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-    TruncateKind operandTruncateKind(size_t index) const override;
-# ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return input()->type() < MIRType::Symbol;
-    }
-
-    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
-
-    ALLOW_CLONE(MTruncateToInt32)
-};
-
-// Converts any type to a string
-class MToString :
-  public MUnaryInstruction,
-  public ToStringPolicy::Data
-{
-    explicit MToString(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::String);
-        setMovable();
-
-        // Objects might override toString and Symbols throw. We bailout in
-        // those cases and run side-effects in baseline instead.
-        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
-            setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToString)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool fallible() const {
-        return input()->mightBeType(MIRType::Object) ||
-               input()->mightBeType(MIRType::Symbol);
-    }
-
-    ALLOW_CLONE(MToString)
-};
-
-// Converts any type to an object, throwing on null or undefined.
-class MToObject :
-  public MUnaryInstruction,
-  public BoxInputsPolicy::Data
-{
-    explicit MToObject(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::Object);
-        setGuard(); // Throws on null or undefined.
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToObject)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MToObject)
-};
-
-// Converts any type to an object or null value, throwing on undefined.
-class MToObjectOrNull :
-  public MUnaryInstruction,
-  public BoxInputsPolicy::Data
-{
-    explicit MToObjectOrNull(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::ObjectOrNull);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToObjectOrNull)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MToObjectOrNull)
-};
-
-class MBitNot
-  : public MUnaryInstruction,
-    public BitwisePolicy::Data
-{
-  protected:
-    explicit MBitNot(MDefinition* input)
-      : MUnaryInstruction(classOpcode, input)
-    {
-        specialization_ = MIRType::None;
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(BitNot)
-    TRIVIAL_NEW_WRAPPERS
-
-    static MBitNot* NewInt32(TempAllocator& alloc, MDefinition* input);
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void setSpecialization(MIRType type) {
-        specialization_ = type;
-        setResultType(type);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        if (specialization_ == MIRType::None)
-            return AliasSet::Store(AliasSet::Any);
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return specialization_ != MIRType::None;
-    }
-
-    ALLOW_CLONE(MBitNot)
-};
-
-class MTypeOf
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    MIRType inputType_;
-    bool inputMaybeCallableOrEmulatesUndefined_;
-
-    MTypeOf(MDefinition* def, MIRType inputType)
-      : MUnaryInstruction(classOpcode, def), inputType_(inputType),
-        inputMaybeCallableOrEmulatesUndefined_(true)
-    {
-        setResultType(MIRType::String);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypeOf)
-    TRIVIAL_NEW_WRAPPERS
-
-    MIRType inputType() const {
-        return inputType_;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints);
-
-    bool inputMaybeCallableOrEmulatesUndefined() const {
-        return inputMaybeCallableOrEmulatesUndefined_;
-    }
-    void markInputNotCallableOrEmulatesUndefined() {
-        inputMaybeCallableOrEmulatesUndefined_ = false;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isTypeOf())
-            return false;
-        if (inputType() != ins->toTypeOf()->inputType())
-            return false;
-        if (inputMaybeCallableOrEmulatesUndefined() !=
-            ins->toTypeOf()->inputMaybeCallableOrEmulatesUndefined())
-        {
-            return false;
-        }
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-class MToAsync
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MToAsync(MDefinition* unwrapped)
-      : MUnaryInstruction(classOpcode, unwrapped)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToAsync)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MToAsyncGen
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MToAsyncGen(MDefinition* unwrapped)
-      : MUnaryInstruction(classOpcode, unwrapped)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToAsyncGen)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MToAsyncIter
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MToAsyncIter(MDefinition* unwrapped)
-      : MUnaryInstruction(classOpcode, unwrapped)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToAsyncIter)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MToId
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    explicit MToId(MDefinition* index)
-      : MUnaryInstruction(classOpcode, index)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ToId)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MBinaryBitwiseInstruction
-  : public MBinaryInstruction,
-    public BitwisePolicy::Data
-{
-  protected:
-    MBinaryBitwiseInstruction(Opcode op, MDefinition* left, MDefinition* right, MIRType type)
-      : MBinaryInstruction(op, left, right), maskMatchesLeftRange(false),
-        maskMatchesRightRange(false)
-    {
-        MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
-        setResultType(type);
-        setMovable();
-    }
-
-    void specializeAs(MIRType type);
-    bool maskMatchesLeftRange;
-    bool maskMatchesRightRange;
-
-  public:
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    MDefinition* foldUnnecessaryBitop();
-    virtual MDefinition* foldIfZero(size_t operand) = 0;
-    virtual MDefinition* foldIfNegOne(size_t operand) = 0;
-    virtual MDefinition* foldIfEqual()  = 0;
-    virtual MDefinition* foldIfAllBitsSet(size_t operand)  = 0;
-    virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
-    void collectRangeInfoPreTrunc() override;
-
-    void setInt32Specialization() {
-        specialization_ = MIRType::Int32;
-        setResultType(MIRType::Int32);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return binaryCongruentTo(ins);
-    }
-    AliasSet getAliasSet() const override {
-        if (specialization_ >= MIRType::Object)
-            return AliasSet::Store(AliasSet::Any);
-        return AliasSet::None();
-    }
-
-    TruncateKind operandTruncateKind(size_t index) const override;
-};
-
 class MBitAnd : public MBinaryBitwiseInstruction
 {
     MBitAnd(MDefinition* left, MDefinition* right, MIRType type)
       : MBinaryBitwiseInstruction(classOpcode, left, right, type)
     { }
 
   public:
     INSTRUCTION_HEADER(BitAnd)
@@ -6274,485 +2716,16 @@ class MUrsh : public MShiftInstruction
     MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return specialization_ < MIRType::Object;
     }
 
     ALLOW_CLONE(MUrsh)
 };
 
-class MSignExtendInt32
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  public:
-    enum Mode {
-        Byte,
-        Half
-    };
-
-  private:
-    Mode mode_;
-
-    MSignExtendInt32(MDefinition* op, Mode mode)
-      : MUnaryInstruction(classOpcode, op), mode_(mode)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SignExtendInt32)
-    TRIVIAL_NEW_WRAPPERS
-
-    Mode mode() const { return mode_; }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        return ins->isSignExtendInt32() && ins->toSignExtendInt32()->mode_ == mode_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MSignExtendInt32)
-};
-
-class MSignExtendInt64
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  public:
-    enum Mode {
-        Byte,
-        Half,
-        Word
-    };
-
-  private:
-    Mode mode_;
-
-    MSignExtendInt64(MDefinition* op, Mode mode)
-      : MUnaryInstruction(classOpcode, op), mode_(mode)
-    {
-        setResultType(MIRType::Int64);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SignExtendInt64)
-    TRIVIAL_NEW_WRAPPERS
-
-    Mode mode() const { return mode_; }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        return ins->isSignExtendInt64() && ins->toSignExtendInt64()->mode_ == mode_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MSignExtendInt64)
-};
-
-class MBinaryArithInstruction
-  : public MBinaryInstruction,
-    public ArithPolicy::Data
-{
-    // Implicit truncate flag is set by the truncate backward range analysis
-    // optimization phase, and by wasm pre-processing. It is used in
-    // NeedNegativeZeroCheck to check if the result of a multiplication needs to
-    // produce -0 double value, and for avoiding overflow checks.
-
-    // This optimization happens when the multiplication cannot be truncated
-    // even if all uses are truncating its result, such as when the range
-    // analysis detect a precision loss in the multiplication.
-    TruncateKind implicitTruncate_;
-
-    // Whether we must preserve NaN semantics, and in particular not fold
-    // (x op id) or (id op x) to x, or replace a division by a multiply of the
-    // exact reciprocal.
-    bool mustPreserveNaN_;
-
-  public:
-    MBinaryArithInstruction(Opcode op, MDefinition* left, MDefinition* right)
-      : MBinaryInstruction(op, left, right),
-        implicitTruncate_(NoTruncate),
-        mustPreserveNaN_(false)
-    {
-        specialization_ = MIRType::None;
-        setMovable();
-    }
-
-    static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
-                                        MDefinition* left, MDefinition* right);
-
-    bool constantDoubleResult(TempAllocator& alloc);
-
-    void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; }
-    bool mustPreserveNaN() const { return mustPreserveNaN_; }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void printOpcode(GenericPrinter& out) const override;
-
-    virtual double getIdentity() = 0;
-
-    void setSpecialization(MIRType type) {
-        specialization_ = type;
-        setResultType(type);
-    }
-    void setInt32Specialization() {
-        specialization_ = MIRType::Int32;
-        setResultType(MIRType::Int32);
-    }
-    void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
-
-    virtual void trySpecializeFloat32(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!binaryCongruentTo(ins))
-            return false;
-        const auto* other = static_cast<const MBinaryArithInstruction*>(ins);
-        return other->mustPreserveNaN_ == mustPreserveNaN_;
-    }
-    AliasSet getAliasSet() const override {
-        if (specialization_ >= MIRType::Object)
-            return AliasSet::Store(AliasSet::Any);
-        return AliasSet::None();
-    }
-
-    bool isTruncated() const {
-        return implicitTruncate_ == Truncate;
-    }
-    TruncateKind truncateKind() const {
-        return implicitTruncate_;
-    }
-    void setTruncateKind(TruncateKind kind) {
-        implicitTruncate_ = Max(implicitTruncate_, kind);
-    }
-};
-
-class MMinMax
-  : public MBinaryInstruction,
-    public ArithPolicy::Data
-{
-    bool isMax_;
-
-    MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax)
-      : MBinaryInstruction(classOpcode, left, right),
-        isMax_(isMax)
-    {
-        MOZ_ASSERT(IsNumberType(type));
-        setResultType(type);
-        setMovable();
-        specialization_ = type;
-    }
-
-  public:
-    INSTRUCTION_HEADER(MinMax)
-    TRIVIAL_NEW_WRAPPERS
-
-    static MMinMax* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right,
-                            MIRType type, bool isMax)
-    {
-        return New(alloc, left, right, type, isMax);
-    }
-
-    bool isMax() const {
-        return isMax_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        const MMinMax* other = ins->toMinMax();
-        return other->isMax() == isMax();
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void computeRange(TempAllocator& alloc) override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    bool isFloat32Commutative() const override { return true; }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MMinMax)
-};
-
-class MAbs
-  : public MUnaryInstruction,
-    public ArithPolicy::Data
-{
-    bool implicitTruncate_;
-
-    MAbs(MDefinition* num, MIRType type)
-      : MUnaryInstruction(classOpcode, num),
-        implicitTruncate_(false)
-    {
-        MOZ_ASSERT(IsNumberType(type));
-        setResultType(type);
-        setMovable();
-        specialization_ = type;
-    }
-
-  public:
-    INSTRUCTION_HEADER(Abs)
-    TRIVIAL_NEW_WRAPPERS
-
-    static MAbs* NewWasm(TempAllocator& alloc, MDefinition* num, MIRType type) {
-        auto* ins = new(alloc) MAbs(num, type);
-        if (type == MIRType::Int32)
-            ins->implicitTruncate_ = true;
-        return ins;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    bool fallible() const;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-    bool isFloat32Commutative() const override { return true; }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MAbs)
-};
-
-class MClz
-  : public MUnaryInstruction
-  , public BitwisePolicy::Data
-{
-    bool operandIsNeverZero_;
-
-    explicit MClz(MDefinition* num, MIRType type)
-      : MUnaryInstruction(classOpcode, num),
-        operandIsNeverZero_(false)
-    {
-        MOZ_ASSERT(IsIntType(type));
-        MOZ_ASSERT(IsNumberType(num->type()));
-        specialization_ = type;
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Clz)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, num))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool operandIsNeverZero() const {
-        return operandIsNeverZero_;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void computeRange(TempAllocator& alloc) override;
-    void collectRangeInfoPreTrunc() override;
-};
-
-class MCtz
-  : public MUnaryInstruction
-  , public BitwisePolicy::Data
-{
-    bool operandIsNeverZero_;
-
-    explicit MCtz(MDefinition* num, MIRType type)
-      : MUnaryInstruction(classOpcode, num),
-        operandIsNeverZero_(false)
-    {
-        MOZ_ASSERT(IsIntType(type));
-        MOZ_ASSERT(IsNumberType(num->type()));
-        specialization_ = type;
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Ctz)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, num))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool operandIsNeverZero() const {
-        return operandIsNeverZero_;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void computeRange(TempAllocator& alloc) override;
-    void collectRangeInfoPreTrunc() override;
-};
-
-class MPopcnt
-  : public MUnaryInstruction
-  , public BitwisePolicy::Data
-{
-    explicit MPopcnt(MDefinition* num, MIRType type)
-      : MUnaryInstruction(classOpcode, num)
-    {
-        MOZ_ASSERT(IsNumberType(num->type()));
-        MOZ_ASSERT(IsIntType(type));
-        specialization_ = type;
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Popcnt)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, num))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    void computeRange(TempAllocator& alloc) override;
-};
-
-// Inline implementation of Math.sqrt().
-class MSqrt
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    MSqrt(MDefinition* num, MIRType type)
-      : MUnaryInstruction(classOpcode, num)
-    {
-        setResultType(type);
-        specialization_ = type;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Sqrt)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-
-    bool isFloat32Commutative() const override { return true; }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MSqrt)
-};
-
-class MCopySign
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    MCopySign(MDefinition* lhs, MDefinition* rhs, MIRType type)
-      : MBinaryInstruction(classOpcode, lhs, rhs)
-    {
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CopySign)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MCopySign)
-};
-
-// Inline implementation of atan2 (arctangent of y/x).
-class MAtan2
-  : public MBinaryInstruction,
-    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
-{
-    MAtan2(MDefinition* y, MDefinition* x)
-      : MBinaryInstruction(classOpcode, y, x)
-    {
-        setResultType(MIRType::Double);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Atan2)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, y), (1, x))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MAtan2)
-};
-
 // Inline implementation of Math.hypot().
 class MHypot
   : public MVariadicInstruction,
     public AllDoublePolicy::Data
 {
     MHypot()
       : MVariadicInstruction(classOpcode)
     {
@@ -6786,254 +2759,16 @@ class MHypot
     }
 
     MInstruction* clone(TempAllocator& alloc,
                         const MDefinitionVector& inputs) const override {
        return MHypot::New(alloc, inputs);
     }
 };
 
-// Inline implementation of Math.pow().
-class MPow
-  : public MBinaryInstruction,
-    public PowPolicy::Data
-{
-    MPow(MDefinition* input, MDefinition* power, MIRType powerType)
-      : MBinaryInstruction(classOpcode, input, power)
-    {
-        MOZ_ASSERT(powerType == MIRType::Double ||
-                   powerType == MIRType::Int32 ||
-                   powerType == MIRType::None);
-        specialization_ = powerType;
-        if (powerType == MIRType::None)
-            setResultType(MIRType::Value);
-        else
-            setResultType(MIRType::Double);
-        setMovable();
-    }
-
-    // Helpers for `foldsTo`
-    MDefinition* foldsConstant(TempAllocator &alloc);
-    MDefinition* foldsConstantPower(TempAllocator &alloc);
-
-  public:
-    INSTRUCTION_HEADER(Pow)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* input() const {
-        return lhs();
-    }
-    MDefinition* power() const {
-        return rhs();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        if (specialization_ == MIRType::None)
-            return AliasSet::Store(AliasSet::Any);
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return specialization_ != MIRType::None;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MPow)
-};
-
-// Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
-class MPowHalf
-  : public MUnaryInstruction,
-    public DoublePolicy<0>::Data
-{
-    bool operandIsNeverNegativeInfinity_;
-    bool operandIsNeverNegativeZero_;
-    bool operandIsNeverNaN_;
-
-    explicit MPowHalf(MDefinition* input)
-      : MUnaryInstruction(classOpcode, input),
-        operandIsNeverNegativeInfinity_(false),
-        operandIsNeverNegativeZero_(false),
-        operandIsNeverNaN_(false)
-    {
-        setResultType(MIRType::Double);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(PowHalf)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    bool operandIsNeverNegativeInfinity() const {
-        return operandIsNeverNegativeInfinity_;
-    }
-    bool operandIsNeverNegativeZero() const {
-        return operandIsNeverNegativeZero_;
-    }
-    bool operandIsNeverNaN() const {
-        return operandIsNeverNaN_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void collectRangeInfoPreTrunc() override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MPowHalf)
-};
-
-// Inline implementation of Math.random().
-class MRandom : public MNullaryInstruction
-{
-    MRandom()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Double);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Random)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-
-    bool canRecoverOnBailout() const override {
-#ifdef JS_MORE_DETERMINISTIC
-        return false;
-#else
-        return true;
-#endif
-    }
-
-    ALLOW_CLONE(MRandom)
-};
-
-class MMathFunction
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-  public:
-    enum Function {
-        Log,
-        Sin,
-        Cos,
-        Exp,
-        Tan,
-        ACos,
-        ASin,
-        ATan,
-        Log10,
-        Log2,
-        Log1P,
-        ExpM1,
-        CosH,
-        SinH,
-        TanH,
-        ACosH,
-        ASinH,
-        ATanH,
-        Sign,
-        Trunc,
-        Cbrt,
-        Floor,
-        Ceil,
-        Round
-    };
-
-  private:
-    Function function_;
-    const MathCache* cache_;
-
-    // A nullptr cache means this function will neither access nor update the cache.
-    MMathFunction(MDefinition* input, Function function, const MathCache* cache)
-      : MUnaryInstruction(classOpcode, input), function_(function), cache_(cache)
-    {
-        setResultType(MIRType::Double);
-        specialization_ = MIRType::Double;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(MathFunction)
-    TRIVIAL_NEW_WRAPPERS
-
-    Function function() const {
-        return function_;
-    }
-    const MathCache* cache() const {
-        return cache_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isMathFunction())
-            return false;
-        if (ins->toMathFunction()->function() != function())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    static const char* FunctionName(Function function);
-
-    bool isFloat32Commutative() const override {
-        return function_ == Floor || function_ == Ceil || function_ == Round;
-    }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-    void computeRange(TempAllocator& alloc) override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        if (input()->type() == MIRType::SinCosDouble)
-            return false;
-        switch(function_) {
-          case Sin:
-          case Log:
-          case Ceil:
-          case Floor:
-          case Round:
-            return true;
-          default:
-            return false;
-        }
-    }
-
-    ALLOW_CLONE(MMathFunction)
-};
-
 class MAdd : public MBinaryArithInstruction
 {
     MAdd(MDefinition* left, MDefinition* right)
       : MBinaryArithInstruction(classOpcode, left, right)
     {
         setResultType(MIRType::Value);
     }
 
@@ -7470,302 +3205,16 @@ class MMod : public MBinaryArithInstruct
 
     bool possiblyCalls() const override {
         return type() == MIRType::Double;
     }
 
     ALLOW_CLONE(MMod)
 };
 
-class MConcat
-  : public MBinaryInstruction,
-    public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
-{
-    MConcat(MDefinition* left, MDefinition* right)
-      : MBinaryInstruction(classOpcode, left, right)
-    {
-        // At least one input should be definitely string
-        MOZ_ASSERT(left->type() == MIRType::String || right->type() == MIRType::String);
-
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Concat)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MConcat)
-};
-
-class MCharCodeAt
-  : public MBinaryInstruction,
-    public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
-{
-    MCharCodeAt(MDefinition* str, MDefinition* index)
-        : MBinaryInstruction(classOpcode, str, index)
-    {
-        setMovable();
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CharCodeAt)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        // Strings are immutable, so there is no implicit dependency.
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MCharCodeAt)
-};
-
-class MFromCharCode
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    explicit MFromCharCode(MDefinition* code)
-      : MUnaryInstruction(classOpcode, code)
-    {
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(FromCharCode)
-    TRIVIAL_NEW_WRAPPERS
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MFromCharCode)
-};
-
-class MFromCodePoint
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    explicit MFromCodePoint(MDefinition* codePoint)
-      : MUnaryInstruction(classOpcode, codePoint)
-    {
-        setGuard(); // throws on invalid code point
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(FromCodePoint)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    ALLOW_CLONE(MFromCodePoint)
-};
-
-class MStringConvertCase
-  : public MUnaryInstruction,
-    public StringPolicy<0>::Data
-{
-  public:
-    enum Mode { LowerCase, UpperCase };
-
-  private:
-    Mode mode_;
-
-    MStringConvertCase(MDefinition* string, Mode mode)
-      : MUnaryInstruction(classOpcode, string), mode_(mode)
-    {
-        setResultType(MIRType::String);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(StringConvertCase)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, string))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) && ins->toStringConvertCase()->mode() == mode();
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    Mode mode() const {
-        return mode_;
-    }
-};
-
-class MSinCos
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    const MathCache* cache_;
-
-    MSinCos(MDefinition *input, const MathCache *cache)
-      : MUnaryInstruction(classOpcode, input),
-        cache_(cache)
-    {
-        setResultType(MIRType::SinCosDouble);
-        specialization_ = MIRType::Double;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SinCos)
-
-    static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
-    {
-        return new (alloc) MSinCos(input, cache);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition *ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    const MathCache* cache() const {
-        return cache_;
-    }
-};
-
-class MStringSplit
-  : public MBinaryInstruction,
-    public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
-{
-    CompilerObjectGroup group_;
-
-    MStringSplit(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* string,
-                 MDefinition* sep, ObjectGroup* group)
-      : MBinaryInstruction(classOpcode, string, sep),
-        group_(group)
-    {
-        setResultType(MIRType::Object);
-        TemporaryTypeSet* types = MakeSingletonTypeSet(alloc, constraints, group);
-        setResultTypeSet(types);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StringSplit)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-    NAMED_OPERANDS((0, string), (1, separator))
-
-    ObjectGroup* group() const {
-        return group_;
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    virtual AliasSet getAliasSet() const override {
-        // Although this instruction returns a new array, we don't have to mark
-        // it as store instruction, see also MNewArray.
-        return AliasSet::None();
-    }
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(group_);
-    }
-};
-
-// Returns the value to use as |this| value. See also ComputeThis and
-// BoxNonStrictThis in Interpreter.h.
-class MComputeThis
-  : public MUnaryInstruction,
-    public BoxPolicy<0>::Data
-{
-    explicit MComputeThis(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ComputeThis)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    // Note: don't override getAliasSet: the thisValue hook can be effectful.
-};
-
-// Load an arrow function's |new.target| value.
-class MArrowNewTarget
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MArrowNewTarget(MDefinition* callee)
-      : MUnaryInstruction(classOpcode, callee)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArrowNewTarget)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, callee))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // An arrow function's lexical |this| value is immutable.
-        return AliasSet::None();
-    }
-};
-
 class MPhi final
   : public MDefinition,
     public InlineListNode<MPhi>,
     public NoTypePolicy::Data
 {
     using InputVector = js::Vector<MUse, 2, JitAllocPolicy>;
     InputVector inputs_;
 
@@ -7944,273 +3393,16 @@ class MPhi final
         canConsumeFloat32_ = can;
     }
 
     TruncateKind operandTruncateKind(size_t index) const override;
     bool needTruncation(TruncateKind kind) override;
     void truncate() override;
 };
 
-// The goal of a Beta node is to split a def at a conditionally taken
-// branch, so that uses dominated by it have a different name.
-class MBeta
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    // This is the range induced by a comparison and branch in a preceding
-    // block. Note that this does not reflect any range constraints from
-    // the input value itself, so this value may differ from the range()
-    // range after it is computed.
-    const Range* comparison_;
-
-    MBeta(MDefinition* val, const Range* comp)
-        : MUnaryInstruction(classOpcode, val),
-          comparison_(comp)
-    {
-        setResultType(val->type());
-        setResultTypeSet(val->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(Beta)
-    TRIVIAL_NEW_WRAPPERS
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-};
-
-// If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the input is returned
-class MNaNToZero
-  : public MUnaryInstruction,
-    public DoublePolicy<0>::Data
-{
-    bool operandIsNeverNaN_;
-    bool operandIsNeverNegativeZero_;
-
-    explicit MNaNToZero(MDefinition* input)
-      : MUnaryInstruction(classOpcode, input),
-        operandIsNeverNaN_(false),
-        operandIsNeverNegativeZero_(false)
-    {
-        setResultType(MIRType::Double);
-        setMovable();
-    }
-  public:
-    INSTRUCTION_HEADER(NaNToZero)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool operandIsNeverNaN() const {
-        return operandIsNeverNaN_;
-    }
-
-    bool operandIsNeverNegativeZero() const {
-        return operandIsNeverNegativeZero_;
-    }
-
-    void collectRangeInfoPreTrunc() override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MNaNToZero)
-};
-
-// MIR representation of a Value on the OSR BaselineFrame.
-// The Value is indexed off of OsrFrameReg.
-class MOsrValue
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    ptrdiff_t frameOffset_;
-
-    MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset)
-      : MUnaryInstruction(classOpcode, entry),
-        frameOffset_(frameOffset)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(OsrValue)
-    TRIVIAL_NEW_WRAPPERS
-
-    ptrdiff_t frameOffset() const {
-        return frameOffset_;
-    }
-
-    MOsrEntry* entry() {
-        return getOperand(0)->toOsrEntry();
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
-// The pointer is indexed off of OsrFrameReg.
-class MOsrEnvironmentChain
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    explicit MOsrEnvironmentChain(MOsrEntry* entry)
-      : MUnaryInstruction(classOpcode, entry)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(OsrEnvironmentChain)
-    TRIVIAL_NEW_WRAPPERS
-
-    MOsrEntry* entry() {
-        return getOperand(0)->toOsrEntry();
-    }
-};
-
-// MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
-// The pointer is indexed off of OsrFrameReg.
-class MOsrArgumentsObject
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    explicit MOsrArgumentsObject(MOsrEntry* entry)
-      : MUnaryInstruction(classOpcode, entry)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(OsrArgumentsObject)
-    TRIVIAL_NEW_WRAPPERS
-
-    MOsrEntry* entry() {
-        return getOperand(0)->toOsrEntry();
-    }
-};
-
-// MIR representation of the return value on the OSR BaselineFrame.
-// The Value is indexed off of OsrFrameReg.
-class MOsrReturnValue
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    explicit MOsrReturnValue(MOsrEntry* entry)
-      : MUnaryInstruction(classOpcode, entry)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(OsrReturnValue)
-    TRIVIAL_NEW_WRAPPERS
-
-    MOsrEntry* entry() {
-        return getOperand(0)->toOsrEntry();
-    }
-};
-
-class MBinarySharedStub
-  : public MBinaryInstruction,
-    public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
-{
-  protected:
-    explicit MBinarySharedStub(MDefinition* left, MDefinition* right)
-      : MBinaryInstruction(classOpcode, left, right)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(BinarySharedStub)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MUnarySharedStub
-  : public MUnaryInstruction,
-    public BoxPolicy<0>::Data
-{
-    explicit MUnarySharedStub(MDefinition* input)
-      : MUnaryInstruction(classOpcode, input)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(UnarySharedStub)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MNullarySharedStub
-  : public MNullaryInstruction
-{
-    explicit MNullarySharedStub()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(NullarySharedStub)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-// Check the current frame for over-recursion past the global stack limit.
-class MCheckOverRecursed
-  : public MNullaryInstruction
-{
-    MCheckOverRecursed()
-      : MNullaryInstruction(classOpcode)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(CheckOverRecursed)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Check whether we need to fire the interrupt handler.
-class MInterruptCheck : public MNullaryInstruction
-{
-    MInterruptCheck()
-      : MNullaryInstruction(classOpcode)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(InterruptCheck)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
 // Directly jumps to the indicated trap, leaving Wasm code and reporting a
 // runtime error.
 
 class MWasmTrap
   : public MAryControlInstruction<0, 0>,
     public NoTypePolicy::Data
 {
     wasm::Trap trap_;
@@ -8229,478 +3421,16 @@ class MWasmTrap
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 
     wasm::Trap trap() const { return trap_; }
     wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
 };
 
-// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
-// it to baseline to throw at the correct pc.
-class MLexicalCheck
-  : public MUnaryInstruction,
-    public BoxPolicy<0>::Data
-{
-    BailoutKind kind_;
-    explicit MLexicalCheck(MDefinition* input, BailoutKind kind = Bailout_UninitializedLexical)
-      : MUnaryInstruction(classOpcode, input),
-        kind_(kind)
-    {
-        setResultType(MIRType::Value);
-        setResultTypeSet(input->resultTypeSet());
-        setMovable();
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LexicalCheck)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    BailoutKind bailoutKind() const {
-        return kind_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-};
-
-// Unconditionally throw an uninitialized let error.
-class MThrowRuntimeLexicalError : public MNullaryInstruction
-{
-    unsigned errorNumber_;
-
-    explicit MThrowRuntimeLexicalError(unsigned errorNumber)
-      : MNullaryInstruction(classOpcode),
-        errorNumber_(errorNumber)
-    {
-        setGuard();
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ThrowRuntimeLexicalError)
-    TRIVIAL_NEW_WRAPPERS
-
-    unsigned errorNumber() const {
-        return errorNumber_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// In the prologues of global and eval scripts, check for redeclarations.
-class MGlobalNameConflictsCheck : public MNullaryInstruction
-{
-    MGlobalNameConflictsCheck()
-      : MNullaryInstruction(classOpcode)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GlobalNameConflictsCheck)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-// If not defined, set a global variable to |undefined|.
-class MDefVar
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    CompilerPropertyName name_; // Target name to be defined.
-    unsigned attrs_; // Attributes to be set.
-
-  private:
-    MDefVar(PropertyName* name, unsigned attrs, MDefinition* envChain)
-      : MUnaryInstruction(classOpcode, envChain),
-        name_(name),
-        attrs_(attrs)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(DefVar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, environmentChain))
-
-    PropertyName* name() const {
-        return name_;
-    }
-    unsigned attrs() const {
-        return attrs_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MDefLexical
-  : public MNullaryInstruction
-{
-    CompilerPropertyName name_; // Target name to be defined.
-    unsigned attrs_; // Attributes to be set.
-
-  private:
-    MDefLexical(PropertyName* name, unsigned attrs)
-      : MNullaryInstruction(classOpcode),
-        name_(name),
-        attrs_(attrs)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(DefLexical)
-    TRIVIAL_NEW_WRAPPERS
-
-    PropertyName* name() const {
-        return name_;
-    }
-    unsigned attrs() const {
-        return attrs_;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MDefFun
-  : public MBinaryInstruction,
-    public ObjectPolicy<0>::Data
-{
-  private:
-    MDefFun(MDefinition* fun, MDefinition* envChain)
-      : MBinaryInstruction(classOpcode, fun, envChain)
-    {}
-
-  public:
-    INSTRUCTION_HEADER(DefFun)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, fun), (1, environmentChain))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MRegExp : public MNullaryInstruction
-{
-    CompilerGCPointer<RegExpObject*> source_;
-    bool mustClone_;
-    bool hasShared_;
-
-    MRegExp(TempAllocator& alloc, CompilerConstraintList* constraints, RegExpObject* source,
-            bool hasShared)
-      : MNullaryInstruction(classOpcode),
-        source_(source),
-        mustClone_(true),
-        hasShared_(hasShared)
-    {
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, source));
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExp)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-
-    void setDoNotClone() {
-        mustClone_ = false;
-    }
-    bool mustClone() const {
-        return mustClone_;
-    }
-    bool hasShared() const {
-        return hasShared_;
-    }
-    RegExpObject* source() const {
-        return source_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(source_);
-    }
-};
-
-class MRegExpMatcher
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>,
-                     StringPolicy<1>,
-                     IntPolicy<2> >::Data
-{
-  private:
-
-    MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
-      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
-    {
-        setMovable();
-        // May be object or null.
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpMatcher)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MRegExpSearcher
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>,
-                     StringPolicy<1>,
-                     IntPolicy<2> >::Data
-{
-  private:
-
-    MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
-      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
-    {
-        setMovable();
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpSearcher)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MRegExpTester
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>,
-                     StringPolicy<1>,
-                     IntPolicy<2> >::Data
-{
-  private:
-
-    MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
-      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
-    {
-        setMovable();
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpTester)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-class MRegExpPrototypeOptimizable
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MRegExpPrototypeOptimizable(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpPrototypeOptimizable)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MRegExpInstanceOptimizable
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
-{
-    explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto)
-      : MBinaryInstruction(classOpcode, object, proto)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(RegExpInstanceOptimizable)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, proto))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MGetFirstDollarIndex
-  : public MUnaryInstruction,
-    public StringPolicy<0>::Data
-{
-    explicit MGetFirstDollarIndex(MDefinition* str)
-      : MUnaryInstruction(classOpcode, str)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetFirstDollarIndex)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, str))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-};
-
-class MStringReplace
-  : public MTernaryInstruction,
-    public MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >::Data
-{
-  private:
-
-    bool isFlatReplacement_;
-
-    MStringReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
-      : MTernaryInstruction(classOpcode, string, pattern, replacement),
-        isFlatReplacement_(false)
-    {
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StringReplace)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, string), (1, pattern), (2, replacement))
-
-    void setFlatReplacement() {
-        MOZ_ASSERT(!isFlatReplacement_);
-        isFlatReplacement_ = true;
-    }
-
-    bool isFlatReplacement() const {
-        return isFlatReplacement_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isStringReplace())
-            return false;
-        if (isFlatReplacement_ != ins->toStringReplace()->isFlatReplacement())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        if (isFlatReplacement_) {
-            MOZ_ASSERT(!pattern()->isRegExp());
-            return true;
-        }
-        return false;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MSubstr
-  : public MTernaryInstruction,
-    public MixPolicy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
-{
-  private:
-
-    MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length)
-      : MTernaryInstruction(classOpcode, string, begin, length)
-    {
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Substr)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, string), (1, begin), (2, length))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MClassConstructor : public MNullaryInstruction
-{
-    jsbytecode* pc_;
-
-    explicit MClassConstructor(jsbytecode* pc)
-      : MNullaryInstruction(classOpcode),
-        pc_(pc)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ClassConstructor)
-    TRIVIAL_NEW_WRAPPERS
-
-    jsbytecode* pc() const {
-      return pc_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
 struct LambdaFunctionInfo
 {
     // The functions used in lambdas are the canonical original function in
     // the script, and are immutable except for delazification. Record this
     // information while still on the active thread to avoid races.
     CompilerFunction fun;
     uint16_t flags;
     uint16_t nargs;
@@ -8725,1027 +3455,27 @@ struct LambdaFunctionInfo
         return roots.append(fun->lazyScript());
     }
 
   private:
     LambdaFunctionInfo(const LambdaFunctionInfo&) = delete;
     void operator=(const LambdaFunctionInfo&) = delete;
 };
 
-class MLambda
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    const LambdaFunctionInfo info_;
-
-    MLambda(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* envChain,
-            MConstant* cst)
-      : MBinaryInstruction(classOpcode, envChain, cst),
-        info_(&cst->toObject().as<JSFunction>())
-    {
-        setResultType(MIRType::Object);
-        if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
-    }
-
-  public:
-    INSTRUCTION_HEADER(Lambda)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-    NAMED_OPERANDS((0, environmentChain))
-
-    MConstant* functionOperand() const {
-        return getOperand(1)->toConstant();
-    }
-    const LambdaFunctionInfo& info() const {
-        return info_;
-    }
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return info_.appendRoots(roots);
-    }
-};
-
-class MLambdaArrow
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>::Data
-{
-    const LambdaFunctionInfo info_;
-
-    MLambdaArrow(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* envChain,
-                 MDefinition* newTarget, MConstant* cst)
-      : MTernaryInstruction(classOpcode, envChain, newTarget, cst),
-        info_(&cst->toObject().as<JSFunction>())
-    {
-        setResultType(MIRType::Object);
-        MOZ_ASSERT(!ObjectGroup::useSingletonForClone(info().fun));
-        if (!info().fun->isSingleton())
-            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
-    }
-
-  public:
-    INSTRUCTION_HEADER(LambdaArrow)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-    NAMED_OPERANDS((0, environmentChain), (1, newTargetDef))
-
-    MConstant* functionOperand() const {
-        return getOperand(2)->toConstant();
-    }
-    const LambdaFunctionInfo& info() const {
-        return info_;
-    }
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return info_.appendRoots(roots);
-    }
-};
-
-class MSetFunName
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
-{
-    uint8_t prefixKind_;
-
-    explicit MSetFunName(MDefinition* fun, MDefinition* name, uint8_t prefixKind)
-      : MBinaryInstruction(classOpcode, fun, name),
-        prefixKind_(prefixKind)
-    {
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetFunName)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, fun), (1, name))
-
-    uint8_t prefixKind() const {
-        return prefixKind_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-// Returns obj->slots.
-class MSlots
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MSlots(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Slots);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Slots)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    ALLOW_CLONE(MSlots)
-};
-
-// Returns obj->elements.
-class MElements
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool unboxed_;
-
-    explicit MElements(MDefinition* object, bool unboxed = false)
-      : MUnaryInstruction(classOpcode, object), unboxed_(unboxed)
-    {
-        setResultType(MIRType::Elements);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Elements)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool unboxed() const {
-        return unboxed_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) &&
-               ins->toElements()->unboxed() == unboxed();
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    ALLOW_CLONE(MElements)
-};
-
-// A constant value for some object's typed array elements.
-class MConstantElements : public MNullaryInstruction
-{
-    SharedMem<void*> value_;
-
-  protected:
-    explicit MConstantElements(SharedMem<void*> v)
-      : MNullaryInstruction(classOpcode),
-        value_(v)
-    {
-        setResultType(MIRType::Elements);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ConstantElements)
-    TRIVIAL_NEW_WRAPPERS
-
-    SharedMem<void*> value() const {
-        return value_;
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    HashNumber valueHash() const override {
-        return (HashNumber)(size_t) value_.asValue();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return ins->isConstantElements() && ins->toConstantElements()->value() == value();
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    ALLOW_CLONE(MConstantElements)
-};
-
-// Passes through an object's elements, after ensuring it is entirely doubles.
-class MConvertElementsToDoubles
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MConvertElementsToDoubles(MDefinition* elements)
-      : MUnaryInstruction(classOpcode, elements)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Elements);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ConvertElementsToDoubles)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // This instruction can read and write to the elements' contents.
-        // However, it is alright to hoist this from loops which explicitly
-        // read or write to the elements: such reads and writes will use double
-        // values and can be reordered freely wrt this conversion, except that
-        // definite double loads must follow the conversion. The latter
-        // property is ensured by chaining this instruction with the elements
-        // themselves, in the same manner as MBoundsCheck.
-        return AliasSet::None();
-    }
-};
-
-// If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
-// double. Else return the original value.
-class MMaybeToDoubleElement
-  : public MBinaryInstruction,
-    public IntPolicy<1>::Data
-{
-    MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
-      : MBinaryInstruction(classOpcode, elements, value)
-    {
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        setMovable();
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(MaybeToDoubleElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, value))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Passes through an object, after ensuring its elements are not copy on write.
-class MMaybeCopyElementsForWrite
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool checkNative_;
-
-    explicit MMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
-      : MUnaryInstruction(classOpcode, object), checkNative_(checkNative)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-        setResultTypeSet(object->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(MaybeCopyElementsForWrite)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool checkNative() const {
-        return checkNative_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) &&
-               checkNative() == ins->toMaybeCopyElementsForWrite()->checkNative();
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields);
-    }
-#ifdef DEBUG
-    bool needsResumePoint() const override {
-        // This instruction is idempotent and does not change observable
-        // behavior, so does not need its own resume point.
-        return false;
-    }
-#endif
-
-};
-
-// Load the initialized length from an elements header.
-class MInitializedLength
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MInitializedLength(MDefinition* elements)
-      : MUnaryInstruction(classOpcode, elements)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(InitializedLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MInitializedLength)
-};
-
-// Store to the initialized length in an elements header. Note the input is an
-// *index*, one less than the desired length.
-class MSetInitializedLength
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    MSetInitializedLength(MDefinition* elements, MDefinition* index)
-      : MBinaryInstruction(classOpcode, elements, index)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(SetInitializedLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields);
-    }
-
-    ALLOW_CLONE(MSetInitializedLength)
-};
-
-// Load the array length from an elements header.
-class MArrayLength
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MArrayLength(MDefinition* elements)
-      : MUnaryInstruction(classOpcode, elements)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArrayLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MArrayLength)
-};
-
-// Store to the length in an elements header. Note the input is an *index*, one
-// less than the desired length.
-class MSetArrayLength
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    MSetArrayLength(MDefinition* elements, MDefinition* index)
-      : MBinaryInstruction(classOpcode, elements, index)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(SetArrayLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields);
-    }
-
-    // By default no, unless built as a recovered instruction.
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return isRecoveredOnBailout();
-    }
-};
-
-class MGetNextEntryForIterator
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
-{
-  public:
-    enum Mode {
-        Map,
-        Set
-    };
-
-  private:
-    Mode mode_;
-
-    explicit MGetNextEntryForIterator(MDefinition* iter, MDefinition* result, Mode mode)
-      : MBinaryInstruction(classOpcode, iter, result), mode_(mode)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetNextEntryForIterator)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, iter), (1, result))
-
-    Mode mode() const {
-        return mode_;
-    }
-};
-
-// Read the length of a typed array.
-class MTypedArrayLength
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MTypedArrayLength(MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypedArrayLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::TypedArrayLength);
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-};
-
-// Load a typed array's elements vector.
-class MTypedArrayElements
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MTypedArrayElements(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Elements);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypedArrayElements)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    ALLOW_CLONE(MTypedArrayElements)
-};
-
-class MSetDisjointTypedElements
-  : public MTernaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MSetDisjointTypedElements(MDefinition* target, MDefinition* targetOffset,
-                                       MDefinition* source)
-      : MTernaryInstruction(classOpcode, target, targetOffset, source)
-    {
-        MOZ_ASSERT(target->type() == MIRType::Object);
-        MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
-        MOZ_ASSERT(source->type() == MIRType::Object);
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetDisjointTypedElements)
-    NAMED_OPERANDS((0, target), (1, targetOffset), (2, source))
-
-    static MSetDisjointTypedElements*
-    New(TempAllocator& alloc, MDefinition* target, MDefinition* targetOffset,
-        MDefinition* source)
-    {
-        return new(alloc) MSetDisjointTypedElements(target, targetOffset, source);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-
-    ALLOW_CLONE(MSetDisjointTypedElements)
-};
-
-// Load a binary data object's "elements", which is just its opaque
-// binary data space. Eventually this should probably be
-// unified with `MTypedArrayElements`.
-class MTypedObjectElements
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool definitelyOutline_;
-
-  private:
-    explicit MTypedObjectElements(MDefinition* object, bool definitelyOutline)
-      : MUnaryInstruction(classOpcode, object),
-        definitelyOutline_(definitelyOutline)
-    {
-        setResultType(MIRType::Elements);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypedObjectElements)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool definitelyOutline() const {
-        return definitelyOutline_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isTypedObjectElements())
-            return false;
-        const MTypedObjectElements* other = ins->toTypedObjectElements();
-        if (other->definitelyOutline() != definitelyOutline())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Inlined version of the js::SetTypedObjectOffset() intrinsic.
-class MSetTypedObjectOffset
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-  private:
-    MSetTypedObjectOffset(MDefinition* object, MDefinition* offset)
-      : MBinaryInstruction(classOpcode, object, offset)
-    {
-        MOZ_ASSERT(object->type() == MIRType::Object);
-        MOZ_ASSERT(offset->type() == MIRType::Int32);
-        setResultType(MIRType::None);
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetTypedObjectOffset)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, offset))
-
-    AliasSet getAliasSet() const override {
-        // This affects the result of MTypedObjectElements,
-        // which is described as a load of ObjectFields.
-        return AliasSet::Store(AliasSet::ObjectFields);
-    }
-};
-
-class MKeepAliveObject
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MKeepAliveObject(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::None);
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(KeepAliveObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-};
-
-// Perform !-operation
-class MNot
-  : public MUnaryInstruction,
-    public TestPolicy::Data
-{
-    bool operandMightEmulateUndefined_;
-    bool operandIsNeverNaN_;
-
-    explicit MNot(MDefinition* input, CompilerConstraintList* constraints = nullptr)
-      : MUnaryInstruction(classOpcode, input),
-        operandMightEmulateUndefined_(true),
-        operandIsNeverNaN_(false)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-        if (constraints)
-            cacheOperandMightEmulateUndefined(constraints);
-    }
-
-    void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
-
-  public:
-    static MNot* NewInt32(TempAllocator& alloc, MDefinition* input) {
-        MOZ_ASSERT(input->type() == MIRType::Int32 || input->type() == MIRType::Int64);
-        auto* ins = new(alloc) MNot(input);
-        ins->setResultType(MIRType::Int32);
-        return ins;
-    }
-
-    INSTRUCTION_HEADER(Not)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    void markNoOperandEmulatesUndefined() {
-        operandMightEmulateUndefined_ = false;
-    }
-    bool operandMightEmulateUndefined() const {
-        return operandMightEmulateUndefined_;
-    }
-    bool operandIsNeverNaN() const {
-        return operandIsNeverNaN_;
-    }
-
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void collectRangeInfoPreTrunc() override;
-
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-    bool isFloat32Commutative() const override { return true; }
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-// Bailout if index + minimum < 0 or index + maximum >= length. The length used
-// in a bounds check must not be negative, or the wrong result may be computed
-// (unsigned comparisons may be used).
-class MBoundsCheck
-  : public MBinaryInstruction,
-    public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
-{
-    // Range over which to perform the bounds check, may be modified by GVN.
-    int32_t minimum_;
-    int32_t maximum_;
-    bool fallible_;
-
-    MBoundsCheck(MDefinition* index, MDefinition* length)
-      : MBinaryInstruction(classOpcode, index, length),
-        minimum_(0), maximum_(0), fallible_(true)
-    {
-        setGuard();
-        setMovable();
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(length->type() == MIRType::Int32);
-
-        // Returns the checked index.
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(BoundsCheck)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, index), (1, length))
-
-    int32_t minimum() const {
-        return minimum_;
-    }
-    void setMinimum(int32_t n) {
-        MOZ_ASSERT(fallible_);
-        minimum_ = n;
-    }
-    int32_t maximum() const {
-        return maximum_;
-    }
-    void setMaximum(int32_t n) {
-        MOZ_ASSERT(fallible_);
-        maximum_ = n;
-    }
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isBoundsCheck())
-            return false;
-        const MBoundsCheck* other = ins->toBoundsCheck();
-        if (minimum() != other->minimum() || maximum() != other->maximum())
-            return false;
-        if (fallible() != other->fallible())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    virtual AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-    bool fallible() const {
-        return fallible_;
-    }
-    void collectRangeInfoPreTrunc() override;
-
-    ALLOW_CLONE(MBoundsCheck)
-};
-
-// Bailout if index < minimum.
-class MBoundsCheckLower
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    int32_t minimum_;
-    bool fallible_;
-
-    explicit MBoundsCheckLower(MDefinition* index)
-      : MUnaryInstruction(classOpcode, index), minimum_(0), fallible_(true)
-    {
-        setGuard();
-        setMovable();
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(BoundsCheckLower)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, index))
-
-    int32_t minimum() const {
-        return minimum_;
-    }
-    void setMinimum(int32_t n) {
-        minimum_ = n;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool fallible() const {
-        return fallible_;
-    }
-    void collectRangeInfoPreTrunc() override;
-};
-
 // Instructions which access an object's elements can either do so on a
 // definition accessing that elements pointer, or on the object itself, if its
 // elements are inline. In the latter case there must be an offset associated
 // with the access.
 static inline bool
 IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment)
 {
     return elements->type() == MIRType::Elements ||
            (elements->type() == MIRType::Object && offsetAdjustment != 0);
 }
 
-// Load a value from a dense array's element vector and does a hole check if the
-// array is not known to be packed.
-class MLoadElement
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool needsHoleCheck_;
-    bool loadDoubles_;
-    int32_t offsetAdjustment_;
-
-    MLoadElement(MDefinition* elements, MDefinition* index,
-                 bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment = 0)
-      : MBinaryInstruction(classOpcode, elements, index),
-        needsHoleCheck_(needsHoleCheck),
-        loadDoubles_(loadDoubles),
-        offsetAdjustment_(offsetAdjustment)
-    {
-        if (needsHoleCheck) {
-            // Uses may be optimized away based on this instruction's result
-            // type. This means it's invalid to DCE this instruction, as we
-            // have to invalidate when we read a hole.
-            setGuard();
-        }
-        setResultType(MIRType::Value);
-        setMovable();
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    bool needsHoleCheck() const {
-        return needsHoleCheck_;
-    }
-    bool loadDoubles() const {
-        return loadDoubles_;
-    }
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool fallible() const {
-        return needsHoleCheck();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadElement())
-            return false;
-        const MLoadElement* other = ins->toLoadElement();
-        if (needsHoleCheck() != other->needsHoleCheck())
-            return false;
-        if (loadDoubles() != other->loadDoubles())
-            return false;
-        if (offsetAdjustment() != other->offsetAdjustment())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    AliasType mightAlias(const MDefinition* store) const override;
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::Element);
-    }
-
-    ALLOW_CLONE(MLoadElement)
-};
-
-// Load a value from the elements vector of a native object. If the index is
-// out-of-bounds, or the indexed slot has a hole, undefined is returned instead.
-class MLoadElementHole
-  : public MTernaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool needsNegativeIntCheck_;
-    bool needsHoleCheck_;
-
-    MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
-                     bool needsHoleCheck)
-      : MTernaryInstruction(classOpcode, elements, index, initLength),
-        needsNegativeIntCheck_(true),
-        needsHoleCheck_(needsHoleCheck)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-
-        // Set the guard flag to make sure we bail when we see a negative
-        // index. We can clear this flag (and needsNegativeIntCheck_) in
-        // collectRangeInfoPreTrunc.
-        setGuard();
-
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(initLength->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadElementHole)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
-
-    bool needsNegativeIntCheck() const {
-        return needsNegativeIntCheck_;
-    }
-    bool needsHoleCheck() const {
-        return needsHoleCheck_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadElementHole())
-            return false;
-        const MLoadElementHole* other = ins->toLoadElementHole();
-        if (needsHoleCheck() != other->needsHoleCheck())
-            return false;
-        if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::Element);
-    }
-    void collectRangeInfoPreTrunc() override;
-
-    ALLOW_CLONE(MLoadElementHole)
-};
-
-class MLoadUnboxedObjectOrNull
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  public:
-    enum NullBehavior {
-        HandleNull,
-        BailOnNull,
-        NullNotPossible
-    };
-
-  private:
-    NullBehavior nullBehavior_;
-    int32_t offsetAdjustment_;
-
-    MLoadUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
-                             NullBehavior nullBehavior, int32_t offsetAdjustment)
-      : MBinaryInstruction(classOpcode, elements, index),
-        nullBehavior_(nullBehavior),
-        offsetAdjustment_(offsetAdjustment)
-    {
-        if (nullBehavior == BailOnNull) {
-            // Don't eliminate loads which bail out on a null pointer, for the
-            // same reason as MLoadElement.
-            setGuard();
-        }
-        setResultType(nullBehavior == HandleNull ? MIRType::Value : MIRType::Object);
-        setMovable();
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    NullBehavior nullBehavior() const {
-        return nullBehavior_;
-    }
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool fallible() const {
-        return nullBehavior() == BailOnNull;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadUnboxedObjectOrNull())
-            return false;
-        const MLoadUnboxedObjectOrNull* other = ins->toLoadUnboxedObjectOrNull();
-        if (nullBehavior() != other->nullBehavior())
-            return false;
-        if (offsetAdjustment() != other->offsetAdjustment())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-    AliasType mightAlias(const MDefinition* store) const override;
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MLoadUnboxedObjectOrNull)
-};
-
-class MLoadUnboxedString
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    int32_t offsetAdjustment_;
-
-    MLoadUnboxedString(MDefinition* elements, MDefinition* index, int32_t offsetAdjustment = 0)
-      : MBinaryInstruction(classOpcode, elements, index),
-        offsetAdjustment_(offsetAdjustment)
-    {
-        setResultType(MIRType::String);
-        setMovable();
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadUnboxedString)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadUnboxedString())
-            return false;
-        const MLoadUnboxedString* other = ins->toLoadUnboxedString();
-        if (offsetAdjustment() != other->offsetAdjustment())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-
-    ALLOW_CLONE(MLoadUnboxedString)
-};
-
 class MStoreElementCommon
 {
     MIRType elementType_;
     bool needsBarrier_;
 
   protected:
     MStoreElementCommon()
       : elementType_(MIRType::Value),
@@ -9763,418 +3493,16 @@ class MStoreElementCommon
     bool needsBarrier() const {
         return needsBarrier_;
     }
     void setNeedsBarrier() {
         needsBarrier_ = true;
     }
 };
 
-// This instruction is used to load an element of a non-escaped inlined array.
-class MLoadElementFromState
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    MLoadElementFromState(MDefinition* array, MDefinition* index)
-      : MBinaryInstruction(classOpcode, array, index)
-    {
-        MOZ_ASSERT(array->isArgumentState());
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        setResultType(MIRType::Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadElementFromState)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, array), (1, index));
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Store a value to a dense array slots vector.
-class MStoreElement
-  : public MTernaryInstruction,
-    public MStoreElementCommon,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
-{
-    bool needsHoleCheck_;
-    int32_t offsetAdjustment_;
-
-    MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value,
-                  bool needsHoleCheck, int32_t offsetAdjustment = 0)
-      : MTernaryInstruction(classOpcode, elements, index, value)
-    {
-        needsHoleCheck_ = needsHoleCheck;
-        offsetAdjustment_ = offsetAdjustment;
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::Element);
-    }
-    bool needsHoleCheck() const {
-        return needsHoleCheck_;
-    }
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool fallible() const {
-        return needsHoleCheck();
-    }
-
-    ALLOW_CLONE(MStoreElement)
-};
-
-// Like MStoreElement, but supports indexes >= initialized length. The downside
-// is that we cannot hoist the elements vector and bounds check, since this
-// instruction may update the (initialized) length and reallocate the elements
-// vector.
-class MStoreElementHole
-  : public MQuaternaryInstruction,
-    public MStoreElementCommon,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
-{
-    MStoreElementHole(MDefinition* object, MDefinition* elements,
-                      MDefinition* index, MDefinition* value)
-      : MQuaternaryInstruction(classOpcode, object, elements, index, value)
-    {
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreElementHole)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
-
-    AliasSet getAliasSet() const override {
-        // StoreElementHole can update the initialized length, the array length
-        // or reallocate obj->elements.
-        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
-    }
-
-    ALLOW_CLONE(MStoreElementHole)
-};
-
-// Try to store a value to a dense array slots vector. May fail due to the object being frozen.
-// Cannot be used on an object that has extra indexed properties.
-class MFallibleStoreElement
-  : public MQuaternaryInstruction,
-    public MStoreElementCommon,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
-{
-    bool strict_;
-
-    MFallibleStoreElement(MDefinition* object, MDefinition* elements,
-                          MDefinition* index, MDefinition* value,
-                          bool strict)
-      : MQuaternaryInstruction(classOpcode, object, elements, index, value),
-        strict_(strict)
-    {
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(FallibleStoreElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
-    }
-    bool strict() const {
-        return strict_;
-    }
-
-    ALLOW_CLONE(MFallibleStoreElement)
-};
-
-
-// Store an unboxed object or null pointer to a v\ector.
-class MStoreUnboxedObjectOrNull
-  : public MQuaternaryInstruction,
-    public StoreUnboxedObjectOrNullPolicy::Data
-{
-    int32_t offsetAdjustment_;
-    bool preBarrier_;
-
-    MStoreUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
-                              MDefinition* value, MDefinition* typedObj,
-                              int32_t offsetAdjustment = 0, bool preBarrier = true)
-      : MQuaternaryInstruction(classOpcode, elements, index, value, typedObj),
-        offsetAdjustment_(offsetAdjustment),
-        preBarrier_(preBarrier)
-    {
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(typedObj->type() == MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value), (3, typedObj))
-
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool preBarrier() const {
-        return preBarrier_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-
-    // For StoreUnboxedObjectOrNullPolicy.
-    void setValue(MDefinition* def) {
-        replaceOperand(2, def);
-    }
-
-    ALLOW_CLONE(MStoreUnboxedObjectOrNull)
-};
-
-// Store an unboxed object or null pointer to a vector.
-class MStoreUnboxedString
-  : public MTernaryInstruction,
-    public MixPolicy<SingleObjectPolicy, ConvertToStringPolicy<2> >::Data
-{
-    int32_t offsetAdjustment_;
-    bool preBarrier_;
-
-    MStoreUnboxedString(MDefinition* elements, MDefinition* index, MDefinition* value,
-                        int32_t offsetAdjustment = 0, bool preBarrier = true)
-      : MTernaryInstruction(classOpcode, elements, index, value),
-        offsetAdjustment_(offsetAdjustment),
-        preBarrier_(preBarrier)
-    {
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreUnboxedString)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value))
-
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    bool preBarrier() const {
-        return preBarrier_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-
-    ALLOW_CLONE(MStoreUnboxedString)
-};
-
-// Passes through an object, after ensuring it is converted from an unboxed
-// object to a native representation.
-class MConvertUnboxedObjectToNative
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    CompilerObjectGroup group_;
-
-    explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
-      : MUnaryInstruction(classOpcode, obj),
-        group_(group)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
-    NAMED_OPERANDS((0, object))
-
-    static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
-                                              ObjectGroup* group);
-
-    ObjectGroup* group() const {
-        return group_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        return ins->toConvertUnboxedObjectToNative()->group() == group();
-    }
-    AliasSet getAliasSet() const override {
-        // This instruction can read and write to all parts of the object, but
-        // is marked as non-effectful so it can be consolidated by LICM and GVN
-        // and avoid inhibiting other optimizations.
-        //
-        // This is valid to do because when unboxed objects might have a native
-        // group they can be converted to, we do not optimize accesses to the
-        // unboxed objects and do not guard on their group or shape (other than
-        // in this opcode).
-        //
-        // Later accesses can assume the object has a native representation
-        // and optimize accordingly. Those accesses cannot be reordered before
-        // this instruction, however. This is prevented by chaining this
-        // instruction with the object itself, in the same way as MBoundsCheck.
-        return AliasSet::None();
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(group_);
-    }
-};
-
-// Array.prototype.pop or Array.prototype.shift on a dense array.
-class MArrayPopShift
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  public:
-    enum Mode {
-        Pop,
-        Shift
-    };
-
-  private:
-    Mode mode_;
-    bool needsHoleCheck_;
-    bool maybeUndefined_;
-
-    MArrayPopShift(MDefinition* object, Mode mode,
-                   bool needsHoleCheck, bool maybeUndefined)
-      : MUnaryInstruction(classOpcode, object), mode_(mode),
-        needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(ArrayPopShift)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool needsHoleCheck() const {
-        return needsHoleCheck_;
-    }
-    bool maybeUndefined() const {
-        return maybeUndefined_;
-    }
-    bool mode() const {
-        return mode_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
-    }
-
-    ALLOW_CLONE(MArrayPopShift)
-};
-
-// Array.prototype.push on a dense array. Returns the new array length.
-class MArrayPush
-  : public MBinaryInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
-{
-    MArrayPush(MDefinition* object, MDefinition* value)
-      : MBinaryInstruction(classOpcode, object, value)
-    {
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArrayPush)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, value))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
-    }
-    void computeRange(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MArrayPush)
-};
-
-// Array.prototype.slice on a dense array.
-class MArraySlice
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
-{
-    CompilerObject templateObj_;
-    gc::InitialHeap initialHeap_;
-
-    MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
-                MDefinition* begin, MDefinition* end,
-                JSObject* templateObj, gc::InitialHeap initialHeap)
-      : MTernaryInstruction(classOpcode, obj, begin, end),
-        templateObj_(templateObj),
-        initialHeap_(initialHeap)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArraySlice)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, begin), (2, end))
-
-    JSObject* templateObj() const {
-        return templateObj_;
-    }
-
-    gc::InitialHeap initialHeap() const {
-        return initialHeap_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObj_);
-    }
-};
-
-class MArrayJoin
-    : public MBinaryInstruction,
-      public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
-{
-    bool optimizeForArray_;
-
-    MArrayJoin(MDefinition* array, MDefinition* sep, bool optimizeForArray)
-        : MBinaryInstruction(classOpcode, array, sep),
-          optimizeForArray_(optimizeForArray)
-    {
-        setResultType(MIRType::String);
-    }
-  public:
-    INSTRUCTION_HEADER(ArrayJoin)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, array), (1, sep))
-
-    bool optimizeForArray() const {
-        return optimizeForArray_;
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    virtual AliasSet getAliasSet() const override {
-        // Array.join might coerce the elements of the Array to strings.  This
-        // coercion might cause the evaluation of the some JavaScript code.
-        return AliasSet::Store(AliasSet::Any);
-    }
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-};
-
 // All barriered operations - MCompareExchangeTypedArrayElement,
 // MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as
 // well as MLoadUnboxedScalar and MStoreUnboxedScalar when they are
 // marked as requiring a memory barrer - have the following
 // attributes:
 //
 // - Not movable
 // - Not removable
@@ -10189,237 +3517,16 @@ class MArrayJoin
 enum MemoryBarrierRequirement
 {
     DoesNotRequireMemoryBarrier,
     DoesRequireMemoryBarrier
 };
 
 // Also see comments at MMemoryBarrierRequirement, above.
 
-// Load an unboxed scalar value from a typed array or other object.
-class MLoadUnboxedScalar
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    Scalar::Type storageType_;
-    Scalar::Type readType_;
-    unsigned numElems_; // used only for SIMD
-    bool requiresBarrier_;
-    int32_t offsetAdjustment_;
-    bool canonicalizeDoubles_;
-
-    MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, Scalar::Type storageType,
-                       MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
-                       int32_t offsetAdjustment = 0, bool canonicalizeDoubles = true)
-      : MBinaryInstruction(classOpcode, elements, index),
-        storageType_(storageType),
-        readType_(storageType),
-        numElems_(1),
-        requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
-        offsetAdjustment_(offsetAdjustment),
-        canonicalizeDoubles_(canonicalizeDoubles)
-    {
-        setResultType(MIRType::Value);
-        if (requiresBarrier_)
-            setGuard();         // Not removable or movable
-        else
-            setMovable();
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadUnboxedScalar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index))
-
-    void setSimdRead(Scalar::Type type, unsigned numElems) {
-        readType_ = type;
-        numElems_ = numElems;
-    }
-    unsigned numElems() const {
-        return numElems_;
-    }
-    Scalar::Type readType() const {
-        return readType_;
-    }
-
-    Scalar::Type storageType() const {
-        return storageType_;
-    }
-    bool fallible() const {
-        // Bailout if the result does not fit in an int32.
-        return readType_ == Scalar::Uint32 && type() == MIRType::Int32;
-    }
-    bool requiresMemoryBarrier() const {
-        return requiresBarrier_;
-    }
-    bool canonicalizeDoubles() const {
-        return canonicalizeDoubles_;
-    }
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    void setOffsetAdjustment(int32_t offsetAdjustment) {
-        offsetAdjustment_ = offsetAdjustment;
-    }
-    AliasSet getAliasSet() const override {
-        // When a barrier is needed make the instruction effectful by
-        // giving it a "store" effect.
-        if (requiresBarrier_)
-            return AliasSet::Store(AliasSet::UnboxedElement);
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (requiresBarrier_)
-            return false;
-        if (!ins->isLoadUnboxedScalar())
-            return false;
-        const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
-        if (storageType_ != other->storageType_)
-            return false;
-        if (readType_ != other->readType_)
-            return false;
-        if (numElems_ != other->numElems_)
-            return false;
-        if (offsetAdjustment() != other->offsetAdjustment())
-            return false;
-        if (canonicalizeDoubles() != other->canonicalizeDoubles())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    void computeRange(TempAllocator& alloc) override;
-
-    bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
-
-    ALLOW_CLONE(MLoadUnboxedScalar)
-};
-
-// Load a value from a typed array. Out-of-bounds accesses are handled in-line.
-class MLoadTypedArrayElementHole
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    Scalar::Type arrayType_;
-    bool allowDouble_;
-
-    MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble)
-      : MBinaryInstruction(classOpcode, object, index),
-        arrayType_(arrayType), allowDouble_(allowDouble)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadTypedArrayElementHole)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, index))
-
-    Scalar::Type arrayType() const {
-        return arrayType_;
-    }
-    bool allowDouble() const {
-        return allowDouble_;
-    }
-    bool fallible() const {
-        return arrayType_ == Scalar::Uint32 && !allowDouble_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadTypedArrayElementHole())
-            return false;
-        const MLoadTypedArrayElementHole* other = ins->toLoadTypedArrayElementHole();
-        if (arrayType() != other->arrayType())
-            return false;
-        if (allowDouble() != other->allowDouble())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-    bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
-
-    ALLOW_CLONE(MLoadTypedArrayElementHole)
-};
-
-// Load a value fallibly or infallibly from a statically known typed array.
-class MLoadTypedArrayElementStatic
-  : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>::Data
-{
-    MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
-                                 int32_t offset = 0, bool needsBoundsCheck = true)
-      : MUnaryInstruction(classOpcode, ptr), someTypedArray_(someTypedArray), offset_(offset),
-        needsBoundsCheck_(needsBoundsCheck), fallible_(true)
-    {
-        int type = accessType();
-        if (type == Scalar::Float32)
-            setResultType(MIRType::Float32);
-        else if (type == Scalar::Float64)
-            setResultType(MIRType::Double);
-        else
-            setResultType(MIRType::Int32);
-    }
-
-    CompilerObject someTypedArray_;
-
-    // An offset to be encoded in the load instruction - taking advantage of the
-    // addressing modes. This is only non-zero when the access is proven to be
-    // within bounds.
-    int32_t offset_;
-    bool needsBoundsCheck_;
-    bool fallible_;
-
-  public:
-    INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
-    TRIVIAL_NEW_WRAPPERS
-
-    Scalar::Type accessType() const {
-        return someTypedArray_->as<TypedArrayObject>().type();
-    }
-    SharedMem<void*> base() const;
-    size_t length() const;
-
-    MDefinition* ptr() const { return getOperand(0); }
-    int32_t offset() const { return offset_; }
-    void setOffset(int32_t offset) { offset_ = offset; }
-    bool congruentTo(const MDefinition* ins) const override;
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::UnboxedElement);
-    }
-
-    bool needsBoundsCheck() const { return needsBoundsCheck_; }
-    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
-
-    bool fallible() const {
-        return fallible_;
-    }
-
-    void setInfallible() {
-        fallible_ = false;
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-    bool needTruncation(TruncateKind kind) override;
-    bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
-    void collectRangeInfoPreTrunc() override;
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(someTypedArray_);
-    }
-};
-
 // Base class for MIR ops that write unboxed scalar values.
 class StoreUnboxedScalarBase
 {
     Scalar::Type writeType_;
 
   protected:
     explicit StoreUnboxedScalarBase(Scalar::Type writeType)
       : writeType_(writeType)
@@ -10450,399 +3557,16 @@ class StoreUnboxedScalarBase
         return writeType_ == Scalar::Float32 ||
                writeType_ == Scalar::Float64;
     }
     bool isSimdWrite() const {
         return Scalar::isSimdType(writeType());
     }
 };
 
-// Store an unboxed scalar value to a typed array or other object.
-class MStoreUnboxedScalar
-  : public MTernaryInstruction,
-    public StoreUnboxedScalarBase,
-    public StoreUnboxedScalarPolicy::Data
-{
-  public:
-    enum TruncateInputKind {
-        DontTruncateInput,
-        TruncateInput
-    };
-
-  private:
-    Scalar::Type storageType_;
-
-    // Whether this store truncates out of range inputs, for use by range analysis.
-    TruncateInputKind truncateInput_;
-
-    bool requiresBarrier_;
-    int32_t offsetAdjustment_;
-    unsigned numElems_; // used only for SIMD
-
-    MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
-                        Scalar::Type storageType, TruncateInputKind truncateInput,
-                        MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
-                        int32_t offsetAdjustment = 0)
-      : MTernaryInstruction(classOpcode, elements, index, value),
-        StoreUnboxedScalarBase(storageType),
-        storageType_(storageType),
-        truncateInput_(truncateInput),
-        requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
-        offsetAdjustment_(offsetAdjustment),
-        numElems_(1)
-    {
-        if (requiresBarrier_)
-            setGuard();         // Not removable or movable
-        else
-            setMovable();
-        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreUnboxedScalar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value))
-
-    void setSimdWrite(Scalar::Type writeType, unsigned numElems) {
-        MOZ_ASSERT(Scalar::isSimdType(writeType));
-        setWriteType(writeType);
-        numElems_ = numElems;
-    }
-    unsigned numElems() const {
-        return numElems_;
-    }
-    Scalar::Type storageType() const {
-        return storageType_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-    TruncateInputKind truncateInput() const {
-        return truncateInput_;
-    }
-    bool requiresMemoryBarrier() const {
-        return requiresBarrier_;
-    }
-    int32_t offsetAdjustment() const {
-        return offsetAdjustment_;
-    }
-    TruncateKind operandTruncateKind(size_t index) const override;
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return use == getUseFor(2) && writeType() == Scalar::Float32;
-    }
-
-    ALLOW_CLONE(MStoreUnboxedScalar)
-};
-
-class MStoreTypedArrayElementHole
-  : public MQuaternaryInstruction,
-    public StoreUnboxedScalarBase,
-    public StoreTypedArrayHolePolicy::Data
-{
-    MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, MDefinition* index,
-                                MDefinition* value, Scalar::Type arrayType)
-      : MQuaternaryInstruction(classOpcode, elements, length, index, value),
-        StoreUnboxedScalarBase(arrayType)
-    {
-        setMovable();
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        MOZ_ASSERT(length->type() == MIRType::Int32);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreTypedArrayElementHole)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value))
-
-    Scalar::Type arrayType() const {
-        MOZ_ASSERT(!Scalar::isSimdType(writeType()),
-                   "arrayType == writeType iff the write type isn't SIMD");
-        return writeType();
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-    TruncateKind operandTruncateKind(size_t index) const override;
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return use == getUseFor(3) && arrayType() == Scalar::Float32;
-    }
-
-    ALLOW_CLONE(MStoreTypedArrayElementHole)
-};
-
-// Store a value infallibly to a statically known typed array.
-class MStoreTypedArrayElementStatic :
-    public MBinaryInstruction,
-    public StoreUnboxedScalarBase,
-    public StoreTypedArrayElementStaticPolicy::Data
-{
-    MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
-                                  int32_t offset = 0, bool needsBoundsCheck = true)
-        : MBinaryInstruction(classOpcode, ptr, v),
-          StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
-          someTypedArray_(someTypedArray),
-          offset_(offset), needsBoundsCheck_(needsBoundsCheck)
-    {}
-
-    CompilerObject someTypedArray_;
-
-    // An offset to be encoded in the store instruction - taking advantage of the
-    // addressing modes. This is only non-zero when the access is proven to be
-    // within bounds.
-    int32_t offset_;
-    bool needsBoundsCheck_;
-
-  public:
-    INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
-    TRIVIAL_NEW_WRAPPERS
-
-    Scalar::Type accessType() const {
-        return writeType();
-    }
-
-    SharedMem<void*> base() const;
-    size_t length() const;
-
-    MDefinition* ptr() const { return getOperand(0); }
-    MDefinition* value() const { return getOperand(1); }
-    bool needsBoundsCheck() const { return needsBoundsCheck_; }
-    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
-    int32_t offset() const { return offset_; }
-    void setOffset(int32_t offset) { offset_ = offset; }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-    TruncateKind operandTruncateKind(size_t index) const override;
-
-    bool canConsumeFloat32(MUse* use) const override {
-        return use == getUseFor(1) && accessType() == Scalar::Float32;
-    }
-    void collectRangeInfoPreTrunc() override;
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(someTypedArray_);
-    }
-};
-
-// Compute an "effective address", i.e., a compound computation of the form:
-//   base + index * scale + displacement
-class MEffectiveAddress
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
-      : MBinaryInstruction(classOpcode, base, index),
-        scale_(scale), displacement_(displacement)
-    {
-        MOZ_ASSERT(base->type() == MIRType::Int32);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        setMovable();
-        setResultType(MIRType::Int32);
-    }
-
-    Scale scale_;
-    int32_t displacement_;
-
-  public:
-    INSTRUCTION_HEADER(EffectiveAddress)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* base() const {
-        return lhs();
-    }
-    MDefinition* index() const {
-        return rhs();
-    }
-    Scale scale() const {
-        return scale_;
-    }
-    int32_t displacement() const {
-        return displacement_;
-    }
-
-    ALLOW_CLONE(MEffectiveAddress)
-};
-
-// Clamp input to range [0, 255] for Uint8ClampedArray.
-class MClampToUint8
-  : public MUnaryInstruction,
-    public ClampPolicy::Data
-{
-    explicit MClampToUint8(MDefinition* input)
-      : MUnaryInstruction(classOpcode, input)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ClampToUint8)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    void computeRange(TempAllocator& alloc) override;
-
-    ALLOW_CLONE(MClampToUint8)
-};
-
-class MLoadFixedSlot
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    size_t slot_;
-
-  protected:
-    MLoadFixedSlot(MDefinition* obj, size_t slot)
-      : MUnaryInstruction(classOpcode, obj), slot_(slot)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadFixedSlot)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    size_t slot() const {
-        return slot_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadFixedSlot())
-            return false;
-        if (slot() != ins->toLoadFixedSlot()->slot())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::FixedSlot);
-    }
-
-    AliasType mightAlias(const MDefinition* store) const override;
-
-    ALLOW_CLONE(MLoadFixedSlot)
-};
-
-class MLoadFixedSlotAndUnbox
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    size_t slot_;
-    MUnbox::Mode mode_;
-    BailoutKind bailoutKind_;
-  protected:
-    MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, MIRType type,
-                           BailoutKind kind)
-      : MUnaryInstruction(classOpcode, obj), slot_(slot), mode_(mode), bailoutKind_(kind)
-    {
-        setResultType(type);
-        setMovable();
-        if (mode_ == MUnbox::TypeBarrier || mode_ == MUnbox::Fallible)
-            setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    size_t slot() const {
-        return slot_;
-    }
-    MUnbox::Mode mode() const {
-        return mode_;
-    }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-    bool fallible() const {
-        return mode_ != MUnbox::Infallible;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadFixedSlotAndUnbox() ||
-            slot() != ins->toLoadFixedSlotAndUnbox()->slot() ||
-            mode() != ins->toLoadFixedSlotAndUnbox()->mode())
-        {
-            return false;
-        }
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::FixedSlot);
-    }
-
-    AliasType mightAlias(const MDefinition* store) const override;
-
-    ALLOW_CLONE(MLoadFixedSlotAndUnbox);
-};
-
-class MStoreFixedSlot
-  : public MBinaryInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
-{
-    bool needsBarrier_;
-    size_t slot_;
-
-    MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, bool barrier)
-      : MBinaryInstruction(classOpcode, obj, rval),
-        needsBarrier_(barrier),
-        slot_(slot)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(StoreFixedSlot)
-    NAMED_OPERANDS((0, object), (1, value))
-
-    static MStoreFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
-                                MDefinition* rval)
-    {
-        return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
-    }
-    static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, size_t slot,
-                                         MDefinition* rval)
-    {
-        return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
-    }
-
-    size_t slot() const {
-        return slot_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::FixedSlot);
-    }
-    bool needsBarrier() const {
-        return needsBarrier_;
-    }
-    void setNeedsBarrier(bool needsBarrier = true) {
-        needsBarrier_ = needsBarrier;
-    }
-
-    ALLOW_CLONE(MStoreFixedSlot)
-};
-
 struct InliningTarget
 {
     JSObject* target;
 
     // If target is a singleton, group is nullptr. If target is not a singleton,
     // this is the group we need to guard on when doing a polymorphic inlining
     // dispatch. Note that this can be different from target->group() due to
     // proto mutation.
@@ -10923,281 +3647,28 @@ class InlinePropertyTable : public TempO
     void trimTo(const InliningTargets& targets, const BoolVector& choiceSet);
 
     // Ensure that the InlinePropertyTable's domain is a subset of |targets|.
     void trimToTargets(const InliningTargets& targets);
 
     bool appendRoots(MRootList& roots) const;
 };
 
-class MGetPropertyCache
-  : public MBinaryInstruction,
-    public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
-{
-    bool idempotent_ : 1;
-    bool monitoredResult_ : 1;
-
-    InlinePropertyTable* inlinePropertyTable_;
-
-    MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
-      : MBinaryInstruction(classOpcode, obj, id),
-        idempotent_(false),
-        monitoredResult_(monitoredResult),
-        inlinePropertyTable_(nullptr)
-    {
-        setResultType(MIRType::Value);
-
-        // The cache will invalidate if there are objects with e.g. lookup or
-        // resolve hooks on the proto chain. setGuard ensures this check is not
-        // eliminated.
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetPropertyCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value), (1, idval))
-
-    InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
-        MOZ_ASSERT(inlinePropertyTable_ == nullptr);
-        inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
-        return inlinePropertyTable_;
-    }
-
-    void clearInlinePropertyTable() {
-        inlinePropertyTable_ = nullptr;
-    }
-
-    InlinePropertyTable* propTable() const {
-        return inlinePropertyTable_;
-    }
-
-    bool idempotent() const {
-        return idempotent_;
-    }
-    void setIdempotent() {
-        idempotent_ = true;
-        setMovable();
-    }
-    bool monitoredResult() const {
-        return monitoredResult_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!idempotent_)
-            return false;
-        if (!ins->isGetPropertyCache())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        if (idempotent_) {
-            return AliasSet::Load(AliasSet::ObjectFields |
-                                  AliasSet::FixedSlot |
-                                  AliasSet::DynamicSlot);
-        }
-        return AliasSet::Store(AliasSet::Any);
-    }
-
-    bool allowDoubleResult() const;
-
-    bool appendRoots(MRootList& roots) const override {
-        if (inlinePropertyTable_)
-            return inlinePropertyTable_->appendRoots(roots);
-        return true;
-    }
-};
-
-class MHomeObjectSuperBase
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MHomeObjectSuperBase(MDefinition* homeObject)
-      : MUnaryInstruction(classOpcode, homeObject)
-    {
-        setResultType(MIRType::Object);
-        setGuard(); // May throw if [[Prototype]] is null
-    }
-
-  public:
-    INSTRUCTION_HEADER(HomeObjectSuperBase)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, homeObject))
-};
-
-class MGetPropSuperCache
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, CacheIdPolicy<2>>::Data
-{
-    MGetPropSuperCache(MDefinition* obj, MDefinition* receiver, MDefinition* id)
-      : MTernaryInstruction(classOpcode, obj, receiver, id)
-    {
-        setResultType(MIRType::Value);
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetPropSuperCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, receiver), (2, idval))
-};
-
 struct PolymorphicEntry {
     // The group and/or shape to guard against.
     ReceiverGuard receiver;
 
     // The property to load, null for loads from unboxed properties.
     Shape* shape;
 
     bool appendRoots(MRootList& roots) const {
         return roots.append(receiver) && roots.append(shape);
     }
 };
 
-// Emit code to load a value from an object if it matches one of the receivers
-// observed by the baseline IC, else bails out.
-class MGetPropertyPolymorphic
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
-    CompilerPropertyName name_;
-
-    MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
-      : MUnaryInstruction(classOpcode, obj),
-        receivers_(alloc),
-        name_(name)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetPropertyPolymorphic)
-    NAMED_OPERANDS((0, object))
-
-    static MGetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name) {
-        return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isGetPropertyPolymorphic())
-            return false;
-        if (name() != ins->toGetPropertyPolymorphic()->name())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
-        PolymorphicEntry entry;
-        entry.receiver = receiver;
-        entry.shape = shape;
-        return receivers_.append(entry);
-    }
-    size_t numReceivers() const {
-        return receivers_.length();
-    }
-    const ReceiverGuard receiver(size_t i) const {
-        return receivers_[i].receiver;
-    }
-    Shape* shape(size_t i) const {
-        return receivers_[i].shape;
-    }
-    PropertyName* name() const {
-        return name_;
-    }
-    AliasSet getAliasSet() const override {
-        bool hasUnboxedLoad = false;
-        for (size_t i = 0; i < numReceivers(); i++) {
-            if (!shape(i)) {
-                hasUnboxedLoad = true;
-                break;
-            }
-        }
-        return AliasSet::Load(AliasSet::ObjectFields |
-                              AliasSet::FixedSlot |
-                              AliasSet::DynamicSlot |
-                              (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
-    }
-
-    AliasType mightAlias(const MDefinition* store) const override;
-
-    bool appendRoots(MRootList& roots) const override;
-};
-
-// Emit code to store a value to an object's slots if its shape/group matches
-// one of the shapes/groups observed by the baseline IC, else bails out.
-class MSetPropertyPolymorphic
-  : public MBinaryInstruction,
-    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
-{
-    Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
-    CompilerPropertyName name_;
-    bool needsBarrier_;
-
-    MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
-                            PropertyName* name)
-      : MBinaryInstruction(classOpcode, obj, value),
-        receivers_(alloc),
-        name_(name),
-        needsBarrier_(false)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetPropertyPolymorphic)
-    NAMED_OPERANDS((0, object), (1, value))
-
-    static MSetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
-                                        PropertyName* name) {
-        return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
-    }
-
-    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
-        PolymorphicEntry entry;
-        entry.receiver = receiver;
-        entry.shape = shape;
-        return receivers_.append(entry);
-    }
-    size_t numReceivers() const {
-        return receivers_.length();
-    }
-    const ReceiverGuard& receiver(size_t i) const {
-        return receivers_[i].receiver;
-    }
-    Shape* shape(size_t i) const {
-        return receivers_[i].shape;
-    }
-    PropertyName* name() const {
-        return name_;
-    }
-    bool needsBarrier() const {
-        return needsBarrier_;
-    }
-    void setNeedsBarrier() {
-        needsBarrier_ = true;
-    }
-    AliasSet getAliasSet() const override {
-        bool hasUnboxedStore = false;
-        for (size_t i = 0; i < numReceivers(); i++) {
-            if (!shape(i)) {
-                hasUnboxedStore = true;
-                break;
-            }
-        }
-        return AliasSet::Store(AliasSet::ObjectFields |
-                               AliasSet::FixedSlot |
-                               AliasSet::DynamicSlot |
-                               (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
-    }
-    bool appendRoots(MRootList& roots) const override;
-};
-
 class MDispatchInstruction
   : public MControlInstruction,
     public SingleObjectPolicy::Data
 {
     // Map from JSFunction* -> MBasicBlock.
     struct Entry {
         JSFunction* func;
         // If |func| has a singleton group, |funcGroup| is null. Otherwise,
@@ -11346,734 +3817,16 @@ class MFunctionDispatch : public MDispat
     INSTRUCTION_HEADER(FunctionDispatch)
 
     static MFunctionDispatch* New(TempAllocator& alloc, MDefinition* ins) {
         return new(alloc) MFunctionDispatch(alloc, ins);
     }
     bool appendRoots(MRootList& roots) const override;
 };
 
-class MBindNameCache
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    CompilerPropertyName name_;
-    CompilerScript script_;
-    jsbytecode* pc_;
-
-    MBindNameCache(MDefinition* envChain, PropertyName* name, JSScript* script, jsbytecode* pc)
-      : MUnaryInstruction(classOpcode, envChain), name_(name), script_(script), pc_(pc)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(BindNameCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, environmentChain))
-
-    PropertyName* name() const {
-        return name_;
-    }
-    JSScript* script() const {
-        return script_;
-    }
-    jsbytecode* pc() const {
-        return pc_;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        // Don't append the script, all scripts are added anyway.
-        return roots.append(name_);
-    }
-};
-
-class MCallBindVar
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MCallBindVar(MDefinition* envChain)
-      : MUnaryInstruction(classOpcode, envChain)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallBindVar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, environmentChain))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isCallBindVar())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Guard on an object's shape.
-class MGuardShape
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    CompilerShape shape_;
-    BailoutKind bailoutKind_;
-
-    MGuardShape(MDefinition* obj, Shape* shape, BailoutKind bailoutKind)
-      : MUnaryInstruction(classOpcode, obj),
-        shape_(shape),
-        bailoutKind_(bailoutKind)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-        setResultTypeSet(obj->resultTypeSet());
-
-        // Disallow guarding on unboxed object shapes. The group is better to
-        // guard on, and guarding on the shape can interact badly with
-        // MConvertUnboxedObjectToNative.
-        MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardShape)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    const Shape* shape() const {
-        return shape_;
-    }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isGuardShape())
-            return false;
-        if (shape() != ins->toGuardShape()->shape())
-            return false;
-        if (bailoutKind() != ins->toGuardShape()->bailoutKind())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(shape_);
-    }
-};
-
-// Bail if the object's shape or unboxed group is not in the input list.
-class MGuardReceiverPolymorphic
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
-
-    MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj),
-        receivers_(alloc)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-        setResultTypeSet(obj->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardReceiverPolymorphic)
-    NAMED_OPERANDS((0, object))
-
-    static MGuardReceiverPolymorphic* New(TempAllocator& alloc, MDefinition* obj) {
-        return new(alloc) MGuardReceiverPolymorphic(alloc, obj);
-    }
-
-    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver) {
-        return receivers_.append(receiver);
-    }
-    size_t numReceivers() const {
-        return receivers_.length();
-    }
-    const ReceiverGuard& receiver(size_t i) const {
-        return receivers_[i];
-    }
-
-    bool congruentTo(const MDefinition* ins) const override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    bool appendRoots(MRootList& roots) const override;
-
-};
-
-// Guard on an object's group, inclusively or exclusively.
-class MGuardObjectGroup
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    CompilerObjectGroup group_;
-    bool bailOnEquality_;
-    BailoutKind bailoutKind_;
-
-    MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
-                      BailoutKind bailoutKind)
-      : MUnaryInstruction(classOpcode, obj),
-        group_(group),
-        bailOnEquality_(bailOnEquality),
-        bailoutKind_(bailoutKind)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-
-        // Unboxed groups which might be converted to natives can't be guarded
-        // on, due to MConvertUnboxedObjectToNative.
-        MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
-                      !group->unboxedLayoutDontCheckGeneration().nativeGroup());
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardObjectGroup)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    const ObjectGroup* group() const {
-        return group_;
-    }
-    bool bailOnEquality() const {
-        return bailOnEquality_;
-    }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isGuardObjectGroup())
-            return false;
-        if (group() != ins->toGuardObjectGroup()->group())
-            return false;
-        if (bailOnEquality() != ins->toGuardObjectGroup()->bailOnEquality())
-            return false;
-        if (bailoutKind() != ins->toGuardObjectGroup()->bailoutKind())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(group_);
-    }
-};
-
-// Guard on an object's identity, inclusively or exclusively.
-class MGuardObjectIdentity
-  : public MBinaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool bailOnEquality_;
-
-    MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
-      : MBinaryInstruction(classOpcode, obj, expected),
-        bailOnEquality_(bailOnEquality)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardObjectIdentity)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, expected))
-
-    bool bailOnEquality() const {
-        return bailOnEquality_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isGuardObjectIdentity())
-            return false;
-        if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Guard on an object's class.
-class MGuardClass
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    const Class* class_;
-
-    MGuardClass(MDefinition* obj, const Class* clasp)
-      : MUnaryInstruction(classOpcode, obj),
-        class_(clasp)
-    {
-        setGuard();
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardClass)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    const Class* getClass() const {
-        return class_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isGuardClass())
-            return false;
-        if (getClass() != ins->toGuardClass()->getClass())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-
-    ALLOW_CLONE(MGuardClass)
-};
-
-// Guard on the presence or absence of an unboxed object's expando.
-class MGuardUnboxedExpando
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool requireExpando_;
-    BailoutKind bailoutKind_;
-
-    MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
-      : MUnaryInstruction(classOpcode, obj),
-        requireExpando_(requireExpando),
-        bailoutKind_(bailoutKind)
-    {
-        setGuard();
-        setMovable();
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GuardUnboxedExpando)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool requireExpando() const {
-        return requireExpando_;
-    }
-    BailoutKind bailoutKind() const {
-        return bailoutKind_;
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!congruentIfOperandsEqual(ins))
-            return false;
-        if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
-            return false;
-        return true;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Load an unboxed plain object's expando.
-class MLoadUnboxedExpando
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  private:
-    explicit MLoadUnboxedExpando(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadUnboxedExpando)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-// Load from vp[slot] (slots that are not inline in an object).
-class MLoadSlot
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    uint32_t slot_;
-
-    MLoadSlot(MDefinition* slots, uint32_t slot)
-      : MUnaryInstruction(classOpcode, slots),
-        slot_(slot)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-        MOZ_ASSERT(slots->type() == MIRType::Slots);
-    }
-
-  public:
-    INSTRUCTION_HEADER(LoadSlot)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, slots))
-
-    uint32_t slot() const {
-        return slot_;
-    }
-
-    HashNumber valueHash() const override;
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isLoadSlot())
-            return false;
-        if (slot() != ins->toLoadSlot()->slot())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        MOZ_ASSERT(slots()->type() == MIRType::Slots);
-        return AliasSet::Load(AliasSet::DynamicSlot);
-    }
-    AliasType mightAlias(const MDefinition* store) const override;
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MLoadSlot)
-};
-
-// Inline call to access a function's environment (scope chain).
-class MFunctionEnvironment
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MFunctionEnvironment(MDefinition* function)
-        : MUnaryInstruction(classOpcode, function)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(FunctionEnvironment)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, function))
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    // A function's environment is fixed.
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Allocate a new LexicalEnvironmentObject.
-class MNewLexicalEnvironmentObject
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    CompilerGCPointer<LexicalScope*> scope_;
-
-    MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
-      : MUnaryInstruction(classOpcode, enclosing),
-        scope_(scope)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, enclosing))
-
-    LexicalScope* scope() const {
-        return scope_;
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(scope_);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Allocate a new LexicalEnvironmentObject from existing one
-class MCopyLexicalEnvironmentObject
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    bool copySlots_;
-
-    MCopyLexicalEnvironmentObject(MDefinition* env, bool copySlots)
-      : MUnaryInstruction(classOpcode, env),
-        copySlots_(copySlots)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CopyLexicalEnvironmentObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, env))
-
-    bool copySlots() const {
-        return copySlots_;
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields |
-                              AliasSet::FixedSlot |
-                              AliasSet::DynamicSlot);
-    }
-};
-
-class MHomeObject
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MHomeObject(MDefinition* function)
-        : MUnaryInstruction(classOpcode, function)
-    {
-        setResultType(MIRType::Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(HomeObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, function))
-
-    // A function's [[HomeObject]] is fixed.
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Store to vp[slot] (slots that are not inline in an object).
-class MStoreSlot
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
-{
-    uint32_t slot_;
-    MIRType slotType_;
-    bool needsBarrier_;
-
-    MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier)
-        : MBinaryInstruction(classOpcode, slots, value),
-          slot_(slot),
-          slotType_(MIRType::Value),
-          needsBarrier_(barrier)
-    {
-        MOZ_ASSERT(slots->type() == MIRType::Slots);
-    }
-
-  public:
-    INSTRUCTION_HEADER(StoreSlot)
-    NAMED_OPERANDS((0, slots), (1, value))
-
-    static MStoreSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
-                           MDefinition* value)
-    {
-        return new(alloc) MStoreSlot(slots, slot, value, false);
-    }
-    static MStoreSlot* NewBarriered(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
-                                    MDefinition* value)
-    {
-        return new(alloc) MStoreSlot(slots, slot, value, true);
-    }
-
-    uint32_t slot() const {
-        return slot_;
-    }
-    MIRType slotType() const {
-        return slotType_;
-    }
-    void setSlotType(MIRType slotType) {
-        MOZ_ASSERT(slotType != MIRType::None);
-        slotType_ = slotType;
-    }
-    bool needsBarrier() const {
-        return needsBarrier_;
-    }
-    void setNeedsBarrier() {
-        needsBarrier_ = true;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::DynamicSlot);
-    }
-    void printOpcode(GenericPrinter& out) const override;
-
-    ALLOW_CLONE(MStoreSlot)
-};
-
-class MGetNameCache
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  private:
-    explicit MGetNameCache(MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetNameCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, envObj))
-};
-
-class MCallGetIntrinsicValue : public MNullaryInstruction
-{
-    CompilerPropertyName name_;
-
-    explicit MCallGetIntrinsicValue(PropertyName* name)
-      : MNullaryInstruction(classOpcode),
-        name_(name)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallGetIntrinsicValue)
-    TRIVIAL_NEW_WRAPPERS
-
-    PropertyName* name() const {
-        return name_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MSetPropertyInstruction : public MBinaryInstruction
-{
-    CompilerPropertyName name_;
-    bool strict_;
-
-  protected:
-    MSetPropertyInstruction(Opcode op, MDefinition* obj, MDefinition* value, PropertyName* name,
-                            bool strict)
-      : MBinaryInstruction(op, obj, value),
-        name_(name), strict_(strict)
-    {}
-
-  public:
-    NAMED_OPERANDS((0, object), (1, value))
-    PropertyName* name() const {
-        return name_;
-    }
-    bool strict() const {
-        return strict_;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MSetElementInstruction
-  : public MTernaryInstruction
-{
-    bool strict_;
-  protected:
-    MSetElementInstruction(Opcode op, MDefinition* object, MDefinition* index, MDefinition* value,
-                           bool strict)
-      : MTernaryInstruction(op, object, index, value),
-        strict_(strict)
-    {
-    }
-
-  public:
-    NAMED_OPERANDS((0, object), (1, index), (2, value))
-    bool strict() const {
-        return strict_;
-    }
-};
-
-class MDeleteProperty
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    CompilerPropertyName name_;
-    bool strict_;
-
-  protected:
-    MDeleteProperty(MDefinition* val, PropertyName* name, bool strict)
-      : MUnaryInstruction(classOpcode, val),
-        name_(name),
-        strict_(strict)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(DeleteProperty)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-
-    PropertyName* name() const {
-        return name_;
-    }
-    bool strict() const {
-        return strict_;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-class MDeleteElement
-  : public MBinaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    bool strict_;
-
-    MDeleteElement(MDefinition* value, MDefinition* index, bool strict)
-      : MBinaryInstruction(classOpcode, value, index),
-        strict_(strict)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(DeleteElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value), (1, index))
-
-    bool strict() const {
-        return strict_;
-    }
-};
-
 // Note: This uses CallSetElementPolicy to always box its second input,
 // ensuring we don't need two LIR instructions to lower this.
 class MCallSetProperty
   : public MSetPropertyInstruction,
     public CallSetElementPolicy::Data
 {
     MCallSetProperty(MDefinition* obj, MDefinition* value, PropertyName* name, bool strict)
       : MSetPropertyInstruction(classOpcode, obj, value, name, strict)
@@ -12084,119 +3837,16 @@ class MCallSetProperty
     INSTRUCTION_HEADER(CallSetProperty)
     TRIVIAL_NEW_WRAPPERS
 
     bool possiblyCalls() const override {
         return true;
     }
 };
 
-class MSetPropertyCache
-  : public MTernaryInstruction,
-    public MixPolicy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
-{
-    bool strict_ : 1;
-    bool needsPostBarrier_ : 1;
-    bool needsTypeBarrier_ : 1;
-    bool guardHoles_ : 1;
-
-    MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
-                      bool needsPostBarrier, bool typeBarrier, bool guardHoles)
-      : MTernaryInstruction(classOpcode, obj, id, value),
-        strict_(strict),
-        needsPostBarrier_(needsPostBarrier),
-        needsTypeBarrier_(typeBarrier),
-        guardHoles_(guardHoles)
-    {
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetPropertyCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, idval), (2, value))
-
-    bool needsPostBarrier() const {
-        return needsPostBarrier_;
-    }
-    bool needsTypeBarrier() const {
-        return needsTypeBarrier_;
-    }
-
-    bool guardHoles() const {
-        return guardHoles_;
-    }
-
-    bool strict() const {
-        return strict_;
-    }
-};
-
-class MCallGetProperty
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    CompilerPropertyName name_;
-    bool idempotent_;
-
-    MCallGetProperty(MDefinition* value, PropertyName* name)
-      : MUnaryInstruction(classOpcode, value), name_(name),
-        idempotent_(false)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallGetProperty)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-
-    PropertyName* name() const {
-        return name_;
-    }
-
-    // Constructors need to perform a GetProp on the function prototype.
-    // Since getters cannot be set on the prototype, fetching is non-effectful.
-    // The operation may be safely repeated in case of bailout.
-    void setIdempotent() {
-        idempotent_ = true;
-    }
-    AliasSet getAliasSet() const override {
-        if (!idempotent_)
-            return AliasSet::Store(AliasSet::Any);
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(name_);
-    }
-};
-
-// Inline call to handle lhs[rhs]. The first input is a Value so that this
-// instruction can handle both objects and strings.
-class MCallGetElement
-  : public MBinaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    MCallGetElement(MDefinition* lhs, MDefinition* rhs)
-      : MBinaryInstruction(classOpcode, lhs, rhs)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallGetElement)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
 class MCallSetElement
   : public MSetElementInstruction,
     public CallSetElementPolicy::Data
 {
     MCallSetElement(MDefinition* object, MDefinition* index, MDefinition* value, bool strict)
       : MSetElementInstruction(classOpcode, object, index, value, strict)
     {
     }
@@ -12205,61 +3855,16 @@ class MCallSetElement
     INSTRUCTION_HEADER(CallSetElement)
     TRIVIAL_NEW_WRAPPERS
 
     bool possiblyCalls() const override {
         return true;
     }
 };
 
-class MCallInitElementArray
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
-{
-    MCallInitElementArray(MDefinition* obj, MDefinition* index, MDefinition* val)
-      : MTernaryInstruction(classOpcode, obj, index, val)
-    {
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallInitElementArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, index), (2, value))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
-class MSetDOMProperty
-  : public MBinaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
-{
-    const JSJitSetterOp func_;
-
-    MSetDOMProperty(const JSJitSetterOp func, MDefinition* obj, MDefinition* val)
-      : MBinaryInstruction(classOpcode, obj, val),
-        func_(func)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(SetDOMProperty)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, value))
-
-    JSJitSetterOp fun() const {
-        return func_;
-    }
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
 class MGetDOMProperty
   : public MVariadicInstruction,
     public ObjectPolicy<0>::Data
 {
     const JSJitInfo* info_;
 
   protected:
     MGetDOMProperty(Opcode op, const JSJitInfo* jitinfo)
@@ -12407,549 +4012,16 @@ class MGetDOMMember : public MGetDOMProp
     bool congruentTo(const MDefinition* ins) const override {
         if (!ins->isGetDOMMember())
             return false;
 
         return MGetDOMProperty::congruentTo(ins->toGetDOMMember());
     }
 };
 
-class MStringLength
-  : public MUnaryInstruction,
-    public StringPolicy<0>::Data
-{
-    explicit MStringLength(MDefinition* string)
-      : MUnaryInstruction(classOpcode, string)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-  public:
-    INSTRUCTION_HEADER(StringLength)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, string))
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // The string |length| property is immutable, so there is no
-        // implicit dependency.
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MStringLength)
-};
-
-// Inlined assembly for Math.floor(double | float32) -> int32.
-class MFloor
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    explicit MFloor(MDefinition* num)
-      : MUnaryInstruction(classOpcode, num)
-    {
-        setResultType(MIRType::Int32);
-        specialization_ = MIRType::Double;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Floor)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool isFloat32Commutative() const override {
-        return true;
-    }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    void computeRange(TempAllocator& alloc) override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MFloor)
-};
-
-// Inlined assembly version for Math.ceil(double | float32) -> int32.
-class MCeil
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    explicit MCeil(MDefinition* num)
-      : MUnaryInstruction(classOpcode, num)
-    {
-        setResultType(MIRType::Int32);
-        specialization_ = MIRType::Double;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Ceil)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool isFloat32Commutative() const override {
-        return true;
-    }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    void computeRange(TempAllocator& alloc) override;
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MCeil)
-};
-
-// Inlined version of Math.round(double | float32) -> int32.
-class MRound
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    explicit MRound(MDefinition* num)
-      : MUnaryInstruction(classOpcode, num)
-    {
-        setResultType(MIRType::Int32);
-        specialization_ = MIRType::Double;
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(Round)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool isFloat32Commutative() const override {
-        return true;
-    }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MRound)
-};
-
-// NearbyInt rounds the floating-point input to the nearest integer, according
-// to the RoundingMode.
-class MNearbyInt
-  : public MUnaryInstruction,
-    public FloatingPointPolicy<0>::Data
-{
-    RoundingMode roundingMode_;
-
-    explicit MNearbyInt(MDefinition* num, MIRType resultType, RoundingMode roundingMode)
-      : MUnaryInstruction(classOpcode, num),
-        roundingMode_(roundingMode)
-    {
-        MOZ_ASSERT(HasAssemblerSupport(roundingMode));
-
-        MOZ_ASSERT(IsFloatingPointType(resultType));
-        setResultType(resultType);
-        specialization_ = resultType;
-
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(NearbyInt)
-    TRIVIAL_NEW_WRAPPERS
-
-    static bool HasAssemblerSupport(RoundingMode mode) {
-        return Assembler::HasRoundInstruction(mode);
-    }
-
-    RoundingMode roundingMode() const { return roundingMode_; }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool isFloat32Commutative() const override {
-        return true;
-    }
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        return true;
-    }
-#endif
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) &&
-               ins->toNearbyInt()->roundingMode() == roundingMode_;
-    }
-
-    void printOpcode(GenericPrinter& out) const override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-
-    bool canRecoverOnBailout() const override {
-        switch (roundingMode_) {
-          case RoundingMode::Up:
-          case RoundingMode::Down:
-            return true;
-          default:
-            return false;
-        }
-    }
-
-    ALLOW_CLONE(MNearbyInt)
-};
-
-class MGetIteratorCache
-  : public MUnaryInstruction,
-    public BoxExceptPolicy<0, MIRType::Object>::Data
-{
-    explicit MGetIteratorCache(MDefinition* val)
-      : MUnaryInstruction(classOpcode, val)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetIteratorCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-};
-
-class MIteratorMore
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MIteratorMore(MDefinition* iter)
-      : MUnaryInstruction(classOpcode, iter)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(IteratorMore)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, iterator))
-
-};
-
-class MIsNoIter
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    explicit MIsNoIter(MDefinition* def)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsNoIter)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MIteratorEnd
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MIteratorEnd(MDefinition* iter)
-      : MUnaryInstruction(classOpcode, iter)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(IteratorEnd)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, iterator))
-
-};
-
-// Implementation for 'in' operator using instruction cache
-class MInCache
-  : public MBinaryInstruction,
-    public MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >::Data
-{
-    MInCache(MDefinition* key, MDefinition* obj)
-      : MBinaryInstruction(classOpcode, key, obj)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(InCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, key), (1, object))
-};
-
-
-// Test whether the index is in the array bounds or a hole.
-class MInArray
-  : public MQuaternaryInstruction,
-    public ObjectPolicy<3>::Data
-{
-    bool needsHoleCheck_;
-    bool needsNegativeIntCheck_;
-
-    MInArray(MDefinition* elements, MDefinition* index,
-             MDefinition* initLength, MDefinition* object,
-             bool needsHoleCheck)
-      : MQuaternaryInstruction(classOpcode, elements, index, initLength, object),
-        needsHoleCheck_(needsHoleCheck),
-        needsNegativeIntCheck_(true)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-        MOZ_ASSERT(elements->type() == MIRType::Elements);
-        MOZ_ASSERT(index->type() == MIRType::Int32);
-        MOZ_ASSERT(initLength->type() == MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(InArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, initLength), (3, object))
-
-    bool needsHoleCheck() const {
-        return needsHoleCheck_;
-    }
-    bool needsNegativeIntCheck() const {
-        return needsNegativeIntCheck_;
-    }
-    void collectRangeInfoPreTrunc() override;
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::Element);
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isInArray())
-            return false;
-        const MInArray* other = ins->toInArray();
-        if (needsHoleCheck() != other->needsHoleCheck())
-            return false;
-        if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
-            return false;
-        return congruentIfOperandsEqual(other);
-    }
-};
-
-class MHasOwnCache
-  : public MBinaryInstruction,
-    public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
-{
-    MHasOwnCache(MDefinition* obj, MDefinition* id)
-      : MBinaryInstruction(classOpcode, obj, id)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(HasOwnCache)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value), (1, idval))
-};
-
-// Implementation for instanceof operator with specific rhs.
-class MInstanceOf
-  : public MUnaryInstruction,
-    public InstanceOfPolicy::Data
-{
-    CompilerObject protoObj_;
-
-    MInstanceOf(MDefinition* obj, JSObject* proto)
-      : MUnaryInstruction(classOpcode, obj),
-        protoObj_(proto)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(InstanceOf)
-    TRIVIAL_NEW_WRAPPERS
-
-    JSObject* prototypeObject() {
-        return protoObj_;
-    }
-
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(protoObj_);
-    }
-};
-
-// Implementation for instanceof operator with unknown rhs.
-class MCallInstanceOf
-  : public MBinaryInstruction,
-    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
-{
-    MCallInstanceOf(MDefinition* obj, MDefinition* proto)
-      : MBinaryInstruction(classOpcode, obj, proto)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(CallInstanceOf)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MArgumentsLength : public MNullaryInstruction
-{
-    MArgumentsLength()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Int32);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArgumentsLength)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // Arguments |length| cannot be mutated by Ion Code.
-        return AliasSet::None();
-    }
-
-    void computeRange(TempAllocator& alloc) override;
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-};
-
-// This MIR instruction is used to get an argument from the actual arguments.
-class MGetFrameArgument
-  : public MUnaryInstruction,
-    public IntPolicy<0>::Data
-{
-    bool scriptHasSetArg_;
-
-    MGetFrameArgument(MDefinition* idx, bool scriptHasSetArg)
-      : MUnaryInstruction(classOpcode, idx),
-        scriptHasSetArg_(scriptHasSetArg)
-    {
-        setResultType(MIRType::Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetFrameArgument)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, index))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
-        // aliased.
-        if (scriptHasSetArg_)
-            return AliasSet::Load(AliasSet::FrameArgument);
-        return AliasSet::None();
-    }
-};
-
-class MNewTarget : public MNullaryInstruction
-{
-    MNewTarget() : MNullaryInstruction(classOpcode) {
-        setResultType(MIRType::Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewTarget)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// This MIR instruction is used to set an argument value in the frame.
-class MSetFrameArgument
-  : public MUnaryInstruction,
-    public NoFloatPolicy<0>::Data
-{
-    uint32_t argno_;
-
-    MSetFrameArgument(uint32_t argno, MDefinition* value)
-      : MUnaryInstruction(classOpcode, value),
-        argno_(argno)
-    {
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(SetFrameArgument)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-
-    uint32_t argno() const {
-        return argno_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return false;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::FrameArgument);
-    }
-};
-
 class MRestCommon
 {
     unsigned numFormals_;
     CompilerGCPointer<ArrayObject*> templateObject_;
 
   protected:
     MRestCommon(unsigned numFormals, ArrayObject* templateObject)
       : numFormals_(numFormals),
@@ -12960,287 +4032,16 @@ class MRestCommon
     unsigned numFormals() const {
         return numFormals_;
     }
     ArrayObject* templateObject() const {
         return templateObject_;
     }
 };
 
-class MRest
-  : public MUnaryInstruction,
-    public MRestCommon,
-    public IntPolicy<0>::Data
-{
-    MRest(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* numActuals,
-          unsigned numFormals, ArrayObject* templateObject)
-      : MUnaryInstruction(classOpcode, numActuals),
-        MRestCommon(numFormals, templateObject)
-    {
-        setResultType(MIRType::Object);
-        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
-    }
-
-  public:
-    INSTRUCTION_HEADER(Rest)
-    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
-    NAMED_OPERANDS((0, numActuals))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool possiblyCalls() const override {
-        return true;
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObject());
-    }
-};
-
-class MFilterTypeSet
-  : public MUnaryInstruction,
-    public FilterTypeSetPolicy::Data
-{
-    MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types)
-      : MUnaryInstruction(classOpcode, def)
-    {
-        MOZ_ASSERT(!types->unknown());
-        setResultType(types->getKnownMIRType());
-        setResultTypeSet(types);
-    }
-
-  public:
-    INSTRUCTION_HEADER(FilterTypeSet)
-    TRIVIAL_NEW_WRAPPERS
-
-    bool congruentTo(const MDefinition* def) const override {
-        return false;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    virtual bool neverHoist() const override {
-        return resultTypeSet()->empty();
-    }
-    void computeRange(TempAllocator& alloc) override;
-
-    bool isFloat32Commutative() const override {
-        return IsFloatingPointType(type());
-    }
-
-    bool canProduceFloat32() const override;
-    bool canConsumeFloat32(MUse* operand) const override;
-    void trySpecializeFloat32(TempAllocator& alloc) override;
-};
-
-// Given a value, guard that the value is in a particular TypeSet, then returns
-// that value.
-class MTypeBarrier
-  : public MUnaryInstruction,
-    public TypeBarrierPolicy::Data
-{
-    BarrierKind barrierKind_;
-
-    MTypeBarrier(MDefinition* def, TemporaryTypeSet* types,
-                 BarrierKind kind = BarrierKind::TypeSet)
-      : MUnaryInstruction(classOpcode, def),
-        barrierKind_(kind)
-    {
-        MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
-
-        MOZ_ASSERT(!types->unknown());
-        setResultType(types->getKnownMIRType());
-        setResultTypeSet(types);
-
-        setGuard();
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypeBarrier)
-    TRIVIAL_NEW_WRAPPERS
-
-    void printOpcode(GenericPrinter& out) const override;
-    bool congruentTo(const MDefinition* def) const override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    virtual bool neverHoist() const override {
-        return resultTypeSet()->empty();
-    }
-    BarrierKind barrierKind() const {
-        return barrierKind_;
-    }
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    bool alwaysBails() const {
-        // If mirtype of input doesn't agree with mirtype of barrier,
-        // we will definitely bail.
-        MIRType type = resultTypeSet()->getKnownMIRType();
-        if (type == MIRType::Value)
-            return false;
-        if (input()->type() == MIRType::Value)
-            return false;
-        if (input()->type() == MIRType::ObjectOrNull) {
-            // The ObjectOrNull optimization is only performed when the
-            // barrier's type is MIRType::Null.
-            MOZ_ASSERT(type == MIRType::Null);
-            return false;
-        }
-        return input()->type() != type;
-    }
-
-    ALLOW_CLONE(MTypeBarrier)
-};
-
-// Like MTypeBarrier, guard that the value is in the given type set. This is
-// used before property writes to ensure the value being written is represented
-// in the property types for the object.
-class MMonitorTypes
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    const TemporaryTypeSet* typeSet_;
-    BarrierKind barrierKind_;
-
-    MMonitorTypes(MDefinition* def, const TemporaryTypeSet* types, BarrierKind kind)
-      : MUnaryInstruction(classOpcode, def),
-        typeSet_(types),
-        barrierKind_(kind)
-    {
-        MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
-
-        setGuard();
-        MOZ_ASSERT(!types->unknown());
-    }
-
-  public:
-    INSTRUCTION_HEADER(MonitorTypes)
-    TRIVIAL_NEW_WRAPPERS
-
-    const TemporaryTypeSet* typeSet() const {
-        return typeSet_;
-    }
-    BarrierKind barrierKind() const {
-        return barrierKind_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-// Given a value being written to another object, update the generational store
-// buffer if the value is in the nursery and object is in the tenured heap.
-class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
-{
-    MPostWriteBarrier(MDefinition* obj, MDefinition* value)
-      : MBinaryInstruction(classOpcode, obj, value)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(PostWriteBarrier)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, value))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        // During lowering, values that neither have object nor value MIR type
-        // are ignored, thus Float32 can show up at this point without any issue.
-        return use == getUseFor(1);
-    }
-#endif
-
-    ALLOW_CLONE(MPostWriteBarrier)
-};
-
-// Given a value being written to another object's elements at the specified
-// index, update the generational store buffer if the value is in the nursery
-// and object is in the tenured heap.
-class MPostWriteElementBarrier : public MTernaryInstruction
-                               , public MixPolicy<ObjectPolicy<0>, IntPolicy<2>>::Data
-{
-    MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, MDefinition* index)
-      : MTernaryInstruction(classOpcode, obj, value, index)
-    {
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(PostWriteElementBarrier)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, value), (2, index))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-#ifdef DEBUG
-    bool isConsistentFloat32Use(MUse* use) const override {
-        // During lowering, values that neither have object nor value MIR type
-        // are ignored, thus Float32 can show up at this point without any issue.
-        return use == getUseFor(1);
-    }
-#endif
-
-    ALLOW_CLONE(MPostWriteElementBarrier)
-};
-
-class MNewNamedLambdaObject : public MNullaryInstruction
-{
-    CompilerGCPointer<LexicalEnvironmentObject*> templateObj_;
-
-    explicit MNewNamedLambdaObject(LexicalEnvironmentObject* templateObj)
-      : MNullaryInstruction(classOpcode),
-        templateObj_(templateObj)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    INSTRUCTION_HEADER(NewNamedLambdaObject)
-    TRIVIAL_NEW_WRAPPERS
-
-    LexicalEnvironmentObject* templateObj() {
-        return templateObj_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool appendRoots(MRootList& roots) const override {
-        return roots.append(templateObj_);
-    }
-};
-
-class MNewCallObjectBase : public MUnaryInstruction
-                         , public SingleObjectPolicy::Data
-{
-  protected:
-    MNewCallObjectBase(Opcode op, MConstant* templateObj)
-      : MUnaryInstruction(op, templateObj)
-    {
-        setResultType(MIRType::Object);
-    }
-
-  public:
-    CallObject* templateObject() const {
-        return &getOperand(0)->toConstant()->toObject().as<CallObject>();
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
 class MNewCallObject : public MNewCallObjectBase
 {
   public:
     INSTRUCTION_HEADER(NewCallObject)
     TRIVIAL_NEW_WRAPPERS
 
     explicit MNewCallObject(MConstant* templateObj)
       : MNewCallObjectBase(classOpcode, templateObj)
@@ -13473,717 +4274,16 @@ class MResumePoint final :
     MStoresToRecoverList::iterator storesEnd() const {
         return stores_.end();
     }
 
     virtual void dump(GenericPrinter& out) const override;
     virtual void dump() const override;
 };
 
-class MIsCallable
-  : public MUnaryInstruction,
-    public BoxExceptPolicy<0, MIRType::Object>::Data
-{
-    explicit MIsCallable(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        MOZ_ASSERT(object->type() == MIRType::Object || object->type() == MIRType::Value);
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsCallable)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MIsConstructor
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-  public:
-    explicit MIsConstructor(MDefinition* object)
-      : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsConstructor)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MIsObject
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    explicit MIsObject(MDefinition* object)
-    : MUnaryInstruction(classOpcode, object)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-  public:
-    INSTRUCTION_HEADER(IsObject)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MHasClass
-    : public MUnaryInstruction,
-      public SingleObjectPolicy::Data
-{
-    const Class* class_;
-
-    MHasClass(MDefinition* object, const Class* clasp)
-      : MUnaryInstruction(classOpcode, object)
-      , class_(clasp)
-    {
-        MOZ_ASSERT(object->type() == MIRType::Object ||
-                   (object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(HasClass)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    const Class* getClass() const {
-        return class_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        if (!ins->isHasClass())
-            return false;
-        if (getClass() != ins->toHasClass()->getClass())
-            return false;
-        return congruentIfOperandsEqual(ins);
-    }
-};
-
-// Note: we might call a proxy trap, so this instruction is effectful.
-class MIsArray
-  : public MUnaryInstruction,
-    public BoxExceptPolicy<0, MIRType::Object>::Data
-{
-    explicit MIsArray(MDefinition* value)
-      : MUnaryInstruction(classOpcode, value)
-    {
-        setResultType(MIRType::Boolean);
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-};
-
-class MIsTypedArray
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MIsTypedArray(MDefinition* value)
-      : MUnaryInstruction(classOpcode, value)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsTypedArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MObjectClassToString
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MObjectClassToString(MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        setMovable();
-        setResultType(MIRType::String);
-    }
-
-  public:
-    INSTRUCTION_HEADER(ObjectClassToString)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-};
-
-class MCheckReturn
-  : public MBinaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
-      : MBinaryInstruction(classOpcode, retVal, thisVal)
-    {
-        setGuard();
-        setResultType(MIRType::Value);
-        setResultTypeSet(retVal->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(CheckReturn)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, returnValue), (1, thisValue))
-
-};
-
-// Increase the warm-up counter of the provided script upon execution and test if
-// the warm-up counter surpasses the threshold. Upon hit it will recompile the
-// outermost script (i.e. not the inlined script).
-class MRecompileCheck : public MNullaryInstruction
-{
-  public:
-    enum RecompileCheckType {
-        RecompileCheck_OptimizationLevel,
-        RecompileCheck_Inlining
-    };
-
-  private:
-    JSScript* script_;
-    uint32_t recompileThreshold_;
-    bool forceRecompilation_;
-    bool increaseWarmUpCounter_;
-
-    MRecompileCheck(JSScript* script, uint32_t recompileThreshold, RecompileCheckType type)
-      : MNullaryInstruction(classOpcode),
-        script_(script),
-        recompileThreshold_(recompileThreshold)
-    {
-        switch (type) {
-          case RecompileCheck_OptimizationLevel:
-            forceRecompilation_ = false;
-            increaseWarmUpCounter_ = true;
-            break;
-          case RecompileCheck_Inlining:
-            forceRecompilation_ = true;
-            increaseWarmUpCounter_ = false;
-            break;
-          default:
-            MOZ_CRASH("Unexpected recompile check type");
-        }
-
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(RecompileCheck)
-    TRIVIAL_NEW_WRAPPERS
-
-    JSScript* script() const {
-        return script_;
-    }
-
-    uint32_t recompileThreshold() const {
-        return recompileThreshold_;
-    }
-
-    bool forceRecompilation() const {
-        return forceRecompilation_;
-    }
-
-    bool increaseWarmUpCounter() const {
-        return increaseWarmUpCounter_;
-    }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MAtomicIsLockFree
-  : public MUnaryInstruction,
-    public ConvertToInt32Policy<0>::Data
-{
-    explicit MAtomicIsLockFree(MDefinition* value)
-      : MUnaryInstruction(classOpcode, value)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(AtomicIsLockFree)
-    TRIVIAL_NEW_WRAPPERS
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
-    bool canRecoverOnBailout() const override {
-        return true;
-    }
-
-    ALLOW_CLONE(MAtomicIsLockFree)
-};
-
-// This applies to an object that is known to be a TypedArray, it bails out
-// if the obj does not map a SharedArrayBuffer.
-
-class MGuardSharedTypedArray
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MGuardSharedTypedArray(MDefinition* obj)
-      : MUnaryInstruction(classOpcode, obj)
-    {
-        setGuard();
-        setMovable();
-    }
-
-public:
-    INSTRUCTION_HEADER(GuardSharedTypedArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MCompareExchangeTypedArrayElement
-  : public MQuaternaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
-{
-    Scalar::Type arrayType_;
-
-    explicit MCompareExchangeTypedArrayElement(MDefinition* elements, MDefinition* index,
-                                               Scalar::Type arrayType, MDefinition* oldval,
-                                               MDefinition* newval)
-      : MQuaternaryInstruction(classOpcode, elements, index, oldval, newval),
-        arrayType_(arrayType)
-    {
-        setGuard();             // Not removable
-    }
-
-  public:
-    INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, oldval), (3, newval))
-
-    bool isByteArray() const {
-        return (arrayType_ == Scalar::Int8 ||
-                arrayType_ == Scalar::Uint8);
-    }
-    int oldvalOperand() {
-        return 2;
-    }
-    Scalar::Type arrayType() const {
-        return arrayType_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-};
-
-class MAtomicExchangeTypedArrayElement
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
-{
-    Scalar::Type arrayType_;
-
-    MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, MDefinition* value,
-                                     Scalar::Type arrayType)
-      : MTernaryInstruction(classOpcode, elements, index, value),
-        arrayType_(arrayType)
-    {
-        MOZ_ASSERT(arrayType <= Scalar::Uint32);
-        setGuard();             // Not removable
-    }
-
-  public:
-    INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value))
-
-    bool isByteArray() const {
-        return (arrayType_ == Scalar::Int8 ||
-                arrayType_ == Scalar::Uint8);
-    }
-    Scalar::Type arrayType() const {
-        return arrayType_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-};
-
-class MAtomicTypedArrayElementBinop
-  : public MTernaryInstruction,
-    public MixPolicy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
-{
-  private:
-    AtomicOp op_;
-    Scalar::Type arrayType_;
-
-  protected:
-    explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, MDefinition* index,
-                                           Scalar::Type arrayType, MDefinition* value)
-      : MTernaryInstruction(classOpcode, elements, index, value),
-        op_(op),
-        arrayType_(arrayType)
-    {
-        setGuard();             // Not removable
-    }
-
-  public:
-    INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, elements), (1, index), (2, value))
-
-    bool isByteArray() const {
-        return (arrayType_ == Scalar::Int8 ||
-                arrayType_ == Scalar::Uint8);
-    }
-    AtomicOp operation() const {
-        return op_;
-    }
-    Scalar::Type arrayType() const {
-        return arrayType_;
-    }
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::UnboxedElement);
-    }
-};
-
-class MDebugger : public MNullaryInstruction
-{
-    MDebugger()
-      : MNullaryInstruction(classOpcode)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(Debugger)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MCheckIsObj
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    uint8_t checkKind_;
-
-    MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
-      : MUnaryInstruction(classOpcode, toCheck),
-        checkKind_(checkKind)
-    {
-        setResultType(MIRType::Value);
-        setResultTypeSet(toCheck->resultTypeSet());
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CheckIsObj)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, checkValue))
-
-    uint8_t checkKind() const { return checkKind_; }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MCheckIsCallable
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    uint8_t checkKind_;
-
-    MCheckIsCallable(MDefinition* toCheck, uint8_t checkKind)
-      : MUnaryInstruction(classOpcode, toCheck),
-        checkKind_(checkKind)
-    {
-        setResultType(MIRType::Value);
-        setResultTypeSet(toCheck->resultTypeSet());
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(CheckIsCallable)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, checkValue))
-
-    uint8_t checkKind() const { return checkKind_; }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-};
-
-class MCheckObjCoercible
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    explicit MCheckObjCoercible(MDefinition* toCheck)
-      : MUnaryInstruction(classOpcode, toCheck)
-    {
-        setGuard();
-        setResultType(MIRType::Value);
-        setResultTypeSet(toCheck->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(CheckObjCoercible)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, checkValue))
-};
-
-class MDebugCheckSelfHosted
-  : public MUnaryInstruction,
-    public BoxInputsPolicy::Data
-{
-    explicit MDebugCheckSelfHosted(MDefinition* toCheck)
-      : MUnaryInstruction(classOpcode, toCheck)
-    {
-        setGuard();
-        setResultType(MIRType::Value);
-        setResultTypeSet(toCheck->resultTypeSet());
-    }
-
-  public:
-    INSTRUCTION_HEADER(DebugCheckSelfHosted)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, checkValue))
-
-};
-
-class MFinishBoundFunctionInit
-  : public MTernaryInstruction,
-    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2>>::Data
-{
-    MFinishBoundFunctionInit(MDefinition* bound, MDefinition* target, MDefinition* argCount)
-      : MTernaryInstruction(classOpcode, bound, target, argCount)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(FinishBoundFunctionInit)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, bound), (1, target), (2, argCount))
-};
-
-class MIsPackedArray
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MIsPackedArray(MDefinition* array)
-      : MUnaryInstruction(classOpcode, array)
-    {
-        setResultType(MIRType::Boolean);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(IsPackedArray)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, array))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
-class MGetPrototypeOf
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MGetPrototypeOf(MDefinition* target)
-      : MUnaryInstruction(classOpcode, target)
-    {
-        setResultType(MIRType::Value);
-        setGuard(); // May throw if target is a proxy.
-    }
-
-  public:
-    INSTRUCTION_HEADER(GetPrototypeOf)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, target))
-};
-
-// Flips the input's sign bit, independently of the rest of the number's
-// payload. Note this is different from multiplying by minus-one, which has
-// side-effects for e.g. NaNs.
-class MWasmNeg
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmNeg(MDefinition* op, MIRType type)
-      : MUnaryInstruction(classOpcode, op)
-    {
-        setResultType(type);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmNeg)
-    TRIVIAL_NEW_WRAPPERS
-};
-
-class MWasmLoadTls
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    uint32_t offset_;
-    AliasSet aliases_;
-
-    explicit MWasmLoadTls(MDefinition* tlsPointer, uint32_t offset, MIRType type, AliasSet aliases)
-      : MUnaryInstruction(classOpcode, tlsPointer),
-        offset_(offset),
-        aliases_(aliases)
-    {
-        // Different Tls data have different alias classes and only those classes are allowed.
-        MOZ_ASSERT(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
-                   aliases_.flags() == AliasSet::None().flags());
-
-        // The only types supported at the moment.
-        MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32);
-
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmLoadTls)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, tlsPtr))
-
-    uint32_t offset() const {
-        return offset_;
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return op() == ins->op() &&
-               offset() == ins->toWasmLoadTls()->offset() &&
-               type() == ins->type();
-    }
-
-    HashNumber valueHash() const override {
-        return addU32ToHash(HashNumber(op()), offset());
-    }
-
-    AliasSet getAliasSet() const override {
-        return aliases_;
-    }
-};
-
-class MWasmBoundsCheck
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
-                              wasm::BytecodeOffset bytecodeOffset)
-      : MBinaryInstruction(classOpcode, index, boundsCheckLimit),
-        bytecodeOffset_(bytecodeOffset)
-    {
-        // Bounds check is effectful: it throws for OOB.
-        setGuard();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmBoundsCheck)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool isRedundant() const {
-        return !isGuard();
-    }
-
-    void setRedundant() {
-        setNotGuard();
-    }
-
-    wasm::BytecodeOffset bytecodeOffset() const {
-        return bytecodeOffset_;
-    }
-};
-
-class MWasmAddOffset
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    uint32_t offset_;
-    wasm::BytecodeOffset bytecodeOffset_;
-
-    MWasmAddOffset(MDefinition* base, uint32_t offset, wasm::BytecodeOffset bytecodeOffset)
-      : MUnaryInstruction(classOpcode, base),
-        offset_(offset),
-        bytecodeOffset_(bytecodeOffset)
-    {
-        setGuard();
-        setResultType(MIRType::Int32);
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmAddOffset)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, base))
-
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    uint32_t offset() const {
-        return offset_;
-    }
-    wasm::BytecodeOffset bytecodeOffset() const {
-        return bytecodeOffset_;
-    }
-};
-
 class MWasmLoad
   : public MVariadicInstruction, // memoryBase is nullptr on some platforms
     public NoTypePolicy::Data
 {
     wasm::MemoryAccessDesc access_;
 
     explicit MWasmLoad(const wasm::MemoryAccessDesc& access, MIRType resultType)
       : MVariadicInstruction(classOpcode),
@@ -14578,91 +4678,16 @@ class MAsmJSAtomicBinopHeap
     MDefinition* tls() const { return getOperand(2); }
     MDefinition* memoryBase() const { return getOperand(3); }
 
     AliasSet getAliasSet() const override {
         return AliasSet::Store(AliasSet::WasmHeap);
     }
 };
 
-class MWasmLoadGlobalVar
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant, MDefinition* tlsPtr)
-      : MUnaryInstruction(classOpcode, tlsPtr),
-        globalDataOffset_(globalDataOffset), isConstant_(isConstant)
-    {
-        MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
-        setResultType(type);
-        setMovable();
-    }
-
-    unsigned globalDataOffset_;
-    bool isConstant_;
-
-  public:
-    INSTRUCTION_HEADER(WasmLoadGlobalVar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, tlsPtr))
-
-    unsigned globalDataOffset() const { return globalDataOffset_; }
-
-    HashNumber valueHash() const override;
-    bool congruentTo(const MDefinition* ins) const override;
-    MDefinition* foldsTo(TempAllocator& alloc) override;
-
-    AliasSet getAliasSet() const override {
-        return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::WasmGlobalVar);
-    }
-
-    AliasType mightAlias(const MDefinition* def) const override;
-};
-
-class MWasmStoreGlobalVar
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value, MDefinition* tlsPtr)
-      : MBinaryInstruction(classOpcode, value, tlsPtr),
-        globalDataOffset_(globalDataOffset)
-    { }
-
-    unsigned globalDataOffset_;
-
-  public:
-    INSTRUCTION_HEADER(WasmStoreGlobalVar)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, value), (1, tlsPtr))
-
-    unsigned globalDataOffset() const { return globalDataOffset_; }
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::Store(AliasSet::WasmGlobalVar);
-    }
-};
-
-class MWasmParameter : public MNullaryInstruction
-{
-    ABIArg abi_;
-
-    MWasmParameter(ABIArg abi, MIRType mirType)
-      : MNullaryInstruction(classOpcode),
-        abi_(abi)
-    {
-        setResultType(mirType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmParameter)
-    TRIVIAL_NEW_WRAPPERS
-
-    ABIArg abi() const { return abi_; }
-};
-
 class MWasmReturn
   : public MAryControlInstruction<1, 0>,
     public NoTypePolicy::Data
 {
     explicit MWasmReturn(MDefinition* ins)
       : MAryControlInstruction(classOpcode)
     {
         initOperand(0, ins);
@@ -14681,40 +4706,16 @@ class MWasmReturnVoid
       : MAryControlInstruction(classOpcode)
     { }
 
   public:
     INSTRUCTION_HEADER(WasmReturnVoid)
     TRIVIAL_NEW_WRAPPERS
 };
 
-class MWasmStackArg
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmStackArg(uint32_t spOffset, MDefinition* ins)
-      : MUnaryInstruction(classOpcode, ins),
-        spOffset_(spOffset)
-    {}
-
-    uint32_t spOffset_;
-
-  public:
-    INSTRUCTION_HEADER(WasmStackArg)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, arg))
-
-    uint32_t spOffset() const {
-        return spOffset_;
-    }
-    void incrementOffset(uint32_t inc) {
-        spOffset_ += inc;
-    }
-};
-
 class MWasmCall final
   : public MVariadicInstruction,
     public NoTypePolicy::Data
 {
     wasm::CallSiteDesc desc_;
     wasm::CalleeDesc callee_;
     FixedList<AnyRegister> argRegs_;
     uint32_t spIncrement_;
@@ -14774,123 +4775,16 @@ class MWasmCall final
         return true;
     }
 
     const ABIArg& instanceArg() const {
         return instanceArg_;
     }
 };
 
-class MWasmSelect
-  : public MTernaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr)
-      : MTernaryInstruction(classOpcode, trueExpr, falseExpr, condExpr)
-    {
-        MOZ_ASSERT(condExpr->type() == MIRType::Int32);
-        MOZ_ASSERT(trueExpr->type() == falseExpr->type());
-        setResultType(trueExpr->type());
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmSelect)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, trueExpr), (1, falseExpr), (2, condExpr))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    ALLOW_CLONE(MWasmSelect)
-};
-
-class MWasmReinterpret
-  : public MUnaryInstruction,
-    public NoTypePolicy::Data
-{
-    MWasmReinterpret(MDefinition* val, MIRType toType)
-      : MUnaryInstruction(classOpcode, val)
-    {
-        switch (val->type()) {
-          case MIRType::Int32:   MOZ_ASSERT(toType == MIRType::Float32); break;
-          case MIRType::Float32: MOZ_ASSERT(toType == MIRType::Int32);   break;
-          case MIRType::Double:  MOZ_ASSERT(toType == MIRType::Int64);   break;
-          case MIRType::Int64:   MOZ_ASSERT(toType == MIRType::Double);  break;
-          default:              MOZ_CRASH("unexpected reinterpret conversion");
-        }
-        setMovable();
-        setResultType(toType);
-    }
-
-  public:
-    INSTRUCTION_HEADER(WasmReinterpret)
-    TRIVIAL_NEW_WRAPPERS
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-
-    ALLOW_CLONE(MWasmReinterpret)
-};
-
-class MRotate
-  : public MBinaryInstruction,
-    public NoTypePolicy::Data
-{
-    bool isLeftRotate_;
-
-    MRotate(MDefinition* input, MDefinition* count, MIRType type, bool isLeftRotate)
-      : MBinaryInstruction(classOpcode, input, count), isLeftRotate_(isLeftRotate)
-    {
-        setMovable();
-        setResultType(type);
-    }
-
-  public:
-    INSTRUCTION_HEADER(Rotate)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, input), (1, count))
-
-    AliasSet getAliasSet() const override {
-        return AliasSet::None();
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins) && ins->toRotate()->isLeftRotate() == isLeftRotate_;
-    }
-
-    bool isLeftRotate() const {
-        return isLeftRotate_;
-    }
-
-    ALLOW_CLONE(MRotate)
-};
-
-class MUnknownValue : public MNullaryInstruction
-{
-  protected:
-    MUnknownValue()
-      : MNullaryInstruction(classOpcode)
-    {
-        setResultType(MIRType::Value);
-    }
-
-  public:
-    INSTRUCTION_HEADER(UnknownValue)
-    TRIVIAL_NEW_WRAPPERS
-};
-
 #undef INSTRUCTION_HEADER
 
 void MUse::init(MDefinition* producer, MNode* consumer)
 {
     MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
     MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer");
     initUnchecked(producer, consumer);
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit/MIRInstruction.h
@@ -0,0 +1,10052 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MIR_INSTRUCTION_H
+#define MIR_INSTRUCTION_H
+
+// Generates an LSnapshot without further effect.
+class MStart : public MNullaryInstruction
+{
+    MStart()
+      : MNullaryInstruction(classOpcode)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(Start)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// Instruction marking on entrypoint for on-stack replacement.
+// OSR may occur at loop headers (at JSOP_TRACE).
+// There is at most one MOsrEntry per MIRGraph.
+class MOsrEntry : public MNullaryInstruction
+{
+  protected:
+    MOsrEntry()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Pointer);
+    }
+
+  public:
+    INSTRUCTION_HEADER(OsrEntry)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// No-op instruction. This cannot be moved or eliminated, and is intended for
+// anchoring resume points at arbitrary points in a block.
+class MNop : public MNullaryInstruction
+{
+  protected:
+    MNop()
+      : MNullaryInstruction(classOpcode)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(Nop)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MNop)
+};
+
+// A constant js::Value.
+class MConstant : public MNullaryInstruction
+{
+    struct Payload {
+        union {
+            bool b;
+            int32_t i32;
+            int64_t i64;
+            float f;
+            double d;
+            JSString* str;
+            JS::Symbol* sym;
+            JSObject* obj;
+            uint64_t asBits;
+        };
+        Payload() : asBits(0) {}
+    };
+
+    Payload payload_;
+
+    static_assert(sizeof(Payload) == sizeof(uint64_t),
+                  "asBits must be big enough for all payload bits");
+
+#ifdef DEBUG
+    void assertInitializedPayload() const;
+#else
+    void assertInitializedPayload() const {}
+#endif
+
+  protected:
+    MConstant(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints);
+    explicit MConstant(JSObject* obj);
+    explicit MConstant(float f);
+    explicit MConstant(int64_t i);
+
+  public:
+    INSTRUCTION_HEADER(Constant)
+    static MConstant* New(TempAllocator& alloc, const Value& v,
+                          CompilerConstraintList* constraints = nullptr);
+    static MConstant* New(TempAllocator::Fallible alloc, const Value& v,
+                          CompilerConstraintList* constraints = nullptr);
+    static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type);
+    static MConstant* NewFloat32(TempAllocator& alloc, double d);
+    static MConstant* NewInt64(TempAllocator& alloc, int64_t i);
+    static MConstant* NewConstraintlessObject(TempAllocator& alloc, JSObject* v);
+    static MConstant* Copy(TempAllocator& alloc, MConstant* src) {
+        return new(alloc) MConstant(*src);
+    }
+
+    // Try to convert this constant to boolean, similar to js::ToBoolean.
+    // Returns false if the type is MIRType::Magic*.
+    bool MOZ_MUST_USE valueToBoolean(bool* res) const;
+
+    // Like valueToBoolean, but returns the result directly instead of using
+    // an outparam. Should not be used if this constant might be a magic value.
+    bool valueToBooleanInfallible() const {
+        bool res;
+        MOZ_ALWAYS_TRUE(valueToBoolean(&res));
+        return res;
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    HashNumber valueHash() const override;
+    bool congruentTo(const MDefinition* ins) const override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool updateForReplacement(MDefinition* def) override {
+        MConstant* c = def->toConstant();
+        // During constant folding, we don't want to replace a float32
+        // value by a double value.
+        if (type() == MIRType::Float32)
+            return c->type() == MIRType::Float32;
+        if (type() == MIRType::Double)
+            return c->type() != MIRType::Float32;
+        return true;
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+    bool needTruncation(TruncateKind kind) override;
+    void truncate() override;
+
+    bool canProduceFloat32() const override;
+
+    ALLOW_CLONE(MConstant)
+
+    bool equals(const MConstant* other) const {
+        assertInitializedPayload();
+        return type() == other->type() && payload_.asBits == other->payload_.asBits;
+    }
+
+    bool toBoolean() const {
+        MOZ_ASSERT(type() == MIRType::Boolean);
+        return payload_.b;
+    }
+    int32_t toInt32() const {
+        MOZ_ASSERT(type() == MIRType::Int32);
+        return payload_.i32;
+    }
+    int64_t toInt64() const {
+        MOZ_ASSERT(type() == MIRType::Int64);
+        return payload_.i64;
+    }
+    bool isInt32(int32_t i) const {
+        return type() == MIRType::Int32 && payload_.i32 == i;
+    }
+    const double& toDouble() const {
+        MOZ_ASSERT(type() == MIRType::Double);
+        return payload_.d;
+    }
+    const float& toFloat32() const {
+        MOZ_ASSERT(type() == MIRType::Float32);
+        return payload_.f;
+    }
+    JSString* toString() const {
+        MOZ_ASSERT(type() == MIRType::String);
+        return payload_.str;
+    }
+    JS::Symbol* toSymbol() const {
+        MOZ_ASSERT(type() == MIRType::Symbol);
+        return payload_.sym;
+    }
+    JSObject& toObject() const {
+        MOZ_ASSERT(type() == MIRType::Object);
+        return *payload_.obj;
+    }
+    JSObject* toObjectOrNull() const {
+        if (type() == MIRType::Object)
+            return payload_.obj;
+        MOZ_ASSERT(type() == MIRType::Null);
+        return nullptr;
+    }
+
+    bool isTypeRepresentableAsDouble() const {
+        return IsTypeRepresentableAsDouble(type());
+    }
+    double numberToDouble() const {
+        MOZ_ASSERT(isTypeRepresentableAsDouble());
+        if (type() == MIRType::Int32)
+            return toInt32();
+        if (type() == MIRType::Double)
+            return toDouble();
+        return toFloat32();
+    }
+
+    // Convert this constant to a js::Value. Float32 constants will be stored
+    // as DoubleValue and NaNs are canonicalized. Callers must be careful: not
+    // all constants can be represented by js::Value (wasm supports int64).
+    Value toJSValue() const;
+
+    bool appendRoots(MRootList& roots) const override;
+};
+
+// Floating-point value as created by wasm. Just a constant value, used to
+// effectively inhibite all the MIR optimizations. This uses the same LIR nodes
+// as a MConstant of the same type would.
+class MWasmFloatConstant : public MNullaryInstruction
+{
+    union {
+        float f32_;
+        double f64_;
+        uint64_t bits_;
+    } u;
+
+    explicit MWasmFloatConstant(MIRType type)
+      : MNullaryInstruction(classOpcode)
+    {
+        u.bits_ = 0;
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmFloatConstant)
+
+    static MWasmFloatConstant* NewDouble(TempAllocator& alloc, double d) {
+        auto* ret = new(alloc) MWasmFloatConstant(MIRType::Double);
+        ret->u.f64_ = d;
+        return ret;
+    }
+
+    static MWasmFloatConstant* NewFloat32(TempAllocator& alloc, float f) {
+        auto* ret = new(alloc) MWasmFloatConstant(MIRType::Float32);
+        ret->u.f32_ = f;
+        return ret;
+    }
+
+    HashNumber valueHash() const override;
+    bool congruentTo(const MDefinition* ins) const override;
+    AliasSet getAliasSet() const override { return AliasSet::None(); }
+
+    const double& toDouble() const {
+        MOZ_ASSERT(type() == MIRType::Double);
+        return u.f64_;
+    }
+    const float& toFloat32() const {
+        MOZ_ASSERT(type() == MIRType::Float32);
+        return u.f32_;
+    }
+};
+
+// A constant SIMD value.
+class MSimdConstant
+  : public MNullaryInstruction
+{
+    SimdConstant value_;
+
+  protected:
+    MSimdConstant(const SimdConstant& v, MIRType type)
+      : MNullaryInstruction(classOpcode),
+        value_(v)
+    {
+        MOZ_ASSERT(IsSimdType(type));
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdConstant)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isSimdConstant())
+            return false;
+        // Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
+        if (type() != ins->type())
+            return false;
+        return value() == ins->toSimdConstant()->value();
+    }
+
+    const SimdConstant& value() const {
+        return value_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MSimdConstant)
+};
+
+class MParameter : public MNullaryInstruction
+{
+    int32_t index_;
+
+    MParameter(int32_t index, TemporaryTypeSet* types)
+      : MNullaryInstruction(classOpcode),
+        index_(index)
+    {
+        setResultType(MIRType::Value);
+        setResultTypeSet(types);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Parameter)
+    TRIVIAL_NEW_WRAPPERS
+
+    static const int32_t THIS_SLOT = -1;
+    int32_t index() const {
+        return index_;
+    }
+    void printOpcode(GenericPrinter& out) const override;
+
+    HashNumber valueHash() const override;
+    bool congruentTo(const MDefinition* ins) const override;
+};
+
+class MCallee : public MNullaryInstruction
+{
+  public:
+    MCallee()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Callee)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MIsConstructing : public MNullaryInstruction
+{
+  public:
+    MIsConstructing()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsConstructing)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MNewArrayCopyOnWrite : public MNullaryInstruction
+{
+    CompilerGCPointer<ArrayObject*> templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MNewArrayCopyOnWrite(TempAllocator& alloc, CompilerConstraintList* constraints,
+                         ArrayObject* templateObject, gc::InitialHeap initialHeap)
+      : MNullaryInstruction(classOpcode),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        MOZ_ASSERT(!templateObject->isSingleton());
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewArrayCopyOnWrite)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    ArrayObject* templateObject() const {
+        return templateObject_;
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject_);
+    }
+};
+
+class MNewTypedObject : public MNullaryInstruction
+{
+    CompilerGCPointer<InlineTypedObject*> templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MNewTypedObject(TempAllocator& alloc, CompilerConstraintList* constraints,
+                    InlineTypedObject* templateObject,
+                    gc::InitialHeap initialHeap)
+      : MNullaryInstruction(classOpcode),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewTypedObject)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    InlineTypedObject* templateObject() const {
+        return templateObject_;
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject_);
+    }
+};
+
+class MBail : public MNullaryInstruction
+{
+  protected:
+    explicit MBail(BailoutKind kind)
+      : MNullaryInstruction(classOpcode)
+    {
+        bailoutKind_ = kind;
+        setGuard();
+    }
+
+  private:
+    BailoutKind bailoutKind_;
+
+  public:
+    INSTRUCTION_HEADER(Bail)
+
+    static MBail*
+    New(TempAllocator& alloc, BailoutKind kind) {
+        return new(alloc) MBail(kind);
+    }
+    static MBail*
+    New(TempAllocator& alloc) {
+        return new(alloc) MBail(Bailout_Inevitable);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+};
+
+// This class serve as a way to force the encoding of a snapshot, even if there
+// is no resume point using it.  This is useful to run MAssertRecoveredOnBailout
+// assertions.
+class MEncodeSnapshot : public MNullaryInstruction
+{
+  protected:
+    MEncodeSnapshot()
+      : MNullaryInstruction(classOpcode)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(EncodeSnapshot)
+
+    static MEncodeSnapshot*
+    New(TempAllocator& alloc) {
+        return new(alloc) MEncodeSnapshot();
+    }
+};
+
+class MRunOncePrologue
+  : public MNullaryInstruction
+{
+  protected:
+    MRunOncePrologue()
+      : MNullaryInstruction(classOpcode)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(RunOncePrologue)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+// Inline implementation of Math.random().
+class MRandom : public MNullaryInstruction
+{
+    MRandom()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Double);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Random)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+#ifdef JS_MORE_DETERMINISTIC
+        return false;
+#else
+        return true;
+#endif
+    }
+
+    ALLOW_CLONE(MRandom)
+};
+
+class MNullarySharedStub
+  : public MNullaryInstruction
+{
+    explicit MNullarySharedStub()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NullarySharedStub)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// Check the current frame for over-recursion past the global stack limit.
+class MCheckOverRecursed
+  : public MNullaryInstruction
+{
+    MCheckOverRecursed()
+      : MNullaryInstruction(classOpcode)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(CheckOverRecursed)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Check whether we need to fire the interrupt handler.
+class MInterruptCheck : public MNullaryInstruction
+{
+    MInterruptCheck()
+      : MNullaryInstruction(classOpcode)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(InterruptCheck)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Unconditionally throw an uninitialized let error.
+class MThrowRuntimeLexicalError : public MNullaryInstruction
+{
+    unsigned errorNumber_;
+
+    explicit MThrowRuntimeLexicalError(unsigned errorNumber)
+      : MNullaryInstruction(classOpcode),
+        errorNumber_(errorNumber)
+    {
+        setGuard();
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ThrowRuntimeLexicalError)
+    TRIVIAL_NEW_WRAPPERS
+
+    unsigned errorNumber() const {
+        return errorNumber_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// In the prologues of global and eval scripts, check for redeclarations.
+class MGlobalNameConflictsCheck : public MNullaryInstruction
+{
+    MGlobalNameConflictsCheck()
+      : MNullaryInstruction(classOpcode)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GlobalNameConflictsCheck)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MDefLexical
+  : public MNullaryInstruction
+{
+    CompilerPropertyName name_; // Target name to be defined.
+    unsigned attrs_; // Attributes to be set.
+
+  private:
+    MDefLexical(PropertyName* name, unsigned attrs)
+      : MNullaryInstruction(classOpcode),
+        name_(name),
+        attrs_(attrs)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(DefLexical)
+    TRIVIAL_NEW_WRAPPERS
+
+    PropertyName* name() const {
+        return name_;
+    }
+    unsigned attrs() const {
+        return attrs_;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MRegExp : public MNullaryInstruction
+{
+    CompilerGCPointer<RegExpObject*> source_;
+    bool mustClone_;
+    bool hasShared_;
+
+    MRegExp(TempAllocator& alloc, CompilerConstraintList* constraints, RegExpObject* source,
+            bool hasShared)
+      : MNullaryInstruction(classOpcode),
+        source_(source),
+        mustClone_(true),
+        hasShared_(hasShared)
+    {
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, source));
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExp)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    void setDoNotClone() {
+        mustClone_ = false;
+    }
+    bool mustClone() const {
+        return mustClone_;
+    }
+    bool hasShared() const {
+        return hasShared_;
+    }
+    RegExpObject* source() const {
+        return source_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(source_);
+    }
+};
+
+class MClassConstructor : public MNullaryInstruction
+{
+    jsbytecode* pc_;
+
+    explicit MClassConstructor(jsbytecode* pc)
+      : MNullaryInstruction(classOpcode),
+        pc_(pc)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ClassConstructor)
+    TRIVIAL_NEW_WRAPPERS
+
+    jsbytecode* pc() const {
+      return pc_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// A constant value for some object's typed array elements.
+class MConstantElements : public MNullaryInstruction
+{
+    SharedMem<void*> value_;
+
+  protected:
+    explicit MConstantElements(SharedMem<void*> v)
+      : MNullaryInstruction(classOpcode),
+        value_(v)
+    {
+        setResultType(MIRType::Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ConstantElements)
+    TRIVIAL_NEW_WRAPPERS
+
+    SharedMem<void*> value() const {
+        return value_;
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    HashNumber valueHash() const override {
+        return (HashNumber)(size_t) value_.asValue();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return ins->isConstantElements() && ins->toConstantElements()->value() == value();
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MConstantElements)
+};
+
+class MCallGetIntrinsicValue : public MNullaryInstruction
+{
+    CompilerPropertyName name_;
+
+    explicit MCallGetIntrinsicValue(PropertyName* name)
+      : MNullaryInstruction(classOpcode),
+        name_(name)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallGetIntrinsicValue)
+    TRIVIAL_NEW_WRAPPERS
+
+    PropertyName* name() const {
+        return name_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MArgumentsLength : public MNullaryInstruction
+{
+    MArgumentsLength()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ArgumentsLength)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        // Arguments |length| cannot be mutated by Ion Code.
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MNewTarget : public MNullaryInstruction
+{
+    MNewTarget() : MNullaryInstruction(classOpcode) {
+        setResultType(MIRType::Value);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewTarget)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MNewNamedLambdaObject : public MNullaryInstruction
+{
+    CompilerGCPointer<LexicalEnvironmentObject*> templateObj_;
+
+    explicit MNewNamedLambdaObject(LexicalEnvironmentObject* templateObj)
+      : MNullaryInstruction(classOpcode),
+        templateObj_(templateObj)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewNamedLambdaObject)
+    TRIVIAL_NEW_WRAPPERS
+
+    LexicalEnvironmentObject* templateObj() {
+        return templateObj_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObj_);
+    }
+};
+
+// Increase the warm-up counter of the provided script upon execution and test if
+// the warm-up counter surpasses the threshold. Upon hit it will recompile the
+// outermost script (i.e. not the inlined script).
+class MRecompileCheck : public MNullaryInstruction
+{
+  public:
+    enum RecompileCheckType {
+        RecompileCheck_OptimizationLevel,
+        RecompileCheck_Inlining
+    };
+
+  private:
+    JSScript* script_;
+    uint32_t recompileThreshold_;
+    bool forceRecompilation_;
+    bool increaseWarmUpCounter_;
+
+    MRecompileCheck(JSScript* script, uint32_t recompileThreshold, RecompileCheckType type)
+      : MNullaryInstruction(classOpcode),
+        script_(script),
+        recompileThreshold_(recompileThreshold)
+    {
+        switch (type) {
+          case RecompileCheck_OptimizationLevel:
+            forceRecompilation_ = false;
+            increaseWarmUpCounter_ = true;
+            break;
+          case RecompileCheck_Inlining:
+            forceRecompilation_ = true;
+            increaseWarmUpCounter_ = false;
+            break;
+          default:
+            MOZ_CRASH("Unexpected recompile check type");
+        }
+
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(RecompileCheck)
+    TRIVIAL_NEW_WRAPPERS
+
+    JSScript* script() const {
+        return script_;
+    }
+
+    uint32_t recompileThreshold() const {
+        return recompileThreshold_;
+    }
+
+    bool forceRecompilation() const {
+        return forceRecompilation_;
+    }
+
+    bool increaseWarmUpCounter() const {
+        return increaseWarmUpCounter_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MDebugger : public MNullaryInstruction
+{
+    MDebugger()
+      : MNullaryInstruction(classOpcode)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(Debugger)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MWasmParameter : public MNullaryInstruction
+{
+    ABIArg abi_;
+
+    MWasmParameter(ABIArg abi, MIRType mirType)
+      : MNullaryInstruction(classOpcode),
+        abi_(abi)
+    {
+        setResultType(mirType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmParameter)
+    TRIVIAL_NEW_WRAPPERS
+
+    ABIArg abi() const { return abi_; }
+};
+
+class MUnknownValue : public MNullaryInstruction
+{
+  protected:
+    MUnknownValue()
+      : MNullaryInstruction(classOpcode)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(UnknownValue)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// Truncation barrier. This is intended for protecting its input against
+// follow-up truncation optimizations.
+class MLimitedTruncate
+  : public MUnaryInstruction,
+    public ConvertToInt32Policy<0>::Data
+{
+  public:
+    TruncateKind truncate_;
+    TruncateKind truncateLimit_;
+
+  protected:
+    MLimitedTruncate(MDefinition* input, TruncateKind limit)
+      : MUnaryInstruction(classOpcode, input),
+        truncate_(NoTruncate),
+        truncateLimit_(limit)
+    {
+        setResultType(MIRType::Int32);
+        setResultTypeSet(input->resultTypeSet());
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LimitedTruncate)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+    bool needTruncation(TruncateKind kind) override;
+    TruncateKind operandTruncateKind(size_t index) const override;
+    TruncateKind truncateKind() const {
+        return truncate_;
+    }
+    void setTruncateKind(TruncateKind kind) {
+        truncate_ = kind;
+    }
+};
+
+// Generic constructor of SIMD values with identical lanes.
+class MSimdSplat
+  : public MUnaryInstruction,
+    public SimdScalarPolicy<0>::Data
+{
+  protected:
+    MSimdSplat(MDefinition* v, MIRType type)
+      : MUnaryInstruction(classOpcode, v)
+    {
+        MOZ_ASSERT(IsSimdType(type));
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdSplat)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return SimdTypeToLaneType(type()) == MIRType::Float32;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MSimdSplat)
+};
+
+// Converts all lanes of a given vector into the type of another vector
+class MSimdConvert
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+    // When either fromType or toType is an integer vector, should it be treated
+    // as signed or unsigned. Note that we don't support int-int conversions -
+    // use MSimdReinterpretCast for that.
+    SimdSign sign_;
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    MSimdConvert(MDefinition* obj, MIRType toType, SimdSign sign,
+                 wasm::BytecodeOffset bytecodeOffset)
+      : MUnaryInstruction(classOpcode, obj), sign_(sign), bytecodeOffset_(bytecodeOffset)
+    {
+        MIRType fromType = obj->type();
+        MOZ_ASSERT(IsSimdType(fromType));
+        MOZ_ASSERT(IsSimdType(toType));
+        // All conversions are int <-> float, so signedness is required.
+        MOZ_ASSERT(sign != SimdSign::NotApplicable);
+
+        setResultType(toType);
+        specialization_ = fromType; // expects fromType as input
+
+        setMovable();
+        if (IsFloatingPointSimdType(fromType) && IsIntegerSimdType(toType)) {
+            // Does the extra range check => do not remove
+            setGuard();
+        }
+    }
+
+    static MSimdConvert* New(TempAllocator& alloc, MDefinition* obj, MIRType toType, SimdSign sign,
+                             wasm::BytecodeOffset bytecodeOffset)
+    {
+        return new (alloc) MSimdConvert(obj, toType, sign, bytecodeOffset);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdConvert)
+
+    // Create a MSimdConvert instruction and add it to the basic block.
+    // Possibly create and add an equivalent sequence of instructions instead if
+    // the current target doesn't support the requested conversion directly.
+    // Return the inserted MInstruction that computes the converted value.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
+                                      MIRType toType, SimdSign sign,
+                                      wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset());
+
+    SimdSign signedness() const {
+        return sign_;
+    }
+    wasm::BytecodeOffset bytecodeOffset() const {
+        return bytecodeOffset_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        const MSimdConvert* other = ins->toSimdConvert();
+        return sign_ == other->sign_;
+    }
+    ALLOW_CLONE(MSimdConvert)
+};
+
+// Casts bits of a vector input to another SIMD type (doesn't generate code).
+class MSimdReinterpretCast
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+    MSimdReinterpretCast(MDefinition* obj, MIRType toType)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        MIRType fromType = obj->type();
+        MOZ_ASSERT(IsSimdType(fromType));
+        MOZ_ASSERT(IsSimdType(toType));
+        setMovable();
+        setResultType(toType);
+        specialization_ = fromType; // expects fromType as input
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdReinterpretCast)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    ALLOW_CLONE(MSimdReinterpretCast)
+};
+
+// Extracts a lane element from a given vector type, given by its lane symbol.
+//
+// For integer SIMD types, a SimdSign must be provided so the lane value can be
+// converted to a scalar correctly.
+class MSimdExtractElement
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+  protected:
+    unsigned lane_;
+    SimdSign sign_;
+
+    MSimdExtractElement(MDefinition* obj, MIRType laneType, unsigned lane, SimdSign sign)
+      : MUnaryInstruction(classOpcode, obj), lane_(lane), sign_(sign)
+    {
+        MIRType vecType = obj->type();
+        MOZ_ASSERT(IsSimdType(vecType));
+        MOZ_ASSERT(lane < SimdTypeToLength(vecType));
+        MOZ_ASSERT(!IsSimdType(laneType));
+        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(vecType),
+                   "Signedness must be specified for integer SIMD extractLanes");
+        // The resulting type should match the lane type.
+        // Allow extracting boolean lanes directly into an Int32 (for wasm).
+        // Allow extracting Uint32 lanes into a double.
+        //
+        // We also allow extracting Uint32 lanes into a MIRType::Int32. This is
+        // equivalent to extracting the Uint32 lane to a double and then
+        // applying MTruncateToInt32, but it bypasses the conversion to/from
+        // double.
+        MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
+                   (IsBooleanSimdType(vecType) && laneType == MIRType::Int32) ||
+                   (vecType == MIRType::Int32x4 && laneType == MIRType::Double &&
+                    sign == SimdSign::Unsigned));
+
+        setMovable();
+        specialization_ = vecType;
+        setResultType(laneType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdExtractElement)
+    TRIVIAL_NEW_WRAPPERS
+
+    unsigned lane() const {
+        return lane_;
+    }
+
+    SimdSign signedness() const {
+        return sign_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isSimdExtractElement())
+            return false;
+        const MSimdExtractElement* other = ins->toSimdExtractElement();
+        if (other->lane_ != lane_ || other->sign_ != sign_)
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    ALLOW_CLONE(MSimdExtractElement)
+};
+
+// Returns true if all lanes are true.
+class MSimdAllTrue
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+  protected:
+    explicit MSimdAllTrue(MDefinition* obj, MIRType result)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        MIRType simdType = obj->type();
+        MOZ_ASSERT(IsBooleanSimdType(simdType));
+        MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
+        setResultType(result);
+        specialization_ = simdType;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdAllTrue)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    ALLOW_CLONE(MSimdAllTrue)
+};
+
+// Returns true if any lane is true.
+class MSimdAnyTrue
+  : public MUnaryInstruction,
+    public SimdPolicy<0>::Data
+{
+  protected:
+    explicit MSimdAnyTrue(MDefinition* obj, MIRType result)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        MIRType simdType = obj->type();
+        MOZ_ASSERT(IsBooleanSimdType(simdType));
+        MOZ_ASSERT(result == MIRType::Boolean || result == MIRType::Int32);
+        setResultType(result);
+        specialization_ = simdType;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdAnyTrue)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MSimdAnyTrue)
+};
+
+// Applies a swizzle operation to the input, putting the input lanes as
+// indicated in the output register's lanes. This implements the SIMD.js
+// "swizzle" function, that takes one vector and an array of lane indexes.
+class MSimdSwizzle
+  : public MUnaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
+{
+  protected:
+    MSimdSwizzle(MDefinition* obj, const uint8_t lanes[])
+      : MUnaryInstruction(classOpcode, obj), MSimdShuffleBase(lanes, obj->type())
+    {
+        for (unsigned i = 0; i < arity_; i++)
+            MOZ_ASSERT(lane(i) < arity_);
+        setResultType(obj->type());
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdSwizzle)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isSimdSwizzle())
+            return false;
+        const MSimdSwizzle* other = ins->toSimdSwizzle();
+        return sameLanes(other) && congruentIfOperandsEqual(other);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MSimdSwizzle)
+};
+
+class MSimdUnaryArith
+  : public MUnaryInstruction,
+    public SimdSameAsReturnedTypePolicy<0>::Data
+{
+  public:
+    enum Operation {
+#define OP_LIST_(OP) OP,
+        FOREACH_FLOAT_SIMD_UNOP(OP_LIST_)
+        neg,
+        not_
+#undef OP_LIST_
+    };
+
+    static const char* OperationName(Operation op) {
+        switch (op) {
+          case abs:                         return "abs";
+          case neg:                         return "neg";
+          case not_:                        return "not";
+          case reciprocalApproximation:     return "reciprocalApproximation";
+          case reciprocalSqrtApproximation: return "reciprocalSqrtApproximation";
+          case sqrt:                        return "sqrt";
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+  private:
+    Operation operation_;
+
+    MSimdUnaryArith(MDefinition* def, Operation op)
+      : MUnaryInstruction(classOpcode, def), operation_(op)
+    {
+        MIRType type = def->type();
+        MOZ_ASSERT(IsSimdType(type));
+        MOZ_ASSERT_IF(IsIntegerSimdType(type), op == neg || op == not_);
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdUnaryArith)
+    TRIVIAL_NEW_WRAPPERS
+
+    Operation operation() const { return operation_; }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdUnaryArith);
+};
+
+// Deep clone a constant JSObject.
+class MCloneLiteral
+  : public MUnaryInstruction,
+    public ObjectPolicy<0>::Data
+{
+  protected:
+    explicit MCloneLiteral(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CloneLiteral)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MNewArray
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    // Number of elements to allocate for the array.
+    uint32_t length_;
+
+    // Heap where the array should be allocated.
+    gc::InitialHeap initialHeap_;
+
+    // Whether values written to this array should be converted to double first.
+    bool convertDoubleElements_;
+
+    jsbytecode* pc_;
+
+    bool vmCall_;
+
+    MNewArray(TempAllocator& alloc, CompilerConstraintList* constraints, uint32_t length,
+              MConstant* templateConst, gc::InitialHeap initialHeap, jsbytecode* pc,
+              bool vmCall = false);
+
+  public:
+    INSTRUCTION_HEADER(NewArray)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    static MNewArray* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
+                            uint32_t length, MConstant* templateConst,
+                            gc::InitialHeap initialHeap, jsbytecode* pc)
+    {
+        return new(alloc) MNewArray(alloc, constraints, length, templateConst, initialHeap, pc,
+                                    true);
+    }
+
+    uint32_t length() const {
+        return length_;
+    }
+
+    JSObject* templateObject() const {
+        return getOperand(0)->toConstant()->toObjectOrNull();
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    jsbytecode* pc() const {
+        return pc_;
+    }
+
+    bool isVMCall() const {
+        return vmCall_;
+    }
+
+    bool convertDoubleElements() const {
+        return convertDoubleElements_;
+    }
+
+    // NewArray is marked as non-effectful because all our allocations are
+    // either lazy when we are using "new Array(length)" or bounded by the
+    // script or the stack size when we are using "new Array(...)" or "[...]"
+    // notations.  So we might have to allocate the array twice if we bail
+    // during the computation of the first element of the square braket
+    // notation.
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        // The template object can safely be used in the recover instruction
+        // because it can never be mutated by any other function execution.
+        return templateObject() != nullptr;
+    }
+};
+
+class MNewArrayDynamicLength
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    CompilerObject templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MNewArrayDynamicLength(TempAllocator& alloc, CompilerConstraintList* constraints,
+                           JSObject* templateObject, gc::InitialHeap initialHeap,
+                           MDefinition* length)
+      : MUnaryInstruction(classOpcode, length),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        setGuard(); // Need to throw if length is negative.
+        setResultType(MIRType::Object);
+        if (!templateObject->isSingleton())
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewArrayDynamicLength)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+    NAMED_OPERANDS((0, length))
+
+    JSObject* templateObject() const {
+        return templateObject_;
+    }
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject_);
+    }
+};
+
+class MNewTypedArray
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    gc::InitialHeap initialHeap_;
+
+    MNewTypedArray(TempAllocator& alloc, CompilerConstraintList* constraints,
+                   MConstant* templateConst, gc::InitialHeap initialHeap)
+      : MUnaryInstruction(classOpcode, templateConst),
+        initialHeap_(initialHeap)
+    {
+        MOZ_ASSERT(!templateObject()->isSingleton());
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewTypedArray)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    TypedArrayObject* templateObject() const {
+        return &getOperand(0)->toConstant()->toObject().as<TypedArrayObject>();
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MNewTypedArrayDynamicLength
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    CompilerObject templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MNewTypedArrayDynamicLength(TempAllocator& alloc, CompilerConstraintList* constraints,
+                                JSObject* templateObject, gc::InitialHeap initialHeap,
+                                MDefinition* length)
+      : MUnaryInstruction(classOpcode, length),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        setGuard(); // Need to throw if length is negative.
+        setResultType(MIRType::Object);
+        if (!templateObject->isSingleton())
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewTypedArrayDynamicLength)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    MDefinition* length() const {
+        return getOperand(0);
+    }
+    JSObject* templateObject() const {
+        return templateObject_;
+    }
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject_);
+    }
+};
+
+class MNewObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  public:
+    enum Mode { ObjectLiteral, ObjectCreate };
+
+  private:
+    gc::InitialHeap initialHeap_;
+    Mode mode_;
+    bool vmCall_;
+
+    MNewObject(TempAllocator& alloc, CompilerConstraintList* constraints, MConstant* templateConst,
+               gc::InitialHeap initialHeap, Mode mode, bool vmCall = false)
+      : MUnaryInstruction(classOpcode, templateConst),
+        initialHeap_(initialHeap),
+        mode_(mode),
+        vmCall_(vmCall)
+    {
+        MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
+        setResultType(MIRType::Object);
+
+        if (JSObject* obj = templateObject())
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, obj));
+
+        // The constant is kept separated in a MConstant, this way we can safely
+        // mark it during GC if we recover the object allocation.  Otherwise, by
+        // making it emittedAtUses, we do not produce register allocations for
+        // it and inline its content inside the code produced by the
+        // CodeGenerator.
+        if (templateConst->toConstant()->type() == MIRType::Object)
+            templateConst->setEmittedAtUses();
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewObject)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    static MNewObject* NewVM(TempAllocator& alloc, CompilerConstraintList* constraints,
+                             MConstant* templateConst, gc::InitialHeap initialHeap,
+                             Mode mode)
+    {
+        return new(alloc) MNewObject(alloc, constraints, templateConst, initialHeap, mode, true);
+    }
+
+    Mode mode() const {
+        return mode_;
+    }
+
+    JSObject* templateObject() const {
+        return getOperand(0)->toConstant()->toObjectOrNull();
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    bool isVMCall() const {
+        return vmCall_;
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        // The template object can safely be used in the recover instruction
+        // because it can never be mutated by any other function execution.
+        return templateObject() != nullptr;
+    }
+};
+
+
+class MNewIterator
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  public:
+    enum Type {
+        ArrayIterator,
+        StringIterator,
+    };
+
+private:
+    Type type_;
+
+    MNewIterator(TempAllocator& alloc, CompilerConstraintList* constraints,
+                 MConstant* templateConst, Type type)
+      : MUnaryInstruction(classOpcode, templateConst),
+        type_(type)
+    {
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
+        templateConst->setEmittedAtUses();
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewIterator)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    Type type() const {
+        return type_;
+    }
+
+    JSObject* templateObject() {
+        return getOperand(0)->toConstant()->toObjectOrNull();
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MTypedObjectDescr
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  private:
+    explicit MTypedObjectDescr(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedObjectDescr)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Generic way for constructing a SIMD object in IonMonkey, this instruction
+// takes as argument a SIMD instruction and returns a new SIMD object which
+// corresponds to the MIRType of its operand.
+class MSimdBox
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  protected:
+    CompilerGCPointer<InlineTypedObject*> templateObject_;
+    SimdType simdType_;
+    gc::InitialHeap initialHeap_;
+
+    MSimdBox(TempAllocator& alloc,
+             CompilerConstraintList* constraints,
+             MDefinition* op,
+             InlineTypedObject* templateObject,
+             SimdType simdType,
+             gc::InitialHeap initialHeap)
+      : MUnaryInstruction(classOpcode, op),
+        templateObject_(templateObject),
+        simdType_(simdType),
+        initialHeap_(initialHeap)
+    {
+        MOZ_ASSERT(IsSimdType(op->type()));
+        setMovable();
+        setResultType(MIRType::Object);
+        if (constraints)
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBox)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    InlineTypedObject* templateObject() const {
+        return templateObject_;
+    }
+
+    SimdType simdType() const {
+        return simdType_;
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        const MSimdBox* box = ins->toSimdBox();
+        if (box->simdType() != simdType())
+            return false;
+        MOZ_ASSERT(box->templateObject() == templateObject());
+        if (box->initialHeap() != initialHeap())
+            return false;
+        return true;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject_);
+    }
+};
+
+class MSimdUnbox
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  protected:
+    SimdType simdType_;
+
+    MSimdUnbox(MDefinition* op, SimdType simdType)
+      : MUnaryInstruction(classOpcode, op),
+        simdType_(simdType)
+    {
+        MIRType type = SimdTypeToMIRType(simdType);
+        MOZ_ASSERT(IsSimdType(type));
+        setGuard();
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdUnbox)
+    TRIVIAL_NEW_WRAPPERS
+    ALLOW_CLONE(MSimdUnbox)
+
+    SimdType simdType() const { return simdType_; }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        return ins->toSimdUnbox()->simdType() == simdType();
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+};
+
+class MAssertRecoveredOnBailout
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  protected:
+    bool mustBeRecovered_;
+
+    MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered)
+      : MUnaryInstruction(classOpcode, ins), mustBeRecovered_(mustBeRecovered)
+    {
+        setResultType(MIRType::Value);
+        setRecoveredOnBailout();
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(AssertRecoveredOnBailout)
+    TRIVIAL_NEW_WRAPPERS
+
+    // Needed to assert that float32 instructions are correctly recovered.
+    bool canConsumeFloat32(MUse* use) const override { return true; }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MAssertFloat32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  protected:
+    bool mustBeFloat32_;
+
+    MAssertFloat32(MDefinition* value, bool mustBeFloat32)
+      : MUnaryInstruction(classOpcode, value), mustBeFloat32_(mustBeFloat32)
+    {
+    }
+
+  public:
+    INSTRUCTION_HEADER(AssertFloat32)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool canConsumeFloat32(MUse* use) const override { return true; }
+
+    bool mustBeFloat32() const { return mustBeFloat32_; }
+};
+
+// Takes a typed value and returns an untyped value.
+class MBox
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    MBox(TempAllocator& alloc, MDefinition* ins)
+      : MUnaryInstruction(classOpcode, ins)
+    {
+        setResultType(MIRType::Value);
+        if (ins->resultTypeSet()) {
+            setResultTypeSet(ins->resultTypeSet());
+        } else if (ins->type() != MIRType::Value) {
+            TypeSet::Type ntype = ins->type() == MIRType::Object
+                                  ? TypeSet::AnyObjectType()
+                                  : TypeSet::PrimitiveType(ValueTypeFromMIRType(ins->type()));
+            setResultTypeSet(alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype));
+        }
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Box)
+    static MBox* New(TempAllocator& alloc, MDefinition* ins)
+    {
+        // Cannot box a box.
+        MOZ_ASSERT(ins->type() != MIRType::Value);
+
+        return new(alloc) MBox(alloc, ins);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MBox)
+};
+
+// Takes a typed value and checks if it is a certain type. If so, the payload
+// is unpacked and returned as that type. Otherwise, it is considered a
+// deoptimization.
+class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
+{
+  public:
+    enum Mode {
+        Fallible,       // Check the type, and deoptimize if unexpected.
+        Infallible,     // Type guard is not necessary.
+        TypeBarrier     // Guard on the type, and act like a TypeBarrier on failure.
+    };
+
+  private:
+    Mode mode_;
+    BailoutKind bailoutKind_;
+
+    MUnbox(MDefinition* ins, MIRType type, Mode mode, BailoutKind kind, TempAllocator& alloc)
+      : MUnaryInstruction(classOpcode, ins),
+        mode_(mode)
+    {
+        // Only allow unboxing a non MIRType::Value when input and output types
+        // don't match. This is often used to force a bailout. Boxing happens
+        // during type analysis.
+        MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type());
+
+        MOZ_ASSERT(type == MIRType::Boolean ||
+                   type == MIRType::Int32   ||
+                   type == MIRType::Double  ||
+                   type == MIRType::String  ||
+                   type == MIRType::Symbol  ||
+                   type == MIRType::Object);
+
+        TemporaryTypeSet* resultSet = ins->resultTypeSet();
+        if (resultSet && type == MIRType::Object)
+            resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc());
+
+        setResultType(type);
+        setResultTypeSet(resultSet);
+        setMovable();
+
+        if (mode_ == TypeBarrier || mode_ == Fallible)
+            setGuard();
+
+        bailoutKind_ = kind;
+    }
+  public:
+    INSTRUCTION_HEADER(Unbox)
+    static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode)
+    {
+        // Unless we were given a specific BailoutKind, pick a default based on
+        // the type we expect.
+        BailoutKind kind;
+        switch (type) {
+          case MIRType::Boolean:
+            kind = Bailout_NonBooleanInput;
+            break;
+          case MIRType::Int32:
+            kind = Bailout_NonInt32Input;
+            break;
+          case MIRType::Double:
+            kind = Bailout_NonNumericInput; // Int32s are fine too
+            break;
+          case MIRType::String:
+            kind = Bailout_NonStringInput;
+            break;
+          case MIRType::Symbol:
+            kind = Bailout_NonSymbolInput;
+            break;
+          case MIRType::Object:
+            kind = Bailout_NonObjectInput;
+            break;
+          default:
+            MOZ_CRASH("Given MIRType cannot be unboxed.");
+        }
+
+        return new(alloc) MUnbox(ins, type, mode, kind, alloc);
+    }
+
+    static MUnbox* New(TempAllocator& alloc, MDefinition* ins, MIRType type, Mode mode,
+                       BailoutKind kind)
+    {
+        return new(alloc) MUnbox(ins, type, mode, kind, alloc);
+    }
+
+    Mode mode() const {
+        return mode_;
+    }
+    BailoutKind bailoutKind() const {
+        // If infallible, no bailout should be generated.
+        MOZ_ASSERT(fallible());
+        return bailoutKind_;
+    }
+    bool fallible() const {
+        return mode() != Infallible;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void printOpcode(GenericPrinter& out) const override;
+    void makeInfallible() {
+        // Should only be called if we're already Infallible or TypeBarrier
+        MOZ_ASSERT(mode() != Fallible);
+        mode_ = Infallible;
+    }
+
+    ALLOW_CLONE(MUnbox)
+};
+
+class MGuardObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MGuardObject(MDefinition* ins)
+      : MUnaryInstruction(classOpcode, ins)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+        setResultTypeSet(ins->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardObject)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MGuardString
+  : public MUnaryInstruction,
+    public StringPolicy<0>::Data
+{
+    explicit MGuardString(MDefinition* ins)
+      : MUnaryInstruction(classOpcode, ins)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardString)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MPolyInlineGuard
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MPolyInlineGuard(MDefinition* ins)
+      : MUnaryInstruction(classOpcode, ins)
+    {
+        setGuard();
+        setResultType(MIRType::Object);
+        setResultTypeSet(ins->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(PolyInlineGuard)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MAssertRange
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    // This is the range checked by the assertion. Don't confuse this with the
+    // range_ member or the range() accessor. Since MAssertRange doesn't return
+    // a value, it doesn't use those.
+    const Range* assertedRange_;
+
+    MAssertRange(MDefinition* ins, const Range* assertedRange)
+      : MUnaryInstruction(classOpcode, ins), assertedRange_(assertedRange)
+    {
+        setGuard();
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(AssertRange)
+    TRIVIAL_NEW_WRAPPERS
+
+    const Range* assertedRange() const {
+        return assertedRange_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+};
+
+// Caller-side allocation of |this| for |new|:
+// Given a templateobject, construct |this| for JSOP_NEW
+class MCreateThisWithTemplate
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    gc::InitialHeap initialHeap_;
+
+    MCreateThisWithTemplate(TempAllocator& alloc, CompilerConstraintList* constraints,
+                            MConstant* templateConst, gc::InitialHeap initialHeap)
+      : MUnaryInstruction(classOpcode, templateConst),
+        initialHeap_(initialHeap)
+    {
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject()));
+    }
+
+  public:
+    INSTRUCTION_HEADER(CreateThisWithTemplate)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+
+    // Template for |this|, provided by TI.
+    JSObject* templateObject() const {
+        return &getOperand(0)->toConstant()->toObject();
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    // Although creation of |this| modifies global state, it is safely repeatable.
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override;
+};
+
+// Eager initialization of arguments object.
+class MCreateArgumentsObject
+  : public MUnaryInstruction,
+    public ObjectPolicy<0>::Data
+{
+    CompilerGCPointer<ArgumentsObject*> templateObj_;
+
+    MCreateArgumentsObject(MDefinition* callObj, ArgumentsObject* templateObj)
+      : MUnaryInstruction(classOpcode, callObj),
+        templateObj_(templateObj)
+    {
+        setResultType(MIRType::Object);
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(CreateArgumentsObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getCallObject))
+
+    ArgumentsObject* templateObject() const {
+        return templateObj_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObj_);
+    }
+};
+
+class MGetArgumentsObjectArg
+  : public MUnaryInstruction,
+    public ObjectPolicy<0>::Data
+{
+    size_t argno_;
+
+    MGetArgumentsObjectArg(MDefinition* argsObject, size_t argno)
+      : MUnaryInstruction(classOpcode, argsObject),
+        argno_(argno)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetArgumentsObjectArg)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getArgsObject))
+
+    size_t argno() const {
+        return argno_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::Any);
+    }
+};
+
+// Converts a uint32 to a double (coming from wasm).
+class MWasmUnsignedToDouble
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MWasmUnsignedToDouble(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::Double);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmUnsignedToDouble)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Converts a uint32 to a float32 (coming from wasm).
+class MWasmUnsignedToFloat32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MWasmUnsignedToFloat32(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::Float32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmUnsignedToFloat32)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool canProduceFloat32() const override { return true; }
+};
+
+class MWrapInt64ToInt32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool bottomHalf_;
+
+    explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf = true)
+      : MUnaryInstruction(classOpcode, def),
+        bottomHalf_(bottomHalf)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WrapInt64ToInt32)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isWrapInt64ToInt32())
+            return false;
+        if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool bottomHalf() const {
+        return bottomHalf_;
+    }
+};
+
+class MExtendInt32ToInt64
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isUnsigned_;
+
+    MExtendInt32ToInt64(MDefinition* def, bool isUnsigned)
+      : MUnaryInstruction(classOpcode, def),
+        isUnsigned_(isUnsigned)
+    {
+        setResultType(MIRType::Int64);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ExtendInt32ToInt64)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool isUnsigned() const { return isUnsigned_; }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isExtendInt32ToInt64())
+            return false;
+        if (ins->toExtendInt32ToInt64()->isUnsigned_ != isUnsigned_)
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MWasmTruncateToInt64
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isUnsigned_;
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    MWasmTruncateToInt64(MDefinition* def, bool isUnsigned, wasm::BytecodeOffset bytecodeOffset)
+      : MUnaryInstruction(classOpcode, def),
+        isUnsigned_(isUnsigned),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        setResultType(MIRType::Int64);
+        setGuard(); // neither removable nor movable because of possible side-effects.
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmTruncateToInt64)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool isUnsigned() const { return isUnsigned_; }
+    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) &&
+               ins->toWasmTruncateToInt64()->isUnsigned() == isUnsigned_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Truncate a value to an int32, with wasm semantics: this will trap when the
+// value is out of range.
+class MWasmTruncateToInt32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isUnsigned_;
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    explicit MWasmTruncateToInt32(MDefinition* def, bool isUnsigned,
+                                  wasm::BytecodeOffset bytecodeOffset)
+      : MUnaryInstruction(classOpcode, def),
+        isUnsigned_(isUnsigned), bytecodeOffset_(bytecodeOffset)
+    {
+        setResultType(MIRType::Int32);
+        setGuard(); // neither removable nor movable because of possible side-effects.
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmTruncateToInt32)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool isUnsigned() const {
+        return isUnsigned_;
+    }
+    wasm::BytecodeOffset bytecodeOffset() const {
+        return bytecodeOffset_;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) &&
+               ins->toWasmTruncateToInt32()->isUnsigned() == isUnsigned_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MInt64ToFloatingPoint
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isUnsigned_;
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    MInt64ToFloatingPoint(MDefinition* def, MIRType type, wasm::BytecodeOffset bytecodeOffset,
+                          bool isUnsigned)
+      : MUnaryInstruction(classOpcode, def),
+        isUnsigned_(isUnsigned),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        MOZ_ASSERT(IsFloatingPointType(type));
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Int64ToFloatingPoint)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool isUnsigned() const { return isUnsigned_; }
+    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isInt64ToFloatingPoint())
+            return false;
+        if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_)
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Converts a primitive (either typed or untyped) to an int32. If the input is
+// not primitive at runtime, a bailout occurs. If the input cannot be converted
+// to an int32 without loss (i.e. "5.5" or undefined) then a bailout occurs.
+class MToInt32
+  : public MUnaryInstruction,
+    public ToInt32Policy::Data
+{
+    bool canBeNegativeZero_;
+    MacroAssembler::IntConversionInputKind conversion_;
+
+    explicit MToInt32(MDefinition* def, MacroAssembler::IntConversionInputKind conversion =
+                                            MacroAssembler::IntConversion_Any)
+      : MUnaryInstruction(classOpcode, def),
+        canBeNegativeZero_(true),
+        conversion_(conversion)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        // ToNumber(symbol) throws.
+        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
+            setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToInt32)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    // this only has backwards information flow.
+    void analyzeEdgeCasesBackward() override;
+
+    bool canBeNegativeZero() const {
+        return canBeNegativeZero_;
+    }
+    void setCanBeNegativeZero(bool negativeZero) {
+        canBeNegativeZero_ = negativeZero;
+    }
+
+    MacroAssembler::IntConversionInputKind conversion() const {
+        return conversion_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isToInt32() || ins->toToInt32()->conversion() != conversion())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+    void collectRangeInfoPreTrunc() override;
+
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override { return true; }
+#endif
+
+    ALLOW_CLONE(MToInt32)
+};
+
+// Converts a value or typed input to a truncated int32, for use with bitwise
+// operations. This is an infallible ValueToECMAInt32.
+class MTruncateToInt32
+  : public MUnaryInstruction,
+    public ToInt32Policy::Data
+{
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    explicit MTruncateToInt32(MDefinition* def,
+                              wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset())
+      : MUnaryInstruction(classOpcode, def),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+
+        // An object might have "valueOf", which means it is effectful.
+        // ToInt32(symbol) throws.
+        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
+            setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TruncateToInt32)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+    TruncateKind operandTruncateKind(size_t index) const override;
+# ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return input()->type() < MIRType::Symbol;
+    }
+
+    wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
+
+    ALLOW_CLONE(MTruncateToInt32)
+};
+
+// Converts any type to a string
+class MToString :
+  public MUnaryInstruction,
+  public ToStringPolicy::Data
+{
+    explicit MToString(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::String);
+        setMovable();
+
+        // Objects might override toString and Symbols throw. We bailout in
+        // those cases and run side-effects in baseline instead.
+        if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
+            setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToString)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool fallible() const {
+        return input()->mightBeType(MIRType::Object) ||
+               input()->mightBeType(MIRType::Symbol);
+    }
+
+    ALLOW_CLONE(MToString)
+};
+
+// Converts any type to an object, throwing on null or undefined.
+class MToObject :
+  public MUnaryInstruction,
+  public BoxInputsPolicy::Data
+{
+    explicit MToObject(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::Object);
+        setGuard(); // Throws on null or undefined.
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToObject)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MToObject)
+};
+
+// Converts any type to an object or null value, throwing on undefined.
+class MToObjectOrNull :
+  public MUnaryInstruction,
+  public BoxInputsPolicy::Data
+{
+    explicit MToObjectOrNull(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::ObjectOrNull);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToObjectOrNull)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MToObjectOrNull)
+};
+
+class MBitNot
+  : public MUnaryInstruction,
+    public BitwisePolicy::Data
+{
+  protected:
+    explicit MBitNot(MDefinition* input)
+      : MUnaryInstruction(classOpcode, input)
+    {
+        specialization_ = MIRType::None;
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(BitNot)
+    TRIVIAL_NEW_WRAPPERS
+
+    static MBitNot* NewInt32(TempAllocator& alloc, MDefinition* input);
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void setSpecialization(MIRType type) {
+        specialization_ = type;
+        setResultType(type);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        if (specialization_ == MIRType::None)
+            return AliasSet::Store(AliasSet::Any);
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return specialization_ != MIRType::None;
+    }
+
+    ALLOW_CLONE(MBitNot)
+};
+
+class MTypeOf
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    MIRType inputType_;
+    bool inputMaybeCallableOrEmulatesUndefined_;
+
+    MTypeOf(MDefinition* def, MIRType inputType)
+      : MUnaryInstruction(classOpcode, def), inputType_(inputType),
+        inputMaybeCallableOrEmulatesUndefined_(true)
+    {
+        setResultType(MIRType::String);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypeOf)
+    TRIVIAL_NEW_WRAPPERS
+
+    MIRType inputType() const {
+        return inputType_;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints);
+
+    bool inputMaybeCallableOrEmulatesUndefined() const {
+        return inputMaybeCallableOrEmulatesUndefined_;
+    }
+    void markInputNotCallableOrEmulatesUndefined() {
+        inputMaybeCallableOrEmulatesUndefined_ = false;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isTypeOf())
+            return false;
+        if (inputType() != ins->toTypeOf()->inputType())
+            return false;
+        if (inputMaybeCallableOrEmulatesUndefined() !=
+            ins->toTypeOf()->inputMaybeCallableOrEmulatesUndefined())
+        {
+            return false;
+        }
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MToAsync
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MToAsync(MDefinition* unwrapped)
+      : MUnaryInstruction(classOpcode, unwrapped)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToAsync)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MToAsyncGen
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MToAsyncGen(MDefinition* unwrapped)
+      : MUnaryInstruction(classOpcode, unwrapped)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToAsyncGen)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MToAsyncIter
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MToAsyncIter(MDefinition* unwrapped)
+      : MUnaryInstruction(classOpcode, unwrapped)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToAsyncIter)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MToId
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MToId(MDefinition* index)
+      : MUnaryInstruction(classOpcode, index)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ToId)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MSignExtendInt32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  public:
+    enum Mode {
+        Byte,
+        Half
+    };
+
+  private:
+    Mode mode_;
+
+    MSignExtendInt32(MDefinition* op, Mode mode)
+      : MUnaryInstruction(classOpcode, op), mode_(mode)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SignExtendInt32)
+    TRIVIAL_NEW_WRAPPERS
+
+    Mode mode() const { return mode_; }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        return ins->isSignExtendInt32() && ins->toSignExtendInt32()->mode_ == mode_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MSignExtendInt32)
+};
+
+class MSignExtendInt64
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  public:
+    enum Mode {
+        Byte,
+        Half,
+        Word
+    };
+
+  private:
+    Mode mode_;
+
+    MSignExtendInt64(MDefinition* op, Mode mode)
+      : MUnaryInstruction(classOpcode, op), mode_(mode)
+    {
+        setResultType(MIRType::Int64);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SignExtendInt64)
+    TRIVIAL_NEW_WRAPPERS
+
+    Mode mode() const { return mode_; }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        return ins->isSignExtendInt64() && ins->toSignExtendInt64()->mode_ == mode_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MSignExtendInt64)
+};
+
+class MAbs
+  : public MUnaryInstruction,
+    public ArithPolicy::Data
+{
+    bool implicitTruncate_;
+
+    MAbs(MDefinition* num, MIRType type)
+      : MUnaryInstruction(classOpcode, num),
+        implicitTruncate_(false)
+    {
+        MOZ_ASSERT(IsNumberType(type));
+        setResultType(type);
+        setMovable();
+        specialization_ = type;
+    }
+
+  public:
+    INSTRUCTION_HEADER(Abs)
+    TRIVIAL_NEW_WRAPPERS
+
+    static MAbs* NewWasm(TempAllocator& alloc, MDefinition* num, MIRType type) {
+        auto* ins = new(alloc) MAbs(num, type);
+        if (type == MIRType::Int32)
+            ins->implicitTruncate_ = true;
+        return ins;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    bool fallible() const;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+    bool isFloat32Commutative() const override { return true; }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MAbs)
+};
+
+class MClz
+  : public MUnaryInstruction
+  , public BitwisePolicy::Data
+{
+    bool operandIsNeverZero_;
+
+    explicit MClz(MDefinition* num, MIRType type)
+      : MUnaryInstruction(classOpcode, num),
+        operandIsNeverZero_(false)
+    {
+        MOZ_ASSERT(IsIntType(type));
+        MOZ_ASSERT(IsNumberType(num->type()));
+        specialization_ = type;
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Clz)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, num))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool operandIsNeverZero() const {
+        return operandIsNeverZero_;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+    void collectRangeInfoPreTrunc() override;
+};
+
+class MCtz
+  : public MUnaryInstruction
+  , public BitwisePolicy::Data
+{
+    bool operandIsNeverZero_;
+
+    explicit MCtz(MDefinition* num, MIRType type)
+      : MUnaryInstruction(classOpcode, num),
+        operandIsNeverZero_(false)
+    {
+        MOZ_ASSERT(IsIntType(type));
+        MOZ_ASSERT(IsNumberType(num->type()));
+        specialization_ = type;
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Ctz)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, num))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool operandIsNeverZero() const {
+        return operandIsNeverZero_;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+    void collectRangeInfoPreTrunc() override;
+};
+
+class MPopcnt
+  : public MUnaryInstruction
+  , public BitwisePolicy::Data
+{
+    explicit MPopcnt(MDefinition* num, MIRType type)
+      : MUnaryInstruction(classOpcode, num)
+    {
+        MOZ_ASSERT(IsNumberType(num->type()));
+        MOZ_ASSERT(IsIntType(type));
+        specialization_ = type;
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Popcnt)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, num))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+};
+
+// Inline implementation of Math.sqrt().
+class MSqrt
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    MSqrt(MDefinition* num, MIRType type)
+      : MUnaryInstruction(classOpcode, num)
+    {
+        setResultType(type);
+        specialization_ = type;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Sqrt)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    bool isFloat32Commutative() const override { return true; }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MSqrt)
+};
+
+// Inline implementation of Math.pow(x, 0.5), which subtly differs from Math.sqrt(x).
+class MPowHalf
+  : public MUnaryInstruction,
+    public DoublePolicy<0>::Data
+{
+    bool operandIsNeverNegativeInfinity_;
+    bool operandIsNeverNegativeZero_;
+    bool operandIsNeverNaN_;
+
+    explicit MPowHalf(MDefinition* input)
+      : MUnaryInstruction(classOpcode, input),
+        operandIsNeverNegativeInfinity_(false),
+        operandIsNeverNegativeZero_(false),
+        operandIsNeverNaN_(false)
+    {
+        setResultType(MIRType::Double);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(PowHalf)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    bool operandIsNeverNegativeInfinity() const {
+        return operandIsNeverNegativeInfinity_;
+    }
+    bool operandIsNeverNegativeZero() const {
+        return operandIsNeverNegativeZero_;
+    }
+    bool operandIsNeverNaN() const {
+        return operandIsNeverNaN_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void collectRangeInfoPreTrunc() override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MPowHalf)
+};
+
+class MMathFunction
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+  public:
+    enum Function {
+        Log,
+        Sin,
+        Cos,
+        Exp,
+        Tan,
+        ACos,
+        ASin,
+        ATan,
+        Log10,
+        Log2,
+        Log1P,
+        ExpM1,
+        CosH,
+        SinH,
+        TanH,
+        ACosH,
+        ASinH,
+        ATanH,
+        Sign,
+        Trunc,
+        Cbrt,
+        Floor,
+        Ceil,
+        Round
+    };
+
+  private:
+    Function function_;
+    const MathCache* cache_;
+
+    // A nullptr cache means this function will neither access nor update the cache.
+    MMathFunction(MDefinition* input, Function function, const MathCache* cache)
+      : MUnaryInstruction(classOpcode, input), function_(function), cache_(cache)
+    {
+        setResultType(MIRType::Double);
+        specialization_ = MIRType::Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(MathFunction)
+    TRIVIAL_NEW_WRAPPERS
+
+    Function function() const {
+        return function_;
+    }
+    const MathCache* cache() const {
+        return cache_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isMathFunction())
+            return false;
+        if (ins->toMathFunction()->function() != function())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    static const char* FunctionName(Function function);
+
+    bool isFloat32Commutative() const override {
+        return function_ == Floor || function_ == Ceil || function_ == Round;
+    }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        if (input()->type() == MIRType::SinCosDouble)
+            return false;
+        switch(function_) {
+          case Sin:
+          case Log:
+          case Ceil:
+          case Floor:
+          case Round:
+            return true;
+          default:
+            return false;
+        }
+    }
+
+    ALLOW_CLONE(MMathFunction)
+};
+
+class MFromCharCode
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    explicit MFromCharCode(MDefinition* code)
+      : MUnaryInstruction(classOpcode, code)
+    {
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(FromCharCode)
+    TRIVIAL_NEW_WRAPPERS
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MFromCharCode)
+};
+
+class MFromCodePoint
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    explicit MFromCodePoint(MDefinition* codePoint)
+      : MUnaryInstruction(classOpcode, codePoint)
+    {
+        setGuard(); // throws on invalid code point
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(FromCodePoint)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MFromCodePoint)
+};
+
+class MStringConvertCase
+  : public MUnaryInstruction,
+    public StringPolicy<0>::Data
+{
+  public:
+    enum Mode { LowerCase, UpperCase };
+
+  private:
+    Mode mode_;
+
+    MStringConvertCase(MDefinition* string, Mode mode)
+      : MUnaryInstruction(classOpcode, string), mode_(mode)
+    {
+        setResultType(MIRType::String);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(StringConvertCase)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, string))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) && ins->toStringConvertCase()->mode() == mode();
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    Mode mode() const {
+        return mode_;
+    }
+};
+
+class MSinCos
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    const MathCache* cache_;
+
+    MSinCos(MDefinition *input, const MathCache *cache)
+      : MUnaryInstruction(classOpcode, input),
+        cache_(cache)
+    {
+        setResultType(MIRType::SinCosDouble);
+        specialization_ = MIRType::Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SinCos)
+
+    static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
+    {
+        return new (alloc) MSinCos(input, cache);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition *ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    const MathCache* cache() const {
+        return cache_;
+    }
+};
+
+// Returns the value to use as |this| value. See also ComputeThis and
+// BoxNonStrictThis in Interpreter.h.
+class MComputeThis
+  : public MUnaryInstruction,
+    public BoxPolicy<0>::Data
+{
+    explicit MComputeThis(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ComputeThis)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    // Note: don't override getAliasSet: the thisValue hook can be effectful.
+};
+
+// Load an arrow function's |new.target| value.
+class MArrowNewTarget
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MArrowNewTarget(MDefinition* callee)
+      : MUnaryInstruction(classOpcode, callee)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ArrowNewTarget)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, callee))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        // An arrow function's lexical |this| value is immutable.
+        return AliasSet::None();
+    }
+};
+
+// The goal of a Beta node is to split a def at a conditionally taken
+// branch, so that uses dominated by it have a different name.
+class MBeta
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    // This is the range induced by a comparison and branch in a preceding
+    // block. Note that this does not reflect any range constraints from
+    // the input value itself, so this value may differ from the range()
+    // range after it is computed.
+    const Range* comparison_;
+
+    MBeta(MDefinition* val, const Range* comp)
+        : MUnaryInstruction(classOpcode, val),
+          comparison_(comp)
+    {
+        setResultType(val->type());
+        setResultTypeSet(val->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(Beta)
+    TRIVIAL_NEW_WRAPPERS
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+};
+
+// If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the input is returned
+class MNaNToZero
+  : public MUnaryInstruction,
+    public DoublePolicy<0>::Data
+{
+    bool operandIsNeverNaN_;
+    bool operandIsNeverNegativeZero_;
+
+    explicit MNaNToZero(MDefinition* input)
+      : MUnaryInstruction(classOpcode, input),
+        operandIsNeverNaN_(false),
+        operandIsNeverNegativeZero_(false)
+    {
+        setResultType(MIRType::Double);
+        setMovable();
+    }
+  public:
+    INSTRUCTION_HEADER(NaNToZero)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool operandIsNeverNaN() const {
+        return operandIsNeverNaN_;
+    }
+
+    bool operandIsNeverNegativeZero() const {
+        return operandIsNeverNegativeZero_;
+    }
+
+    void collectRangeInfoPreTrunc() override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MNaNToZero)
+};
+
+// MIR representation of a Value on the OSR BaselineFrame.
+// The Value is indexed off of OsrFrameReg.
+class MOsrValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    ptrdiff_t frameOffset_;
+
+    MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset)
+      : MUnaryInstruction(classOpcode, entry),
+        frameOffset_(frameOffset)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(OsrValue)
+    TRIVIAL_NEW_WRAPPERS
+
+    ptrdiff_t frameOffset() const {
+        return frameOffset_;
+    }
+
+    MOsrEntry* entry() {
+        return getOperand(0)->toOsrEntry();
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
+// The pointer is indexed off of OsrFrameReg.
+class MOsrEnvironmentChain
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    explicit MOsrEnvironmentChain(MOsrEntry* entry)
+      : MUnaryInstruction(classOpcode, entry)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(OsrEnvironmentChain)
+    TRIVIAL_NEW_WRAPPERS
+
+    MOsrEntry* entry() {
+        return getOperand(0)->toOsrEntry();
+    }
+};
+
+// MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
+// The pointer is indexed off of OsrFrameReg.
+class MOsrArgumentsObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    explicit MOsrArgumentsObject(MOsrEntry* entry)
+      : MUnaryInstruction(classOpcode, entry)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(OsrArgumentsObject)
+    TRIVIAL_NEW_WRAPPERS
+
+    MOsrEntry* entry() {
+        return getOperand(0)->toOsrEntry();
+    }
+};
+
+// MIR representation of the return value on the OSR BaselineFrame.
+// The Value is indexed off of OsrFrameReg.
+class MOsrReturnValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    explicit MOsrReturnValue(MOsrEntry* entry)
+      : MUnaryInstruction(classOpcode, entry)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(OsrReturnValue)
+    TRIVIAL_NEW_WRAPPERS
+
+    MOsrEntry* entry() {
+        return getOperand(0)->toOsrEntry();
+    }
+};
+
+class MUnarySharedStub
+  : public MUnaryInstruction,
+    public BoxPolicy<0>::Data
+{
+    explicit MUnarySharedStub(MDefinition* input)
+      : MUnaryInstruction(classOpcode, input)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(UnarySharedStub)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving
+// it to baseline to throw at the correct pc.
+class MLexicalCheck
+  : public MUnaryInstruction,
+    public BoxPolicy<0>::Data
+{
+    BailoutKind kind_;
+    explicit MLexicalCheck(MDefinition* input, BailoutKind kind = Bailout_UninitializedLexical)
+      : MUnaryInstruction(classOpcode, input),
+        kind_(kind)
+    {
+        setResultType(MIRType::Value);
+        setResultTypeSet(input->resultTypeSet());
+        setMovable();
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LexicalCheck)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    BailoutKind bailoutKind() const {
+        return kind_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+};
+
+// If not defined, set a global variable to |undefined|.
+class MDefVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    CompilerPropertyName name_; // Target name to be defined.
+    unsigned attrs_; // Attributes to be set.
+
+  private:
+    MDefVar(PropertyName* name, unsigned attrs, MDefinition* envChain)
+      : MUnaryInstruction(classOpcode, envChain),
+        name_(name),
+        attrs_(attrs)
+    {
+    }
+
+  public:
+    INSTRUCTION_HEADER(DefVar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, environmentChain))
+
+    PropertyName* name() const {
+        return name_;
+    }
+    unsigned attrs() const {
+        return attrs_;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MRegExpPrototypeOptimizable
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MRegExpPrototypeOptimizable(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExpPrototypeOptimizable)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MGetFirstDollarIndex
+  : public MUnaryInstruction,
+    public StringPolicy<0>::Data
+{
+    explicit MGetFirstDollarIndex(MDefinition* str)
+      : MUnaryInstruction(classOpcode, str)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetFirstDollarIndex)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, str))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+};
+
+// Returns obj->slots.
+class MSlots
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MSlots(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Slots);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Slots)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    ALLOW_CLONE(MSlots)
+};
+
+// Returns obj->elements.
+class MElements
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool unboxed_;
+
+    explicit MElements(MDefinition* object, bool unboxed = false)
+      : MUnaryInstruction(classOpcode, object), unboxed_(unboxed)
+    {
+        setResultType(MIRType::Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Elements)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool unboxed() const {
+        return unboxed_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) &&
+               ins->toElements()->unboxed() == unboxed();
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    ALLOW_CLONE(MElements)
+};
+
+// Passes through an object's elements, after ensuring it is entirely doubles.
+class MConvertElementsToDoubles
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MConvertElementsToDoubles(MDefinition* elements)
+      : MUnaryInstruction(classOpcode, elements)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Elements);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ConvertElementsToDoubles)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        // This instruction can read and write to the elements' contents.
+        // However, it is alright to hoist this from loops which explicitly
+        // read or write to the elements: such reads and writes will use double
+        // values and can be reordered freely wrt this conversion, except that
+        // definite double loads must follow the conversion. The latter
+        // property is ensured by chaining this instruction with the elements
+        // themselves, in the same manner as MBoundsCheck.
+        return AliasSet::None();
+    }
+};
+
+// Passes through an object, after ensuring its elements are not copy on write.
+class MMaybeCopyElementsForWrite
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool checkNative_;
+
+    explicit MMaybeCopyElementsForWrite(MDefinition* object, bool checkNative)
+      : MUnaryInstruction(classOpcode, object), checkNative_(checkNative)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+        setResultTypeSet(object->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(MaybeCopyElementsForWrite)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool checkNative() const {
+        return checkNative_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) &&
+               checkNative() == ins->toMaybeCopyElementsForWrite()->checkNative();
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields);
+    }
+#ifdef DEBUG
+    bool needsResumePoint() const override {
+        // This instruction is idempotent and does not change observable
+        // behavior, so does not need its own resume point.
+        return false;
+    }
+#endif
+
+};
+
+// Load the initialized length from an elements header.
+class MInitializedLength
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MInitializedLength(MDefinition* elements)
+      : MUnaryInstruction(classOpcode, elements)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(InitializedLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MInitializedLength)
+};
+
+// Load the array length from an elements header.
+class MArrayLength
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MArrayLength(MDefinition* elements)
+      : MUnaryInstruction(classOpcode, elements)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ArrayLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MArrayLength)
+};
+
+// Read the length of a typed array.
+class MTypedArrayLength
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MTypedArrayLength(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedArrayLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::TypedArrayLength);
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+};
+
+// Load a typed array's elements vector.
+class MTypedArrayElements
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MTypedArrayElements(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedArrayElements)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    ALLOW_CLONE(MTypedArrayElements)
+};
+
+// Load a binary data object's "elements", which is just its opaque
+// binary data space. Eventually this should probably be
+// unified with `MTypedArrayElements`.
+class MTypedObjectElements
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool definitelyOutline_;
+
+  private:
+    explicit MTypedObjectElements(MDefinition* object, bool definitelyOutline)
+      : MUnaryInstruction(classOpcode, object),
+        definitelyOutline_(definitelyOutline)
+    {
+        setResultType(MIRType::Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedObjectElements)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool definitelyOutline() const {
+        return definitelyOutline_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isTypedObjectElements())
+            return false;
+        const MTypedObjectElements* other = ins->toTypedObjectElements();
+        if (other->definitelyOutline() != definitelyOutline())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+class MKeepAliveObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MKeepAliveObject(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::None);
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(KeepAliveObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+};
+
+// Perform !-operation
+class MNot
+  : public MUnaryInstruction,
+    public TestPolicy::Data
+{
+    bool operandMightEmulateUndefined_;
+    bool operandIsNeverNaN_;
+
+    explicit MNot(MDefinition* input, CompilerConstraintList* constraints = nullptr)
+      : MUnaryInstruction(classOpcode, input),
+        operandMightEmulateUndefined_(true),
+        operandIsNeverNaN_(false)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+        if (constraints)
+            cacheOperandMightEmulateUndefined(constraints);
+    }
+
+    void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
+
+  public:
+    static MNot* NewInt32(TempAllocator& alloc, MDefinition* input) {
+        MOZ_ASSERT(input->type() == MIRType::Int32 || input->type() == MIRType::Int64);
+        auto* ins = new(alloc) MNot(input);
+        ins->setResultType(MIRType::Int32);
+        return ins;
+    }
+
+    INSTRUCTION_HEADER(Not)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    void markNoOperandEmulatesUndefined() {
+        operandMightEmulateUndefined_ = false;
+    }
+    bool operandMightEmulateUndefined() const {
+        return operandMightEmulateUndefined_;
+    }
+    bool operandIsNeverNaN() const {
+        return operandIsNeverNaN_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void collectRangeInfoPreTrunc() override;
+
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+    bool isFloat32Commutative() const override { return true; }
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+// Bailout if index < minimum.
+class MBoundsCheckLower
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    int32_t minimum_;
+    bool fallible_;
+
+    explicit MBoundsCheckLower(MDefinition* index)
+      : MUnaryInstruction(classOpcode, index), minimum_(0), fallible_(true)
+    {
+        setGuard();
+        setMovable();
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(BoundsCheckLower)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, index))
+
+    int32_t minimum() const {
+        return minimum_;
+    }
+    void setMinimum(int32_t n) {
+        minimum_ = n;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool fallible() const {
+        return fallible_;
+    }
+    void collectRangeInfoPreTrunc() override;
+};
+
+// Passes through an object, after ensuring it is converted from an unboxed
+// object to a native representation.
+class MConvertUnboxedObjectToNative
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerObjectGroup group_;
+
+    explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
+      : MUnaryInstruction(classOpcode, obj),
+        group_(group)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
+    NAMED_OPERANDS((0, object))
+
+    static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
+                                              ObjectGroup* group);
+
+    ObjectGroup* group() const {
+        return group_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        return ins->toConvertUnboxedObjectToNative()->group() == group();
+    }
+    AliasSet getAliasSet() const override {
+        // This instruction can read and write to all parts of the object, but
+        // is marked as non-effectful so it can be consolidated by LICM and GVN
+        // and avoid inhibiting other optimizations.
+        //
+        // This is valid to do because when unboxed objects might have a native
+        // group they can be converted to, we do not optimize accesses to the
+        // unboxed objects and do not guard on their group or shape (other than
+        // in this opcode).
+        //
+        // Later accesses can assume the object has a native representation
+        // and optimize accordingly. Those accesses cannot be reordered before
+        // this instruction, however. This is prevented by chaining this
+        // instruction with the object itself, in the same way as MBoundsCheck.
+        return AliasSet::None();
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(group_);
+    }
+};
+
+// Array.prototype.pop or Array.prototype.shift on a dense array.
+class MArrayPopShift
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  public:
+    enum Mode {
+        Pop,
+        Shift
+    };
+
+  private:
+    Mode mode_;
+    bool needsHoleCheck_;
+    bool maybeUndefined_;
+
+    MArrayPopShift(MDefinition* object, Mode mode,
+                   bool needsHoleCheck, bool maybeUndefined)
+      : MUnaryInstruction(classOpcode, object), mode_(mode),
+        needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(ArrayPopShift)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool needsHoleCheck() const {
+        return needsHoleCheck_;
+    }
+    bool maybeUndefined() const {
+        return maybeUndefined_;
+    }
+    bool mode() const {
+        return mode_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+    }
+
+    ALLOW_CLONE(MArrayPopShift)
+};
+
+// Load a value fallibly or infallibly from a statically known typed array.
+class MLoadTypedArrayElementStatic
+  : public MUnaryInstruction,
+    public ConvertToInt32Policy<0>::Data
+{
+    MLoadTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr,
+                                 int32_t offset = 0, bool needsBoundsCheck = true)
+      : MUnaryInstruction(classOpcode, ptr), someTypedArray_(someTypedArray), offset_(offset),
+        needsBoundsCheck_(needsBoundsCheck), fallible_(true)
+    {
+        int type = accessType();
+        if (type == Scalar::Float32)
+            setResultType(MIRType::Float32);
+        else if (type == Scalar::Float64)
+            setResultType(MIRType::Double);
+        else
+            setResultType(MIRType::Int32);
+    }
+
+    CompilerObject someTypedArray_;
+
+    // An offset to be encoded in the load instruction - taking advantage of the
+    // addressing modes. This is only non-zero when the access is proven to be
+    // within bounds.
+    int32_t offset_;
+    bool needsBoundsCheck_;
+    bool fallible_;
+
+  public:
+    INSTRUCTION_HEADER(LoadTypedArrayElementStatic)
+    TRIVIAL_NEW_WRAPPERS
+
+    Scalar::Type accessType() const {
+        return someTypedArray_->as<TypedArrayObject>().type();
+    }
+    SharedMem<void*> base() const;
+    size_t length() const;
+
+    MDefinition* ptr() const { return getOperand(0); }
+    int32_t offset() const { return offset_; }
+    void setOffset(int32_t offset) { offset_ = offset; }
+    bool congruentTo(const MDefinition* ins) const override;
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::UnboxedElement);
+    }
+
+    bool needsBoundsCheck() const { return needsBoundsCheck_; }
+    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
+
+    bool fallible() const {
+        return fallible_;
+    }
+
+    void setInfallible() {
+        fallible_ = false;
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+    bool needTruncation(TruncateKind kind) override;
+    bool canProduceFloat32() const override { return accessType() == Scalar::Float32; }
+    void collectRangeInfoPreTrunc() override;
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(someTypedArray_);
+    }
+};
+
+// Clamp input to range [0, 255] for Uint8ClampedArray.
+class MClampToUint8
+  : public MUnaryInstruction,
+    public ClampPolicy::Data
+{
+    explicit MClampToUint8(MDefinition* input)
+      : MUnaryInstruction(classOpcode, input)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(ClampToUint8)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MClampToUint8)
+};
+
+class MLoadFixedSlot
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    size_t slot_;
+
+  protected:
+    MLoadFixedSlot(MDefinition* obj, size_t slot)
+      : MUnaryInstruction(classOpcode, obj), slot_(slot)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadFixedSlot)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    size_t slot() const {
+        return slot_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadFixedSlot())
+            return false;
+        if (slot() != ins->toLoadFixedSlot()->slot())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::FixedSlot);
+    }
+
+    AliasType mightAlias(const MDefinition* store) const override;
+
+    ALLOW_CLONE(MLoadFixedSlot)
+};
+
+class MLoadFixedSlotAndUnbox
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    size_t slot_;
+    MUnbox::Mode mode_;
+    BailoutKind bailoutKind_;
+  protected:
+    MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, MIRType type,
+                           BailoutKind kind)
+      : MUnaryInstruction(classOpcode, obj), slot_(slot), mode_(mode), bailoutKind_(kind)
+    {
+        setResultType(type);
+        setMovable();
+        if (mode_ == MUnbox::TypeBarrier || mode_ == MUnbox::Fallible)
+            setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadFixedSlotAndUnbox)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    size_t slot() const {
+        return slot_;
+    }
+    MUnbox::Mode mode() const {
+        return mode_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool fallible() const {
+        return mode_ != MUnbox::Infallible;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadFixedSlotAndUnbox() ||
+            slot() != ins->toLoadFixedSlotAndUnbox()->slot() ||
+            mode() != ins->toLoadFixedSlotAndUnbox()->mode())
+        {
+            return false;
+        }
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::FixedSlot);
+    }
+
+    AliasType mightAlias(const MDefinition* store) const override;
+
+    ALLOW_CLONE(MLoadFixedSlotAndUnbox);
+};
+
+class MHomeObjectSuperBase
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MHomeObjectSuperBase(MDefinition* homeObject)
+      : MUnaryInstruction(classOpcode, homeObject)
+    {
+        setResultType(MIRType::Object);
+        setGuard(); // May throw if [[Prototype]] is null
+    }
+
+  public:
+    INSTRUCTION_HEADER(HomeObjectSuperBase)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, homeObject))
+};
+
+// Emit code to load a value from an object if it matches one of the receivers
+// observed by the baseline IC, else bails out.
+class MGetPropertyPolymorphic
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
+    CompilerPropertyName name_;
+
+    MGetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, PropertyName* name)
+      : MUnaryInstruction(classOpcode, obj),
+        receivers_(alloc),
+        name_(name)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetPropertyPolymorphic)
+    NAMED_OPERANDS((0, object))
+
+    static MGetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, PropertyName* name) {
+        return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGetPropertyPolymorphic())
+            return false;
+        if (name() != ins->toGetPropertyPolymorphic()->name())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
+        PolymorphicEntry entry;
+        entry.receiver = receiver;
+        entry.shape = shape;
+        return receivers_.append(entry);
+    }
+    size_t numReceivers() const {
+        return receivers_.length();
+    }
+    const ReceiverGuard receiver(size_t i) const {
+        return receivers_[i].receiver;
+    }
+    Shape* shape(size_t i) const {
+        return receivers_[i].shape;
+    }
+    PropertyName* name() const {
+        return name_;
+    }
+    AliasSet getAliasSet() const override {
+        bool hasUnboxedLoad = false;
+        for (size_t i = 0; i < numReceivers(); i++) {
+            if (!shape(i)) {
+                hasUnboxedLoad = true;
+                break;
+            }
+        }
+        return AliasSet::Load(AliasSet::ObjectFields |
+                              AliasSet::FixedSlot |
+                              AliasSet::DynamicSlot |
+                              (hasUnboxedLoad ? AliasSet::UnboxedElement : 0));
+    }
+
+    AliasType mightAlias(const MDefinition* store) const override;
+
+    bool appendRoots(MRootList& roots) const override;
+};
+
+class MBindNameCache
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerPropertyName name_;
+    CompilerScript script_;
+    jsbytecode* pc_;
+
+    MBindNameCache(MDefinition* envChain, PropertyName* name, JSScript* script, jsbytecode* pc)
+      : MUnaryInstruction(classOpcode, envChain), name_(name), script_(script), pc_(pc)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(BindNameCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, environmentChain))
+
+    PropertyName* name() const {
+        return name_;
+    }
+    JSScript* script() const {
+        return script_;
+    }
+    jsbytecode* pc() const {
+        return pc_;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        // Don't append the script, all scripts are added anyway.
+        return roots.append(name_);
+    }
+};
+
+class MCallBindVar
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MCallBindVar(MDefinition* envChain)
+      : MUnaryInstruction(classOpcode, envChain)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallBindVar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, environmentChain))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isCallBindVar())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Guard on an object's shape.
+class MGuardShape
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerShape shape_;
+    BailoutKind bailoutKind_;
+
+    MGuardShape(MDefinition* obj, Shape* shape, BailoutKind bailoutKind)
+      : MUnaryInstruction(classOpcode, obj),
+        shape_(shape),
+        bailoutKind_(bailoutKind)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+        setResultTypeSet(obj->resultTypeSet());
+
+        // Disallow guarding on unboxed object shapes. The group is better to
+        // guard on, and guarding on the shape can interact badly with
+        // MConvertUnboxedObjectToNative.
+        MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardShape)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    const Shape* shape() const {
+        return shape_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGuardShape())
+            return false;
+        if (shape() != ins->toGuardShape()->shape())
+            return false;
+        if (bailoutKind() != ins->toGuardShape()->bailoutKind())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(shape_);
+    }
+};
+
+// Bail if the object's shape or unboxed group is not in the input list.
+class MGuardReceiverPolymorphic
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
+
+    MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj),
+        receivers_(alloc)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+        setResultTypeSet(obj->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardReceiverPolymorphic)
+    NAMED_OPERANDS((0, object))
+
+    static MGuardReceiverPolymorphic* New(TempAllocator& alloc, MDefinition* obj) {
+        return new(alloc) MGuardReceiverPolymorphic(alloc, obj);
+    }
+
+    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver) {
+        return receivers_.append(receiver);
+    }
+    size_t numReceivers() const {
+        return receivers_.length();
+    }
+    const ReceiverGuard& receiver(size_t i) const {
+        return receivers_[i];
+    }
+
+    bool congruentTo(const MDefinition* ins) const override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    bool appendRoots(MRootList& roots) const override;
+
+};
+
+// Guard on an object's group, inclusively or exclusively.
+class MGuardObjectGroup
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerObjectGroup group_;
+    bool bailOnEquality_;
+    BailoutKind bailoutKind_;
+
+    MGuardObjectGroup(MDefinition* obj, ObjectGroup* group, bool bailOnEquality,
+                      BailoutKind bailoutKind)
+      : MUnaryInstruction(classOpcode, obj),
+        group_(group),
+        bailOnEquality_(bailOnEquality),
+        bailoutKind_(bailoutKind)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+
+        // Unboxed groups which might be converted to natives can't be guarded
+        // on, due to MConvertUnboxedObjectToNative.
+        MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
+                      !group->unboxedLayoutDontCheckGeneration().nativeGroup());
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardObjectGroup)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    const ObjectGroup* group() const {
+        return group_;
+    }
+    bool bailOnEquality() const {
+        return bailOnEquality_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGuardObjectGroup())
+            return false;
+        if (group() != ins->toGuardObjectGroup()->group())
+            return false;
+        if (bailOnEquality() != ins->toGuardObjectGroup()->bailOnEquality())
+            return false;
+        if (bailoutKind() != ins->toGuardObjectGroup()->bailoutKind())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(group_);
+    }
+};
+
+// Guard on an object's class.
+class MGuardClass
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    const Class* class_;
+
+    MGuardClass(MDefinition* obj, const Class* clasp)
+      : MUnaryInstruction(classOpcode, obj),
+        class_(clasp)
+    {
+        setGuard();
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardClass)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    const Class* getClass() const {
+        return class_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGuardClass())
+            return false;
+        if (getClass() != ins->toGuardClass()->getClass())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+
+    ALLOW_CLONE(MGuardClass)
+};
+
+// Guard on the presence or absence of an unboxed object's expando.
+class MGuardUnboxedExpando
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool requireExpando_;
+    BailoutKind bailoutKind_;
+
+    MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
+      : MUnaryInstruction(classOpcode, obj),
+        requireExpando_(requireExpando),
+        bailoutKind_(bailoutKind)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardUnboxedExpando)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool requireExpando() const {
+        return requireExpando_;
+    }
+    BailoutKind bailoutKind() const {
+        return bailoutKind_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
+            return false;
+        return true;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Load an unboxed plain object's expando.
+class MLoadUnboxedExpando
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  private:
+    explicit MLoadUnboxedExpando(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadUnboxedExpando)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Load from vp[slot] (slots that are not inline in an object).
+class MLoadSlot
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    uint32_t slot_;
+
+    MLoadSlot(MDefinition* slots, uint32_t slot)
+      : MUnaryInstruction(classOpcode, slots),
+        slot_(slot)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+        MOZ_ASSERT(slots->type() == MIRType::Slots);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadSlot)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, slots))
+
+    uint32_t slot() const {
+        return slot_;
+    }
+
+    HashNumber valueHash() const override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadSlot())
+            return false;
+        if (slot() != ins->toLoadSlot()->slot())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        MOZ_ASSERT(slots()->type() == MIRType::Slots);
+        return AliasSet::Load(AliasSet::DynamicSlot);
+    }
+    AliasType mightAlias(const MDefinition* store) const override;
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MLoadSlot)
+};
+
+// Inline call to access a function's environment (scope chain).
+class MFunctionEnvironment
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MFunctionEnvironment(MDefinition* function)
+        : MUnaryInstruction(classOpcode, function)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(FunctionEnvironment)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, function))
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    // A function's environment is fixed.
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Allocate a new LexicalEnvironmentObject.
+class MNewLexicalEnvironmentObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    CompilerGCPointer<LexicalScope*> scope_;
+
+    MNewLexicalEnvironmentObject(MDefinition* enclosing, LexicalScope* scope)
+      : MUnaryInstruction(classOpcode, enclosing),
+        scope_(scope)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewLexicalEnvironmentObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, enclosing))
+
+    LexicalScope* scope() const {
+        return scope_;
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(scope_);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Allocate a new LexicalEnvironmentObject from existing one
+class MCopyLexicalEnvironmentObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool copySlots_;
+
+    MCopyLexicalEnvironmentObject(MDefinition* env, bool copySlots)
+      : MUnaryInstruction(classOpcode, env),
+        copySlots_(copySlots)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CopyLexicalEnvironmentObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, env))
+
+    bool copySlots() const {
+        return copySlots_;
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields |
+                              AliasSet::FixedSlot |
+                              AliasSet::DynamicSlot);
+    }
+};
+
+class MHomeObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MHomeObject(MDefinition* function)
+        : MUnaryInstruction(classOpcode, function)
+    {
+        setResultType(MIRType::Object);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(HomeObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, function))
+
+    // A function's [[HomeObject]] is fixed.
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MGetNameCache
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  private:
+    explicit MGetNameCache(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetNameCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, envObj))
+};
+
+class MDeleteProperty
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    CompilerPropertyName name_;
+    bool strict_;
+
+  protected:
+    MDeleteProperty(MDefinition* val, PropertyName* name, bool strict)
+      : MUnaryInstruction(classOpcode, val),
+        name_(name),
+        strict_(strict)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(DeleteProperty)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+
+    PropertyName* name() const {
+        return name_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MCallGetProperty
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    CompilerPropertyName name_;
+    bool idempotent_;
+
+    MCallGetProperty(MDefinition* value, PropertyName* name)
+      : MUnaryInstruction(classOpcode, value), name_(name),
+        idempotent_(false)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallGetProperty)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+
+    PropertyName* name() const {
+        return name_;
+    }
+
+    // Constructors need to perform a GetProp on the function prototype.
+    // Since getters cannot be set on the prototype, fetching is non-effectful.
+    // The operation may be safely repeated in case of bailout.
+    void setIdempotent() {
+        idempotent_ = true;
+    }
+    AliasSet getAliasSet() const override {
+        if (!idempotent_)
+            return AliasSet::Store(AliasSet::Any);
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MStringLength
+  : public MUnaryInstruction,
+    public StringPolicy<0>::Data
+{
+    explicit MStringLength(MDefinition* string)
+      : MUnaryInstruction(classOpcode, string)
+    {
+        setResultType(MIRType::Int32);
+        setMovable();
+    }
+  public:
+    INSTRUCTION_HEADER(StringLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, string))
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        // The string |length| property is immutable, so there is no
+        // implicit dependency.
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MStringLength)
+};
+
+// Inlined assembly for Math.floor(double | float32) -> int32.
+class MFloor
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    explicit MFloor(MDefinition* num)
+      : MUnaryInstruction(classOpcode, num)
+    {
+        setResultType(MIRType::Int32);
+        specialization_ = MIRType::Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Floor)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool isFloat32Commutative() const override {
+        return true;
+    }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    void computeRange(TempAllocator& alloc) override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MFloor)
+};
+
+// Inlined assembly version for Math.ceil(double | float32) -> int32.
+class MCeil
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    explicit MCeil(MDefinition* num)
+      : MUnaryInstruction(classOpcode, num)
+    {
+        setResultType(MIRType::Int32);
+        specialization_ = MIRType::Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Ceil)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool isFloat32Commutative() const override {
+        return true;
+    }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    void computeRange(TempAllocator& alloc) override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MCeil)
+};
+
+// Inlined version of Math.round(double | float32) -> int32.
+class MRound
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    explicit MRound(MDefinition* num)
+      : MUnaryInstruction(classOpcode, num)
+    {
+        setResultType(MIRType::Int32);
+        specialization_ = MIRType::Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Round)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool isFloat32Commutative() const override {
+        return true;
+    }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MRound)
+};
+
+// NearbyInt rounds the floating-point input to the nearest integer, according
+// to the RoundingMode.
+class MNearbyInt
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    RoundingMode roundingMode_;
+
+    explicit MNearbyInt(MDefinition* num, MIRType resultType, RoundingMode roundingMode)
+      : MUnaryInstruction(classOpcode, num),
+        roundingMode_(roundingMode)
+    {
+        MOZ_ASSERT(HasAssemblerSupport(roundingMode));
+
+        MOZ_ASSERT(IsFloatingPointType(resultType));
+        setResultType(resultType);
+        specialization_ = resultType;
+
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(NearbyInt)
+    TRIVIAL_NEW_WRAPPERS
+
+    static bool HasAssemblerSupport(RoundingMode mode) {
+        return Assembler::HasRoundInstruction(mode);
+    }
+
+    RoundingMode roundingMode() const { return roundingMode_; }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool isFloat32Commutative() const override {
+        return true;
+    }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        return true;
+    }
+#endif
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) &&
+               ins->toNearbyInt()->roundingMode() == roundingMode_;
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+        switch (roundingMode_) {
+          case RoundingMode::Up:
+          case RoundingMode::Down:
+            return true;
+          default:
+            return false;
+        }
+    }
+
+    ALLOW_CLONE(MNearbyInt)
+};
+
+class MGetIteratorCache
+  : public MUnaryInstruction,
+    public BoxExceptPolicy<0, MIRType::Object>::Data
+{
+    explicit MGetIteratorCache(MDefinition* val)
+      : MUnaryInstruction(classOpcode, val)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetIteratorCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+};
+
+class MIteratorMore
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MIteratorMore(MDefinition* iter)
+      : MUnaryInstruction(classOpcode, iter)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(IteratorMore)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, iterator))
+
+};
+
+class MIsNoIter
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MIsNoIter(MDefinition* def)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsNoIter)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MIteratorEnd
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MIteratorEnd(MDefinition* iter)
+      : MUnaryInstruction(classOpcode, iter)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(IteratorEnd)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, iterator))
+
+};
+
+// Implementation for instanceof operator with specific rhs.
+class MInstanceOf
+  : public MUnaryInstruction,
+    public InstanceOfPolicy::Data
+{
+    CompilerObject protoObj_;
+
+    MInstanceOf(MDefinition* obj, JSObject* proto)
+      : MUnaryInstruction(classOpcode, obj),
+        protoObj_(proto)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(InstanceOf)
+    TRIVIAL_NEW_WRAPPERS
+
+    JSObject* prototypeObject() {
+        return protoObj_;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(protoObj_);
+    }
+};
+
+// This MIR instruction is used to get an argument from the actual arguments.
+class MGetFrameArgument
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    bool scriptHasSetArg_;
+
+    MGetFrameArgument(MDefinition* idx, bool scriptHasSetArg)
+      : MUnaryInstruction(classOpcode, idx),
+        scriptHasSetArg_(scriptHasSetArg)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetFrameArgument)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, index))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
+        // aliased.
+        if (scriptHasSetArg_)
+            return AliasSet::Load(AliasSet::FrameArgument);
+        return AliasSet::None();
+    }
+};
+
+// This MIR instruction is used to set an argument value in the frame.
+class MSetFrameArgument
+  : public MUnaryInstruction,
+    public NoFloatPolicy<0>::Data
+{
+    uint32_t argno_;
+
+    MSetFrameArgument(uint32_t argno, MDefinition* value)
+      : MUnaryInstruction(classOpcode, value),
+        argno_(argno)
+    {
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetFrameArgument)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+
+    uint32_t argno() const {
+        return argno_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return false;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::FrameArgument);
+    }
+};
+
+class MRest
+  : public MUnaryInstruction,
+    public MRestCommon,
+    public IntPolicy<0>::Data
+{
+    MRest(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* numActuals,
+          unsigned numFormals, ArrayObject* templateObject)
+      : MUnaryInstruction(classOpcode, numActuals),
+        MRestCommon(numFormals, templateObject)
+    {
+        setResultType(MIRType::Object);
+        setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(Rest)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+    NAMED_OPERANDS((0, numActuals))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObject());
+    }
+};
+
+class MFilterTypeSet
+  : public MUnaryInstruction,
+    public FilterTypeSetPolicy::Data
+{
+    MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types)
+      : MUnaryInstruction(classOpcode, def)
+    {
+        MOZ_ASSERT(!types->unknown());
+        setResultType(types->getKnownMIRType());
+        setResultTypeSet(types);
+    }
+
+  public:
+    INSTRUCTION_HEADER(FilterTypeSet)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* def) const override {
+        return false;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    virtual bool neverHoist() const override {
+        return resultTypeSet()->empty();
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    bool isFloat32Commutative() const override {
+        return IsFloatingPointType(type());
+    }
+
+    bool canProduceFloat32() const override;
+    bool canConsumeFloat32(MUse* operand) const override;
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+};
+
+// Given a value, guard that the value is in a particular TypeSet, then returns
+// that value.
+class MTypeBarrier
+  : public MUnaryInstruction,
+    public TypeBarrierPolicy::Data
+{
+    BarrierKind barrierKind_;
+
+    MTypeBarrier(MDefinition* def, TemporaryTypeSet* types,
+                 BarrierKind kind = BarrierKind::TypeSet)
+      : MUnaryInstruction(classOpcode, def),
+        barrierKind_(kind)
+    {
+        MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
+
+        MOZ_ASSERT(!types->unknown());
+        setResultType(types->getKnownMIRType());
+        setResultTypeSet(types);
+
+        setGuard();
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypeBarrier)
+    TRIVIAL_NEW_WRAPPERS
+
+    void printOpcode(GenericPrinter& out) const override;
+    bool congruentTo(const MDefinition* def) const override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    virtual bool neverHoist() const override {
+        return resultTypeSet()->empty();
+    }
+    BarrierKind barrierKind() const {
+        return barrierKind_;
+    }
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    bool alwaysBails() const {
+        // If mirtype of input doesn't agree with mirtype of barrier,
+        // we will definitely bail.
+        MIRType type = resultTypeSet()->getKnownMIRType();
+        if (type == MIRType::Value)
+            return false;
+        if (input()->type() == MIRType::Value)
+            return false;
+        if (input()->type() == MIRType::ObjectOrNull) {
+            // The ObjectOrNull optimization is only performed when the
+            // barrier's type is MIRType::Null.
+            MOZ_ASSERT(type == MIRType::Null);
+            return false;
+        }
+        return input()->type() != type;
+    }
+
+    ALLOW_CLONE(MTypeBarrier)
+};
+
+// Like MTypeBarrier, guard that the value is in the given type set. This is
+// used before property writes to ensure the value being written is represented
+// in the property types for the object.
+class MMonitorTypes
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    const TemporaryTypeSet* typeSet_;
+    BarrierKind barrierKind_;
+
+    MMonitorTypes(MDefinition* def, const TemporaryTypeSet* types, BarrierKind kind)
+      : MUnaryInstruction(classOpcode, def),
+        typeSet_(types),
+        barrierKind_(kind)
+    {
+        MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
+
+        setGuard();
+        MOZ_ASSERT(!types->unknown());
+    }
+
+  public:
+    INSTRUCTION_HEADER(MonitorTypes)
+    TRIVIAL_NEW_WRAPPERS
+
+    const TemporaryTypeSet* typeSet() const {
+        return typeSet_;
+    }
+    BarrierKind barrierKind() const {
+        return barrierKind_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MNewCallObjectBase : public MUnaryInstruction
+                         , public SingleObjectPolicy::Data
+{
+  protected:
+    MNewCallObjectBase(Opcode op, MConstant* templateObj)
+      : MUnaryInstruction(op, templateObj)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    CallObject* templateObject() const {
+        return &getOperand(0)->toConstant()->toObject().as<CallObject>();
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MIsCallable
+  : public MUnaryInstruction,
+    public BoxExceptPolicy<0, MIRType::Object>::Data
+{
+    explicit MIsCallable(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        MOZ_ASSERT(object->type() == MIRType::Object || object->type() == MIRType::Value);
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsCallable)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MIsConstructor
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  public:
+    explicit MIsConstructor(MDefinition* object)
+      : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsConstructor)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MIsObject
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MIsObject(MDefinition* object)
+    : MUnaryInstruction(classOpcode, object)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+  public:
+    INSTRUCTION_HEADER(IsObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MHasClass
+    : public MUnaryInstruction,
+      public SingleObjectPolicy::Data
+{
+    const Class* class_;
+
+    MHasClass(MDefinition* object, const Class* clasp)
+      : MUnaryInstruction(classOpcode, object)
+      , class_(clasp)
+    {
+        MOZ_ASSERT(object->type() == MIRType::Object ||
+                   (object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(HasClass)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    const Class* getClass() const {
+        return class_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isHasClass())
+            return false;
+        if (getClass() != ins->toHasClass()->getClass())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+};
+
+// Note: we might call a proxy trap, so this instruction is effectful.
+class MIsArray
+  : public MUnaryInstruction,
+    public BoxExceptPolicy<0, MIRType::Object>::Data
+{
+    explicit MIsArray(MDefinition* value)
+      : MUnaryInstruction(classOpcode, value)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+};
+
+class MIsTypedArray
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MIsTypedArray(MDefinition* value)
+      : MUnaryInstruction(classOpcode, value)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsTypedArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MObjectClassToString
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MObjectClassToString(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ObjectClassToString)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+};
+
+class MAtomicIsLockFree
+  : public MUnaryInstruction,
+    public ConvertToInt32Policy<0>::Data
+{
+    explicit MAtomicIsLockFree(MDefinition* value)
+      : MUnaryInstruction(classOpcode, value)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(AtomicIsLockFree)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MAtomicIsLockFree)
+};
+
+// This applies to an object that is known to be a TypedArray, it bails out
+// if the obj does not map a SharedArrayBuffer.
+
+class MGuardSharedTypedArray
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MGuardSharedTypedArray(MDefinition* obj)
+      : MUnaryInstruction(classOpcode, obj)
+    {
+        setGuard();
+        setMovable();
+    }
+
+public:
+    INSTRUCTION_HEADER(GuardSharedTypedArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MCheckIsObj
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    uint8_t checkKind_;
+
+    MCheckIsObj(MDefinition* toCheck, uint8_t checkKind)
+      : MUnaryInstruction(classOpcode, toCheck),
+        checkKind_(checkKind)
+    {
+        setResultType(MIRType::Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(CheckIsObj)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, checkValue))
+
+    uint8_t checkKind() const { return checkKind_; }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MCheckIsCallable
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    uint8_t checkKind_;
+
+    MCheckIsCallable(MDefinition* toCheck, uint8_t checkKind)
+      : MUnaryInstruction(classOpcode, toCheck),
+        checkKind_(checkKind)
+    {
+        setResultType(MIRType::Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(CheckIsCallable)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, checkValue))
+
+    uint8_t checkKind() const { return checkKind_; }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MCheckObjCoercible
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MCheckObjCoercible(MDefinition* toCheck)
+      : MUnaryInstruction(classOpcode, toCheck)
+    {
+        setGuard();
+        setResultType(MIRType::Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(CheckObjCoercible)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, checkValue))
+};
+
+class MDebugCheckSelfHosted
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MDebugCheckSelfHosted(MDefinition* toCheck)
+      : MUnaryInstruction(classOpcode, toCheck)
+    {
+        setGuard();
+        setResultType(MIRType::Value);
+        setResultTypeSet(toCheck->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(DebugCheckSelfHosted)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, checkValue))
+
+};
+
+class MIsPackedArray
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MIsPackedArray(MDefinition* array)
+      : MUnaryInstruction(classOpcode, array)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(IsPackedArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, array))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+class MGetPrototypeOf
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    explicit MGetPrototypeOf(MDefinition* target)
+      : MUnaryInstruction(classOpcode, target)
+    {
+        setResultType(MIRType::Value);
+        setGuard(); // May throw if target is a proxy.
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetPrototypeOf)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, target))
+};
+
+// Flips the input's sign bit, independently of the rest of the number's
+// payload. Note this is different from multiplying by minus-one, which has
+// side-effects for e.g. NaNs.
+class MWasmNeg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmNeg(MDefinition* op, MIRType type)
+      : MUnaryInstruction(classOpcode, op)
+    {
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmNeg)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MWasmLoadTls
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    uint32_t offset_;
+    AliasSet aliases_;
+
+    explicit MWasmLoadTls(MDefinition* tlsPointer, uint32_t offset, MIRType type, AliasSet aliases)
+      : MUnaryInstruction(classOpcode, tlsPointer),
+        offset_(offset),
+        aliases_(aliases)
+    {
+        // Different Tls data have different alias classes and only those classes are allowed.
+        MOZ_ASSERT(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
+                   aliases_.flags() == AliasSet::None().flags());
+
+        // The only types supported at the moment.
+        MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32);
+
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmLoadTls)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, tlsPtr))
+
+    uint32_t offset() const {
+        return offset_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return op() == ins->op() &&
+               offset() == ins->toWasmLoadTls()->offset() &&
+               type() == ins->type();
+    }
+
+    HashNumber valueHash() const override {
+        return addU32ToHash(HashNumber(op()), offset());
+    }
+
+    AliasSet getAliasSet() const override {
+        return aliases_;
+    }
+};
+
+class MWasmAddOffset
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    uint32_t offset_;
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    MWasmAddOffset(MDefinition* base, uint32_t offset, wasm::BytecodeOffset bytecodeOffset)
+      : MUnaryInstruction(classOpcode, base),
+        offset_(offset),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        setGuard();
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmAddOffset)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, base))
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    uint32_t offset() const {
+        return offset_;
+    }
+    wasm::BytecodeOffset bytecodeOffset() const {
+        return bytecodeOffset_;
+    }
+};
+
+class MWasmLoadGlobalVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant, MDefinition* tlsPtr)
+      : MUnaryInstruction(classOpcode, tlsPtr),
+        globalDataOffset_(globalDataOffset), isConstant_(isConstant)
+    {
+        MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
+        setResultType(type);
+        setMovable();
+    }
+
+    unsigned globalDataOffset_;
+    bool isConstant_;
+
+  public:
+    INSTRUCTION_HEADER(WasmLoadGlobalVar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, tlsPtr))
+
+    unsigned globalDataOffset() const { return globalDataOffset_; }
+
+    HashNumber valueHash() const override;
+    bool congruentTo(const MDefinition* ins) const override;
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    AliasSet getAliasSet() const override {
+        return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::WasmGlobalVar);
+    }
+
+    AliasType mightAlias(const MDefinition* def) const override;
+};
+
+class MWasmStackArg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmStackArg(uint32_t spOffset, MDefinition* ins)
+      : MUnaryInstruction(classOpcode, ins),
+        spOffset_(spOffset)
+    {}
+
+    uint32_t spOffset_;
+
+  public:
+    INSTRUCTION_HEADER(WasmStackArg)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, arg))
+
+    uint32_t spOffset() const {
+        return spOffset_;
+    }
+    void incrementOffset(uint32_t inc) {
+        spOffset_ += inc;
+    }
+};
+
+class MWasmReinterpret
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmReinterpret(MDefinition* val, MIRType toType)
+      : MUnaryInstruction(classOpcode, val)
+    {
+        switch (val->type()) {
+          case MIRType::Int32:   MOZ_ASSERT(toType == MIRType::Float32); break;
+          case MIRType::Float32: MOZ_ASSERT(toType == MIRType::Int32);   break;
+          case MIRType::Double:  MOZ_ASSERT(toType == MIRType::Int64);   break;
+          case MIRType::Int64:   MOZ_ASSERT(toType == MIRType::Double);  break;
+          default:              MOZ_CRASH("unexpected reinterpret conversion");
+        }
+        setMovable();
+        setResultType(toType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmReinterpret)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MWasmReinterpret)
+};
+
+// Store a value infallibly to a statically known typed array.
+class MStoreTypedArrayElementStatic :
+    public MBinaryInstruction,
+    public StoreUnboxedScalarBase,
+    public StoreTypedArrayElementStaticPolicy::Data
+{
+    MStoreTypedArrayElementStatic(JSObject* someTypedArray, MDefinition* ptr, MDefinition* v,
+                                  int32_t offset = 0, bool needsBoundsCheck = true)
+        : MBinaryInstruction(classOpcode, ptr, v),
+          StoreUnboxedScalarBase(someTypedArray->as<TypedArrayObject>().type()),
+          someTypedArray_(someTypedArray),
+          offset_(offset), needsBoundsCheck_(needsBoundsCheck)
+    {}
+
+    CompilerObject someTypedArray_;
+
+    // An offset to be encoded in the store instruction - taking advantage of the
+    // addressing modes. This is only non-zero when the access is proven to be
+    // within bounds.
+    int32_t offset_;
+    bool needsBoundsCheck_;
+
+  public:
+    INSTRUCTION_HEADER(StoreTypedArrayElementStatic)
+    TRIVIAL_NEW_WRAPPERS
+
+    Scalar::Type accessType() const {
+        return writeType();
+    }
+
+    SharedMem<void*> base() const;
+    size_t length() const;
+
+    MDefinition* ptr() const { return getOperand(0); }
+    MDefinition* value() const { return getOperand(1); }
+    bool needsBoundsCheck() const { return needsBoundsCheck_; }
+    void setNeedsBoundsCheck(bool v) { needsBoundsCheck_ = v; }
+    int32_t offset() const { return offset_; }
+    void setOffset(int32_t offset) { offset_ = offset; }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+    TruncateKind operandTruncateKind(size_t index) const override;
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return use == getUseFor(1) && accessType() == Scalar::Float32;
+    }
+    void collectRangeInfoPreTrunc() override;
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(someTypedArray_);
+    }
+};
+
+// Setting __proto__ in an object literal.
+class MMutateProto
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
+{
+  protected:
+    MMutateProto(MDefinition* obj, MDefinition* value)
+      : MBinaryInstruction(classOpcode, obj, value)
+    {
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(MutateProto)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getObject), (1, getValue))
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MInitPropGetterSetter
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
+{
+    CompilerPropertyName name_;
+
+    MInitPropGetterSetter(MDefinition* obj, PropertyName* name, MDefinition* value)
+      : MBinaryInstruction(classOpcode, obj, value),
+        name_(name)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(InitPropGetterSetter)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, value))
+
+    PropertyName* name() const {
+        return name_;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MGetDynamicName
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >::Data
+{
+  protected:
+    MGetDynamicName(MDefinition* envChain, MDefinition* name)
+      : MBinaryInstruction(classOpcode, envChain, name)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetDynamicName)
+    NAMED_OPERANDS((0, getEnvironmentChain), (1, getName))
+
+    static MGetDynamicName*
+    New(TempAllocator& alloc, MDefinition* envChain, MDefinition* name) {
+        return new(alloc) MGetDynamicName(envChain, name);
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MCompare
+  : public MBinaryInstruction,
+    public ComparePolicy::Data
+{
+  public:
+    enum CompareType {
+
+        // Anything compared to Undefined
+        Compare_Undefined,
+
+        // Anything compared to Null
+        Compare_Null,
+
+        // Undefined compared to Boolean
+        // Null      compared to Boolean
+        // Double    compared to Boolean
+        // String    compared to Boolean
+        // Symbol    compared to Boolean
+        // Object    compared to Boolean
+        // Value     compared to Boolean
+        Compare_Boolean,
+
+        // Int32   compared to Int32
+        // Boolean compared to Boolean
+        Compare_Int32,
+        Compare_Int32MaybeCoerceBoth,
+        Compare_Int32MaybeCoerceLHS,
+        Compare_Int32MaybeCoerceRHS,
+
+        // Int32 compared as unsigneds
+        Compare_UInt32,
+
+        // Int64 compared to Int64.
+        Compare_Int64,
+
+        // Int64 compared as unsigneds.
+        Compare_UInt64,
+
+        // Double compared to Double
+        Compare_Double,
+
+        Compare_DoubleMaybeCoerceLHS,
+        Compare_DoubleMaybeCoerceRHS,
+
+        // Float compared to Float
+        Compare_Float32,
+
+        // String compared to String
+        Compare_String,
+
+        // Symbol compared to Symbol
+        Compare_Symbol,
+
+        // Undefined compared to String
+        // Null      compared to String
+        // Boolean   compared to String
+        // Int32     compared to String
+        // Double    compared to String
+        // Object    compared to String
+        // Value     compared to String
+        Compare_StrictString,
+
+        // Object compared to Object
+        Compare_Object,
+
+        // Compare 2 values bitwise
+        Compare_Bitwise,
+
+        // All other possible compares
+        Compare_Unknown
+    };
+
+  private:
+    CompareType compareType_;
+    JSOp jsop_;
+    bool operandMightEmulateUndefined_;
+    bool operandsAreNeverNaN_;
+
+    // When a floating-point comparison is converted to an integer comparison
+    // (when range analysis proves it safe), we need to convert the operands
+    // to integer as well.
+    bool truncateOperands_;
+
+    MCompare(MDefinition* left, MDefinition* right, JSOp jsop)
+      : MBinaryInstruction(classOpcode, left, right),
+        compareType_(Compare_Unknown),
+        jsop_(jsop),
+        operandMightEmulateUndefined_(true),
+        operandsAreNeverNaN_(false),
+        truncateOperands_(false)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+    }
+
+    MCompare(MDefinition* left, MDefinition* right, JSOp jsop, CompareType compareType)
+      : MCompare(left, right, jsop)
+    {
+        MOZ_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||
+                   compareType == Compare_Int64 || compareType == Compare_UInt64 ||
+                   compareType == Compare_Double || compareType == Compare_Float32);
+        compareType_ = compareType;
+        operandMightEmulateUndefined_ = false;
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Compare)
+    TRIVIAL_NEW_WRAPPERS
+
+    MOZ_MUST_USE bool tryFold(bool* result);
+    MOZ_MUST_USE bool evaluateConstantOperands(TempAllocator& alloc, bool* result);
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
+                                bool* filtersNull);
+
+    CompareType compareType() const {
+        return compareType_;
+    }
+    bool isInt32Comparison() const {
+        return compareType() == Compare_Int32 ||
+               compareType() == Compare_Int32MaybeCoerceBoth ||
+               compareType() == Compare_Int32MaybeCoerceLHS ||
+               compareType() == Compare_Int32MaybeCoerceRHS;
+    }
+    bool isDoubleComparison() const {
+        return compareType() == Compare_Double ||
+               compareType() == Compare_DoubleMaybeCoerceLHS ||
+               compareType() == Compare_DoubleMaybeCoerceRHS;
+    }
+    bool isFloat32Comparison() const {
+        return compareType() == Compare_Float32;
+    }
+    bool isNumericComparison() const {
+        return isInt32Comparison() ||
+               isDoubleComparison() ||
+               isFloat32Comparison();
+    }
+    void setCompareType(CompareType type) {
+        compareType_ = type;
+    }
+    MIRType inputType();
+
+    JSOp jsop() const {
+        return jsop_;
+    }
+    void markNoOperandEmulatesUndefined() {
+        operandMightEmulateUndefined_ = false;
+    }
+    bool operandMightEmulateUndefined() const {
+        return operandMightEmulateUndefined_;
+    }
+    bool operandsAreNeverNaN() const {
+        return operandsAreNeverNaN_;
+    }
+    AliasSet getAliasSet() const override {
+        // Strict equality is never effectful.
+        if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE)
+            return AliasSet::None();
+        if (compareType_ == Compare_Unknown)
+            return AliasSet::Store(AliasSet::Any);
+        MOZ_ASSERT(compareType_ <= Compare_Bitwise);
+        return AliasSet::None();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+    void collectRangeInfoPreTrunc() override;
+
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+    bool isFloat32Commutative() const override { return true; }
+    bool needTruncation(TruncateKind kind) override;
+    void truncate() override;
+    TruncateKind operandTruncateKind(size_t index) const override;
+
+    static CompareType determineCompareType(JSOp op, MDefinition* left, MDefinition* right);
+    void cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints);
+
+# ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        // Both sides of the compare can be Float32
+        return compareType_ == Compare_Float32;
+    }
+# endif
+
+    ALLOW_CLONE(MCompare)
+
+  protected:
+    MOZ_MUST_USE bool tryFoldEqualOperands(bool* result);
+    MOZ_MUST_USE bool tryFoldTypeOf(bool* result);
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        return compareType() == ins->toCompare()->compareType() &&
+               jsop() == ins->toCompare()->jsop();
+    }
+};
+
+// Caller-side allocation of |this| for |new|:
+// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
+class MCreateThis
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
+{
+    explicit MCreateThis(MDefinition* callee, MDefinition* newTarget)
+      : MBinaryInstruction(classOpcode, callee, newTarget)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CreateThis)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getCallee), (1, getNewTarget))
+
+    // Although creation of |this| modifies global state, it is safely repeatable.
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MSetArgumentsObjectArg
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
+{
+    size_t argno_;
+
+    MSetArgumentsObjectArg(MDefinition* argsObj, size_t argno, MDefinition* value)
+      : MBinaryInstruction(classOpcode, argsObj, value),
+        argno_(argno)
+    {
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetArgumentsObjectArg)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getArgsObject), (1, getValue))
+
+    size_t argno() const {
+        return argno_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::Any);
+    }
+};
+
+// Given a MIRType::Value A and a MIRType::Object B:
+// If the Value may be safely unboxed to an Object, return Object(A).
+// Otherwise, return B.
+// Used to implement return behavior for inlined constructors.
+class MReturnFromCtor
+  : public MBinaryInstruction,
+    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
+{
+    MReturnFromCtor(MDefinition* value, MDefinition* object)
+      : MBinaryInstruction(classOpcode, value, object)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ReturnFromCtor)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getValue), (1, getObject))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MBinaryBitwiseInstruction
+  : public MBinaryInstruction,
+    public BitwisePolicy::Data
+{
+  protected:
+    MBinaryBitwiseInstruction(Opcode op, MDefinition* left, MDefinition* right, MIRType type)
+      : MBinaryInstruction(op, left, right), maskMatchesLeftRange(false),
+        maskMatchesRightRange(false)
+    {
+        MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
+        setResultType(type);
+        setMovable();
+    }
+
+    void specializeAs(MIRType type);
+    bool maskMatchesLeftRange;
+    bool maskMatchesRightRange;
+
+  public:
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    MDefinition* foldUnnecessaryBitop();
+    virtual MDefinition* foldIfZero(size_t operand) = 0;
+    virtual MDefinition* foldIfNegOne(size_t operand) = 0;
+    virtual MDefinition* foldIfEqual()  = 0;
+    virtual MDefinition* foldIfAllBitsSet(size_t operand)  = 0;
+    virtual void infer(BaselineInspector* inspector, jsbytecode* pc);
+    void collectRangeInfoPreTrunc() override;
+
+    void setInt32Specialization() {
+        specialization_ = MIRType::Int32;
+        setResultType(MIRType::Int32);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return binaryCongruentTo(ins);
+    }
+    AliasSet getAliasSet() const override {
+        if (specialization_ >= MIRType::Object)
+            return AliasSet::Store(AliasSet::Any);
+        return AliasSet::None();
+    }
+
+    TruncateKind operandTruncateKind(size_t index) const override;
+};
+
+class MBinaryArithInstruction
+  : public MBinaryInstruction,
+    public ArithPolicy::Data
+{
+    // Implicit truncate flag is set by the truncate backward range analysis
+    // optimization phase, and by wasm pre-processing. It is used in
+    // NeedNegativeZeroCheck to check if the result of a multiplication needs to
+    // produce -0 double value, and for avoiding overflow checks.
+
+    // This optimization happens when the multiplication cannot be truncated
+    // even if all uses are truncating its result, such as when the range
+    // analysis detect a precision loss in the multiplication.
+    TruncateKind implicitTruncate_;
+
+    // Whether we must preserve NaN semantics, and in particular not fold
+    // (x op id) or (id op x) to x, or replace a division by a multiply of the
+    // exact reciprocal.
+    bool mustPreserveNaN_;
+
+  public:
+    MBinaryArithInstruction(Opcode op, MDefinition* left, MDefinition* right)
+      : MBinaryInstruction(op, left, right),
+        implicitTruncate_(NoTruncate),
+        mustPreserveNaN_(false)
+    {
+        specialization_ = MIRType::None;
+        setMovable();
+    }
+
+    static MBinaryArithInstruction* New(TempAllocator& alloc, Opcode op,
+                                        MDefinition* left, MDefinition* right);
+
+    bool constantDoubleResult(TempAllocator& alloc);
+
+    void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; }
+    bool mustPreserveNaN() const { return mustPreserveNaN_; }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void printOpcode(GenericPrinter& out) const override;
+
+    virtual double getIdentity() = 0;
+
+    void setSpecialization(MIRType type) {
+        specialization_ = type;
+        setResultType(type);
+    }
+    void setInt32Specialization() {
+        specialization_ = MIRType::Int32;
+        setResultType(MIRType::Int32);
+    }
+    void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc);
+
+    virtual void trySpecializeFloat32(TempAllocator& alloc) override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        const auto* other = static_cast<const MBinaryArithInstruction*>(ins);
+        return other->mustPreserveNaN_ == mustPreserveNaN_;
+    }
+    AliasSet getAliasSet() const override {
+        if (specialization_ >= MIRType::Object)
+            return AliasSet::Store(AliasSet::Any);
+        return AliasSet::None();
+    }
+
+    bool isTruncated() const {
+        return implicitTruncate_ == Truncate;
+    }
+    TruncateKind truncateKind() const {
+        return implicitTruncate_;
+    }
+    void setTruncateKind(TruncateKind kind) {
+        implicitTruncate_ = Max(implicitTruncate_, kind);
+    }
+};
+
+class MMinMax
+  : public MBinaryInstruction,
+    public ArithPolicy::Data
+{
+    bool isMax_;
+
+    MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax)
+      : MBinaryInstruction(classOpcode, left, right),
+        isMax_(isMax)
+    {
+        MOZ_ASSERT(IsNumberType(type));
+        setResultType(type);
+        setMovable();
+        specialization_ = type;
+    }
+
+  public:
+    INSTRUCTION_HEADER(MinMax)
+    TRIVIAL_NEW_WRAPPERS
+
+    static MMinMax* NewWasm(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+                            MIRType type, bool isMax)
+    {
+        return New(alloc, left, right, type, isMax);
+    }
+
+    bool isMax() const {
+        return isMax_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!congruentIfOperandsEqual(ins))
+            return false;
+        const MMinMax* other = ins->toMinMax();
+        return other->isMax() == isMax();
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    bool isFloat32Commutative() const override { return true; }
+    void trySpecializeFloat32(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MMinMax)
+};
+
+class MCopySign
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    MCopySign(MDefinition* lhs, MDefinition* rhs, MIRType type)
+      : MBinaryInstruction(classOpcode, lhs, rhs)
+    {
+        setResultType(type);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(CopySign)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MCopySign)
+};
+
+// Inline implementation of atan2 (arctangent of y/x).
+class MAtan2
+  : public MBinaryInstruction,
+    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
+{
+    MAtan2(MDefinition* y, MDefinition* x)
+      : MBinaryInstruction(classOpcode, y, x)
+    {
+        setResultType(MIRType::Double);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Atan2)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, y), (1, x))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MAtan2)
+};
+
+// Inline implementation of Math.pow().
+class MPow
+  : public MBinaryInstruction,
+    public PowPolicy::Data
+{
+    MPow(MDefinition* input, MDefinition* power, MIRType powerType)
+      : MBinaryInstruction(classOpcode, input, power)
+    {
+        MOZ_ASSERT(powerType == MIRType::Double ||
+                   powerType == MIRType::Int32 ||
+                   powerType == MIRType::None);
+        specialization_ = powerType;
+        if (powerType == MIRType::None)
+            setResultType(MIRType::Value);
+        else
+            setResultType(MIRType::Double);
+        setMovable();
+    }
+
+    // Helpers for `foldsTo`
+    MDefinition* foldsConstant(TempAllocator &alloc);
+    MDefinition* foldsConstantPower(TempAllocator &alloc);
+
+  public:
+    INSTRUCTION_HEADER(Pow)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* input() const {
+        return lhs();
+    }
+    MDefinition* power() const {
+        return rhs();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        if (specialization_ == MIRType::None)
+            return AliasSet::Store(AliasSet::Any);
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return specialization_ != MIRType::None;
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MPow)
+};
+
+class MConcat
+  : public MBinaryInstruction,
+    public MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >::Data
+{
+    MConcat(MDefinition* left, MDefinition* right)
+      : MBinaryInstruction(classOpcode, left, right)
+    {
+        // At least one input should be definitely string
+        MOZ_ASSERT(left->type() == MIRType::String || right->type() == MIRType::String);
+
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Concat)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MConcat)
+};
+
+class MCharCodeAt
+  : public MBinaryInstruction,
+    public MixPolicy<StringPolicy<0>, IntPolicy<1> >::Data
+{
+    MCharCodeAt(MDefinition* str, MDefinition* index)
+        : MBinaryInstruction(classOpcode, str, index)
+    {
+        setMovable();
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CharCodeAt)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        // Strings are immutable, so there is no implicit dependency.
+        return AliasSet::None();
+    }
+
+    void computeRange(TempAllocator& alloc) override;
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    ALLOW_CLONE(MCharCodeAt)
+};
+
+class MStringSplit
+  : public MBinaryInstruction,
+    public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
+{
+    CompilerObjectGroup group_;
+
+    MStringSplit(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* string,
+                 MDefinition* sep, ObjectGroup* group)
+      : MBinaryInstruction(classOpcode, string, sep),
+        group_(group)
+    {
+        setResultType(MIRType::Object);
+        TemporaryTypeSet* types = MakeSingletonTypeSet(alloc, constraints, group);
+        setResultTypeSet(types);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StringSplit)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+    NAMED_OPERANDS((0, string), (1, separator))
+
+    ObjectGroup* group() const {
+        return group_;
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    virtual AliasSet getAliasSet() const override {
+        // Although this instruction returns a new array, we don't have to mark
+        // it as store instruction, see also MNewArray.
+        return AliasSet::None();
+    }
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(group_);
+    }
+};
+
+// Replaces the datum in the given lane by a scalar value of the same type.
+class MSimdInsertElement
+  : public MBinaryInstruction,
+    public MixPolicy< SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
+{
+  private:
+    unsigned lane_;
+
+    MSimdInsertElement(MDefinition* vec, MDefinition* val, unsigned lane)
+      : MBinaryInstruction(classOpcode, vec, val), lane_(lane)
+    {
+        MIRType type = vec->type();
+        MOZ_ASSERT(IsSimdType(type));
+        MOZ_ASSERT(lane < SimdTypeToLength(type));
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdInsertElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, vector), (1, value))
+
+    unsigned lane() const {
+        return lane_;
+    }
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return use == getUseFor(1) && SimdTypeToLaneType(type()) == MIRType::Float32;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdInsertElement)
+};
+
+// Applies a shuffle operation to the inputs. The lane indexes select a source
+// lane from the concatenation of the two input vectors.
+class MSimdShuffle
+  : public MBinaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
+{
+    MSimdShuffle(MDefinition* lhs, MDefinition* rhs, const uint8_t lanes[])
+      : MBinaryInstruction(classOpcode, lhs, rhs), MSimdShuffleBase(lanes, lhs->type())
+    {
+        MOZ_ASSERT(IsSimdType(lhs->type()));
+        MOZ_ASSERT(IsSimdType(rhs->type()));
+        MOZ_ASSERT(lhs->type() == rhs->type());
+        for (unsigned i = 0; i < arity_; i++)
+            MOZ_ASSERT(lane(i) < 2 * arity_);
+        setResultType(lhs->type());
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdShuffle)
+
+    static MInstruction* New(TempAllocator& alloc, MDefinition* lhs, MDefinition* rhs,
+                             const uint8_t lanes[])
+    {
+        unsigned arity = SimdTypeToLength(lhs->type());
+
+        // Swap operands so that new lanes come from LHS in majority.
+        // In the balanced case, swap operands if needs be, in order to be able
+        // to do only one vshufps on x86.
+        unsigned lanesFromLHS = 0;
+        for (unsigned i = 0; i < arity; i++) {
+            if (lanes[i] < arity)
+                lanesFromLHS++;
+        }
+
+        if (lanesFromLHS < arity / 2 ||
+            (arity == 4 && lanesFromLHS == 2 && lanes[0] >= 4 && lanes[1] >= 4)) {
+            mozilla::Array<uint8_t, 16> newLanes;
+            for (unsigned i = 0; i < arity; i++)
+                newLanes[i] = (lanes[i] + arity) % (2 * arity);
+            return New(alloc, rhs, lhs, &newLanes[0]);
+        }
+
+        // If all lanes come from the same vector, just use swizzle instead.
+        if (lanesFromLHS == arity)
+            return MSimdSwizzle::New(alloc, lhs, lanes);
+
+        return new(alloc) MSimdShuffle(lhs, rhs, lanes);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isSimdShuffle())
+            return false;
+        const MSimdShuffle* other = ins->toSimdShuffle();
+        return sameLanes(other) && binaryCongruentTo(other);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    ALLOW_CLONE(MSimdShuffle)
+};
+
+// Compares each value of a SIMD vector to each corresponding lane's value of
+// another SIMD vector, and returns a boolean vector containing the results of
+// the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
+// When comparing integer vectors, a SimdSign must be provided to request signed
+// or unsigned comparison.
+class MSimdBinaryComp
+  : public MBinaryInstruction,
+    public SimdAllPolicy::Data
+{
+  public:
+    enum Operation {
+#define NAME_(x) x,
+        FOREACH_COMP_SIMD_OP(NAME_)
+#undef NAME_
+    };
+
+    static const char* OperationName(Operation op) {
+        switch (op) {
+#define NAME_(x) case x: return #x;
+        FOREACH_COMP_SIMD_OP(NAME_)
+#undef NAME_
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+  private:
+    Operation operation_;
+    SimdSign sign_;
+
+    MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
+      : MBinaryInstruction(classOpcode, left, right), operation_(op), sign_(sign)
+    {
+        MOZ_ASSERT(left->type() == right->type());
+        MIRType opType = left->type();
+        MOZ_ASSERT(IsSimdType(opType));
+        MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(opType),
+                   "Signedness must be specified for integer SIMD compares");
+        setResultType(MIRTypeToBooleanSimdType(opType));
+        specialization_ = opType;
+        setMovable();
+        if (op == equal || op == notEqual)
+            setCommutative();
+    }
+
+    static MSimdBinaryComp* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+                                Operation op, SimdSign sign)
+    {
+        return new (alloc) MSimdBinaryComp(left, right, op, sign);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBinaryComp)
+
+    // Create a MSimdBinaryComp or an equivalent sequence of instructions
+    // supported by the current target.
+    // Add all instructions to the basic block |addTo|.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
+                                      MDefinition* right, Operation op, SimdSign sign);
+
+    AliasSet getAliasSet() const override
+    {
+        return AliasSet::None();
+    }
+
+    Operation operation() const { return operation_; }
+    SimdSign signedness() const { return sign_; }
+    MIRType specialization() const { return specialization_; }
+
+    // Swap the operands and reverse the comparison predicate.
+    void reverse() {
+        switch (operation()) {
+          case greaterThan:        operation_ = lessThan; break;
+          case greaterThanOrEqual: operation_ = lessThanOrEqual; break;
+          case lessThan:           operation_ = greaterThan; break;
+          case lessThanOrEqual:    operation_ = greaterThanOrEqual; break;
+          case equal:
+          case notEqual:
+            break;
+          default: MOZ_CRASH("Unexpected compare operation");
+        }
+        swapOperands();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        const MSimdBinaryComp* other = ins->toSimdBinaryComp();
+        return specialization_ == other->specialization() &&
+               operation_ == other->operation() &&
+               sign_ == other->signedness();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdBinaryComp)
+};
+
+class MSimdBinaryArith
+  : public MBinaryInstruction,
+    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
+{
+  public:
+    enum Operation {
+#define OP_LIST_(OP) Op_##OP,
+        FOREACH_NUMERIC_SIMD_BINOP(OP_LIST_)
+        FOREACH_FLOAT_SIMD_BINOP(OP_LIST_)
+#undef OP_LIST_
+    };
+
+    static const char* OperationName(Operation op) {
+        switch (op) {
+#define OP_CASE_LIST_(OP) case Op_##OP: return #OP;
+          FOREACH_NUMERIC_SIMD_BINOP(OP_CASE_LIST_)
+          FOREACH_FLOAT_SIMD_BINOP(OP_CASE_LIST_)
+#undef OP_CASE_LIST_
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+  private:
+    Operation operation_;
+
+    MSimdBinaryArith(MDefinition* left, MDefinition* right, Operation op)
+      : MBinaryInstruction(classOpcode, left, right), operation_(op)
+    {
+        MOZ_ASSERT(left->type() == right->type());
+        MIRType type = left->type();
+        MOZ_ASSERT(IsSimdType(type));
+        MOZ_ASSERT_IF(IsIntegerSimdType(type), op == Op_add || op == Op_sub || op == Op_mul);
+        setResultType(type);
+        setMovable();
+        if (op == Op_add || op == Op_mul || op == Op_min || op == Op_max)
+            setCommutative();
+    }
+
+    static MSimdBinaryArith* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+                                 Operation op)
+    {
+        return new (alloc) MSimdBinaryArith(left, right, op);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBinaryArith)
+
+    // Create an MSimdBinaryArith instruction and add it to the basic block. Possibly
+    // create and add an equivalent sequence of instructions instead if the
+    // current target doesn't support the requested shift operation directly.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
+                                      MDefinition* right, Operation op);
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    Operation operation() const { return operation_; }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        return operation_ == ins->toSimdBinaryArith()->operation();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdBinaryArith)
+};
+
+class MSimdBinarySaturating
+  : public MBinaryInstruction,
+    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1>>::Data
+{
+  public:
+    enum Operation
+    {
+        add,
+        sub,
+    };
+
+    static const char* OperationName(Operation op)
+    {
+        switch (op) {
+          case add:
+            return "add";
+          case sub:
+            return "sub";
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+  private:
+    Operation operation_;
+    SimdSign sign_;
+
+    MSimdBinarySaturating(MDefinition* left, MDefinition* right, Operation op, SimdSign sign)
+      : MBinaryInstruction(classOpcode, left, right)
+      , operation_(op)
+      , sign_(sign)
+    {
+        MOZ_ASSERT(left->type() == right->type());
+        MIRType type = left->type();
+        MOZ_ASSERT(type == MIRType::Int8x16 || type == MIRType::Int16x8);
+        setResultType(type);
+        setMovable();
+        if (op == add)
+            setCommutative();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBinarySaturating)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override { return AliasSet::None(); }
+
+    Operation operation() const { return operation_; }
+    SimdSign signedness() const { return sign_; }
+
+    bool congruentTo(const MDefinition* ins) const override
+    {
+        if (!binaryCongruentTo(ins))
+            return false;
+        return operation_ == ins->toSimdBinarySaturating()->operation() &&
+               sign_ == ins->toSimdBinarySaturating()->signedness();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdBinarySaturating)
+};
+
+class MSimdBinaryBitwise
+  : public MBinaryInstruction,
+    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
+{
+  public:
+    enum Operation {
+        and_,
+        or_,
+        xor_
+    };
+
+    static const char* OperationName(Operation op) {
+        switch (op) {
+          case and_: return "and";
+          case or_:  return "or";
+          case xor_: return "xor";
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+  private:
+    Operation operation_;
+
+    MSimdBinaryBitwise(MDefinition* left, MDefinition* right, Operation op)
+      : MBinaryInstruction(classOpcode, left, right), operation_(op)
+    {
+        MOZ_ASSERT(left->type() == right->type());
+        MIRType type = left->type();
+        MOZ_ASSERT(IsSimdType(type));
+        setResultType(type);
+        setMovable();
+        setCommutative();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdBinaryBitwise)
+    TRIVIAL_NEW_WRAPPERS
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    Operation operation() const { return operation_; }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        return operation_ == ins->toSimdBinaryBitwise()->operation();
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MSimdBinaryBitwise)
+};
+
+class MSimdShift
+  : public MBinaryInstruction,
+    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1> >::Data
+{
+  public:
+    enum Operation {
+        lsh,
+        rsh,
+        ursh
+    };
+
+  private:
+    Operation operation_;
+
+    MSimdShift(MDefinition* left, MDefinition* right, Operation op)
+      : MBinaryInstruction(classOpcode, left, right), operation_(op)
+    {
+        MIRType type = left->type();
+        MOZ_ASSERT(IsIntegerSimdType(type));
+        setResultType(type);
+        setMovable();
+    }
+
+    static MSimdShift* New(TempAllocator& alloc, MDefinition* left, MDefinition* right,
+                           Operation op)
+    {
+        return new (alloc) MSimdShift(left, right, op);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdShift)
+
+    // Create an MSimdShift instruction and add it to the basic block. Possibly
+    // create and add an equivalent sequence of instructions instead if the
+    // current target doesn't support the requested shift operation directly.
+    // Return the inserted MInstruction that computes the shifted value.
+    static MInstruction* AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
+                                      MDefinition* right, Operation op);
+
+    // Get the relevant right shift operation given the signedness of a type.
+    static Operation rshForSign(SimdSign sign) {
+        return sign == SimdSign::Unsigned ? ursh : rsh;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    Operation operation() const { return operation_; }
+
+    static const char* OperationName(Operation op) {
+        switch (op) {
+          case lsh:  return "lsh";
+          case rsh:  return "rsh-arithmetic";
+          case ursh: return "rsh-logical";
+        }
+        MOZ_CRASH("unexpected operation");
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!binaryCongruentTo(ins))
+            return false;
+        return operation_ == ins->toSimdShift()->operation();
+    }
+
+    ALLOW_CLONE(MSimdShift)
+};
+
+class MBinarySharedStub
+  : public MBinaryInstruction,
+    public MixPolicy<BoxPolicy<0>, BoxPolicy<1> >::Data
+{
+  protected:
+    explicit MBinarySharedStub(MDefinition* left, MDefinition* right)
+      : MBinaryInstruction(classOpcode, left, right)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(BinarySharedStub)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+class MDefFun
+  : public MBinaryInstruction,
+    public ObjectPolicy<0>::Data
+{
+  private:
+    MDefFun(MDefinition* fun, MDefinition* envChain)
+      : MBinaryInstruction(classOpcode, fun, envChain)
+    {}
+
+  public:
+    INSTRUCTION_HEADER(DefFun)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, fun), (1, environmentChain))
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MRegExpInstanceOptimizable
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
+{
+    explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto)
+      : MBinaryInstruction(classOpcode, object, proto)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExpInstanceOptimizable)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, proto))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MLambda
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    const LambdaFunctionInfo info_;
+
+    MLambda(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* envChain,
+            MConstant* cst)
+      : MBinaryInstruction(classOpcode, envChain, cst),
+        info_(&cst->toObject().as<JSFunction>())
+    {
+        setResultType(MIRType::Object);
+        if (!info().fun->isSingleton() && !ObjectGroup::useSingletonForClone(info().fun))
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
+    }
+
+  public:
+    INSTRUCTION_HEADER(Lambda)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+    NAMED_OPERANDS((0, environmentChain))
+
+    MConstant* functionOperand() const {
+        return getOperand(1)->toConstant();
+    }
+    const LambdaFunctionInfo& info() const {
+        return info_;
+    }
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return info_.appendRoots(roots);
+    }
+};
+
+class MSetFunName
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
+{
+    uint8_t prefixKind_;
+
+    explicit MSetFunName(MDefinition* fun, MDefinition* name, uint8_t prefixKind)
+      : MBinaryInstruction(classOpcode, fun, name),
+        prefixKind_(prefixKind)
+    {
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetFunName)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, fun), (1, name))
+
+    uint8_t prefixKind() const {
+        return prefixKind_;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+// If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert value to
+// double. Else return the original value.
+class MMaybeToDoubleElement
+  : public MBinaryInstruction,
+    public IntPolicy<1>::Data
+{
+    MMaybeToDoubleElement(MDefinition* elements, MDefinition* value)
+      : MBinaryInstruction(classOpcode, elements, value)
+    {
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        setMovable();
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(MaybeToDoubleElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, value))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Store to the initialized length in an elements header. Note the input is an
+// *index*, one less than the desired length.
+class MSetInitializedLength
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    MSetInitializedLength(MDefinition* elements, MDefinition* index)
+      : MBinaryInstruction(classOpcode, elements, index)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(SetInitializedLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields);
+    }
+
+    ALLOW_CLONE(MSetInitializedLength)
+};
+
+// Store to the length in an elements header. Note the input is an *index*, one
+// less than the desired length.
+class MSetArrayLength
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    MSetArrayLength(MDefinition* elements, MDefinition* index)
+      : MBinaryInstruction(classOpcode, elements, index)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(SetArrayLength)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields);
+    }
+
+    // By default no, unless built as a recovered instruction.
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return isRecoveredOnBailout();
+    }
+};
+
+class MGetNextEntryForIterator
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
+{
+  public:
+    enum Mode {
+        Map,
+        Set
+    };
+
+  private:
+    Mode mode_;
+
+    explicit MGetNextEntryForIterator(MDefinition* iter, MDefinition* result, Mode mode)
+      : MBinaryInstruction(classOpcode, iter, result), mode_(mode)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetNextEntryForIterator)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, iter), (1, result))
+
+    Mode mode() const {
+        return mode_;
+    }
+};
+
+// Inlined version of the js::SetTypedObjectOffset() intrinsic.
+class MSetTypedObjectOffset
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+  private:
+    MSetTypedObjectOffset(MDefinition* object, MDefinition* offset)
+      : MBinaryInstruction(classOpcode, object, offset)
+    {
+        MOZ_ASSERT(object->type() == MIRType::Object);
+        MOZ_ASSERT(offset->type() == MIRType::Int32);
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetTypedObjectOffset)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, offset))
+
+    AliasSet getAliasSet() const override {
+        // This affects the result of MTypedObjectElements,
+        // which is described as a load of ObjectFields.
+        return AliasSet::Store(AliasSet::ObjectFields);
+    }
+};
+
+// Bailout if index + minimum < 0 or index + maximum >= length. The length used
+// in a bounds check must not be negative, or the wrong result may be computed
+// (unsigned comparisons may be used).
+class MBoundsCheck
+  : public MBinaryInstruction,
+    public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
+{
+    // Range over which to perform the bounds check, may be modified by GVN.
+    int32_t minimum_;
+    int32_t maximum_;
+    bool fallible_;
+
+    MBoundsCheck(MDefinition* index, MDefinition* length)
+      : MBinaryInstruction(classOpcode, index, length),
+        minimum_(0), maximum_(0), fallible_(true)
+    {
+        setGuard();
+        setMovable();
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(length->type() == MIRType::Int32);
+
+        // Returns the checked index.
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(BoundsCheck)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, index), (1, length))
+
+    int32_t minimum() const {
+        return minimum_;
+    }
+    void setMinimum(int32_t n) {
+        MOZ_ASSERT(fallible_);
+        minimum_ = n;
+    }
+    int32_t maximum() const {
+        return maximum_;
+    }
+    void setMaximum(int32_t n) {
+        MOZ_ASSERT(fallible_);
+        maximum_ = n;
+    }
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isBoundsCheck())
+            return false;
+        const MBoundsCheck* other = ins->toBoundsCheck();
+        if (minimum() != other->minimum() || maximum() != other->maximum())
+            return false;
+        if (fallible() != other->fallible())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+    bool fallible() const {
+        return fallible_;
+    }
+    void collectRangeInfoPreTrunc() override;
+
+    ALLOW_CLONE(MBoundsCheck)
+};
+
+// Load a value from a dense array's element vector and does a hole check if the
+// array is not known to be packed.
+class MLoadElement
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool needsHoleCheck_;
+    bool loadDoubles_;
+    int32_t offsetAdjustment_;
+
+    MLoadElement(MDefinition* elements, MDefinition* index,
+                 bool needsHoleCheck, bool loadDoubles, int32_t offsetAdjustment = 0)
+      : MBinaryInstruction(classOpcode, elements, index),
+        needsHoleCheck_(needsHoleCheck),
+        loadDoubles_(loadDoubles),
+        offsetAdjustment_(offsetAdjustment)
+    {
+        if (needsHoleCheck) {
+            // Uses may be optimized away based on this instruction's result
+            // type. This means it's invalid to DCE this instruction, as we
+            // have to invalidate when we read a hole.
+            setGuard();
+        }
+        setResultType(MIRType::Value);
+        setMovable();
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    bool needsHoleCheck() const {
+        return needsHoleCheck_;
+    }
+    bool loadDoubles() const {
+        return loadDoubles_;
+    }
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool fallible() const {
+        return needsHoleCheck();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadElement())
+            return false;
+        const MLoadElement* other = ins->toLoadElement();
+        if (needsHoleCheck() != other->needsHoleCheck())
+            return false;
+        if (loadDoubles() != other->loadDoubles())
+            return false;
+        if (offsetAdjustment() != other->offsetAdjustment())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    AliasType mightAlias(const MDefinition* store) const override;
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::Element);
+    }
+
+    ALLOW_CLONE(MLoadElement)
+};
+
+class MLoadUnboxedObjectOrNull
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  public:
+    enum NullBehavior {
+        HandleNull,
+        BailOnNull,
+        NullNotPossible
+    };
+
+  private:
+    NullBehavior nullBehavior_;
+    int32_t offsetAdjustment_;
+
+    MLoadUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
+                             NullBehavior nullBehavior, int32_t offsetAdjustment)
+      : MBinaryInstruction(classOpcode, elements, index),
+        nullBehavior_(nullBehavior),
+        offsetAdjustment_(offsetAdjustment)
+    {
+        if (nullBehavior == BailOnNull) {
+            // Don't eliminate loads which bail out on a null pointer, for the
+            // same reason as MLoadElement.
+            setGuard();
+        }
+        setResultType(nullBehavior == HandleNull ? MIRType::Value : MIRType::Object);
+        setMovable();
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadUnboxedObjectOrNull)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    NullBehavior nullBehavior() const {
+        return nullBehavior_;
+    }
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool fallible() const {
+        return nullBehavior() == BailOnNull;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadUnboxedObjectOrNull())
+            return false;
+        const MLoadUnboxedObjectOrNull* other = ins->toLoadUnboxedObjectOrNull();
+        if (nullBehavior() != other->nullBehavior())
+            return false;
+        if (offsetAdjustment() != other->offsetAdjustment())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::UnboxedElement);
+    }
+    AliasType mightAlias(const MDefinition* store) const override;
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MLoadUnboxedObjectOrNull)
+};
+
+class MLoadUnboxedString
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    int32_t offsetAdjustment_;
+
+    MLoadUnboxedString(MDefinition* elements, MDefinition* index, int32_t offsetAdjustment = 0)
+      : MBinaryInstruction(classOpcode, elements, index),
+        offsetAdjustment_(offsetAdjustment)
+    {
+        setResultType(MIRType::String);
+        setMovable();
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadUnboxedString)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadUnboxedString())
+            return false;
+        const MLoadUnboxedString* other = ins->toLoadUnboxedString();
+        if (offsetAdjustment() != other->offsetAdjustment())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::UnboxedElement);
+    }
+
+    ALLOW_CLONE(MLoadUnboxedString)
+};
+
+// This instruction is used to load an element of a non-escaped inlined array.
+class MLoadElementFromState
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    MLoadElementFromState(MDefinition* array, MDefinition* index)
+      : MBinaryInstruction(classOpcode, array, index)
+    {
+        MOZ_ASSERT(array->isArgumentState());
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        setResultType(MIRType::Value);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadElementFromState)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, array), (1, index));
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+// Array.prototype.push on a dense array. Returns the new array length.
+class MArrayPush
+  : public MBinaryInstruction,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
+{
+    MArrayPush(MDefinition* object, MDefinition* value)
+      : MBinaryInstruction(classOpcode, object, value)
+    {
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ArrayPush)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, value))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MArrayPush)
+};
+
+class MArrayJoin
+    : public MBinaryInstruction,
+      public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
+{
+    bool optimizeForArray_;
+
+    MArrayJoin(MDefinition* array, MDefinition* sep, bool optimizeForArray)
+        : MBinaryInstruction(classOpcode, array, sep),
+          optimizeForArray_(optimizeForArray)
+    {
+        setResultType(MIRType::String);
+    }
+  public:
+    INSTRUCTION_HEADER(ArrayJoin)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, array), (1, sep))
+
+    bool optimizeForArray() const {
+        return optimizeForArray_;
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    virtual AliasSet getAliasSet() const override {
+        // Array.join might coerce the elements of the Array to strings.  This
+        // coercion might cause the evaluation of the some JavaScript code.
+        return AliasSet::Store(AliasSet::Any);
+    }
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+};
+
+// Load an unboxed scalar value from a typed array or other object.
+class MLoadUnboxedScalar
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    Scalar::Type storageType_;
+    Scalar::Type readType_;
+    unsigned numElems_; // used only for SIMD
+    bool requiresBarrier_;
+    int32_t offsetAdjustment_;
+    bool canonicalizeDoubles_;
+
+    MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, Scalar::Type storageType,
+                       MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
+                       int32_t offsetAdjustment = 0, bool canonicalizeDoubles = true)
+      : MBinaryInstruction(classOpcode, elements, index),
+        storageType_(storageType),
+        readType_(storageType),
+        numElems_(1),
+        requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
+        offsetAdjustment_(offsetAdjustment),
+        canonicalizeDoubles_(canonicalizeDoubles)
+    {
+        setResultType(MIRType::Value);
+        if (requiresBarrier_)
+            setGuard();         // Not removable or movable
+        else
+            setMovable();
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadUnboxedScalar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index))
+
+    void setSimdRead(Scalar::Type type, unsigned numElems) {
+        readType_ = type;
+        numElems_ = numElems;
+    }
+    unsigned numElems() const {
+        return numElems_;
+    }
+    Scalar::Type readType() const {
+        return readType_;
+    }
+
+    Scalar::Type storageType() const {
+        return storageType_;
+    }
+    bool fallible() const {
+        // Bailout if the result does not fit in an int32.
+        return readType_ == Scalar::Uint32 && type() == MIRType::Int32;
+    }
+    bool requiresMemoryBarrier() const {
+        return requiresBarrier_;
+    }
+    bool canonicalizeDoubles() const {
+        return canonicalizeDoubles_;
+    }
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    void setOffsetAdjustment(int32_t offsetAdjustment) {
+        offsetAdjustment_ = offsetAdjustment;
+    }
+    AliasSet getAliasSet() const override {
+        // When a barrier is needed make the instruction effectful by
+        // giving it a "store" effect.
+        if (requiresBarrier_)
+            return AliasSet::Store(AliasSet::UnboxedElement);
+        return AliasSet::Load(AliasSet::UnboxedElement);
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (requiresBarrier_)
+            return false;
+        if (!ins->isLoadUnboxedScalar())
+            return false;
+        const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar();
+        if (storageType_ != other->storageType_)
+            return false;
+        if (readType_ != other->readType_)
+            return false;
+        if (numElems_ != other->numElems_)
+            return false;
+        if (offsetAdjustment() != other->offsetAdjustment())
+            return false;
+        if (canonicalizeDoubles() != other->canonicalizeDoubles())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+
+    void printOpcode(GenericPrinter& out) const override;
+
+    void computeRange(TempAllocator& alloc) override;
+
+    bool canProduceFloat32() const override { return storageType_ == Scalar::Float32; }
+
+    ALLOW_CLONE(MLoadUnboxedScalar)
+};
+
+// Load a value from a typed array. Out-of-bounds accesses are handled in-line.
+class MLoadTypedArrayElementHole
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    Scalar::Type arrayType_;
+    bool allowDouble_;
+
+    MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, Scalar::Type arrayType, bool allowDouble)
+      : MBinaryInstruction(classOpcode, object, index),
+        arrayType_(arrayType), allowDouble_(allowDouble)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadTypedArrayElementHole)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, index))
+
+    Scalar::Type arrayType() const {
+        return arrayType_;
+    }
+    bool allowDouble() const {
+        return allowDouble_;
+    }
+    bool fallible() const {
+        return arrayType_ == Scalar::Uint32 && !allowDouble_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadTypedArrayElementHole())
+            return false;
+        const MLoadTypedArrayElementHole* other = ins->toLoadTypedArrayElementHole();
+        if (arrayType() != other->arrayType())
+            return false;
+        if (allowDouble() != other->allowDouble())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::UnboxedElement);
+    }
+    bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; }
+
+    ALLOW_CLONE(MLoadTypedArrayElementHole)
+};
+
+// Compute an "effective address", i.e., a compound computation of the form:
+//   base + index * scale + displacement
+class MEffectiveAddress
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, int32_t displacement)
+      : MBinaryInstruction(classOpcode, base, index),
+        scale_(scale), displacement_(displacement)
+    {
+        MOZ_ASSERT(base->type() == MIRType::Int32);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        setMovable();
+        setResultType(MIRType::Int32);
+    }
+
+    Scale scale_;
+    int32_t displacement_;
+
+  public:
+    INSTRUCTION_HEADER(EffectiveAddress)
+    TRIVIAL_NEW_WRAPPERS
+
+    MDefinition* base() const {
+        return lhs();
+    }
+    MDefinition* index() const {
+        return rhs();
+    }
+    Scale scale() const {
+        return scale_;
+    }
+    int32_t displacement() const {
+        return displacement_;
+    }
+
+    ALLOW_CLONE(MEffectiveAddress)
+};
+
+class MStoreFixedSlot
+  : public MBinaryInstruction,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
+{
+    bool needsBarrier_;
+    size_t slot_;
+
+    MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, bool barrier)
+      : MBinaryInstruction(classOpcode, obj, rval),
+        needsBarrier_(barrier),
+        slot_(slot)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(StoreFixedSlot)
+    NAMED_OPERANDS((0, object), (1, value))
+
+    static MStoreFixedSlot* New(TempAllocator& alloc, MDefinition* obj, size_t slot,
+                                MDefinition* rval)
+    {
+        return new(alloc) MStoreFixedSlot(obj, rval, slot, false);
+    }
+    static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, size_t slot,
+                                         MDefinition* rval)
+    {
+        return new(alloc) MStoreFixedSlot(obj, rval, slot, true);
+    }
+
+    size_t slot() const {
+        return slot_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::FixedSlot);
+    }
+    bool needsBarrier() const {
+        return needsBarrier_;
+    }
+    void setNeedsBarrier(bool needsBarrier = true) {
+        needsBarrier_ = needsBarrier;
+    }
+
+    ALLOW_CLONE(MStoreFixedSlot)
+};
+
+class MGetPropertyCache
+  : public MBinaryInstruction,
+    public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
+{
+    bool idempotent_ : 1;
+    bool monitoredResult_ : 1;
+
+    InlinePropertyTable* inlinePropertyTable_;
+
+    MGetPropertyCache(MDefinition* obj, MDefinition* id, bool monitoredResult)
+      : MBinaryInstruction(classOpcode, obj, id),
+        idempotent_(false),
+        monitoredResult_(monitoredResult),
+        inlinePropertyTable_(nullptr)
+    {
+        setResultType(MIRType::Value);
+
+        // The cache will invalidate if there are objects with e.g. lookup or
+        // resolve hooks on the proto chain. setGuard ensures this check is not
+        // eliminated.
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetPropertyCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value), (1, idval))
+
+    InlinePropertyTable* initInlinePropertyTable(TempAllocator& alloc, jsbytecode* pc) {
+        MOZ_ASSERT(inlinePropertyTable_ == nullptr);
+        inlinePropertyTable_ = new(alloc) InlinePropertyTable(alloc, pc);
+        return inlinePropertyTable_;
+    }
+
+    void clearInlinePropertyTable() {
+        inlinePropertyTable_ = nullptr;
+    }
+
+    InlinePropertyTable* propTable() const {
+        return inlinePropertyTable_;
+    }
+
+    bool idempotent() const {
+        return idempotent_;
+    }
+    void setIdempotent() {
+        idempotent_ = true;
+        setMovable();
+    }
+    bool monitoredResult() const {
+        return monitoredResult_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!idempotent_)
+            return false;
+        if (!ins->isGetPropertyCache())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        if (idempotent_) {
+            return AliasSet::Load(AliasSet::ObjectFields |
+                                  AliasSet::FixedSlot |
+                                  AliasSet::DynamicSlot);
+        }
+        return AliasSet::Store(AliasSet::Any);
+    }
+
+    bool allowDoubleResult() const;
+
+    bool appendRoots(MRootList& roots) const override {
+        if (inlinePropertyTable_)
+            return inlinePropertyTable_->appendRoots(roots);
+        return true;
+    }
+};
+
+// Emit code to store a value to an object's slots if its shape/group matches
+// one of the shapes/groups observed by the baseline IC, else bails out.
+class MSetPropertyPolymorphic
+  : public MBinaryInstruction,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
+{
+    Vector<PolymorphicEntry, 4, JitAllocPolicy> receivers_;
+    CompilerPropertyName name_;
+    bool needsBarrier_;
+
+    MSetPropertyPolymorphic(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
+                            PropertyName* name)
+      : MBinaryInstruction(classOpcode, obj, value),
+        receivers_(alloc),
+        name_(name),
+        needsBarrier_(false)
+    {
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetPropertyPolymorphic)
+    NAMED_OPERANDS((0, object), (1, value))
+
+    static MSetPropertyPolymorphic* New(TempAllocator& alloc, MDefinition* obj, MDefinition* value,
+                                        PropertyName* name) {
+        return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
+    }
+
+    MOZ_MUST_USE bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
+        PolymorphicEntry entry;
+        entry.receiver = receiver;
+        entry.shape = shape;
+        return receivers_.append(entry);
+    }
+    size_t numReceivers() const {
+        return receivers_.length();
+    }
+    const ReceiverGuard& receiver(size_t i) const {
+        return receivers_[i].receiver;
+    }
+    Shape* shape(size_t i) const {
+        return receivers_[i].shape;
+    }
+    PropertyName* name() const {
+        return name_;
+    }
+    bool needsBarrier() const {
+        return needsBarrier_;
+    }
+    void setNeedsBarrier() {
+        needsBarrier_ = true;
+    }
+    AliasSet getAliasSet() const override {
+        bool hasUnboxedStore = false;
+        for (size_t i = 0; i < numReceivers(); i++) {
+            if (!shape(i)) {
+                hasUnboxedStore = true;
+                break;
+            }
+        }
+        return AliasSet::Store(AliasSet::ObjectFields |
+                               AliasSet::FixedSlot |
+                               AliasSet::DynamicSlot |
+                               (hasUnboxedStore ? AliasSet::UnboxedElement : 0));
+    }
+    bool appendRoots(MRootList& roots) const override;
+};
+
+// Guard on an object's identity, inclusively or exclusively.
+class MGuardObjectIdentity
+  : public MBinaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool bailOnEquality_;
+
+    MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
+      : MBinaryInstruction(classOpcode, obj, expected),
+        bailOnEquality_(bailOnEquality)
+    {
+        setGuard();
+        setMovable();
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GuardObjectIdentity)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, expected))
+
+    bool bailOnEquality() const {
+        return bailOnEquality_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isGuardObjectIdentity())
+            return false;
+        if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
+// Store to vp[slot] (slots that are not inline in an object).
+class MStoreSlot
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >::Data
+{
+    uint32_t slot_;
+    MIRType slotType_;
+    bool needsBarrier_;
+
+    MStoreSlot(MDefinition* slots, uint32_t slot, MDefinition* value, bool barrier)
+        : MBinaryInstruction(classOpcode, slots, value),
+          slot_(slot),
+          slotType_(MIRType::Value),
+          needsBarrier_(barrier)
+    {
+        MOZ_ASSERT(slots->type() == MIRType::Slots);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreSlot)
+    NAMED_OPERANDS((0, slots), (1, value))
+
+    static MStoreSlot* New(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
+                           MDefinition* value)
+    {
+        return new(alloc) MStoreSlot(slots, slot, value, false);
+    }
+    static MStoreSlot* NewBarriered(TempAllocator& alloc, MDefinition* slots, uint32_t slot,
+                                    MDefinition* value)
+    {
+        return new(alloc) MStoreSlot(slots, slot, value, true);
+    }
+
+    uint32_t slot() const {
+        return slot_;
+    }
+    MIRType slotType() const {
+        return slotType_;
+    }
+    void setSlotType(MIRType slotType) {
+        MOZ_ASSERT(slotType != MIRType::None);
+        slotType_ = slotType;
+    }
+    bool needsBarrier() const {
+        return needsBarrier_;
+    }
+    void setNeedsBarrier() {
+        needsBarrier_ = true;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::DynamicSlot);
+    }
+    void printOpcode(GenericPrinter& out) const override;
+
+    ALLOW_CLONE(MStoreSlot)
+};
+
+class MSetPropertyInstruction : public MBinaryInstruction
+{
+    CompilerPropertyName name_;
+    bool strict_;
+
+  protected:
+    MSetPropertyInstruction(Opcode op, MDefinition* obj, MDefinition* value, PropertyName* name,
+                            bool strict)
+      : MBinaryInstruction(op, obj, value),
+        name_(name), strict_(strict)
+    {}
+
+  public:
+    NAMED_OPERANDS((0, object), (1, value))
+    PropertyName* name() const {
+        return name_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(name_);
+    }
+};
+
+class MDeleteElement
+  : public MBinaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    bool strict_;
+
+    MDeleteElement(MDefinition* value, MDefinition* index, bool strict)
+      : MBinaryInstruction(classOpcode, value, index),
+        strict_(strict)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(DeleteElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value), (1, index))
+
+    bool strict() const {
+        return strict_;
+    }
+};
+
+// Inline call to handle lhs[rhs]. The first input is a Value so that this
+// instruction can handle both objects and strings.
+class MCallGetElement
+  : public MBinaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    MCallGetElement(MDefinition* lhs, MDefinition* rhs)
+      : MBinaryInstruction(classOpcode, lhs, rhs)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallGetElement)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MSetDOMProperty
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
+{
+    const JSJitSetterOp func_;
+
+    MSetDOMProperty(const JSJitSetterOp func, MDefinition* obj, MDefinition* val)
+      : MBinaryInstruction(classOpcode, obj, val),
+        func_(func)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(SetDOMProperty)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, value))
+
+    JSJitSetterOp fun() const {
+        return func_;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+// Implementation for 'in' operator using instruction cache
+class MInCache
+  : public MBinaryInstruction,
+    public MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1> >::Data
+{
+    MInCache(MDefinition* key, MDefinition* obj)
+      : MBinaryInstruction(classOpcode, key, obj)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(InCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, key), (1, object))
+};
+
+class MHasOwnCache
+  : public MBinaryInstruction,
+    public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>::Data
+{
+    MHasOwnCache(MDefinition* obj, MDefinition* id)
+      : MBinaryInstruction(classOpcode, obj, id)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(HasOwnCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value), (1, idval))
+};
+
+// Implementation for instanceof operator with unknown rhs.
+class MCallInstanceOf
+  : public MBinaryInstruction,
+    public MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >::Data
+{
+    MCallInstanceOf(MDefinition* obj, MDefinition* proto)
+      : MBinaryInstruction(classOpcode, obj, proto)
+    {
+        setResultType(MIRType::Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallInstanceOf)
+    TRIVIAL_NEW_WRAPPERS
+};
+
+// Given a value being written to another object, update the generational store
+// buffer if the value is in the nursery and object is in the tenured heap.
+class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>::Data
+{
+    MPostWriteBarrier(MDefinition* obj, MDefinition* value)
+      : MBinaryInstruction(classOpcode, obj, value)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(PostWriteBarrier)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, value))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        // During lowering, values that neither have object nor value MIR type
+        // are ignored, thus Float32 can show up at this point without any issue.
+        return use == getUseFor(1);
+    }
+#endif
+
+    ALLOW_CLONE(MPostWriteBarrier)
+};
+
+class MCheckReturn
+  : public MBinaryInstruction,
+    public BoxInputsPolicy::Data
+{
+    explicit MCheckReturn(MDefinition* retVal, MDefinition* thisVal)
+      : MBinaryInstruction(classOpcode, retVal, thisVal)
+    {
+        setGuard();
+        setResultType(MIRType::Value);
+        setResultTypeSet(retVal->resultTypeSet());
+    }
+
+  public:
+    INSTRUCTION_HEADER(CheckReturn)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, returnValue), (1, thisValue))
+
+};
+
+class MWasmBoundsCheck
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit,
+                              wasm::BytecodeOffset bytecodeOffset)
+      : MBinaryInstruction(classOpcode, index, boundsCheckLimit),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        // Bounds check is effectful: it throws for OOB.
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmBoundsCheck)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool isRedundant() const {
+        return !isGuard();
+    }
+
+    void setRedundant() {
+        setNotGuard();
+    }
+
+    wasm::BytecodeOffset bytecodeOffset() const {
+        return bytecodeOffset_;
+    }
+};
+
+class MWasmStoreGlobalVar
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value, MDefinition* tlsPtr)
+      : MBinaryInstruction(classOpcode, value, tlsPtr),
+        globalDataOffset_(globalDataOffset)
+    { }
+
+    unsigned globalDataOffset_;
+
+  public:
+    INSTRUCTION_HEADER(WasmStoreGlobalVar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, value), (1, tlsPtr))
+
+    unsigned globalDataOffset() const { return globalDataOffset_; }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::WasmGlobalVar);
+    }
+};
+
+class MRotate
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
+{
+    bool isLeftRotate_;
+
+    MRotate(MDefinition* input, MDefinition* count, MIRType type, bool isLeftRotate)
+      : MBinaryInstruction(classOpcode, input, count), isLeftRotate_(isLeftRotate)
+    {
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Rotate)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, input), (1, count))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins) && ins->toRotate()->isLeftRotate() == isLeftRotate_;
+    }
+
+    bool isLeftRotate() const {
+        return isLeftRotate_;
+    }
+
+    ALLOW_CLONE(MRotate)
+};
+
+// Creates a new derived type object. At runtime, this is just a call
+// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
+// compile to particularly optimized code. However, using a distinct
+// MIR for creating derived type objects allows the compiler to
+// optimize ephemeral typed objects as would be created for a
+// reference like `a.b.c` -- here, the `a.b` will create an ephemeral
+// derived type object that aliases the memory of `a` itself. The
+// specific nature of `a.b` is revealed by using
+// `MNewDerivedTypedObject` rather than `MGetProperty` or what have
+// you. Moreover, the compiler knows that there are no side-effects,
+// so `MNewDerivedTypedObject` instructions can be reordered or pruned
+// as dead code.
+class MNewDerivedTypedObject
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>,
+                     ObjectPolicy<1>,
+                     IntPolicy<2> >::Data
+{
+  private:
+    TypedObjectPrediction prediction_;
+
+    MNewDerivedTypedObject(TypedObjectPrediction prediction,
+                           MDefinition* type,
+                           MDefinition* owner,
+                           MDefinition* offset)
+      : MTernaryInstruction(classOpcode, type, owner, offset),
+        prediction_(prediction)
+    {
+        setMovable();
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewDerivedTypedObject)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, type), (1, owner), (2, offset))
+
+    TypedObjectPrediction prediction() const {
+        return prediction_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MInitElem
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
+{
+    MInitElem(MDefinition* obj, MDefinition* id, MDefinition* value)
+      : MTernaryInstruction(classOpcode, obj, id, value)
+    {
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(InitElem)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getObject), (1, getId), (2, getValue))
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MInitElemGetterSetter
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >::Data
+{
+    MInitElemGetterSetter(MDefinition* obj, MDefinition* id, MDefinition* value)
+      : MTernaryInstruction(classOpcode, obj, id, value)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(InitElemGetterSetter)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, idValue), (2, value))
+
+};
+
+// fun.apply(self, arguments)
+class MApplyArgs
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
+{
+  protected:
+    // Monomorphic cache of single target from TI, or nullptr.
+    WrappedFunction* target_;
+
+    MApplyArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, MDefinition* self)
+      : MTernaryInstruction(classOpcode, fun, argc, self),
+        target_(target)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ApplyArgs)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis))
+
+    // For TI-informed monomorphic callsites.
+    WrappedFunction* getSingleTarget() const {
+        return target_;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        if (target_)
+            return target_->appendRoots(roots);
+        return true;
+    }
+};
+
+// fun.apply(fn, array)
+class MApplyArray
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2> >::Data
+{
+  protected:
+    // Monomorphic cache of single target from TI, or nullptr.
+    WrappedFunction* target_;
+
+    MApplyArray(WrappedFunction* target, MDefinition* fun, MDefinition* elements, MDefinition* self)
+      : MTernaryInstruction(classOpcode, fun, elements, self),
+        target_(target)
+    {
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ApplyArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis))
+
+    // For TI-informed monomorphic callsites.
+    WrappedFunction* getSingleTarget() const {
+        return target_;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    bool appendRoots(MRootList& roots) const override {
+        if (target_)
+            return target_->appendRoots(roots);
+        return true;
+    }
+};
+
+// Caller-side allocation of |this| for |new|:
+// Given a prototype operand, construct |this| for JSOP_NEW.
+class MCreateThisWithProto
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2> >::Data
+{
+    MCreateThisWithProto(MDefinition* callee, MDefinition* newTarget, MDefinition* prototype)
+      : MTernaryInstruction(classOpcode, callee, newTarget, prototype)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CreateThisWithProto)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, getCallee), (1, getNewTarget), (2, getPrototype))
+
+    // Although creation of |this| modifies global state, it is safely repeatable.
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MSimdSelect
+  : public MTernaryInstruction,
+    public SimdSelectPolicy::Data
+{
+    MSimdSelect(MDefinition* mask, MDefinition* lhs, MDefinition* rhs)
+      : MTernaryInstruction(classOpcode, mask, lhs, rhs)
+    {
+        MOZ_ASSERT(IsBooleanSimdType(mask->type()));
+        MOZ_ASSERT(lhs->type() == lhs->type());
+        MIRType type = lhs->type();
+        MOZ_ASSERT(IsSimdType(type));
+        setResultType(type);
+        specialization_ = type;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdSelect)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, mask))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MSimdSelect)
+};
+
+class MRegExpMatcher
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>,
+                     StringPolicy<1>,
+                     IntPolicy<2> >::Data
+{
+  private:
+
+    MRegExpMatcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
+    {
+        setMovable();
+        // May be object or null.
+        setResultType(MIRType::Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExpMatcher)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MRegExpSearcher
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>,
+                     StringPolicy<1>,
+                     IntPolicy<2> >::Data
+{
+  private:
+
+    MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
+    {
+        setMovable();
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExpSearcher)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MRegExpTester
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>,
+                     StringPolicy<1>,
+                     IntPolicy<2> >::Data
+{
+  private:
+
+    MRegExpTester(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex)
+      : MTernaryInstruction(classOpcode, regexp, string, lastIndex)
+    {
+        setMovable();
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(RegExpTester)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, regexp), (1, string), (2, lastIndex))
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+};
+
+class MStringReplace
+  : public MTernaryInstruction,
+    public MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >::Data
+{
+  private:
+
+    bool isFlatReplacement_;
+
+    MStringReplace(MDefinition* string, MDefinition* pattern, MDefinition* replacement)
+      : MTernaryInstruction(classOpcode, string, pattern, replacement),
+        isFlatReplacement_(false)
+    {
+        setMovable();
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StringReplace)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, string), (1, pattern), (2, replacement))
+
+    void setFlatReplacement() {
+        MOZ_ASSERT(!isFlatReplacement_);
+        isFlatReplacement_ = true;
+    }
+
+    bool isFlatReplacement() const {
+        return isFlatReplacement_;
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isStringReplace())
+            return false;
+        if (isFlatReplacement_ != ins->toStringReplace()->isFlatReplacement())
+            return false;
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        if (isFlatReplacement_) {
+            MOZ_ASSERT(!pattern()->isRegExp());
+            return true;
+        }
+        return false;
+    }
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+class MSubstr
+  : public MTernaryInstruction,
+    public MixPolicy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
+{
+  private:
+
+    MSubstr(MDefinition* string, MDefinition* begin, MDefinition* length)
+      : MTernaryInstruction(classOpcode, string, begin, length)
+    {
+        setResultType(MIRType::String);
+    }
+
+  public:
+    INSTRUCTION_HEADER(Substr)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, string), (1, begin), (2, length))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
+class MLambdaArrow
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>::Data
+{
+    const LambdaFunctionInfo info_;
+
+    MLambdaArrow(TempAllocator& alloc, CompilerConstraintList* constraints, MDefinition* envChain,
+                 MDefinition* newTarget, MConstant* cst)
+      : MTernaryInstruction(classOpcode, envChain, newTarget, cst),
+        info_(&cst->toObject().as<JSFunction>())
+    {
+        setResultType(MIRType::Object);
+        MOZ_ASSERT(!ObjectGroup::useSingletonForClone(info().fun));
+        if (!info().fun->isSingleton())
+            setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, info().fun));
+    }
+
+  public:
+    INSTRUCTION_HEADER(LambdaArrow)
+    TRIVIAL_NEW_WRAPPERS_WITH_ALLOC
+    NAMED_OPERANDS((0, environmentChain), (1, newTargetDef))
+
+    MConstant* functionOperand() const {
+        return getOperand(2)->toConstant();
+    }
+    const LambdaFunctionInfo& info() const {
+        return info_;
+    }
+    MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
+    bool canRecoverOnBailout() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return info_.appendRoots(roots);
+    }
+};
+
+class MSetDisjointTypedElements
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
+{
+    explicit MSetDisjointTypedElements(MDefinition* target, MDefinition* targetOffset,
+                                       MDefinition* source)
+      : MTernaryInstruction(classOpcode, target, targetOffset, source)
+    {
+        MOZ_ASSERT(target->type() == MIRType::Object);
+        MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
+        MOZ_ASSERT(source->type() == MIRType::Object);
+        setResultType(MIRType::None);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetDisjointTypedElements)
+    NAMED_OPERANDS((0, target), (1, targetOffset), (2, source))
+
+    static MSetDisjointTypedElements*
+    New(TempAllocator& alloc, MDefinition* target, MDefinition* targetOffset,
+        MDefinition* source)
+    {
+        return new(alloc) MSetDisjointTypedElements(target, targetOffset, source);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+
+    ALLOW_CLONE(MSetDisjointTypedElements)
+};
+
+// Load a value from the elements vector of a native object. If the index is
+// out-of-bounds, or the indexed slot has a hole, undefined is returned instead.
+class MLoadElementHole
+  : public MTernaryInstruction,
+    public SingleObjectPolicy::Data
+{
+    bool needsNegativeIntCheck_;
+    bool needsHoleCheck_;
+
+    MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
+                     bool needsHoleCheck)
+      : MTernaryInstruction(classOpcode, elements, index, initLength),
+        needsNegativeIntCheck_(true),
+        needsHoleCheck_(needsHoleCheck)
+    {
+        setResultType(MIRType::Value);
+        setMovable();
+
+        // Set the guard flag to make sure we bail when we see a negative
+        // index. We can clear this flag (and needsNegativeIntCheck_) in
+        // collectRangeInfoPreTrunc.
+        setGuard();
+
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(initLength->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(LoadElementHole)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
+
+    bool needsNegativeIntCheck() const {
+        return needsNegativeIntCheck_;
+    }
+    bool needsHoleCheck() const {
+        return needsHoleCheck_;
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isLoadElementHole())
+            return false;
+        const MLoadElementHole* other = ins->toLoadElementHole();
+        if (needsHoleCheck() != other->needsHoleCheck())
+            return false;
+        if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::Element);
+    }
+    void collectRangeInfoPreTrunc() override;
+
+    ALLOW_CLONE(MLoadElementHole)
+};
+
+// Store a value to a dense array slots vector.
+class MStoreElement
+  : public MTernaryInstruction,
+    public MStoreElementCommon,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<2> >::Data
+{
+    bool needsHoleCheck_;
+    int32_t offsetAdjustment_;
+
+    MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value,
+                  bool needsHoleCheck, int32_t offsetAdjustment = 0)
+      : MTernaryInstruction(classOpcode, elements, index, value)
+    {
+        needsHoleCheck_ = needsHoleCheck;
+        offsetAdjustment_ = offsetAdjustment;
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::Element);
+    }
+    bool needsHoleCheck() const {
+        return needsHoleCheck_;
+    }
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool fallible() const {
+        return needsHoleCheck();
+    }
+
+    ALLOW_CLONE(MStoreElement)
+};
+
+// Store an unboxed object or null pointer to a vector.
+class MStoreUnboxedString
+  : public MTernaryInstruction,
+    public MixPolicy<SingleObjectPolicy, ConvertToStringPolicy<2> >::Data
+{
+    int32_t offsetAdjustment_;
+    bool preBarrier_;
+
+    MStoreUnboxedString(MDefinition* elements, MDefinition* index, MDefinition* value,
+                        int32_t offsetAdjustment = 0, bool preBarrier = true)
+      : MTernaryInstruction(classOpcode, elements, index, value),
+        offsetAdjustment_(offsetAdjustment),
+        preBarrier_(preBarrier)
+    {
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreUnboxedString)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value))
+
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool preBarrier() const {
+        return preBarrier_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+
+    ALLOW_CLONE(MStoreUnboxedString)
+};
+
+// Array.prototype.slice on a dense array.
+class MArraySlice
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
+{
+    CompilerObject templateObj_;
+    gc::InitialHeap initialHeap_;
+
+    MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
+                MDefinition* begin, MDefinition* end,
+                JSObject* templateObj, gc::InitialHeap initialHeap)
+      : MTernaryInstruction(classOpcode, obj, begin, end),
+        templateObj_(templateObj),
+        initialHeap_(initialHeap)
+    {
+        setResultType(MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(ArraySlice)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, begin), (2, end))
+
+    JSObject* templateObj() const {
+        return templateObj_;
+    }
+
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    bool appendRoots(MRootList& roots) const override {
+        return roots.append(templateObj_);
+    }
+};
+
+// Store an unboxed scalar value to a typed array or other object.
+class MStoreUnboxedScalar
+  : public MTernaryInstruction,
+    public StoreUnboxedScalarBase,
+    public StoreUnboxedScalarPolicy::Data
+{
+  public:
+    enum TruncateInputKind {
+        DontTruncateInput,
+        TruncateInput
+    };
+
+  private:
+    Scalar::Type storageType_;
+
+    // Whether this store truncates out of range inputs, for use by range analysis.
+    TruncateInputKind truncateInput_;
+
+    bool requiresBarrier_;
+    int32_t offsetAdjustment_;
+    unsigned numElems_; // used only for SIMD
+
+    MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, MDefinition* value,
+                        Scalar::Type storageType, TruncateInputKind truncateInput,
+                        MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier,
+                        int32_t offsetAdjustment = 0)
+      : MTernaryInstruction(classOpcode, elements, index, value),
+        StoreUnboxedScalarBase(storageType),
+        storageType_(storageType),
+        truncateInput_(truncateInput),
+        requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
+        offsetAdjustment_(offsetAdjustment),
+        numElems_(1)
+    {
+        if (requiresBarrier_)
+            setGuard();         // Not removable or movable
+        else
+            setMovable();
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreUnboxedScalar)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value))
+
+    void setSimdWrite(Scalar::Type writeType, unsigned numElems) {
+        MOZ_ASSERT(Scalar::isSimdType(writeType));
+        setWriteType(writeType);
+        numElems_ = numElems;
+    }
+    unsigned numElems() const {
+        return numElems_;
+    }
+    Scalar::Type storageType() const {
+        return storageType_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+    TruncateInputKind truncateInput() const {
+        return truncateInput_;
+    }
+    bool requiresMemoryBarrier() const {
+        return requiresBarrier_;
+    }
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    TruncateKind operandTruncateKind(size_t index) const override;
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return use == getUseFor(2) && writeType() == Scalar::Float32;
+    }
+
+    ALLOW_CLONE(MStoreUnboxedScalar)
+};
+
+class MGetPropSuperCache
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, CacheIdPolicy<2>>::Data
+{
+    MGetPropSuperCache(MDefinition* obj, MDefinition* receiver, MDefinition* id)
+      : MTernaryInstruction(classOpcode, obj, receiver, id)
+    {
+        setResultType(MIRType::Value);
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetPropSuperCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, receiver), (2, idval))
+};
+
+class MSetElementInstruction
+  : public MTernaryInstruction
+{
+    bool strict_;
+  protected:
+    MSetElementInstruction(Opcode op, MDefinition* object, MDefinition* index, MDefinition* value,
+                           bool strict)
+      : MTernaryInstruction(op, object, index, value),
+        strict_(strict)
+    {
+    }
+
+  public:
+    NAMED_OPERANDS((0, object), (1, index), (2, value))
+    bool strict() const {
+        return strict_;
+    }
+};
+
+class MSetPropertyCache
+  : public MTernaryInstruction,
+    public MixPolicy<SingleObjectPolicy, CacheIdPolicy<1>, NoFloatPolicy<2>>::Data
+{
+    bool strict_ : 1;
+    bool needsPostBarrier_ : 1;
+    bool needsTypeBarrier_ : 1;
+    bool guardHoles_ : 1;
+
+    MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, bool strict,
+                      bool needsPostBarrier, bool typeBarrier, bool guardHoles)
+      : MTernaryInstruction(classOpcode, obj, id, value),
+        strict_(strict),
+        needsPostBarrier_(needsPostBarrier),
+        needsTypeBarrier_(typeBarrier),
+        guardHoles_(guardHoles)
+    {
+    }
+
+  public:
+    INSTRUCTION_HEADER(SetPropertyCache)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, idval), (2, value))
+
+    bool needsPostBarrier() const {
+        return needsPostBarrier_;
+    }
+    bool needsTypeBarrier() const {
+        return needsTypeBarrier_;
+    }
+
+    bool guardHoles() const {
+        return guardHoles_;
+    }
+
+    bool strict() const {
+        return strict_;
+    }
+};
+
+class MCallInitElementArray
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
+{
+    MCallInitElementArray(MDefinition* obj, MDefinition* index, MDefinition* val)
+      : MTernaryInstruction(classOpcode, obj, index, val)
+    {
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(CallInitElementArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, index), (2, value))
+
+    bool possiblyCalls() const override {
+        return true;
+    }
+};
+
+// Given a value being written to another object's elements at the specified
+// index, update the generational store buffer if the value is in the nursery
+// and object is in the tenured heap.
+class MPostWriteElementBarrier : public MTernaryInstruction
+                               , public MixPolicy<ObjectPolicy<0>, IntPolicy<2>>::Data
+{
+    MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, MDefinition* index)
+      : MTernaryInstruction(classOpcode, obj, value, index)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(PostWriteElementBarrier)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, value), (2, index))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+#ifdef DEBUG
+    bool isConsistentFloat32Use(MUse* use) const override {
+        // During lowering, values that neither have object nor value MIR type
+        // are ignored, thus Float32 can show up at this point without any issue.
+        return use == getUseFor(1);
+    }
+#endif
+
+    ALLOW_CLONE(MPostWriteElementBarrier)
+};
+
+class MAtomicExchangeTypedArrayElement
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>>::Data
+{
+    Scalar::Type arrayType_;
+
+    MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, MDefinition* value,
+                                     Scalar::Type arrayType)
+      : MTernaryInstruction(classOpcode, elements, index, value),
+        arrayType_(arrayType)
+    {
+        MOZ_ASSERT(arrayType <= Scalar::Uint32);
+        setGuard();             // Not removable
+    }
+
+  public:
+    INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value))
+
+    bool isByteArray() const {
+        return (arrayType_ == Scalar::Int8 ||
+                arrayType_ == Scalar::Uint8);
+    }
+    Scalar::Type arrayType() const {
+        return arrayType_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+};
+
+class MAtomicTypedArrayElementBinop
+  : public MTernaryInstruction,
+    public MixPolicy< ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2> >::Data
+{
+  private:
+    AtomicOp op_;
+    Scalar::Type arrayType_;
+
+  protected:
+    explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, MDefinition* index,
+                                           Scalar::Type arrayType, MDefinition* value)
+      : MTernaryInstruction(classOpcode, elements, index, value),
+        op_(op),
+        arrayType_(arrayType)
+    {
+        setGuard();             // Not removable
+    }
+
+  public:
+    INSTRUCTION_HEADER(AtomicTypedArrayElementBinop)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value))
+
+    bool isByteArray() const {
+        return (arrayType_ == Scalar::Int8 ||
+                arrayType_ == Scalar::Uint8);
+    }
+    AtomicOp operation() const {
+        return op_;
+    }
+    Scalar::Type arrayType() const {
+        return arrayType_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+};
+
+class MFinishBoundFunctionInit
+  : public MTernaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2>>::Data
+{
+    MFinishBoundFunctionInit(MDefinition* bound, MDefinition* target, MDefinition* argCount)
+      : MTernaryInstruction(classOpcode, bound, target, argCount)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(FinishBoundFunctionInit)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, bound), (1, target), (2, argCount))
+};
+
+class MWasmSelect
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
+{
+    MWasmSelect(MDefinition* trueExpr, MDefinition* falseExpr, MDefinition *condExpr)
+      : MTernaryInstruction(classOpcode, trueExpr, falseExpr, condExpr)
+    {
+        MOZ_ASSERT(condExpr->type() == MIRType::Int32);
+        MOZ_ASSERT(trueExpr->type() == falseExpr->type());
+        setResultType(trueExpr->type());
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmSelect)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, trueExpr), (1, falseExpr), (2, condExpr))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    ALLOW_CLONE(MWasmSelect)
+};
+
+// Generic constructor of SIMD valuesX4.
+class MSimdValueX4
+  : public MQuaternaryInstruction,
+    public MixPolicy<SimdScalarPolicy<0>, SimdScalarPolicy<1>,
+                     SimdScalarPolicy<2>, SimdScalarPolicy<3> >::Data
+{
+  protected:
+    MSimdValueX4(MIRType type, MDefinition* x, MDefinition* y, MDefinition* z, MDefinition* w)
+      : MQuaternaryInstruction(classOpcode, x, y, z, w)
+    {
+        MOZ_ASSERT(IsSimdType(type));
+        MOZ_ASSERT(SimdTypeToLength(type) == 4);
+
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdValueX4)
+    TRIVIAL_NEW_WRAPPERS
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return SimdTypeToLaneType(type()) == MIRType::Float32;
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MSimdValueX4)
+};
+
+// Try to store a value to a dense array slots vector. May fail due to the object being frozen.
+// Cannot be used on an object that has extra indexed properties.
+class MFallibleStoreElement
+  : public MQuaternaryInstruction,
+    public MStoreElementCommon,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
+{
+    bool strict_;
+
+    MFallibleStoreElement(MDefinition* object, MDefinition* elements,
+                          MDefinition* index, MDefinition* value,
+                          bool strict)
+      : MQuaternaryInstruction(classOpcode, object, elements, index, value),
+        strict_(strict)
+    {
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(FallibleStoreElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+    }
+    bool strict() const {
+        return strict_;
+    }
+
+    ALLOW_CLONE(MFallibleStoreElement)
+};
+
+
+// Store an unboxed object or null pointer to a v\ector.
+class MStoreUnboxedObjectOrNull
+  : public MQuaternaryInstruction,
+    public StoreUnboxedObjectOrNullPolicy::Data
+{
+    int32_t offsetAdjustment_;
+    bool preBarrier_;
+
+    MStoreUnboxedObjectOrNull(MDefinition* elements, MDefinition* index,
+                              MDefinition* value, MDefinition* typedObj,
+                              int32_t offsetAdjustment = 0, bool preBarrier = true)
+      : MQuaternaryInstruction(classOpcode, elements, index, value, typedObj),
+        offsetAdjustment_(offsetAdjustment),
+        preBarrier_(preBarrier)
+    {
+        MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(typedObj->type() == MIRType::Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreUnboxedObjectOrNull)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, value), (3, typedObj))
+
+    int32_t offsetAdjustment() const {
+        return offsetAdjustment_;
+    }
+    bool preBarrier() const {
+        return preBarrier_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+
+    // For StoreUnboxedObjectOrNullPolicy.
+    void setValue(MDefinition* def) {
+        replaceOperand(2, def);
+    }
+
+    ALLOW_CLONE(MStoreUnboxedObjectOrNull)
+};
+
+class MStoreTypedArrayElementHole
+  : public MQuaternaryInstruction,
+    public StoreUnboxedScalarBase,
+    public StoreTypedArrayHolePolicy::Data
+{
+    MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, MDefinition* index,
+                                MDefinition* value, Scalar::Type arrayType)
+      : MQuaternaryInstruction(classOpcode, elements, length, index, value),
+        StoreUnboxedScalarBase(arrayType)
+    {
+        setMovable();
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        MOZ_ASSERT(length->type() == MIRType::Int32);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreTypedArrayElementHole)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value))
+
+    Scalar::Type arrayType() const {
+        MOZ_ASSERT(!Scalar::isSimdType(writeType()),
+                   "arrayType == writeType iff the write type isn't SIMD");
+        return writeType();
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+    TruncateKind operandTruncateKind(size_t index) const override;
+
+    bool canConsumeFloat32(MUse* use) const override {
+        return use == getUseFor(3) && arrayType() == Scalar::Float32;
+    }
+
+    ALLOW_CLONE(MStoreTypedArrayElementHole)
+};
+
+// Test whether the index is in the array bounds or a hole.
+class MInArray
+  : public MQuaternaryInstruction,
+    public ObjectPolicy<3>::Data
+{
+    bool needsHoleCheck_;
+    bool needsNegativeIntCheck_;
+
+    MInArray(MDefinition* elements, MDefinition* index,
+             MDefinition* initLength, MDefinition* object,
+             bool needsHoleCheck)
+      : MQuaternaryInstruction(classOpcode, elements, index, initLength, object),
+        needsHoleCheck_(needsHoleCheck),
+        needsNegativeIntCheck_(true)
+    {
+        setResultType(MIRType::Boolean);
+        setMovable();
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(initLength->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(InArray)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, initLength), (3, object))
+
+    bool needsHoleCheck() const {
+        return needsHoleCheck_;
+    }
+    bool needsNegativeIntCheck() const {
+        return needsNegativeIntCheck_;
+    }
+    void collectRangeInfoPreTrunc() override;
+    AliasSet getAliasSet() const override {
+        return AliasSet::Load(AliasSet::Element);
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        if (!ins->isInArray())
+            return false;
+        const MInArray* other = ins->toInArray();
+        if (needsHoleCheck() != other->needsHoleCheck())
+            return false;
+        if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
+            return false;
+        return congruentIfOperandsEqual(other);
+    }
+};
+
+class MCompareExchangeTypedArrayElement
+  : public MQuaternaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, IntPolicy<1>, TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>::Data
+{
+    Scalar::Type arrayType_;
+
+    explicit MCompareExchangeTypedArrayElement(MDefinition* elements, MDefinition* index,
+                                               Scalar::Type arrayType, MDefinition* oldval,
+                                               MDefinition* newval)
+      : MQuaternaryInstruction(classOpcode, elements, index, oldval, newval),
+        arrayType_(arrayType)
+    {
+        setGuard();             // Not removable
+    }
+
+  public:
+    INSTRUCTION_HEADER(CompareExchangeTypedArrayElement)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, elements), (1, index), (2, oldval), (3, newval))
+
+    bool isByteArray() const {
+        return (arrayType_ == Scalar::Int8 ||
+                arrayType_ == Scalar::Uint8);
+    }
+    int oldvalOperand() {
+        return 2;
+    }
+    Scalar::Type arrayType() const {
+        return arrayType_;
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::Store(AliasSet::UnboxedElement);
+    }
+};
+
+class MQuaternaryInstruction : public MAryInstruction<4>
+{
+  protected:
+    MQuaternaryInstruction(Opcode op,
+                           MDefinition* first, MDefinition* second,
+                           MDefinition* third, MDefinition* fourth)
+      : MAryInstruction(op)
+    {
+        initOperand(0, first);
+        initOperand(1, second);
+        initOperand(2, third);
+        initOperand(3, fourth);
+    }
+
+    HashNumber valueHash() const override;
+};
+
+// Like MStoreElement, but supports indexes >= initialized length. The downside
+// is that we cannot hoist the elements vector and bounds check, since this
+// instruction may update the (initialized) length and reallocate the elements
+// vector.
+class MStoreElementHole
+  : public MQuaternaryInstruction,
+    public MStoreElementCommon,
+    public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
+{
+    MStoreElementHole(MDefinition* object, MDefinition* elements,
+                      MDefinition* index, MDefinition* value)
+      : MQuaternaryInstruction(classOpcode, object, elements, index, value)
+    {
+        MOZ_ASSERT(elements->type() == MIRType::Elements);
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(StoreElementHole)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
+
+    AliasSet getAliasSet() const override {
+        // StoreElementHole can update the initialized length, the array length
+        // or reallocate obj->elements.
+        return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+    }
+
+    ALLOW_CLONE(MStoreElementHole)
+};
+
+#endif
\ No newline at end of file