summaryrefslogtreecommitdiffstats
path: root/js/src/jit/shared/LIR-shared.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/shared/LIR-shared.h')
-rw-r--r--js/src/jit/shared/LIR-shared.h8904
1 files changed, 8904 insertions, 0 deletions
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
new file mode 100644
index 000000000..a352f5d8a
--- /dev/null
+++ b/js/src/jit/shared/LIR-shared.h
@@ -0,0 +1,8904 @@
+/* -*- 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 jit_shared_LIR_shared_h
+#define jit_shared_LIR_shared_h
+
+#include "jsutil.h"
+
+#include "jit/AtomicOp.h"
+#include "jit/shared/Assembler-shared.h"
+
+// This file declares LIR instructions that are common to every platform.
+
+namespace js {
+namespace jit {
+
+class LBox : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ MIRType type_;
+
+ public:
+ LIR_HEADER(Box);
+
+ LBox(const LAllocation& payload, MIRType type)
+ : type_(type)
+ {
+ setOperand(0, payload);
+ }
+
+ MIRType type() const {
+ return type_;
+ }
+ const char* extraName() const {
+ return StringFromMIRType(type_);
+ }
+};
+
+template <size_t Temps, size_t ExtraUses = 0>
+class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps>
+{
+ public:
+ const LAllocation* lhs() {
+ return this->getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return this->getOperand(1);
+ }
+};
+
+// An LOsiPoint captures a snapshot after a call and ensures enough space to
+// patch in a call to the invalidation mechanism.
+//
+// Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the
+// corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it
+// gets CG'd.
+class LOsiPoint : public LInstructionHelper<0, 0, 0>
+{
+ LSafepoint* safepoint_;
+
+ public:
+ LOsiPoint(LSafepoint* safepoint, LSnapshot* snapshot)
+ : safepoint_(safepoint)
+ {
+ MOZ_ASSERT(safepoint && snapshot);
+ assignSnapshot(snapshot);
+ }
+
+ LSafepoint* associatedSafepoint() {
+ return safepoint_;
+ }
+
+ LIR_HEADER(OsiPoint)
+};
+
+class LMove
+{
+ LAllocation from_;
+ LAllocation to_;
+ LDefinition::Type type_;
+
+ public:
+ LMove(LAllocation from, LAllocation to, LDefinition::Type type)
+ : from_(from),
+ to_(to),
+ type_(type)
+ { }
+
+ LAllocation from() const {
+ return from_;
+ }
+ LAllocation to() const {
+ return to_;
+ }
+ LDefinition::Type type() const {
+ return type_;
+ }
+};
+
+class LMoveGroup : public LInstructionHelper<0, 0, 0>
+{
+ js::Vector<LMove, 2, JitAllocPolicy> moves_;
+
+#ifdef JS_CODEGEN_X86
+ // Optional general register available for use when executing moves.
+ LAllocation scratchRegister_;
+#endif
+
+ explicit LMoveGroup(TempAllocator& alloc)
+ : moves_(alloc)
+ { }
+
+ public:
+ LIR_HEADER(MoveGroup)
+
+ static LMoveGroup* New(TempAllocator& alloc) {
+ return new(alloc) LMoveGroup(alloc);
+ }
+
+ void printOperands(GenericPrinter& out);
+
+ // Add a move which takes place simultaneously with all others in the group.
+ bool add(LAllocation from, LAllocation to, LDefinition::Type type);
+
+ // Add a move which takes place after existing moves in the group.
+ bool addAfter(LAllocation from, LAllocation to, LDefinition::Type type);
+
+ size_t numMoves() const {
+ return moves_.length();
+ }
+ const LMove& getMove(size_t i) const {
+ return moves_[i];
+ }
+
+#ifdef JS_CODEGEN_X86
+ void setScratchRegister(Register reg) {
+ scratchRegister_ = LGeneralReg(reg);
+ }
+ LAllocation maybeScratchRegister() {
+ return scratchRegister_;
+ }
+#endif
+
+ bool uses(Register reg) {
+ for (size_t i = 0; i < numMoves(); i++) {
+ LMove move = getMove(i);
+ if (move.from() == LGeneralReg(reg) || move.to() == LGeneralReg(reg))
+ return true;
+ }
+ return false;
+ }
+};
+
+
+// Constructs a SIMD object (value type) based on the MIRType of its input.
+class LSimdBox : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(SimdBox)
+
+ explicit LSimdBox(const LAllocation& simd, const LDefinition& temp)
+ {
+ setOperand(0, simd);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MSimdBox* mir() const {
+ return mir_->toSimdBox();
+ }
+};
+
+class LSimdUnbox : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(SimdUnbox)
+
+ LSimdUnbox(const LAllocation& obj, const LDefinition& temp)
+ {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MSimdUnbox* mir() const {
+ return mir_->toSimdUnbox();
+ }
+};
+
+// Constructs a SIMD value with 16 equal components (int8x16).
+class LSimdSplatX16 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdSplatX16)
+ explicit LSimdSplatX16(const LAllocation& v)
+ {
+ setOperand(0, v);
+ }
+
+ MSimdSplat* mir() const {
+ return mir_->toSimdSplat();
+ }
+};
+
+// Constructs a SIMD value with 8 equal components (int16x8).
+class LSimdSplatX8 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdSplatX8)
+ explicit LSimdSplatX8(const LAllocation& v)
+ {
+ setOperand(0, v);
+ }
+
+ MSimdSplat* mir() const {
+ return mir_->toSimdSplat();
+ }
+};
+
+// Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4).
+class LSimdSplatX4 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdSplatX4)
+ explicit LSimdSplatX4(const LAllocation& v)
+ {
+ setOperand(0, v);
+ }
+
+ MSimdSplat* mir() const {
+ return mir_->toSimdSplat();
+ }
+};
+
+// Reinterpret the bits of a SIMD value with a different type.
+class LSimdReinterpretCast : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdReinterpretCast)
+ explicit LSimdReinterpretCast(const LAllocation& v)
+ {
+ setOperand(0, v);
+ }
+
+ MSimdReinterpretCast* mir() const {
+ return mir_->toSimdReinterpretCast();
+ }
+};
+
+class LSimdExtractElementBase : public LInstructionHelper<1, 1, 0>
+{
+ protected:
+ explicit LSimdExtractElementBase(const LAllocation& base) {
+ setOperand(0, base);
+ }
+
+ public:
+ const LAllocation* getBase() {
+ return getOperand(0);
+ }
+ MSimdExtractElement* mir() const {
+ return mir_->toSimdExtractElement();
+ }
+};
+
+// Extracts an element from a given SIMD bool32x4 lane.
+class LSimdExtractElementB : public LSimdExtractElementBase
+{
+ public:
+ LIR_HEADER(SimdExtractElementB);
+ explicit LSimdExtractElementB(const LAllocation& base)
+ : LSimdExtractElementBase(base)
+ {}
+};
+
+// Extracts an element from a given SIMD int32x4 lane.
+class LSimdExtractElementI : public LSimdExtractElementBase
+{
+ public:
+ LIR_HEADER(SimdExtractElementI);
+ explicit LSimdExtractElementI(const LAllocation& base)
+ : LSimdExtractElementBase(base)
+ {}
+};
+
+// Extracts an element from a given SIMD float32x4 lane.
+class LSimdExtractElementF : public LSimdExtractElementBase
+{
+ public:
+ LIR_HEADER(SimdExtractElementF);
+ explicit LSimdExtractElementF(const LAllocation& base)
+ : LSimdExtractElementBase(base)
+ {}
+};
+
+// Extracts an element from an Uint32x4 SIMD vector, converts to double.
+class LSimdExtractElementU2D : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(SimdExtractElementU2D);
+ explicit LSimdExtractElementU2D(const LAllocation& base, const LDefinition& temp) {
+ setOperand(0, base);
+ setTemp(0, temp);
+ }
+ MSimdExtractElement* mir() const {
+ return mir_->toSimdExtractElement();
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+
+class LSimdInsertElementBase : public LInstructionHelper<1, 2, 0>
+{
+ protected:
+ LSimdInsertElementBase(const LAllocation& vec, const LAllocation& val)
+ {
+ setOperand(0, vec);
+ setOperand(1, val);
+ }
+
+ public:
+ const LAllocation* vector() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ unsigned lane() const {
+ return mir_->toSimdInsertElement()->lane();
+ }
+ unsigned length() const {
+ return SimdTypeToLength(mir_->toSimdInsertElement()->type());
+ }
+};
+
+// Replace an element from a given SIMD integer or boolean lane with a given value.
+// The value inserted into a boolean lane should be 0 or -1.
+class LSimdInsertElementI : public LSimdInsertElementBase
+{
+ public:
+ LIR_HEADER(SimdInsertElementI);
+ LSimdInsertElementI(const LAllocation& vec, const LAllocation& val)
+ : LSimdInsertElementBase(vec, val)
+ {}
+};
+
+// Replace an element from a given SIMD float32x4 lane with a given value.
+class LSimdInsertElementF : public LSimdInsertElementBase
+{
+ public:
+ LIR_HEADER(SimdInsertElementF);
+ LSimdInsertElementF(const LAllocation& vec, const LAllocation& val)
+ : LSimdInsertElementBase(vec, val)
+ {}
+};
+
+// Base class for both int32x4 and float32x4 shuffle instructions.
+class LSimdSwizzleBase : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ explicit LSimdSwizzleBase(const LAllocation& base)
+ {
+ setOperand(0, base);
+ }
+
+ const LAllocation* getBase() {
+ return getOperand(0);
+ }
+
+ unsigned numLanes() const { return mir_->toSimdSwizzle()->numLanes(); }
+ uint32_t lane(unsigned i) const { return mir_->toSimdSwizzle()->lane(i); }
+
+ bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
+ return mir_->toSimdSwizzle()->lanesMatch(x, y, z, w);
+ }
+};
+
+// Shuffles a int32x4 into another int32x4 vector.
+class LSimdSwizzleI : public LSimdSwizzleBase
+{
+ public:
+ LIR_HEADER(SimdSwizzleI);
+ explicit LSimdSwizzleI(const LAllocation& base) : LSimdSwizzleBase(base)
+ {}
+};
+// Shuffles a float32x4 into another float32x4 vector.
+class LSimdSwizzleF : public LSimdSwizzleBase
+{
+ public:
+ LIR_HEADER(SimdSwizzleF);
+ explicit LSimdSwizzleF(const LAllocation& base) : LSimdSwizzleBase(base)
+ {}
+};
+
+class LSimdGeneralShuffleBase : public LVariadicInstruction<1, 1>
+{
+ public:
+ explicit LSimdGeneralShuffleBase(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+ const LAllocation* vector(unsigned i) {
+ MOZ_ASSERT(i < mir()->numVectors());
+ return getOperand(i);
+ }
+ const LAllocation* lane(unsigned i) {
+ MOZ_ASSERT(i < mir()->numLanes());
+ return getOperand(mir()->numVectors() + i);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MSimdGeneralShuffle* mir() const {
+ return mir_->toSimdGeneralShuffle();
+ }
+};
+
+class LSimdGeneralShuffleI : public LSimdGeneralShuffleBase
+{
+ public:
+ LIR_HEADER(SimdGeneralShuffleI);
+ explicit LSimdGeneralShuffleI(const LDefinition& temp)
+ : LSimdGeneralShuffleBase(temp)
+ {}
+};
+
+class LSimdGeneralShuffleF : public LSimdGeneralShuffleBase
+{
+ public:
+ LIR_HEADER(SimdGeneralShuffleF);
+ explicit LSimdGeneralShuffleF(const LDefinition& temp)
+ : LSimdGeneralShuffleBase(temp)
+ {}
+};
+
+// Base class for both int32x4 and float32x4 shuffle instructions.
+class LSimdShuffleX4 : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(SimdShuffleX4);
+ LSimdShuffleX4()
+ {}
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ uint32_t lane(unsigned i) const { return mir_->toSimdShuffle()->lane(i); }
+
+ bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
+ return mir_->toSimdShuffle()->lanesMatch(x, y, z, w);
+ }
+};
+
+// Remaining shuffles (8x16, 16x8).
+class LSimdShuffle : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(SimdShuffle);
+ LSimdShuffle()
+ {}
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ unsigned numLanes() const { return mir_->toSimdShuffle()->numLanes(); }
+ unsigned lane(unsigned i) const { return mir_->toSimdShuffle()->lane(i); }
+};
+
+// Binary SIMD comparison operation between two SIMD operands
+class LSimdBinaryComp: public LInstructionHelper<1, 2, 0>
+{
+ protected:
+ LSimdBinaryComp() {}
+
+public:
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return getOperand(1);
+ }
+ MSimdBinaryComp::Operation operation() const {
+ return mir_->toSimdBinaryComp()->operation();
+ }
+ const char* extraName() const {
+ return MSimdBinaryComp::OperationName(operation());
+ }
+};
+
+// Binary SIMD comparison operation between two Int8x16 operands.
+class LSimdBinaryCompIx16 : public LSimdBinaryComp
+{
+ public:
+ LIR_HEADER(SimdBinaryCompIx16);
+ LSimdBinaryCompIx16() : LSimdBinaryComp() {}
+};
+
+// Binary SIMD comparison operation between two Int16x8 operands.
+class LSimdBinaryCompIx8 : public LSimdBinaryComp
+{
+ public:
+ LIR_HEADER(SimdBinaryCompIx8);
+ LSimdBinaryCompIx8() : LSimdBinaryComp() {}
+};
+
+// Binary SIMD comparison operation between two Int32x4 operands.
+class LSimdBinaryCompIx4 : public LSimdBinaryComp
+{
+ public:
+ LIR_HEADER(SimdBinaryCompIx4);
+ LSimdBinaryCompIx4() : LSimdBinaryComp() {}
+};
+
+// Binary SIMD comparison operation between two Float32x4 operands
+class LSimdBinaryCompFx4 : public LSimdBinaryComp
+{
+ public:
+ LIR_HEADER(SimdBinaryCompFx4);
+ LSimdBinaryCompFx4() : LSimdBinaryComp() {}
+};
+
+// Binary SIMD arithmetic operation between two SIMD operands
+class LSimdBinaryArith : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LSimdBinaryArith() {}
+
+ const LAllocation* lhs() {
+ return this->getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return this->getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MSimdBinaryArith::Operation operation() const {
+ return this->mir_->toSimdBinaryArith()->operation();
+ }
+ const char* extraName() const {
+ return MSimdBinaryArith::OperationName(operation());
+ }
+};
+
+// Binary SIMD arithmetic operation between two Int8x16 operands
+class LSimdBinaryArithIx16 : public LSimdBinaryArith
+{
+ public:
+ LIR_HEADER(SimdBinaryArithIx16);
+ LSimdBinaryArithIx16() : LSimdBinaryArith() {}
+};
+
+// Binary SIMD arithmetic operation between two Int16x8 operands
+class LSimdBinaryArithIx8 : public LSimdBinaryArith
+{
+ public:
+ LIR_HEADER(SimdBinaryArithIx8);
+ LSimdBinaryArithIx8() : LSimdBinaryArith() {}
+};
+
+// Binary SIMD arithmetic operation between two Int32x4 operands
+class LSimdBinaryArithIx4 : public LSimdBinaryArith
+{
+ public:
+ LIR_HEADER(SimdBinaryArithIx4);
+ LSimdBinaryArithIx4() : LSimdBinaryArith() {}
+};
+
+// Binary SIMD arithmetic operation between two Float32x4 operands
+class LSimdBinaryArithFx4 : public LSimdBinaryArith
+{
+ public:
+ LIR_HEADER(SimdBinaryArithFx4);
+ LSimdBinaryArithFx4() : LSimdBinaryArith() {}
+};
+
+// Binary SIMD saturating arithmetic operation between two SIMD operands
+class LSimdBinarySaturating : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(SimdBinarySaturating);
+ LSimdBinarySaturating() {}
+
+ const LAllocation* lhs() {
+ return this->getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return this->getOperand(1);
+ }
+
+ MSimdBinarySaturating::Operation operation() const {
+ return this->mir_->toSimdBinarySaturating()->operation();
+ }
+ SimdSign signedness() const {
+ return this->mir_->toSimdBinarySaturating()->signedness();
+ }
+ MIRType type() const {
+ return mir_->type();
+ }
+ const char* extraName() const {
+ return MSimdBinarySaturating::OperationName(operation());
+ }
+};
+
+// Unary SIMD arithmetic operation on a SIMD operand
+class LSimdUnaryArith : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ explicit LSimdUnaryArith(const LAllocation& in) {
+ setOperand(0, in);
+ }
+ MSimdUnaryArith::Operation operation() const {
+ return mir_->toSimdUnaryArith()->operation();
+ }
+};
+
+// Unary SIMD arithmetic operation on a Int8x16 operand
+class LSimdUnaryArithIx16 : public LSimdUnaryArith
+{
+ public:
+ LIR_HEADER(SimdUnaryArithIx16);
+ explicit LSimdUnaryArithIx16(const LAllocation& in) : LSimdUnaryArith(in) {}
+};
+
+// Unary SIMD arithmetic operation on a Int16x8 operand
+class LSimdUnaryArithIx8 : public LSimdUnaryArith
+{
+ public:
+ LIR_HEADER(SimdUnaryArithIx8);
+ explicit LSimdUnaryArithIx8(const LAllocation& in) : LSimdUnaryArith(in) {}
+};
+
+// Unary SIMD arithmetic operation on a Int32x4 operand
+class LSimdUnaryArithIx4 : public LSimdUnaryArith
+{
+ public:
+ LIR_HEADER(SimdUnaryArithIx4);
+ explicit LSimdUnaryArithIx4(const LAllocation& in) : LSimdUnaryArith(in) {}
+};
+
+// Unary SIMD arithmetic operation on a Float32x4 operand
+class LSimdUnaryArithFx4 : public LSimdUnaryArith
+{
+ public:
+ LIR_HEADER(SimdUnaryArithFx4);
+ explicit LSimdUnaryArithFx4(const LAllocation& in) : LSimdUnaryArith(in) {}
+};
+
+// Binary SIMD bitwise operation between two 128-bit operands.
+class LSimdBinaryBitwise : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(SimdBinaryBitwise);
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return getOperand(1);
+ }
+ MSimdBinaryBitwise::Operation operation() const {
+ return mir_->toSimdBinaryBitwise()->operation();
+ }
+ const char* extraName() const {
+ return MSimdBinaryBitwise::OperationName(operation());
+ }
+ MIRType type() const {
+ return mir_->type();
+ }
+};
+
+// Shift a SIMD vector by a scalar amount.
+// The temp register is only required if the shift amount is a dynamical
+// value. If it is a constant, use a BogusTemp instead.
+class LSimdShift : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(SimdShift)
+ LSimdShift(const LAllocation& vec, const LAllocation& val, const LDefinition& temp) {
+ setOperand(0, vec);
+ setOperand(1, val);
+ setTemp(0, temp);
+ }
+ const LAllocation* vector() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MSimdShift::Operation operation() const {
+ return mir_->toSimdShift()->operation();
+ }
+ const char* extraName() const {
+ return MSimdShift::OperationName(operation());
+ }
+ MSimdShift* mir() const {
+ return mir_->toSimdShift();
+ }
+ MIRType type() const {
+ return mir_->type();
+ }
+};
+
+// SIMD selection of lanes from two int32x4 or float32x4 arguments based on a
+// int32x4 argument.
+class LSimdSelect : public LInstructionHelper<1, 3, 1>
+{
+ public:
+ LIR_HEADER(SimdSelect);
+ const LAllocation* mask() {
+ return getOperand(0);
+ }
+ const LAllocation* lhs() {
+ return getOperand(1);
+ }
+ const LAllocation* rhs() {
+ return getOperand(2);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MSimdSelect* mir() const {
+ return mir_->toSimdSelect();
+ }
+};
+
+class LSimdAnyTrue : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdAnyTrue)
+ explicit LSimdAnyTrue(const LAllocation& input) {
+ setOperand(0, input);
+ }
+ const LAllocation* vector() {
+ return getOperand(0);
+ }
+ MSimdAnyTrue* mir() const {
+ return mir_->toSimdAnyTrue();
+ }
+};
+
+class LSimdAllTrue : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SimdAllTrue)
+ explicit LSimdAllTrue(const LAllocation& input) {
+ setOperand(0, input);
+ }
+ const LAllocation* vector() {
+ return getOperand(0);
+ }
+ MSimdAllTrue* mir() const {
+ return mir_->toSimdAllTrue();
+ }
+};
+
+
+// Constant 32-bit integer.
+class LInteger : public LInstructionHelper<1, 0, 0>
+{
+ int32_t i32_;
+
+ public:
+ LIR_HEADER(Integer)
+
+ explicit LInteger(int32_t i32)
+ : i32_(i32)
+ { }
+
+ int32_t getValue() const {
+ return i32_;
+ }
+};
+
+// Constant 64-bit integer.
+class LInteger64 : public LInstructionHelper<INT64_PIECES, 0, 0>
+{
+ int64_t i64_;
+
+ public:
+ LIR_HEADER(Integer64)
+
+ explicit LInteger64(int64_t i64)
+ : i64_(i64)
+ { }
+
+ int64_t getValue() const {
+ return i64_;
+ }
+};
+
+// Constant pointer.
+class LPointer : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ enum Kind {
+ GC_THING,
+ NON_GC_THING
+ };
+
+ private:
+ void* ptr_;
+ Kind kind_;
+
+ public:
+ LIR_HEADER(Pointer)
+
+ explicit LPointer(gc::Cell* ptr)
+ : ptr_(ptr), kind_(GC_THING)
+ { }
+
+ LPointer(void* ptr, Kind kind)
+ : ptr_(ptr), kind_(kind)
+ { }
+
+ void* ptr() const {
+ return ptr_;
+ }
+ Kind kind() const {
+ return kind_;
+ }
+ const char* extraName() const {
+ return kind_ == GC_THING ? "GC_THING" : "NON_GC_THING";
+ }
+
+ gc::Cell* gcptr() const {
+ MOZ_ASSERT(kind() == GC_THING);
+ return (gc::Cell*) ptr_;
+ }
+};
+
+// Constant double.
+class LDouble : public LInstructionHelper<1, 0, 0>
+{
+ wasm::RawF64 d_;
+ public:
+ LIR_HEADER(Double);
+
+ explicit LDouble(wasm::RawF64 d) : d_(d)
+ { }
+
+ wasm::RawF64 getDouble() const {
+ return d_;
+ }
+};
+
+// Constant float32.
+class LFloat32 : public LInstructionHelper<1, 0, 0>
+{
+ wasm::RawF32 f_;
+ public:
+ LIR_HEADER(Float32);
+
+ explicit LFloat32(wasm::RawF32 f)
+ : f_(f)
+ { }
+
+ wasm::RawF32 getFloat() const {
+ return f_;
+ }
+};
+
+// Constant 128-bit SIMD integer vector (8x16, 16x8, 32x4).
+// Also used for Bool32x4, Bool16x8, etc.
+class LSimd128Int : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(Simd128Int);
+
+ explicit LSimd128Int() {}
+ const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
+};
+
+// Constant 128-bit SIMD floating point vector (32x4, 64x2).
+class LSimd128Float : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(Simd128Float);
+
+ explicit LSimd128Float() {}
+ const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
+};
+
+// A constant Value.
+class LValue : public LInstructionHelper<BOX_PIECES, 0, 0>
+{
+ Value v_;
+
+ public:
+ LIR_HEADER(Value)
+
+ explicit LValue(const Value& v)
+ : v_(v)
+ { }
+
+ Value value() const {
+ return v_;
+ }
+};
+
+// Clone an object literal such as we are not modifying the object contained in
+// the sources.
+class LCloneLiteral : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CloneLiteral)
+
+ explicit LCloneLiteral(const LAllocation& obj)
+ {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* getObjectLiteral() {
+ return getOperand(0);
+ }
+
+ MCloneLiteral* mir() const {
+ return mir_->toCloneLiteral();
+ }
+};
+
+// Formal argument for a function, returning a box. Formal arguments are
+// initially read from the stack.
+class LParameter : public LInstructionHelper<BOX_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(Parameter)
+};
+
+// Stack offset for a word-sized immutable input value to a frame.
+class LCallee : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(Callee)
+};
+
+class LIsConstructing : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(IsConstructing)
+};
+
+// Base class for control instructions (goto, branch, etc.)
+template <size_t Succs, size_t Operands, size_t Temps>
+class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> {
+
+ mozilla::Array<MBasicBlock*, Succs> successors_;
+
+ public:
+ virtual size_t numSuccessors() const final override { return Succs; }
+
+ virtual MBasicBlock* getSuccessor(size_t i) const final override {
+ return successors_[i];
+ }
+
+ virtual void setSuccessor(size_t i, MBasicBlock* successor) final override {
+ successors_[i] = successor;
+ }
+};
+
+// Jumps to the start of a basic block.
+class LGoto : public LControlInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(Goto)
+
+ explicit LGoto(MBasicBlock* block)
+ {
+ setSuccessor(0, block);
+ }
+
+ MBasicBlock* target() const {
+ return getSuccessor(0);
+ }
+};
+
+class LNewArray : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewArray)
+
+ explicit LNewArray(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const char* extraName() const {
+ return mir()->isVMCall() ? "VMCall" : nullptr;
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewArray* mir() const {
+ return mir_->toNewArray();
+ }
+};
+
+class LNewArrayCopyOnWrite : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewArrayCopyOnWrite)
+
+ explicit LNewArrayCopyOnWrite(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewArrayCopyOnWrite* mir() const {
+ return mir_->toNewArrayCopyOnWrite();
+ }
+};
+
+class LNewArrayDynamicLength : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(NewArrayDynamicLength)
+
+ explicit LNewArrayDynamicLength(const LAllocation& length, const LDefinition& temp) {
+ setOperand(0, length);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* length() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewArrayDynamicLength* mir() const {
+ return mir_->toNewArrayDynamicLength();
+ }
+};
+
+class LNewTypedArray : public LInstructionHelper<1, 0, 2>
+{
+ public:
+ LIR_HEADER(NewTypedArray)
+
+ explicit LNewTypedArray(const LDefinition& temp1, const LDefinition& temp2) {
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+
+ MNewTypedArray* mir() const {
+ return mir_->toNewTypedArray();
+ }
+};
+
+class LNewTypedArrayDynamicLength : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(NewTypedArrayDynamicLength)
+
+ explicit LNewTypedArrayDynamicLength(const LAllocation& length, const LDefinition& temp) {
+ setOperand(0, length);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* length() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewTypedArrayDynamicLength* mir() const {
+ return mir_->toNewTypedArrayDynamicLength();
+ }
+};
+
+class LNewObject : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewObject)
+
+ explicit LNewObject(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const char* extraName() const {
+ return mir()->isVMCall() ? "VMCall" : nullptr;
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewObject* mir() const {
+ return mir_->toNewObject();
+ }
+};
+
+class LNewTypedObject : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewTypedObject)
+
+ explicit LNewTypedObject(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewTypedObject* mir() const {
+ return mir_->toNewTypedObject();
+ }
+};
+
+// Allocates a new NamedLambdaObject.
+//
+// This instruction generates two possible instruction sets:
+// (1) An inline allocation of the call object is attempted.
+// (2) Otherwise, a callVM create a new object.
+//
+class LNewNamedLambdaObject : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewNamedLambdaObject);
+
+ explicit LNewNamedLambdaObject(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewNamedLambdaObject* mir() const {
+ return mir_->toNewNamedLambdaObject();
+ }
+};
+
+// Allocates a new CallObject.
+//
+// This instruction generates two possible instruction sets:
+// (1) If the call object is extensible, this is a callVM to create the
+// call object.
+// (2) Otherwise, an inline allocation of the call object is attempted.
+//
+class LNewCallObject : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewCallObject)
+
+ explicit LNewCallObject(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+
+ MNewCallObject* mir() const {
+ return mir_->toNewCallObject();
+ }
+};
+
+// Performs a callVM to allocate a new CallObject with singleton type.
+class LNewSingletonCallObject : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(NewSingletonCallObject)
+
+ explicit LNewSingletonCallObject(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MNewSingletonCallObject* mir() const {
+ return mir_->toNewSingletonCallObject();
+ }
+};
+
+class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
+{
+ public:
+ LIR_HEADER(NewDerivedTypedObject);
+
+ LNewDerivedTypedObject(const LAllocation& type,
+ const LAllocation& owner,
+ const LAllocation& offset) {
+ setOperand(0, type);
+ setOperand(1, owner);
+ setOperand(2, offset);
+ }
+
+ const LAllocation* type() {
+ return getOperand(0);
+ }
+
+ const LAllocation* owner() {
+ return getOperand(1);
+ }
+
+ const LAllocation* offset() {
+ return getOperand(2);
+ }
+};
+
+class LNewStringObject : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(NewStringObject)
+
+ LNewStringObject(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MNewStringObject* mir() const {
+ return mir_->toNewStringObject();
+ }
+};
+
+class LInitElem : public LCallInstructionHelper<0, 1 + 2*BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(InitElem)
+
+ LInitElem(const LAllocation& object, const LBoxAllocation& id, const LBoxAllocation& value) {
+ setOperand(0, object);
+ setBoxOperand(IdIndex, id);
+ setBoxOperand(ValueIndex, value);
+ }
+
+ static const size_t IdIndex = 1;
+ static const size_t ValueIndex = 1 + BOX_PIECES;
+
+ const LAllocation* getObject() {
+ return getOperand(0);
+ }
+ MInitElem* mir() const {
+ return mir_->toInitElem();
+ }
+};
+
+class LInitElemGetterSetter : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(InitElemGetterSetter)
+
+ LInitElemGetterSetter(const LAllocation& object, const LBoxAllocation& id,
+ const LAllocation& value) {
+ setOperand(0, object);
+ setOperand(1, value);
+ setBoxOperand(IdIndex, id);
+ }
+
+ static const size_t IdIndex = 2;
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ MInitElemGetterSetter* mir() const {
+ return mir_->toInitElemGetterSetter();
+ }
+};
+
+// Takes in an Object and a Value.
+class LMutateProto : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(MutateProto)
+
+ LMutateProto(const LAllocation& object, const LBoxAllocation& value) {
+ setOperand(0, object);
+ setBoxOperand(ValueIndex, value);
+ }
+
+ static const size_t ValueIndex = 1;
+
+ const LAllocation* getObject() {
+ return getOperand(0);
+ }
+ const LAllocation* getValue() {
+ return getOperand(1);
+ }
+};
+
+// Takes in an Object and a Value.
+class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(InitProp)
+
+ LInitProp(const LAllocation& object, const LBoxAllocation& value) {
+ setOperand(0, object);
+ setBoxOperand(ValueIndex, value);
+ }
+
+ static const size_t ValueIndex = 1;
+
+ const LAllocation* getObject() {
+ return getOperand(0);
+ }
+ const LAllocation* getValue() {
+ return getOperand(1);
+ }
+
+ MInitProp* mir() const {
+ return mir_->toInitProp();
+ }
+};
+
+class LInitPropGetterSetter : public LCallInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(InitPropGetterSetter)
+
+ LInitPropGetterSetter(const LAllocation& object, const LAllocation& value) {
+ setOperand(0, object);
+ setOperand(1, value);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+
+ MInitPropGetterSetter* mir() const {
+ return mir_->toInitPropGetterSetter();
+ }
+};
+
+class LCheckOverRecursed : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(CheckOverRecursed)
+
+ LCheckOverRecursed()
+ { }
+
+ MCheckOverRecursed* mir() const {
+ return mir_->toCheckOverRecursed();
+ }
+};
+
+class LWasmTrap : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(WasmTrap);
+
+ LWasmTrap()
+ { }
+
+ const MWasmTrap* mir() const {
+ return mir_->toWasmTrap();
+ }
+};
+
+template<size_t Defs, size_t Ops>
+class LWasmReinterpretBase : public LInstructionHelper<Defs, Ops, 0>
+{
+ typedef LInstructionHelper<Defs, Ops, 0> Base;
+
+ public:
+ const LAllocation* input() {
+ return Base::getOperand(0);
+ }
+ MWasmReinterpret* mir() const {
+ return Base::mir_->toWasmReinterpret();
+ }
+};
+
+class LWasmReinterpret : public LWasmReinterpretBase<1, 1>
+{
+ public:
+ LIR_HEADER(WasmReinterpret);
+ explicit LWasmReinterpret(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+class LWasmReinterpretFromI64 : public LWasmReinterpretBase<1, INT64_PIECES>
+{
+ public:
+ LIR_HEADER(WasmReinterpretFromI64);
+ explicit LWasmReinterpretFromI64(const LInt64Allocation& input) {
+ setInt64Operand(0, input);
+ }
+};
+
+class LWasmReinterpretToI64 : public LWasmReinterpretBase<INT64_PIECES, 1>
+{
+ public:
+ LIR_HEADER(WasmReinterpretToI64);
+ explicit LWasmReinterpretToI64(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+namespace details {
+ template<size_t Defs, size_t Ops, size_t Temps>
+ class RotateBase : public LInstructionHelper<Defs, Ops, Temps>
+ {
+ typedef LInstructionHelper<Defs, Ops, Temps> Base;
+ public:
+ MRotate* mir() {
+ return Base::mir_->toRotate();
+ }
+ };
+} // details
+
+class LRotate : public details::RotateBase<1, 2, 0>
+{
+ public:
+ LIR_HEADER(Rotate);
+
+ const LAllocation* input() { return getOperand(0); }
+ LAllocation* count() { return getOperand(1); }
+};
+
+class LRotateI64 : public details::RotateBase<INT64_PIECES, INT64_PIECES + 1, 1>
+{
+ public:
+ LIR_HEADER(RotateI64);
+
+ LRotateI64()
+ {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ static const size_t Input = 0;
+ static const size_t Count = INT64_PIECES;
+
+ const LInt64Allocation input() { return getInt64Operand(Input); }
+ const LDefinition* temp() { return getTemp(0); }
+ LAllocation* count() { return getOperand(Count); }
+};
+
+class LInterruptCheck : public LInstructionHelper<0, 0, 0>
+{
+ Label* oolEntry_;
+
+ // Whether this is an implicit interrupt check. Implicit interrupt checks
+ // use a patchable backedge and signal handlers instead of an explicit
+ // rt->interrupt check.
+ bool implicit_;
+
+ public:
+ LIR_HEADER(InterruptCheck)
+
+ LInterruptCheck()
+ : oolEntry_(nullptr),
+ implicit_(false)
+ {}
+
+ Label* oolEntry() {
+ MOZ_ASSERT(implicit_);
+ return oolEntry_;
+ }
+
+ void setOolEntry(Label* oolEntry) {
+ MOZ_ASSERT(implicit_);
+ oolEntry_ = oolEntry;
+ }
+ MInterruptCheck* mir() const {
+ return mir_->toInterruptCheck();
+ }
+
+ void setImplicit() {
+ implicit_ = true;
+ }
+ bool implicit() const {
+ return implicit_;
+ }
+};
+
+class LDefVar : public LCallInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(DefVar)
+
+ explicit LDefVar(const LAllocation& envChain)
+ {
+ setOperand(0, envChain);
+ }
+
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ MDefVar* mir() const {
+ return mir_->toDefVar();
+ }
+};
+
+class LDefLexical : public LCallInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(DefLexical)
+
+ MDefLexical* mir() const {
+ return mir_->toDefLexical();
+ }
+};
+
+class LDefFun : public LCallInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(DefFun)
+
+ LDefFun(const LAllocation& fun, const LAllocation& envChain)
+ {
+ setOperand(0, fun);
+ setOperand(1, envChain);
+ }
+
+ const LAllocation* fun() {
+ return getOperand(0);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(1);
+ }
+ MDefFun* mir() const {
+ return mir_->toDefFun();
+ }
+};
+
+class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(TypeOfV)
+
+ LTypeOfV(const LBoxAllocation& input, const LDefinition& tempToUnbox) {
+ setBoxOperand(Input, input);
+ setTemp(0, tempToUnbox);
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* tempToUnbox() {
+ return getTemp(0);
+ }
+
+ MTypeOf* mir() const {
+ return mir_->toTypeOf();
+ }
+};
+
+class LToAsync : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ToAsync)
+ explicit LToAsync(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* unwrapped() {
+ return getOperand(0);
+ }
+};
+
+class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(ToIdV)
+
+ LToIdV(const LBoxAllocation& input, const LDefinition& temp)
+ {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 0;
+
+ MToId* mir() const {
+ return mir_->toToId();
+ }
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+};
+
+// Allocate an object for |new| on the caller-side,
+// when there is no templateObject or prototype known
+class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 2, 0>
+{
+ public:
+ LIR_HEADER(CreateThis)
+
+ LCreateThis(const LAllocation& callee, const LAllocation& newTarget)
+ {
+ setOperand(0, callee);
+ setOperand(1, newTarget);
+ }
+
+ const LAllocation* getCallee() {
+ return getOperand(0);
+ }
+ const LAllocation* getNewTarget() {
+ return getOperand(1);
+ }
+
+ MCreateThis* mir() const {
+ return mir_->toCreateThis();
+ }
+};
+
+// Allocate an object for |new| on the caller-side,
+// when the prototype is known.
+class LCreateThisWithProto : public LCallInstructionHelper<1, 3, 0>
+{
+ public:
+ LIR_HEADER(CreateThisWithProto)
+
+ LCreateThisWithProto(const LAllocation& callee, const LAllocation& newTarget,
+ const LAllocation& prototype)
+ {
+ setOperand(0, callee);
+ setOperand(1, newTarget);
+ setOperand(2, prototype);
+ }
+
+ const LAllocation* getCallee() {
+ return getOperand(0);
+ }
+ const LAllocation* getNewTarget() {
+ return getOperand(1);
+ }
+ const LAllocation* getPrototype() {
+ return getOperand(2);
+ }
+
+ MCreateThis* mir() const {
+ return mir_->toCreateThis();
+ }
+};
+
+// Allocate an object for |new| on the caller-side.
+// Always performs object initialization with a fast path.
+class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 1>
+{
+ public:
+ LIR_HEADER(CreateThisWithTemplate)
+
+ explicit LCreateThisWithTemplate(const LDefinition& temp) {
+ setTemp(0, temp);
+ }
+
+ MCreateThisWithTemplate* mir() const {
+ return mir_->toCreateThisWithTemplate();
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Allocate a new arguments object for the frame.
+class LCreateArgumentsObject : public LCallInstructionHelper<1, 1, 3>
+{
+ public:
+ LIR_HEADER(CreateArgumentsObject)
+
+ LCreateArgumentsObject(const LAllocation& callObj, const LDefinition& temp0,
+ const LDefinition& temp1, const LDefinition& temp2)
+ {
+ setOperand(0, callObj);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+ const LDefinition* temp2() {
+ return getTemp(2);
+ }
+
+ const LAllocation* getCallObject() {
+ return getOperand(0);
+ }
+
+ MCreateArgumentsObject* mir() const {
+ return mir_->toCreateArgumentsObject();
+ }
+};
+
+// Get argument from arguments object.
+class LGetArgumentsObjectArg : public LInstructionHelper<BOX_PIECES, 1, 1>
+{
+ public:
+ LIR_HEADER(GetArgumentsObjectArg)
+
+ LGetArgumentsObjectArg(const LAllocation& argsObj, const LDefinition& temp)
+ {
+ setOperand(0, argsObj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* getArgsObject() {
+ return getOperand(0);
+ }
+
+ MGetArgumentsObjectArg* mir() const {
+ return mir_->toGetArgumentsObjectArg();
+ }
+};
+
+// Set argument on arguments object.
+class LSetArgumentsObjectArg : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(SetArgumentsObjectArg)
+
+ LSetArgumentsObjectArg(const LAllocation& argsObj, const LBoxAllocation& value,
+ const LDefinition& temp)
+ {
+ setOperand(0, argsObj);
+ setBoxOperand(ValueIndex, value);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* getArgsObject() {
+ return getOperand(0);
+ }
+
+ MSetArgumentsObjectArg* mir() const {
+ return mir_->toSetArgumentsObjectArg();
+ }
+
+ static const size_t ValueIndex = 1;
+};
+
+// If the Value is an Object, return unbox(Value).
+// Otherwise, return the other Object.
+class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0>
+{
+ public:
+ LIR_HEADER(ReturnFromCtor)
+
+ LReturnFromCtor(const LBoxAllocation& value, const LAllocation& object)
+ {
+ setBoxOperand(ValueIndex, value);
+ setOperand(ObjectIndex, object);
+ }
+
+ const LAllocation* getObject() {
+ return getOperand(ObjectIndex);
+ }
+
+ static const size_t ValueIndex = 0;
+ static const size_t ObjectIndex = BOX_PIECES;
+};
+
+class LComputeThis : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(ComputeThis)
+
+ static const size_t ValueIndex = 0;
+
+ explicit LComputeThis(const LBoxAllocation& value) {
+ setBoxOperand(ValueIndex, value);
+ }
+
+ const LDefinition* output() {
+ return getDef(0);
+ }
+
+ MComputeThis* mir() const {
+ return mir_->toComputeThis();
+ }
+};
+
+// Writes a typed argument for a function call to the frame's argument vector.
+class LStackArgT : public LInstructionHelper<0, 1, 0>
+{
+ uint32_t argslot_; // Index into frame-scope argument vector.
+ MIRType type_;
+
+ public:
+ LIR_HEADER(StackArgT)
+
+ LStackArgT(uint32_t argslot, MIRType type, const LAllocation& arg)
+ : argslot_(argslot),
+ type_(type)
+ {
+ setOperand(0, arg);
+ }
+ uint32_t argslot() const {
+ return argslot_;
+ }
+ MIRType type() const {
+ return type_;
+ }
+ const LAllocation* getArgument() {
+ return getOperand(0);
+ }
+};
+
+// Writes an untyped argument for a function call to the frame's argument vector.
+class LStackArgV : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+ uint32_t argslot_; // Index into frame-scope argument vector.
+
+ public:
+ LIR_HEADER(StackArgV)
+
+ LStackArgV(uint32_t argslot, const LBoxAllocation& value)
+ : argslot_(argslot)
+ {
+ setBoxOperand(0, value);
+ }
+
+ uint32_t argslot() const {
+ return argslot_;
+ }
+};
+
+// Common code for LIR descended from MCall.
+template <size_t Defs, size_t Operands, size_t Temps>
+class LJSCallInstructionHelper : public LCallInstructionHelper<Defs, Operands, Temps>
+{
+ public:
+ uint32_t argslot() const {
+ if (JitStackValueAlignment > 1)
+ return AlignBytes(mir()->numStackArgs(), JitStackValueAlignment);
+ return mir()->numStackArgs();
+ }
+ MCall* mir() const {
+ return this->mir_->toCall();
+ }
+
+ bool hasSingleTarget() const {
+ return getSingleTarget() != nullptr;
+ }
+ WrappedFunction* getSingleTarget() const {
+ return mir()->getSingleTarget();
+ }
+
+ // Does not include |this|.
+ uint32_t numActualArgs() const {
+ return mir()->numActualArgs();
+ }
+
+ bool isConstructing() const {
+ return mir()->isConstructing();
+ }
+};
+
+// Generates a polymorphic callsite, wherein the function being called is
+// unknown and anticipated to vary.
+class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2>
+{
+ public:
+ LIR_HEADER(CallGeneric)
+
+ LCallGeneric(const LAllocation& func, const LDefinition& nargsreg,
+ const LDefinition& tmpobjreg)
+ {
+ setOperand(0, func);
+ setTemp(0, nargsreg);
+ setTemp(1, tmpobjreg);
+ }
+
+ const LAllocation* getFunction() {
+ return getOperand(0);
+ }
+ const LDefinition* getNargsReg() {
+ return getTemp(0);
+ }
+ const LDefinition* getTempObject() {
+ return getTemp(1);
+ }
+};
+
+// Generates a hardcoded callsite for a known, non-native target.
+class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1>
+{
+ public:
+ LIR_HEADER(CallKnown)
+
+ LCallKnown(const LAllocation& func, const LDefinition& tmpobjreg)
+ {
+ setOperand(0, func);
+ setTemp(0, tmpobjreg);
+ }
+
+ const LAllocation* getFunction() {
+ return getOperand(0);
+ }
+ const LDefinition* getTempObject() {
+ return getTemp(0);
+ }
+};
+
+// Generates a hardcoded callsite for a known, native target.
+class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4>
+{
+ public:
+ LIR_HEADER(CallNative)
+
+ LCallNative(const LDefinition& argContext, const LDefinition& argUintN,
+ const LDefinition& argVp, const LDefinition& tmpreg)
+ {
+ // Registers used for callWithABI().
+ setTemp(0, argContext);
+ setTemp(1, argUintN);
+ setTemp(2, argVp);
+
+ // Temporary registers.
+ setTemp(3, tmpreg);
+ }
+
+ const LDefinition* getArgContextReg() {
+ return getTemp(0);
+ }
+ const LDefinition* getArgUintNReg() {
+ return getTemp(1);
+ }
+ const LDefinition* getArgVpReg() {
+ return getTemp(2);
+ }
+ const LDefinition* getTempReg() {
+ return getTemp(3);
+ }
+};
+
+// Generates a hardcoded callsite for a known, DOM-native target.
+class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4>
+{
+ public:
+ LIR_HEADER(CallDOMNative)
+
+ LCallDOMNative(const LDefinition& argJSContext, const LDefinition& argObj,
+ const LDefinition& argPrivate, const LDefinition& argArgs)
+ {
+ setTemp(0, argJSContext);
+ setTemp(1, argObj);
+ setTemp(2, argPrivate);
+ setTemp(3, argArgs);
+ }
+
+ const LDefinition* getArgJSContext() {
+ return getTemp(0);
+ }
+ const LDefinition* getArgObj() {
+ return getTemp(1);
+ }
+ const LDefinition* getArgPrivate() {
+ return getTemp(2);
+ }
+ const LDefinition* getArgArgs() {
+ return getTemp(3);
+ }
+};
+
+class LBail : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(Bail)
+};
+
+class LUnreachable : public LControlInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(Unreachable)
+};
+
+class LEncodeSnapshot : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(EncodeSnapshot)
+};
+
+template <size_t defs, size_t ops>
+class LDOMPropertyInstructionHelper : public LCallInstructionHelper<defs, 1 + ops, 3>
+{
+ protected:
+ LDOMPropertyInstructionHelper(const LDefinition& JSContextReg, const LAllocation& ObjectReg,
+ const LDefinition& PrivReg, const LDefinition& ValueReg)
+ {
+ this->setOperand(0, ObjectReg);
+ this->setTemp(0, JSContextReg);
+ this->setTemp(1, PrivReg);
+ this->setTemp(2, ValueReg);
+ }
+
+ public:
+ const LDefinition* getJSContextReg() {
+ return this->getTemp(0);
+ }
+ const LAllocation* getObjectReg() {
+ return this->getOperand(0);
+ }
+ const LDefinition* getPrivReg() {
+ return this->getTemp(1);
+ }
+ const LDefinition* getValueReg() {
+ return this->getTemp(2);
+ }
+};
+
+
+class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(GetDOMProperty)
+
+ LGetDOMProperty(const LDefinition& JSContextReg, const LAllocation& ObjectReg,
+ const LDefinition& PrivReg, const LDefinition& ValueReg)
+ : LDOMPropertyInstructionHelper<BOX_PIECES, 0>(JSContextReg, ObjectReg,
+ PrivReg, ValueReg)
+ { }
+
+ MGetDOMProperty* mir() const {
+ return mir_->toGetDOMProperty();
+ }
+};
+
+class LGetDOMMemberV : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(GetDOMMemberV);
+ explicit LGetDOMMemberV(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ MGetDOMMember* mir() const {
+ return mir_->toGetDOMMember();
+ }
+};
+
+class LGetDOMMemberT : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(GetDOMMemberT);
+ explicit LGetDOMMemberT(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ MGetDOMMember* mir() const {
+ return mir_->toGetDOMMember();
+ }
+};
+
+class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES>
+{
+ public:
+ LIR_HEADER(SetDOMProperty)
+
+ LSetDOMProperty(const LDefinition& JSContextReg, const LAllocation& ObjectReg,
+ const LBoxAllocation& value, const LDefinition& PrivReg,
+ const LDefinition& ValueReg)
+ : LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg,
+ PrivReg, ValueReg)
+ {
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ MSetDOMProperty* mir() const {
+ return mir_->toSetDOMProperty();
+ }
+};
+
+// Generates a polymorphic callsite, wherein the function being called is
+// unknown and anticipated to vary.
+class LApplyArgsGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2>
+{
+ public:
+ LIR_HEADER(ApplyArgsGeneric)
+
+ LApplyArgsGeneric(const LAllocation& func, const LAllocation& argc,
+ const LBoxAllocation& thisv, const LDefinition& tmpobjreg,
+ const LDefinition& tmpcopy)
+ {
+ setOperand(0, func);
+ setOperand(1, argc);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ setTemp(1, tmpcopy);
+ }
+
+ MApplyArgs* mir() const {
+ return mir_->toApplyArgs();
+ }
+
+ bool hasSingleTarget() const {
+ return getSingleTarget() != nullptr;
+ }
+ WrappedFunction* getSingleTarget() const {
+ return mir()->getSingleTarget();
+ }
+
+ const LAllocation* getFunction() {
+ return getOperand(0);
+ }
+ const LAllocation* getArgc() {
+ return getOperand(1);
+ }
+ static const size_t ThisIndex = 2;
+
+ const LDefinition* getTempObject() {
+ return getTemp(0);
+ }
+ const LDefinition* getTempStackCounter() {
+ return getTemp(1);
+ }
+};
+
+class LApplyArrayGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2>
+{
+ public:
+ LIR_HEADER(ApplyArrayGeneric)
+
+ LApplyArrayGeneric(const LAllocation& func, const LAllocation& elements,
+ const LBoxAllocation& thisv, const LDefinition& tmpobjreg,
+ const LDefinition& tmpcopy)
+ {
+ setOperand(0, func);
+ setOperand(1, elements);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ setTemp(1, tmpcopy);
+ }
+
+ MApplyArray* mir() const {
+ return mir_->toApplyArray();
+ }
+
+ bool hasSingleTarget() const {
+ return getSingleTarget() != nullptr;
+ }
+ WrappedFunction* getSingleTarget() const {
+ return mir()->getSingleTarget();
+ }
+
+ const LAllocation* getFunction() {
+ return getOperand(0);
+ }
+ const LAllocation* getElements() {
+ return getOperand(1);
+ }
+ // argc is mapped to the same register as elements: argc becomes
+ // live as elements is dying, all registers are calltemps.
+ const LAllocation* getArgc() {
+ return getOperand(1);
+ }
+ static const size_t ThisIndex = 2;
+
+ const LDefinition* getTempObject() {
+ return getTemp(0);
+ }
+ const LDefinition* getTempStackCounter() {
+ return getTemp(1);
+ }
+};
+
+class LArraySplice : public LCallInstructionHelper<0, 3, 0>
+{
+ public:
+ LIR_HEADER(ArraySplice)
+
+ LArraySplice(const LAllocation& object, const LAllocation& start,
+ const LAllocation& deleteCount)
+ {
+ setOperand(0, object);
+ setOperand(1, start);
+ setOperand(2, deleteCount);
+ }
+
+ MArraySplice* mir() const {
+ return mir_->toArraySplice();
+ }
+
+ const LAllocation* getObject() {
+ return getOperand(0);
+ }
+ const LAllocation* getStart() {
+ return getOperand(1);
+ }
+ const LAllocation* getDeleteCount() {
+ return getOperand(2);
+ }
+};
+
+class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
+{
+ public:
+ LIR_HEADER(GetDynamicName)
+
+ LGetDynamicName(const LAllocation& envChain, const LAllocation& name,
+ const LDefinition& temp1, const LDefinition& temp2, const LDefinition& temp3)
+ {
+ setOperand(0, envChain);
+ setOperand(1, name);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ MGetDynamicName* mir() const {
+ return mir_->toGetDynamicName();
+ }
+
+ const LAllocation* getEnvironmentChain() {
+ return getOperand(0);
+ }
+ const LAllocation* getName() {
+ return getOperand(1);
+ }
+
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+ const LDefinition* temp3() {
+ return getTemp(2);
+ }
+};
+
+class LCallDirectEval : public LCallInstructionHelper<BOX_PIECES, 2 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallDirectEval)
+
+ LCallDirectEval(const LAllocation& envChain, const LAllocation& string,
+ const LBoxAllocation& newTarget)
+ {
+ setOperand(0, envChain);
+ setOperand(1, string);
+ setBoxOperand(NewTarget, newTarget);
+ }
+
+ static const size_t NewTarget = 2;
+
+ MCallDirectEval* mir() const {
+ return mir_->toCallDirectEval();
+ }
+
+ const LAllocation* getEnvironmentChain() {
+ return getOperand(0);
+ }
+ const LAllocation* getString() {
+ return getOperand(1);
+ }
+};
+
+// Takes in either an integer or boolean input and tests it for truthiness.
+class LTestIAndBranch : public LControlInstructionHelper<2, 1, 0>
+{
+ public:
+ LIR_HEADER(TestIAndBranch)
+
+ LTestIAndBranch(const LAllocation& in, MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+// Takes in an int64 input and tests it for truthiness.
+class LTestI64AndBranch : public LControlInstructionHelper<2, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(TestI64AndBranch)
+
+ LTestI64AndBranch(const LInt64Allocation& in, MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ {
+ setInt64Operand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+// Takes in either an integer or boolean input and tests it for truthiness.
+class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0>
+{
+ public:
+ LIR_HEADER(TestDAndBranch)
+
+ LTestDAndBranch(const LAllocation& in, MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+// Takes in either an integer or boolean input and tests it for truthiness.
+class LTestFAndBranch : public LControlInstructionHelper<2, 1, 0>
+{
+ public:
+ LIR_HEADER(TestFAndBranch)
+
+ LTestFAndBranch(const LAllocation& in, MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ {
+ setOperand(0, in);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+// Takes an object and tests it for truthiness. An object is falsy iff it
+// emulates |undefined|; see js::EmulatesUndefined.
+class LTestOAndBranch : public LControlInstructionHelper<2, 1, 1>
+{
+ public:
+ LIR_HEADER(TestOAndBranch)
+
+ LTestOAndBranch(const LAllocation& input, MBasicBlock* ifTruthy, MBasicBlock* ifFalsy,
+ const LDefinition& temp)
+ {
+ setOperand(0, input);
+ setSuccessor(0, ifTruthy);
+ setSuccessor(1, ifFalsy);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MBasicBlock* ifTruthy() {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalsy() {
+ return getSuccessor(1);
+ }
+
+ MTest* mir() {
+ return mir_->toTest();
+ }
+};
+
+// Takes in a boxed value and tests it for truthiness.
+class LTestVAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 3>
+{
+ public:
+ LIR_HEADER(TestVAndBranch)
+
+ LTestVAndBranch(MBasicBlock* ifTruthy, MBasicBlock* ifFalsy, const LBoxAllocation& input,
+ const LDefinition& temp0, const LDefinition& temp1, const LDefinition& temp2)
+ {
+ setSuccessor(0, ifTruthy);
+ setSuccessor(1, ifFalsy);
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const char* extraName() const {
+ return mir()->operandMightEmulateUndefined() ? "MightEmulateUndefined" : nullptr;
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+
+ const LDefinition* temp2() {
+ return getTemp(2);
+ }
+
+ MBasicBlock* ifTruthy() {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalsy() {
+ return getSuccessor(1);
+ }
+
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+};
+
+// Dispatches control flow to a successor based on incoming JSFunction*.
+// Used to implemenent polymorphic inlining.
+class LFunctionDispatch : public LInstructionHelper<0, 1, 0>
+{
+ // Dispatch is performed based on a function -> block map
+ // stored in the MIR.
+
+ public:
+ LIR_HEADER(FunctionDispatch);
+
+ explicit LFunctionDispatch(const LAllocation& in) {
+ setOperand(0, in);
+ }
+
+ MFunctionDispatch* mir() const {
+ return mir_->toFunctionDispatch();
+ }
+};
+
+class LObjectGroupDispatch : public LInstructionHelper<0, 1, 1>
+{
+ // Dispatch is performed based on an ObjectGroup -> block
+ // map inferred by the MIR.
+
+ public:
+ LIR_HEADER(ObjectGroupDispatch);
+
+ const char* extraName() const {
+ return mir()->hasFallback() ? "HasFallback" : "NoFallback";
+ }
+
+ LObjectGroupDispatch(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MObjectGroupDispatch* mir() const {
+ return mir_->toObjectGroupDispatch();
+ }
+};
+
+// Compares two integral values of the same JS type, either integer or object.
+// For objects, both operands are in registers.
+class LCompare : public LInstructionHelper<1, 2, 0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(Compare)
+ LCompare(JSOp jsop, const LAllocation& left, const LAllocation& right)
+ : jsop_(jsop)
+ {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+class LCompareI64 : public LInstructionHelper<1, 2 * INT64_PIECES, 0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ LCompareI64(JSOp jsop, const LInt64Allocation& left, const LInt64Allocation& right)
+ : jsop_(jsop)
+ {
+ setInt64Operand(Lhs, left);
+ setInt64Operand(Rhs, right);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+class LCompareI64AndBranch : public LControlInstructionHelper<2, 2 * INT64_PIECES, 0>
+{
+ MCompare* cmpMir_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareI64AndBranch)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ LCompareI64AndBranch(MCompare* cmpMir, JSOp jsop,
+ const LInt64Allocation& left, const LInt64Allocation& right,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : cmpMir_(cmpMir), jsop_(jsop)
+ {
+ setInt64Operand(Lhs, left);
+ setInt64Operand(Rhs, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+// Compares two integral values of the same JS type, either integer or object.
+// For objects, both operands are in registers.
+class LCompareAndBranch : public LControlInstructionHelper<2, 2, 0>
+{
+ MCompare* cmpMir_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(CompareAndBranch)
+ LCompareAndBranch(MCompare* cmpMir, JSOp jsop,
+ const LAllocation& left, const LAllocation& right,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : cmpMir_(cmpMir), jsop_(jsop)
+ {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+class LCompareD : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(CompareD)
+ LCompareD(const LAllocation& left, const LAllocation& right) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+class LCompareF : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(CompareF)
+ LCompareF(const LAllocation& left, const LAllocation& right) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareDAndBranch)
+ LCompareDAndBranch(MCompare* cmpMir, const LAllocation& left, const LAllocation& right,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : cmpMir_(cmpMir)
+ {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+};
+
+class LCompareFAndBranch : public LControlInstructionHelper<2, 2, 0>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareFAndBranch)
+ LCompareFAndBranch(MCompare* cmpMir, const LAllocation& left, const LAllocation& right,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : cmpMir_(cmpMir)
+ {
+ setOperand(0, left);
+ setOperand(1, right);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+};
+
+class LCompareS : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(CompareS)
+ LCompareS(const LAllocation& left, const LAllocation& right) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+// strict-equality between value and string.
+class LCompareStrictS : public LInstructionHelper<1, BOX_PIECES + 1, 1>
+{
+ public:
+ LIR_HEADER(CompareStrictS)
+ LCompareStrictS(const LBoxAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+ setBoxOperand(Lhs, lhs);
+ setOperand(BOX_PIECES, rhs);
+ setTemp(0, temp);
+ }
+
+ static const size_t Lhs = 0;
+
+ const LAllocation* right() {
+ return getOperand(BOX_PIECES);
+ }
+ const LDefinition* tempToUnbox() {
+ return getTemp(0);
+ }
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+// Used for strict-equality comparisons where one side is a boolean
+// and the other is a value. Note that CompareI is used to compare
+// two booleans.
+class LCompareB : public LInstructionHelper<1, BOX_PIECES + 1, 0>
+{
+ public:
+ LIR_HEADER(CompareB)
+
+ LCompareB(const LBoxAllocation& lhs, const LAllocation& rhs) {
+ setBoxOperand(Lhs, lhs);
+ setOperand(BOX_PIECES, rhs);
+ }
+
+ static const size_t Lhs = 0;
+
+ const LAllocation* rhs() {
+ return getOperand(BOX_PIECES);
+ }
+
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+class LCompareBAndBranch : public LControlInstructionHelper<2, BOX_PIECES + 1, 0>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareBAndBranch)
+
+ LCompareBAndBranch(MCompare* cmpMir, const LBoxAllocation& lhs, const LAllocation& rhs,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : cmpMir_(cmpMir)
+ {
+ setBoxOperand(Lhs, lhs);
+ setOperand(BOX_PIECES, rhs);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ static const size_t Lhs = 0;
+
+ const LAllocation* rhs() {
+ return getOperand(BOX_PIECES);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+};
+
+class LCompareBitwise : public LInstructionHelper<1, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CompareBitwise)
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+
+ LCompareBitwise(const LBoxAllocation& lhs, const LBoxAllocation& rhs) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ MCompare* mir() const {
+ return mir_->toCompare();
+ }
+};
+
+class LCompareBitwiseAndBranch : public LControlInstructionHelper<2, 2 * BOX_PIECES, 0>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(CompareBitwiseAndBranch)
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+
+ LCompareBitwiseAndBranch(MCompare* cmpMir, MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& lhs, const LBoxAllocation& rhs)
+ : cmpMir_(cmpMir)
+ {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+};
+
+class LCompareVM : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CompareVM)
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+
+ LCompareVM(const LBoxAllocation& lhs, const LBoxAllocation& rhs) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ MCompare* mir() const {
+ return mir_->toCompare();
+ }
+};
+
+class LBitAndAndBranch : public LControlInstructionHelper<2, 2, 0>
+{
+ public:
+ LIR_HEADER(BitAndAndBranch)
+ LBitAndAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ const LAllocation* left() {
+ return getOperand(0);
+ }
+ const LAllocation* right() {
+ return getOperand(1);
+ }
+};
+
+// Takes a value and tests whether it is null, undefined, or is an object that
+// emulates |undefined|, as determined by the JSCLASS_EMULATES_UNDEFINED class
+// flag on unwrapped objects. See also js::EmulatesUndefined.
+class LIsNullOrLikeUndefinedV : public LInstructionHelper<1, BOX_PIECES, 2>
+{
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedV)
+
+ LIsNullOrLikeUndefinedV(const LBoxAllocation& value, const LDefinition& temp,
+ const LDefinition& tempToUnbox)
+ {
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, tempToUnbox);
+ }
+
+ static const size_t Value = 0;
+
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ const LDefinition* tempToUnbox() {
+ return getTemp(1);
+ }
+};
+
+// Takes an object or object-or-null pointer and tests whether it is null or is
+// an object that emulates |undefined|, as above.
+class LIsNullOrLikeUndefinedT : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedT)
+
+ explicit LIsNullOrLikeUndefinedT(const LAllocation& input)
+ {
+ setOperand(0, input);
+ }
+
+ MCompare* mir() {
+ return mir_->toCompare();
+ }
+};
+
+class LIsNullOrLikeUndefinedAndBranchV : public LControlInstructionHelper<2, BOX_PIECES, 2>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedAndBranchV)
+
+ LIsNullOrLikeUndefinedAndBranchV(MCompare* cmpMir, MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& value, const LDefinition& temp,
+ const LDefinition& tempToUnbox)
+ : cmpMir_(cmpMir)
+ {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, tempToUnbox);
+ }
+
+ static const size_t Value = 0;
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const LDefinition* tempToUnbox() {
+ return getTemp(1);
+ }
+};
+
+class LIsNullOrLikeUndefinedAndBranchT : public LControlInstructionHelper<2, 1, 1>
+{
+ MCompare* cmpMir_;
+
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedAndBranchT)
+
+ LIsNullOrLikeUndefinedAndBranchT(MCompare* cmpMir, const LAllocation& input,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LDefinition& temp)
+ : cmpMir_(cmpMir)
+ {
+ setOperand(0, input);
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setTemp(0, temp);
+ }
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+ MTest* mir() const {
+ return mir_->toTest();
+ }
+ MCompare* cmpMir() const {
+ return cmpMir_;
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Not operation on an integer.
+class LNotI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NotI)
+
+ explicit LNotI(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+// Not operation on an int64.
+class LNotI64 : public LInstructionHelper<1, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(NotI64)
+
+ explicit LNotI64(const LInt64Allocation& input) {
+ setInt64Operand(0, input);
+ }
+};
+
+// Not operation on a double.
+class LNotD : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NotD)
+
+ explicit LNotD(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ MNot* mir() {
+ return mir_->toNot();
+ }
+};
+
+// Not operation on a float32.
+class LNotF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NotF)
+
+ explicit LNotF(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ MNot* mir() {
+ return mir_->toNot();
+ }
+};
+
+// Boolean complement operation on an object.
+class LNotO : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NotO)
+
+ explicit LNotO(const LAllocation& input)
+ {
+ setOperand(0, input);
+ }
+
+ MNot* mir() {
+ return mir_->toNot();
+ }
+};
+
+// Boolean complement operation on a value.
+class LNotV : public LInstructionHelper<1, BOX_PIECES, 3>
+{
+ public:
+ LIR_HEADER(NotV)
+
+ static const size_t Input = 0;
+ LNotV(const LBoxAllocation& input, const LDefinition& temp0, const LDefinition& temp1,
+ const LDefinition& temp2)
+ {
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+
+ const LDefinition* temp2() {
+ return getTemp(2);
+ }
+
+ MNot* mir() {
+ return mir_->toNot();
+ }
+};
+
+// Bitwise not operation, takes a 32-bit integer as input and returning
+// a 32-bit integer result as an output.
+class LBitNotI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(BitNotI)
+};
+
+// Call a VM function to perform a BITNOT operation.
+class LBitNotV : public LCallInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(BitNotV)
+
+ static const size_t Input = 0;
+
+ explicit LBitNotV(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+};
+
+// Binary bitwise operation, taking two 32-bit integers as inputs and returning
+// a 32-bit integer result as an output.
+class LBitOpI : public LInstructionHelper<1, 2, 0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(BitOpI)
+
+ explicit LBitOpI(JSOp op)
+ : op_(op)
+ { }
+
+ const char* extraName() const {
+ if (bitop() == JSOP_URSH && mir_->toUrsh()->bailoutsDisabled())
+ return "ursh:BailoutsDisabled";
+ return CodeName[op_];
+ }
+
+ JSOp bitop() const {
+ return op_;
+ }
+};
+
+class LBitOpI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(BitOpI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ explicit LBitOpI64(JSOp op)
+ : op_(op)
+ { }
+
+ const char* extraName() const {
+ return CodeName[op_];
+ }
+
+ JSOp bitop() const {
+ return op_;
+ }
+};
+
+// Call a VM function to perform a bitwise operation.
+class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(BitOpV)
+
+ LBitOpV(JSOp jsop, const LBoxAllocation& lhs, const LBoxAllocation& rhs)
+ : jsop_(jsop)
+ {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+};
+
+// Shift operation, taking two 32-bit integers as inputs and returning
+// a 32-bit integer result as an output.
+class LShiftI : public LBinaryMath<0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(ShiftI)
+
+ explicit LShiftI(JSOp op)
+ : op_(op)
+ { }
+
+ JSOp bitop() {
+ return op_;
+ }
+
+ MInstruction* mir() {
+ return mir_->toInstruction();
+ }
+
+ const char* extraName() const {
+ return CodeName[op_];
+ }
+};
+
+class LShiftI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES + 1, 0>
+{
+ JSOp op_;
+
+ public:
+ LIR_HEADER(ShiftI64)
+
+ explicit LShiftI64(JSOp op)
+ : op_(op)
+ { }
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+
+ JSOp bitop() {
+ return op_;
+ }
+
+ MInstruction* mir() {
+ return mir_->toInstruction();
+ }
+
+ const char* extraName() const {
+ return CodeName[op_];
+ }
+};
+
+// Sign extension
+class LSignExtend : public LInstructionHelper<1, 1, 0>
+{
+ MSignExtend::Mode mode_;
+
+ public:
+ LIR_HEADER(SignExtend);
+ explicit LSignExtend(const LAllocation& num, MSignExtend::Mode mode)
+ : mode_(mode)
+ {
+ setOperand(0, num);
+ }
+
+ MSignExtend::Mode mode() { return mode_; }
+};
+
+class LUrshD : public LBinaryMath<1>
+{
+ public:
+ LIR_HEADER(UrshD)
+
+ LUrshD(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Returns from the function being compiled (not used in inlined frames). The
+// input must be a box.
+class LReturn : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(Return)
+};
+
+class LThrow : public LCallInstructionHelper<0, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(Throw)
+
+ static const size_t Value = 0;
+
+ explicit LThrow(const LBoxAllocation& value) {
+ setBoxOperand(Value, value);
+ }
+};
+
+class LMinMaxBase : public LInstructionHelper<1, 2, 0>
+{
+ protected:
+ LMinMaxBase(const LAllocation& first, const LAllocation& second)
+ {
+ setOperand(0, first);
+ setOperand(1, second);
+ }
+
+ public:
+ const LAllocation* first() {
+ return this->getOperand(0);
+ }
+ const LAllocation* second() {
+ return this->getOperand(1);
+ }
+ const LDefinition* output() {
+ return this->getDef(0);
+ }
+ MMinMax* mir() const {
+ return mir_->toMinMax();
+ }
+ const char* extraName() const {
+ return mir()->isMax() ? "Max" : "Min";
+ }
+};
+
+class LMinMaxI : public LMinMaxBase
+{
+ public:
+ LIR_HEADER(MinMaxI)
+ LMinMaxI(const LAllocation& first, const LAllocation& second) : LMinMaxBase(first, second)
+ {}
+};
+
+class LMinMaxD : public LMinMaxBase
+{
+ public:
+ LIR_HEADER(MinMaxD)
+ LMinMaxD(const LAllocation& first, const LAllocation& second) : LMinMaxBase(first, second)
+ {}
+};
+
+class LMinMaxF : public LMinMaxBase
+{
+ public:
+ LIR_HEADER(MinMaxF)
+ LMinMaxF(const LAllocation& first, const LAllocation& second) : LMinMaxBase(first, second)
+ {}
+};
+
+// Negative of an integer
+class LNegI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NegI);
+ explicit LNegI(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Negative of a double.
+class LNegD : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NegD)
+ explicit LNegD(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Negative of a float32.
+class LNegF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(NegF)
+ explicit LNegF(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Absolute value of an integer.
+class LAbsI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(AbsI)
+ explicit LAbsI(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Absolute value of a double.
+class LAbsD : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(AbsD)
+ explicit LAbsD(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Absolute value of a float32.
+class LAbsF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(AbsF)
+ explicit LAbsF(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Copysign for doubles.
+class LCopySignD : public LInstructionHelper<1, 2, 2>
+{
+ public:
+ LIR_HEADER(CopySignD)
+ explicit LCopySignD() {}
+};
+
+// Copysign for float32.
+class LCopySignF : public LInstructionHelper<1, 2, 2>
+{
+ public:
+ LIR_HEADER(CopySignF)
+ explicit LCopySignF() {}
+};
+
+// Count leading zeroes on an int32.
+class LClzI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ClzI)
+ explicit LClzI(const LAllocation& num) {
+ setOperand(0, num);
+ }
+
+ MClz* mir() const {
+ return mir_->toClz();
+ }
+};
+
+// Count leading zeroes on an int64.
+class LClzI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(ClzI64)
+ explicit LClzI64(const LInt64Allocation& num) {
+ setInt64Operand(0, num);
+ }
+
+ MClz* mir() const {
+ return mir_->toClz();
+ }
+};
+
+// Count trailing zeroes on an int32.
+class LCtzI : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CtzI)
+ explicit LCtzI(const LAllocation& num) {
+ setOperand(0, num);
+ }
+
+ MCtz* mir() const {
+ return mir_->toCtz();
+ }
+};
+
+// Count trailing zeroes on an int64.
+class LCtzI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CtzI64)
+ explicit LCtzI64(const LInt64Allocation& num) {
+ setInt64Operand(0, num);
+ }
+
+ MCtz* mir() const {
+ return mir_->toCtz();
+ }
+};
+
+// Count population on an int32.
+class LPopcntI : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(PopcntI)
+ explicit LPopcntI(const LAllocation& num, const LDefinition& temp) {
+ setOperand(0, num);
+ setTemp(0, temp);
+ }
+
+ MPopcnt* mir() const {
+ return mir_->toPopcnt();
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Count population on an int64.
+class LPopcntI64 : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 1>
+{
+ public:
+ LIR_HEADER(PopcntI64)
+ explicit LPopcntI64(const LInt64Allocation& num, const LDefinition& temp) {
+ setInt64Operand(0, num);
+ setTemp(0, temp);
+ }
+
+ MPopcnt* mir() const {
+ return mir_->toPopcnt();
+ }
+};
+
+// Square root of a double.
+class LSqrtD : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SqrtD)
+ explicit LSqrtD(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Square root of a float32.
+class LSqrtF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(SqrtF)
+ explicit LSqrtF(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+class LAtan2D : public LCallInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(Atan2D)
+ LAtan2D(const LAllocation& y, const LAllocation& x, const LDefinition& temp) {
+ setOperand(0, y);
+ setOperand(1, x);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* y() {
+ return getOperand(0);
+ }
+
+ const LAllocation* x() {
+ return getOperand(1);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ const LDefinition* output() {
+ return getDef(0);
+ }
+};
+
+class LHypot : public LCallInstructionHelper<1, 4, 1>
+{
+ uint32_t numOperands_;
+ public:
+ LIR_HEADER(Hypot)
+ LHypot(const LAllocation& x, const LAllocation& y, const LDefinition& temp)
+ : numOperands_(2)
+ {
+ setOperand(0, x);
+ setOperand(1, y);
+ setTemp(0, temp);
+ }
+
+ LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z, const LDefinition& temp)
+ : numOperands_(3)
+ {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ setTemp(0, temp);
+ }
+
+ LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z, const LAllocation& w, const LDefinition& temp)
+ : numOperands_(4)
+ {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ setOperand(3, w);
+ setTemp(0, temp);
+ }
+
+ uint32_t numArgs() const { return numOperands_; }
+
+ const LAllocation* x() {
+ return getOperand(0);
+ }
+
+ const LAllocation* y() {
+ return getOperand(1);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ const LDefinition* output() {
+ return getDef(0);
+ }
+};
+
+// Double raised to an integer power.
+class LPowI : public LCallInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(PowI)
+ LPowI(const LAllocation& value, const LAllocation& power, const LDefinition& temp) {
+ setOperand(0, value);
+ setOperand(1, power);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* value() {
+ return getOperand(0);
+ }
+ const LAllocation* power() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Double raised to a double power.
+class LPowD : public LCallInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(PowD)
+ LPowD(const LAllocation& value, const LAllocation& power, const LDefinition& temp) {
+ setOperand(0, value);
+ setOperand(1, power);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* value() {
+ return getOperand(0);
+ }
+ const LAllocation* power() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+class LMathFunctionD : public LCallInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(MathFunctionD)
+ LMathFunctionD(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MMathFunction* mir() const {
+ return mir_->toMathFunction();
+ }
+ const char* extraName() const {
+ return MMathFunction::FunctionName(mir()->function());
+ }
+};
+
+class LMathFunctionF : public LCallInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(MathFunctionF)
+ LMathFunctionF(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MMathFunction* mir() const {
+ return mir_->toMathFunction();
+ }
+ const char* extraName() const {
+ return MMathFunction::FunctionName(mir()->function());
+ }
+};
+
+// Adds two integers, returning an integer value.
+class LAddI : public LBinaryMath<0>
+{
+ bool recoversInput_;
+
+ public:
+ LIR_HEADER(AddI)
+
+ LAddI()
+ : recoversInput_(false)
+ { }
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ virtual bool recoversInput() const {
+ return recoversInput_;
+ }
+ void setRecoversInput() {
+ recoversInput_ = true;
+ }
+
+ MAdd* mir() const {
+ return mir_->toAdd();
+ }
+};
+
+class LAddI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(AddI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+};
+
+// Subtracts two integers, returning an integer value.
+class LSubI : public LBinaryMath<0>
+{
+ bool recoversInput_;
+
+ public:
+ LIR_HEADER(SubI)
+
+ LSubI()
+ : recoversInput_(false)
+ { }
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ virtual bool recoversInput() const {
+ return recoversInput_;
+ }
+ void setRecoversInput() {
+ recoversInput_ = true;
+ }
+ MSub* mir() const {
+ return mir_->toSub();
+ }
+};
+
+class LSubI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(SubI64)
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+};
+
+class LMulI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 1>
+{
+ public:
+ LIR_HEADER(MulI64)
+
+ explicit LMulI64()
+ {
+ setTemp(0, LDefinition());
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ static const size_t Lhs = 0;
+ static const size_t Rhs = INT64_PIECES;
+};
+
+// Performs an add, sub, mul, or div on two double values.
+class LMathD : public LBinaryMath<0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(MathD)
+
+ explicit LMathD(JSOp jsop)
+ : jsop_(jsop)
+ { }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+// Performs an add, sub, mul, or div on two double values.
+class LMathF: public LBinaryMath<0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(MathF)
+
+ explicit LMathF(JSOp jsop)
+ : jsop_(jsop)
+ { }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+};
+
+class LModD : public LBinaryMath<1>
+{
+ public:
+ LIR_HEADER(ModD)
+
+ LModD(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ bool isCall() const {
+ return true;
+ }
+};
+
+// Call a VM function to perform a binary operation.
+class LBinaryV : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
+{
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(BinaryV)
+
+ LBinaryV(JSOp jsop, const LBoxAllocation& lhs, const LBoxAllocation& rhs)
+ : jsop_(jsop)
+ {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ JSOp jsop() const {
+ return jsop_;
+ }
+
+ const char* extraName() const {
+ return CodeName[jsop_];
+ }
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+};
+
+// Adds two string, returning a string.
+class LConcat : public LInstructionHelper<1, 2, 5>
+{
+ public:
+ LIR_HEADER(Concat)
+
+ LConcat(const LAllocation& lhs, const LAllocation& rhs, const LDefinition& temp1,
+ const LDefinition& temp2, const LDefinition& temp3, const LDefinition& temp4,
+ const LDefinition& temp5)
+ {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ setTemp(3, temp4);
+ setTemp(4, temp5);
+ }
+
+ const LAllocation* lhs() {
+ return this->getOperand(0);
+ }
+ const LAllocation* rhs() {
+ return this->getOperand(1);
+ }
+ const LDefinition* temp1() {
+ return this->getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return this->getTemp(1);
+ }
+ const LDefinition* temp3() {
+ return this->getTemp(2);
+ }
+ const LDefinition* temp4() {
+ return this->getTemp(3);
+ }
+ const LDefinition* temp5() {
+ return this->getTemp(4);
+ }
+};
+
+// Get uint16 character code from a string.
+class LCharCodeAt : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(CharCodeAt)
+
+ LCharCodeAt(const LAllocation& str, const LAllocation& index) {
+ setOperand(0, str);
+ setOperand(1, index);
+ }
+
+ const LAllocation* str() {
+ return this->getOperand(0);
+ }
+ const LAllocation* index() {
+ return this->getOperand(1);
+ }
+};
+
+// Convert uint16 character code to a string.
+class LFromCharCode : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(FromCharCode)
+
+ explicit LFromCharCode(const LAllocation& code) {
+ setOperand(0, code);
+ }
+
+ const LAllocation* code() {
+ return this->getOperand(0);
+ }
+};
+
+// Convert uint32 code point to a string.
+class LFromCodePoint : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(FromCodePoint)
+
+ explicit LFromCodePoint(const LAllocation& codePoint) {
+ setOperand(0, codePoint);
+ }
+
+ const LAllocation* codePoint() {
+ return this->getOperand(0);
+ }
+};
+
+// Calculates sincos(x) and returns two values (sin/cos).
+class LSinCos : public LCallInstructionHelper<2, 1, 2>
+{
+ public:
+ LIR_HEADER(SinCos)
+
+ LSinCos(const LAllocation &input, const LDefinition &temp, const LDefinition &temp2)
+ {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setTemp(1, temp2);
+ }
+ const LAllocation *input() {
+ return getOperand(0);
+ }
+ const LDefinition *outputSin() {
+ return getDef(0);
+ }
+ const LDefinition *outputCos() {
+ return getDef(1);
+ }
+ const LDefinition *temp() {
+ return getTemp(0);
+ }
+ const LDefinition *temp2() {
+ return getTemp(1);
+ }
+ const MSinCos *mir() const {
+ return mir_->toSinCos();
+ }
+};
+
+class LStringSplit : public LCallInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(StringSplit)
+
+ LStringSplit(const LAllocation& string, const LAllocation& separator) {
+ setOperand(0, string);
+ setOperand(1, separator);
+ }
+ const LAllocation* string() {
+ return getOperand(0);
+ }
+ const LAllocation* separator() {
+ return getOperand(1);
+ }
+ const MStringSplit* mir() const {
+ return mir_->toStringSplit();
+ }
+};
+
+class LSubstr : public LInstructionHelper<1, 3, 3>
+{
+ public:
+ LIR_HEADER(Substr)
+
+ LSubstr(const LAllocation& string, const LAllocation& begin, const LAllocation& length,
+ const LDefinition& temp, const LDefinition& temp2, const LDefinition& temp3)
+ {
+ setOperand(0, string);
+ setOperand(1, begin);
+ setOperand(2, length);
+ setTemp(0, temp);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+ const LAllocation* string() {
+ return getOperand(0);
+ }
+ const LAllocation* begin() {
+ return getOperand(1);
+ }
+ const LAllocation* length() {
+ return getOperand(2);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+ const LDefinition* temp3() {
+ return getTemp(2);
+ }
+ const MStringSplit* mir() const {
+ return mir_->toStringSplit();
+ }
+};
+
+// Convert a 32-bit integer to a double.
+class LInt32ToDouble : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Int32ToDouble)
+
+ explicit LInt32ToDouble(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+// Convert a 32-bit float to a double.
+class LFloat32ToDouble : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Float32ToDouble)
+
+ explicit LFloat32ToDouble(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+// Convert a double to a 32-bit float.
+class LDoubleToFloat32 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(DoubleToFloat32)
+
+ explicit LDoubleToFloat32(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+// Convert a 32-bit integer to a float32.
+class LInt32ToFloat32 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Int32ToFloat32)
+
+ explicit LInt32ToFloat32(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+// Convert a value to a double.
+class LValueToDouble : public LInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(ValueToDouble)
+ static const size_t Input = 0;
+
+ explicit LValueToDouble(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ MToDouble* mir() {
+ return mir_->toToDouble();
+ }
+};
+
+// Convert a value to a float32.
+class LValueToFloat32 : public LInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(ValueToFloat32)
+ static const size_t Input = 0;
+
+ explicit LValueToFloat32(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ MToFloat32* mir() {
+ return mir_->toToFloat32();
+ }
+};
+
+// Convert a value to an int32.
+// Input: components of a Value
+// Output: 32-bit integer
+// Bailout: undefined, string, object, or non-int32 double
+// Temps: one float register, one GP register
+//
+// This instruction requires a temporary float register.
+class LValueToInt32 : public LInstructionHelper<1, BOX_PIECES, 2>
+{
+ public:
+ enum Mode {
+ NORMAL,
+ TRUNCATE
+ };
+
+ private:
+ Mode mode_;
+
+ public:
+ LIR_HEADER(ValueToInt32)
+
+ LValueToInt32(const LBoxAllocation& input, const LDefinition& temp0, const LDefinition& temp1,
+ Mode mode)
+ : mode_(mode)
+ {
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ return mode() == NORMAL ? "Normal" : "Truncate";
+ }
+
+ static const size_t Input = 0;
+
+ Mode mode() const {
+ return mode_;
+ }
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(1);
+ }
+ MToInt32* mirNormal() const {
+ MOZ_ASSERT(mode_ == NORMAL);
+ return mir_->toToInt32();
+ }
+ MTruncateToInt32* mirTruncate() const {
+ MOZ_ASSERT(mode_ == TRUNCATE);
+ return mir_->toTruncateToInt32();
+ }
+ MInstruction* mir() const {
+ return mir_->toInstruction();
+ }
+};
+
+// Convert a double to an int32.
+// Input: floating-point register
+// Output: 32-bit integer
+// Bailout: if the double cannot be converted to an integer.
+class LDoubleToInt32 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(DoubleToInt32)
+
+ explicit LDoubleToInt32(const LAllocation& in) {
+ setOperand(0, in);
+ }
+
+ MToInt32* mir() const {
+ return mir_->toToInt32();
+ }
+};
+
+// Convert a float32 to an int32.
+// Input: floating-point register
+// Output: 32-bit integer
+// Bailout: if the float32 cannot be converted to an integer.
+class LFloat32ToInt32 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Float32ToInt32)
+
+ explicit LFloat32ToInt32(const LAllocation& in) {
+ setOperand(0, in);
+ }
+
+ MToInt32* mir() const {
+ return mir_->toToInt32();
+ }
+};
+
+// Convert a double to a truncated int32.
+// Input: floating-point register
+// Output: 32-bit integer
+class LTruncateDToInt32 : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(TruncateDToInt32)
+
+ LTruncateDToInt32(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+
+ MTruncateToInt32* mir() const {
+ return mir_->toTruncateToInt32();
+ }
+};
+
+// Convert a float32 to a truncated int32.
+// Input: floating-point register
+// Output: 32-bit integer
+class LTruncateFToInt32 : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(TruncateFToInt32)
+
+ LTruncateFToInt32(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+
+ MTruncateToInt32* mir() const {
+ return mir_->toTruncateToInt32();
+ }
+};
+
+class LWasmTruncateToInt32 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmTruncateToInt32)
+
+ explicit LWasmTruncateToInt32(const LAllocation& in) {
+ setOperand(0, in);
+ }
+
+ MWasmTruncateToInt32* mir() const {
+ return mir_->toWasmTruncateToInt32();
+ }
+};
+
+class LWrapInt64ToInt32 : public LInstructionHelper<1, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(WrapInt64ToInt32)
+
+ static const size_t Input = 0;
+
+ explicit LWrapInt64ToInt32(const LInt64Allocation& input) {
+ setInt64Operand(Input, input);
+ }
+
+ const MWrapInt64ToInt32* mir() {
+ return mir_->toWrapInt64ToInt32();
+ }
+};
+
+class LExtendInt32ToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(ExtendInt32ToInt64)
+
+ explicit LExtendInt32ToInt64(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const MExtendInt32ToInt64* mir() {
+ return mir_->toExtendInt32ToInt64();
+ }
+};
+
+// Convert a boolean value to a string.
+class LBooleanToString : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(BooleanToString)
+
+ explicit LBooleanToString(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const MToString* mir() {
+ return mir_->toToString();
+ }
+};
+
+// Convert an integer hosted on one definition to a string with a function call.
+class LIntToString : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(IntToString)
+
+ explicit LIntToString(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const MToString* mir() {
+ return mir_->toToString();
+ }
+};
+
+// Convert a double hosted on one definition to a string with a function call.
+class LDoubleToString : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(DoubleToString)
+
+ LDoubleToString(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempInt() {
+ return getTemp(0);
+ }
+ const MToString* mir() {
+ return mir_->toToString();
+ }
+};
+
+// Convert a primitive to a string with a function call.
+class LValueToString : public LInstructionHelper<1, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(ValueToString)
+
+ LValueToString(const LBoxAllocation& input, const LDefinition& tempToUnbox)
+ {
+ setBoxOperand(Input, input);
+ setTemp(0, tempToUnbox);
+ }
+
+ static const size_t Input = 0;
+
+ const MToString* mir() {
+ return mir_->toToString();
+ }
+
+ const LDefinition* tempToUnbox() {
+ return getTemp(0);
+ }
+};
+
+// Convert a value to an object or null pointer.
+class LValueToObjectOrNull : public LInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(ValueToObjectOrNull)
+
+ explicit LValueToObjectOrNull(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ const MToObjectOrNull* mir() {
+ return mir_->toToObjectOrNull();
+ }
+};
+
+class LInt32x4ToFloat32x4 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Int32x4ToFloat32x4);
+ explicit LInt32x4ToFloat32x4(const LAllocation& input) {
+ setOperand(0, input);
+ }
+};
+
+class LFloat32x4ToInt32x4 : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(Float32x4ToInt32x4);
+ explicit LFloat32x4ToInt32x4(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const MSimdConvert* mir() const {
+ return mir_->toSimdConvert();
+ }
+};
+
+// Float32x4 to Uint32x4 needs one GPR temp and one FloatReg temp.
+class LFloat32x4ToUint32x4 : public LInstructionHelper<1, 1, 2>
+{
+ public:
+ LIR_HEADER(Float32x4ToUint32x4);
+ explicit LFloat32x4ToUint32x4(const LAllocation& input, const LDefinition& tempR,
+ const LDefinition& tempF)
+ {
+ setOperand(0, input);
+ setTemp(0, tempR);
+ setTemp(1, tempF);
+ }
+ const LDefinition* tempR() {
+ return getTemp(0);
+ }
+ const LDefinition* tempF() {
+ return getTemp(1);
+ }
+ const MSimdConvert* mir() const {
+ return mir_->toSimdConvert();
+ }
+};
+
+// Double raised to a half power.
+class LPowHalfD : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(PowHalfD);
+ explicit LPowHalfD(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+ const LDefinition* output() {
+ return getDef(0);
+ }
+ MPowHalf* mir() const {
+ return mir_->toPowHalf();
+ }
+};
+
+// No-op instruction that is used to hold the entry snapshot. This simplifies
+// register allocation as it doesn't need to sniff the snapshot out of the
+// LIRGraph.
+class LStart : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(Start)
+};
+
+class LNaNToZero : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(NaNToZero)
+
+ explicit LNaNToZero(const LAllocation& input, const LDefinition& tempDouble) {
+ setOperand(0, input);
+ setTemp(0, tempDouble);
+ }
+
+ const MNaNToZero* mir() {
+ return mir_->toNaNToZero();
+ }
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+ const LDefinition* output() {
+ return getDef(0);
+ }
+ const LDefinition* tempDouble() {
+ return getTemp(0);
+ }
+};
+
+// Passed the BaselineFrame address in the OsrFrameReg by SideCannon().
+// Forwards this object to the LOsrValues for Value materialization.
+class LOsrEntry : public LInstructionHelper<1, 0, 1>
+{
+ protected:
+ Label label_;
+ uint32_t frameDepth_;
+
+ public:
+ LIR_HEADER(OsrEntry)
+
+ explicit LOsrEntry(const LDefinition& temp)
+ : frameDepth_(0)
+ {
+ setTemp(0, temp);
+ }
+
+ void setFrameDepth(uint32_t depth) {
+ frameDepth_ = depth;
+ }
+ uint32_t getFrameDepth() {
+ return frameDepth_;
+ }
+ Label* label() {
+ return &label_;
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Materialize a Value stored in an interpreter frame for OSR.
+class LOsrValue : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(OsrValue)
+
+ explicit LOsrValue(const LAllocation& entry)
+ {
+ setOperand(0, entry);
+ }
+
+ const MOsrValue* mir() {
+ return mir_->toOsrValue();
+ }
+};
+
+// Materialize a JSObject env chain stored in an interpreter frame for OSR.
+class LOsrEnvironmentChain : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(OsrEnvironmentChain)
+
+ explicit LOsrEnvironmentChain(const LAllocation& entry)
+ {
+ setOperand(0, entry);
+ }
+
+ const MOsrEnvironmentChain* mir() {
+ return mir_->toOsrEnvironmentChain();
+ }
+};
+
+// Materialize a JSObject env chain stored in an interpreter frame for OSR.
+class LOsrReturnValue : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(OsrReturnValue)
+
+ explicit LOsrReturnValue(const LAllocation& entry)
+ {
+ setOperand(0, entry);
+ }
+
+ const MOsrReturnValue* mir() {
+ return mir_->toOsrReturnValue();
+ }
+};
+
+// Materialize a JSObject ArgumentsObject stored in an interpreter frame for OSR.
+class LOsrArgumentsObject : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(OsrArgumentsObject)
+
+ explicit LOsrArgumentsObject(const LAllocation& entry)
+ {
+ setOperand(0, entry);
+ }
+
+ const MOsrArgumentsObject* mir() {
+ return mir_->toOsrArgumentsObject();
+ }
+};
+
+class LRegExp : public LCallInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(RegExp)
+
+ const MRegExp* mir() const {
+ return mir_->toRegExp();
+ }
+};
+
+class LRegExpMatcher : public LCallInstructionHelper<BOX_PIECES, 3, 0>
+{
+ public:
+ LIR_HEADER(RegExpMatcher)
+
+ LRegExpMatcher(const LAllocation& regexp, const LAllocation& string,
+ const LAllocation& lastIndex)
+ {
+ setOperand(0, regexp);
+ setOperand(1, string);
+ setOperand(2, lastIndex);
+ }
+
+ const LAllocation* regexp() {
+ return getOperand(0);
+ }
+ const LAllocation* string() {
+ return getOperand(1);
+ }
+ const LAllocation* lastIndex() {
+ return getOperand(2);
+ }
+
+ const MRegExpMatcher* mir() const {
+ return mir_->toRegExpMatcher();
+ }
+};
+
+class LRegExpSearcher : public LCallInstructionHelper<1, 3, 0>
+{
+ public:
+ LIR_HEADER(RegExpSearcher)
+
+ LRegExpSearcher(const LAllocation& regexp, const LAllocation& string,
+ const LAllocation& lastIndex)
+ {
+ setOperand(0, regexp);
+ setOperand(1, string);
+ setOperand(2, lastIndex);
+ }
+
+ const LAllocation* regexp() {
+ return getOperand(0);
+ }
+ const LAllocation* string() {
+ return getOperand(1);
+ }
+ const LAllocation* lastIndex() {
+ return getOperand(2);
+ }
+
+ const MRegExpSearcher* mir() const {
+ return mir_->toRegExpSearcher();
+ }
+};
+
+class LRegExpTester : public LCallInstructionHelper<1, 3, 0>
+{
+ public:
+ LIR_HEADER(RegExpTester)
+
+ LRegExpTester(const LAllocation& regexp, const LAllocation& string,
+ const LAllocation& lastIndex)
+ {
+ setOperand(0, regexp);
+ setOperand(1, string);
+ setOperand(2, lastIndex);
+ }
+
+ const LAllocation* regexp() {
+ return getOperand(0);
+ }
+ const LAllocation* string() {
+ return getOperand(1);
+ }
+ const LAllocation* lastIndex() {
+ return getOperand(2);
+ }
+
+ const MRegExpTester* mir() const {
+ return mir_->toRegExpTester();
+ }
+};
+
+class LRegExpPrototypeOptimizable : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(RegExpPrototypeOptimizable);
+ explicit LRegExpPrototypeOptimizable(const LAllocation& object, const LDefinition& temp) {
+ setOperand(0, object);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MRegExpPrototypeOptimizable* mir() const {
+ return mir_->toRegExpPrototypeOptimizable();
+ }
+};
+
+class LRegExpInstanceOptimizable : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(RegExpInstanceOptimizable);
+ explicit LRegExpInstanceOptimizable(const LAllocation& object, const LAllocation& proto,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, proto);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* proto() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MRegExpInstanceOptimizable* mir() const {
+ return mir_->toRegExpInstanceOptimizable();
+ }
+};
+
+class LGetFirstDollarIndex : public LInstructionHelper<1, 1, 3>
+{
+ public:
+ LIR_HEADER(GetFirstDollarIndex);
+ explicit LGetFirstDollarIndex(const LAllocation& str, const LDefinition& temp0,
+ const LDefinition& temp1, const LDefinition& temp2) {
+ setOperand(0, str);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const LAllocation* str() {
+ return getOperand(0);
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+ const LDefinition* temp2() {
+ return getTemp(2);
+ }
+};
+
+class LStringReplace: public LCallInstructionHelper<1, 3, 0>
+{
+ public:
+ LIR_HEADER(StringReplace);
+
+ LStringReplace(const LAllocation& string, const LAllocation& pattern,
+ const LAllocation& replacement)
+ {
+ setOperand(0, string);
+ setOperand(1, pattern);
+ setOperand(2, replacement);
+ }
+
+ const MStringReplace* mir() const {
+ return mir_->toStringReplace();
+ }
+
+ const LAllocation* string() {
+ return getOperand(0);
+ }
+ const LAllocation* pattern() {
+ return getOperand(1);
+ }
+ const LAllocation* replacement() {
+ return getOperand(2);
+ }
+};
+
+class LBinarySharedStub : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(BinarySharedStub)
+
+ LBinarySharedStub(const LBoxAllocation& lhs, const LBoxAllocation& rhs) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ const MBinarySharedStub* mir() const {
+ return mir_->toBinarySharedStub();
+ }
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+};
+
+class LUnarySharedStub : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(UnarySharedStub)
+
+ explicit LUnarySharedStub(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ const MUnarySharedStub* mir() const {
+ return mir_->toUnarySharedStub();
+ }
+
+ static const size_t Input = 0;
+};
+
+class LNullarySharedStub : public LCallInstructionHelper<BOX_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(NullarySharedStub)
+
+ const MNullarySharedStub* mir() const {
+ return mir_->toNullarySharedStub();
+ }
+};
+
+class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LambdaForSingleton)
+
+ explicit LLambdaForSingleton(const LAllocation& envChain)
+ {
+ setOperand(0, envChain);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ const MLambda* mir() const {
+ return mir_->toLambda();
+ }
+};
+
+class LLambda : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(Lambda)
+
+ LLambda(const LAllocation& envChain, const LDefinition& temp) {
+ setOperand(0, envChain);
+ setTemp(0, temp);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const MLambda* mir() const {
+ return mir_->toLambda();
+ }
+};
+
+class LLambdaArrow : public LInstructionHelper<1, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(LambdaArrow)
+
+ static const size_t NewTargetValue = 1;
+
+ LLambdaArrow(const LAllocation& envChain, const LBoxAllocation& newTarget) {
+ setOperand(0, envChain);
+ setBoxOperand(NewTargetValue, newTarget);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ const MLambdaArrow* mir() const {
+ return mir_->toLambdaArrow();
+ }
+};
+
+class LKeepAliveObject : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(KeepAliveObject)
+
+ explicit LKeepAliveObject(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+// Load the "slots" member out of a JSObject.
+// Input: JSObject pointer
+// Output: slots pointer
+class LSlots : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Slots)
+
+ explicit LSlots(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+// Load the "elements" member out of a JSObject.
+// Input: JSObject pointer
+// Output: elements pointer
+class LElements : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Elements)
+
+ explicit LElements(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ const MElements* mir() const {
+ return mir_->toElements();
+ }
+};
+
+// If necessary, convert any int32 elements in a vector into doubles.
+class LConvertElementsToDoubles : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(ConvertElementsToDoubles)
+
+ explicit LConvertElementsToDoubles(const LAllocation& elements) {
+ setOperand(0, elements);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+};
+
+// If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert int32 value to
+// double. Else return the original value.
+class LMaybeToDoubleElement : public LInstructionHelper<BOX_PIECES, 2, 1>
+{
+ public:
+ LIR_HEADER(MaybeToDoubleElement)
+
+ LMaybeToDoubleElement(const LAllocation& elements, const LAllocation& value,
+ const LDefinition& tempFloat) {
+ setOperand(0, elements);
+ setOperand(1, value);
+ setTemp(0, tempFloat);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+};
+
+// If necessary, copy the elements in an object so they may be written to.
+class LMaybeCopyElementsForWrite : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(MaybeCopyElementsForWrite)
+
+ explicit LMaybeCopyElementsForWrite(const LAllocation& obj, const LDefinition& temp) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ const MMaybeCopyElementsForWrite* mir() const {
+ return mir_->toMaybeCopyElementsForWrite();
+ }
+};
+
+// Load the initialized length from an elements header.
+class LInitializedLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(InitializedLength)
+
+ explicit LInitializedLength(const LAllocation& elements) {
+ setOperand(0, elements);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+};
+
+// Store to the initialized length in an elements header. Note the input is an
+// *index*, one less than the desired initialized length.
+class LSetInitializedLength : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(SetInitializedLength)
+
+ LSetInitializedLength(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LUnboxedArrayLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(UnboxedArrayLength)
+
+ explicit LUnboxedArrayLength(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+class LUnboxedArrayInitializedLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(UnboxedArrayInitializedLength)
+
+ explicit LUnboxedArrayInitializedLength(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(IncrementUnboxedArrayInitializedLength)
+
+ explicit LIncrementUnboxedArrayInitializedLength(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+class LSetUnboxedArrayInitializedLength : public LInstructionHelper<0, 2, 1>
+{
+ public:
+ LIR_HEADER(SetUnboxedArrayInitializedLength)
+
+ explicit LSetUnboxedArrayInitializedLength(const LAllocation& object,
+ const LAllocation& length,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, length);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* length() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Load the length from an elements header.
+class LArrayLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ArrayLength)
+
+ explicit LArrayLength(const LAllocation& elements) {
+ setOperand(0, elements);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+};
+
+// Store to the length in an elements header. Note the input is an *index*,
+// one less than the desired length.
+class LSetArrayLength : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(SetArrayLength)
+
+ LSetArrayLength(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LGetNextEntryForIterator : public LInstructionHelper<1, 2, 3>
+{
+ public:
+ LIR_HEADER(GetNextEntryForIterator)
+
+ explicit LGetNextEntryForIterator(const LAllocation& iter, const LAllocation& result,
+ const LDefinition& temp0, const LDefinition& temp1,
+ const LDefinition& temp2)
+ {
+ setOperand(0, iter);
+ setOperand(1, result);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ const MGetNextEntryForIterator* mir() const {
+ return mir_->toGetNextEntryForIterator();
+ }
+ const LAllocation* iter() {
+ return getOperand(0);
+ }
+ const LAllocation* result() {
+ return getOperand(1);
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+ const LDefinition* temp2() {
+ return getTemp(2);
+ }
+};
+
+// Read the length of a typed array.
+class LTypedArrayLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(TypedArrayLength)
+
+ explicit LTypedArrayLength(const LAllocation& obj) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+// Load a typed array's elements vector.
+class LTypedArrayElements : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(TypedArrayElements)
+
+ explicit LTypedArrayElements(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+// Assign
+//
+// target[targetOffset..targetOffset + source.length] = source[0..source.length]
+//
+// where the source element range doesn't overlap the target element range in
+// memory.
+class LSetDisjointTypedElements : public LCallInstructionHelper<0, 3, 1>
+{
+ public:
+ LIR_HEADER(SetDisjointTypedElements)
+
+ explicit LSetDisjointTypedElements(const LAllocation& target, const LAllocation& targetOffset,
+ const LAllocation& source, const LDefinition& temp)
+ {
+ setOperand(0, target);
+ setOperand(1, targetOffset);
+ setOperand(2, source);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* target() {
+ return getOperand(0);
+ }
+
+ const LAllocation* targetOffset() {
+ return getOperand(1);
+ }
+
+ const LAllocation* source() {
+ return getOperand(2);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Load a typed object's descriptor.
+class LTypedObjectDescr : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(TypedObjectDescr)
+
+ explicit LTypedObjectDescr(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+};
+
+// Load a typed object's elements vector.
+class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(TypedObjectElements)
+
+ explicit LTypedObjectElements(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const MTypedObjectElements* mir() const {
+ return mir_->toTypedObjectElements();
+ }
+};
+
+// Load a typed array's elements vector.
+class LSetTypedObjectOffset : public LInstructionHelper<0, 2, 2>
+{
+ public:
+ LIR_HEADER(SetTypedObjectOffset)
+
+ LSetTypedObjectOffset(const LAllocation& object,
+ const LAllocation& offset,
+ const LDefinition& temp0,
+ const LDefinition& temp1)
+ {
+ setOperand(0, object);
+ setOperand(1, offset);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* offset() {
+ return getOperand(1);
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+};
+
+// Bailout if index >= length.
+class LBoundsCheck : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(BoundsCheck)
+
+ LBoundsCheck(const LAllocation& index, const LAllocation& length) {
+ setOperand(0, index);
+ setOperand(1, length);
+ }
+ const MBoundsCheck* mir() const {
+ return mir_->toBoundsCheck();
+ }
+ const LAllocation* index() {
+ return getOperand(0);
+ }
+ const LAllocation* length() {
+ return getOperand(1);
+ }
+};
+
+// Bailout if index + minimum < 0 or index + maximum >= length.
+class LBoundsCheckRange : public LInstructionHelper<0, 2, 1>
+{
+ public:
+ LIR_HEADER(BoundsCheckRange)
+
+ LBoundsCheckRange(const LAllocation& index, const LAllocation& length,
+ const LDefinition& temp)
+ {
+ setOperand(0, index);
+ setOperand(1, length);
+ setTemp(0, temp);
+ }
+ const MBoundsCheck* mir() const {
+ return mir_->toBoundsCheck();
+ }
+ const LAllocation* index() {
+ return getOperand(0);
+ }
+ const LAllocation* length() {
+ return getOperand(1);
+ }
+};
+
+// Bailout if index < minimum.
+class LBoundsCheckLower : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(BoundsCheckLower)
+
+ explicit LBoundsCheckLower(const LAllocation& index)
+ {
+ setOperand(0, index);
+ }
+ MBoundsCheckLower* mir() const {
+ return mir_->toBoundsCheckLower();
+ }
+ const LAllocation* index() {
+ return getOperand(0);
+ }
+};
+
+// Load a value from a dense array's elements vector. Bail out if it's the hole value.
+class LLoadElementV : public LInstructionHelper<BOX_PIECES, 2, 0>
+{
+ public:
+ LIR_HEADER(LoadElementV)
+
+ LLoadElementV(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ const MLoadElement* mir() const {
+ return mir_->toLoadElement();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LInArray : public LInstructionHelper<1, 4, 0>
+{
+ public:
+ LIR_HEADER(InArray)
+
+ LInArray(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& initLength, const LAllocation& object)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, initLength);
+ setOperand(3, object);
+ }
+ const MInArray* mir() const {
+ return mir_->toInArray();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* initLength() {
+ return getOperand(2);
+ }
+ const LAllocation* object() {
+ return getOperand(3);
+ }
+};
+
+
+// Load a value from an array's elements vector, loading |undefined| if we hit a hole.
+// Bail out if we get a negative index.
+class LLoadElementHole : public LInstructionHelper<BOX_PIECES, 3, 0>
+{
+ public:
+ LIR_HEADER(LoadElementHole)
+
+ LLoadElementHole(const LAllocation& elements, const LAllocation& index, const LAllocation& initLength) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, initLength);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ const MLoadElementHole* mir() const {
+ return mir_->toLoadElementHole();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* initLength() {
+ return getOperand(2);
+ }
+};
+
+// Load a typed value from a dense array's elements vector. The array must be
+// known to be packed, so that we don't have to check for the hole value.
+// This instruction does not load the type tag and can directly load into a
+// FP register.
+class LLoadElementT : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(LoadElementT)
+
+ LLoadElementT(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck"
+ : (mir()->loadDoubles() ? "Doubles" : nullptr);
+ }
+
+ const MLoadElement* mir() const {
+ return mir_->toLoadElement();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LLoadUnboxedPointerV : public LInstructionHelper<BOX_PIECES, 2, 0>
+{
+ public:
+ LIR_HEADER(LoadUnboxedPointerV)
+
+ LLoadUnboxedPointerV(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const MLoadUnboxedObjectOrNull* mir() const {
+ return mir_->toLoadUnboxedObjectOrNull();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LLoadUnboxedPointerT : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(LoadUnboxedPointerT)
+
+ LLoadUnboxedPointerT(const LAllocation& elements, const LAllocation& index) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ MDefinition* mir() {
+ MOZ_ASSERT(mir_->isLoadUnboxedObjectOrNull() || mir_->isLoadUnboxedString());
+ return mir_;
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LUnboxObjectOrNull : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(UnboxObjectOrNull);
+
+ explicit LUnboxObjectOrNull(const LAllocation& input)
+ {
+ setOperand(0, input);
+ }
+
+ MUnbox* mir() const {
+ return mir_->toUnbox();
+ }
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+};
+
+// Store a boxed value to a dense array's element vector.
+class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(StoreElementV)
+
+ LStoreElementV(const LAllocation& elements, const LAllocation& index,
+ const LBoxAllocation& value) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setBoxOperand(Value, value);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ static const size_t Value = 2;
+
+ const MStoreElement* mir() const {
+ return mir_->toStoreElement();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+// Store a typed value to a dense array's elements vector. Compared to
+// LStoreElementV, this instruction can store doubles and constants directly,
+// and does not store the type tag if the array is monomorphic and known to
+// be packed.
+class LStoreElementT : public LInstructionHelper<0, 3, 0>
+{
+ public:
+ LIR_HEADER(StoreElementT)
+
+ LStoreElementT(const LAllocation& elements, const LAllocation& index, const LAllocation& value) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ }
+
+ const char* extraName() const {
+ return mir()->needsHoleCheck() ? "HoleCheck" : nullptr;
+ }
+
+ const MStoreElement* mir() const {
+ return mir_->toStoreElement();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ return getOperand(2);
+ }
+};
+
+// Like LStoreElementV, but supports indexes >= initialized length.
+class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(StoreElementHoleV)
+
+ LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
+ const LAllocation& index, const LBoxAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Value = 3;
+
+ const MStoreElementHole* mir() const {
+ return mir_->toStoreElementHole();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* elements() {
+ return getOperand(1);
+ }
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+};
+
+// Like LStoreElementT, but supports indexes >= initialized length.
+class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
+{
+ public:
+ LIR_HEADER(StoreElementHoleT)
+
+ LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
+ const LAllocation& index, const LAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setOperand(3, value);
+ setTemp(0, temp);
+ }
+
+ const MStoreElementHole* mir() const {
+ return mir_->toStoreElementHole();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* elements() {
+ return getOperand(1);
+ }
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+ const LAllocation* value() {
+ return getOperand(3);
+ }
+};
+
+// Like LStoreElementV, but can just ignore assignment (for eg. frozen objects)
+class LFallibleStoreElementV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(FallibleStoreElementV)
+
+ LFallibleStoreElementV(const LAllocation& object, const LAllocation& elements,
+ const LAllocation& index, const LBoxAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Value = 3;
+
+ const MFallibleStoreElement* mir() const {
+ return mir_->toFallibleStoreElement();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* elements() {
+ return getOperand(1);
+ }
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+};
+
+// Like LStoreElementT, but can just ignore assignment (for eg. frozen objects)
+class LFallibleStoreElementT : public LInstructionHelper<0, 4, 1>
+{
+ public:
+ LIR_HEADER(FallibleStoreElementT)
+
+ LFallibleStoreElementT(const LAllocation& object, const LAllocation& elements,
+ const LAllocation& index, const LAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setOperand(3, value);
+ setTemp(0, temp);
+ }
+
+ const MFallibleStoreElement* mir() const {
+ return mir_->toFallibleStoreElement();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* elements() {
+ return getOperand(1);
+ }
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+ const LAllocation* value() {
+ return getOperand(3);
+ }
+};
+
+class LStoreUnboxedPointer : public LInstructionHelper<0, 3, 0>
+{
+ public:
+ LIR_HEADER(StoreUnboxedPointer)
+
+ LStoreUnboxedPointer(LAllocation elements, LAllocation index, LAllocation value) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ }
+
+ MDefinition* mir() {
+ MOZ_ASSERT(mir_->isStoreUnboxedObjectOrNull() || mir_->isStoreUnboxedString());
+ return mir_;
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ return getOperand(2);
+ }
+};
+
+// If necessary, convert an unboxed object in a particular group to its native
+// representation.
+class LConvertUnboxedObjectToNative : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(ConvertUnboxedObjectToNative)
+
+ explicit LConvertUnboxedObjectToNative(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ MConvertUnboxedObjectToNative* mir() {
+ return mir_->toConvertUnboxedObjectToNative();
+ }
+};
+
+class LArrayPopShiftV : public LInstructionHelper<BOX_PIECES, 1, 2>
+{
+ public:
+ LIR_HEADER(ArrayPopShiftV)
+
+ LArrayPopShiftV(const LAllocation& object, const LDefinition& temp0, const LDefinition& temp1) {
+ setOperand(0, object);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift";
+ }
+
+ const MArrayPopShift* mir() const {
+ return mir_->toArrayPopShift();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+};
+
+class LArrayPopShiftT : public LInstructionHelper<1, 1, 2>
+{
+ public:
+ LIR_HEADER(ArrayPopShiftT)
+
+ LArrayPopShiftT(const LAllocation& object, const LDefinition& temp0, const LDefinition& temp1) {
+ setOperand(0, object);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift";
+ }
+
+ const MArrayPopShift* mir() const {
+ return mir_->toArrayPopShift();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+};
+
+class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(ArrayPushV)
+
+ LArrayPushV(const LAllocation& object, const LBoxAllocation& value, const LDefinition& temp) {
+ setOperand(0, object);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Value = 1;
+
+ const MArrayPush* mir() const {
+ return mir_->toArrayPush();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+class LArrayPushT : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(ArrayPushT)
+
+ LArrayPushT(const LAllocation& object, const LAllocation& value, const LDefinition& temp) {
+ setOperand(0, object);
+ setOperand(1, value);
+ setTemp(0, temp);
+ }
+
+ const MArrayPush* mir() const {
+ return mir_->toArrayPush();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+class LArraySlice : public LCallInstructionHelper<1, 3, 2>
+{
+ public:
+ LIR_HEADER(ArraySlice)
+
+ LArraySlice(const LAllocation& obj, const LAllocation& begin, const LAllocation& end,
+ const LDefinition& temp1, const LDefinition& temp2) {
+ setOperand(0, obj);
+ setOperand(1, begin);
+ setOperand(2, end);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+ const MArraySlice* mir() const {
+ return mir_->toArraySlice();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* begin() {
+ return getOperand(1);
+ }
+ const LAllocation* end() {
+ return getOperand(2);
+ }
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+};
+
+class LArrayJoin : public LCallInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(ArrayJoin)
+
+ LArrayJoin(const LAllocation& array, const LAllocation& sep) {
+ setOperand(0, array);
+ setOperand(1, sep);
+ }
+
+ const MArrayJoin* mir() const {
+ return mir_->toArrayJoin();
+ }
+ const LAllocation* array() {
+ return getOperand(0);
+ }
+ const LAllocation* separator() {
+ return getOperand(1);
+ }
+};
+
+class LLoadUnboxedScalar : public LInstructionHelper<1, 2, 1>
+{
+ public:
+ LIR_HEADER(LoadUnboxedScalar)
+
+ LLoadUnboxedScalar(const LAllocation& elements, const LAllocation& index,
+ const LDefinition& temp) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setTemp(0, temp);
+ }
+ const MLoadUnboxedScalar* mir() const {
+ return mir_->toLoadUnboxedScalar();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+class LLoadTypedArrayElementHole : public LInstructionHelper<BOX_PIECES, 2, 0>
+{
+ public:
+ LIR_HEADER(LoadTypedArrayElementHole)
+
+ LLoadTypedArrayElementHole(const LAllocation& object, const LAllocation& index) {
+ setOperand(0, object);
+ setOperand(1, index);
+ }
+ const MLoadTypedArrayElementHole* mir() const {
+ return mir_->toLoadTypedArrayElementHole();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LLoadTypedArrayElementStatic : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadTypedArrayElementStatic);
+ explicit LLoadTypedArrayElementStatic(const LAllocation& ptr) {
+ setOperand(0, ptr);
+ }
+ MLoadTypedArrayElementStatic* mir() const {
+ return mir_->toLoadTypedArrayElementStatic();
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+};
+
+class LStoreUnboxedScalar : public LInstructionHelper<0, 3, 0>
+{
+ public:
+ LIR_HEADER(StoreUnboxedScalar)
+
+ LStoreUnboxedScalar(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ }
+
+ const MStoreUnboxedScalar* mir() const {
+ return mir_->toStoreUnboxedScalar();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ return getOperand(2);
+ }
+};
+
+class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0>
+{
+ public:
+ LIR_HEADER(StoreTypedArrayElementHole)
+
+ LStoreTypedArrayElementHole(const LAllocation& elements, const LAllocation& length,
+ const LAllocation& index, const LAllocation& value)
+ {
+ setOperand(0, elements);
+ setOperand(1, length);
+ setOperand(2, index);
+ setOperand(3, value);
+ }
+
+ const MStoreTypedArrayElementHole* mir() const {
+ return mir_->toStoreTypedArrayElementHole();
+ }
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* length() {
+ return getOperand(1);
+ }
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+ const LAllocation* value() {
+ return getOperand(3);
+ }
+};
+
+class LStoreTypedArrayElementStatic : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(StoreTypedArrayElementStatic);
+ LStoreTypedArrayElementStatic(const LAllocation& ptr, const LAllocation& value) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ }
+ MStoreTypedArrayElementStatic* mir() const {
+ return mir_->toStoreTypedArrayElementStatic();
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+};
+
+class LAtomicIsLockFree : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(AtomicIsLockFree)
+
+ explicit LAtomicIsLockFree(const LAllocation& value) {
+ setOperand(0, value);
+ }
+ const LAllocation* value() {
+ return getOperand(0);
+ }
+};
+
+class LCompareExchangeTypedArrayElement : public LInstructionHelper<1, 4, 4>
+{
+ public:
+ LIR_HEADER(CompareExchangeTypedArrayElement)
+
+ LCompareExchangeTypedArrayElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& oldval, const LAllocation& newval,
+ const LDefinition& temp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setTemp(0, temp);
+ }
+ LCompareExchangeTypedArrayElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& oldval, const LAllocation& newval,
+ const LDefinition& temp, const LDefinition& valueTemp,
+ const LDefinition& offsetTemp, const LDefinition& maskTemp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setTemp(0, temp);
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* oldval() {
+ return getOperand(2);
+ }
+ const LAllocation* newval() {
+ return getOperand(3);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(1);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(3);
+ }
+
+ const MCompareExchangeTypedArrayElement* mir() const {
+ return mir_->toCompareExchangeTypedArrayElement();
+ }
+};
+
+class LAtomicExchangeTypedArrayElement : public LInstructionHelper<1, 3, 4>
+{
+ public:
+ LIR_HEADER(AtomicExchangeTypedArrayElement)
+
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LDefinition& temp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp);
+ }
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LDefinition& temp,
+ const LDefinition& valueTemp, const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp);
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ return getOperand(2);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(1);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(3);
+ }
+
+ const MAtomicExchangeTypedArrayElement* mir() const {
+ return mir_->toAtomicExchangeTypedArrayElement();
+ }
+};
+
+class LAtomicTypedArrayElementBinop : public LInstructionHelper<1, 3, 5>
+{
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinop)
+
+ static const int32_t valueOp = 2;
+
+ LAtomicTypedArrayElementBinop(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LDefinition& temp1,
+ const LDefinition& temp2)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+ LAtomicTypedArrayElementBinop(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LDefinition& temp1,
+ const LDefinition& temp2, const LDefinition& valueTemp,
+ const LDefinition& offsetTemp, const LDefinition& maskTemp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, valueTemp);
+ setTemp(3, offsetTemp);
+ setTemp(4, maskTemp);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ MOZ_ASSERT(valueOp == 2);
+ return getOperand(2);
+ }
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(3);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(4);
+ }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+// Atomic binary operation where the result is discarded.
+class LAtomicTypedArrayElementBinopForEffect : public LInstructionHelper<0, 3, 4>
+{
+ public:
+ LIR_HEADER(AtomicTypedArrayElementBinopForEffect)
+
+ LAtomicTypedArrayElementBinopForEffect(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp())
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, flagTemp);
+ }
+ LAtomicTypedArrayElementBinopForEffect(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LDefinition& flagTemp,
+ const LDefinition& valueTemp, const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, flagTemp);
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* elements() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+ const LAllocation* value() {
+ return getOperand(2);
+ }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() {
+ return getTemp(0);
+ }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(1);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(3);
+ }
+
+ const MAtomicTypedArrayElementBinop* mir() const {
+ return mir_->toAtomicTypedArrayElementBinop();
+ }
+};
+
+class LEffectiveAddress : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(EffectiveAddress);
+
+ LEffectiveAddress(const LAllocation& base, const LAllocation& index) {
+ setOperand(0, base);
+ setOperand(1, index);
+ }
+ const MEffectiveAddress* mir() const {
+ return mir_->toEffectiveAddress();
+ }
+ const LAllocation* base() {
+ return getOperand(0);
+ }
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+};
+
+class LClampIToUint8 : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(ClampIToUint8)
+
+ explicit LClampIToUint8(const LAllocation& in) {
+ setOperand(0, in);
+ }
+};
+
+class LClampDToUint8 : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(ClampDToUint8)
+
+ LClampDToUint8(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+};
+
+class LClampVToUint8 : public LInstructionHelper<1, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(ClampVToUint8)
+
+ LClampVToUint8(const LBoxAllocation& input, const LDefinition& tempFloat) {
+ setBoxOperand(Input, input);
+ setTemp(0, tempFloat);
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* tempFloat() {
+ return getTemp(0);
+ }
+ const MClampToUint8* mir() const {
+ return mir_->toClampToUint8();
+ }
+};
+
+// Load a boxed value from an object's fixed slot.
+class LLoadFixedSlotV : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadFixedSlotV)
+
+ explicit LLoadFixedSlotV(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const MLoadFixedSlot* mir() const {
+ return mir_->toLoadFixedSlot();
+ }
+};
+
+// Load a typed value from an object's fixed slot.
+class LLoadFixedSlotT : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadFixedSlotT)
+
+ explicit LLoadFixedSlotT(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const MLoadFixedSlot* mir() const {
+ return mir_->toLoadFixedSlot();
+ }
+};
+
+class LLoadFixedSlotAndUnbox : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadFixedSlotAndUnbox)
+
+ explicit LLoadFixedSlotAndUnbox(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const MLoadFixedSlotAndUnbox* mir() const {
+ return mir_->toLoadFixedSlotAndUnbox();
+ }
+};
+
+// Store a boxed value to an object's fixed slot.
+class LStoreFixedSlotV : public LInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(StoreFixedSlotV)
+
+ LStoreFixedSlotV(const LAllocation& obj, const LBoxAllocation& value) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ const MStoreFixedSlot* mir() const {
+ return mir_->toStoreFixedSlot();
+ }
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+};
+
+// Store a typed value to an object's fixed slot.
+class LStoreFixedSlotT : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(StoreFixedSlotT)
+
+ LStoreFixedSlotT(const LAllocation& obj, const LAllocation& value)
+ {
+ setOperand(0, obj);
+ setOperand(1, value);
+ }
+ const MStoreFixedSlot* mir() const {
+ return mir_->toStoreFixedSlot();
+ }
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+};
+
+// Note, Name ICs always return a Value. There are no V/T variants.
+class LGetNameCache : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(GetNameCache)
+
+ explicit LGetNameCache(const LAllocation& envObj) {
+ setOperand(0, envObj);
+ }
+ const LAllocation* envObj() {
+ return getOperand(0);
+ }
+ const MGetNameCache* mir() const {
+ return mir_->toGetNameCache();
+ }
+};
+
+class LCallGetIntrinsicValue : public LCallInstructionHelper<BOX_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(CallGetIntrinsicValue)
+
+ const MCallGetIntrinsicValue* mir() const {
+ return mir_->toCallGetIntrinsicValue();
+ }
+};
+
+// Patchable jump to stubs generated for a GetProperty cache, which loads a
+// boxed value.
+class LGetPropertyCacheV : public LInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(GetPropertyCacheV)
+
+ static const size_t Id = 1;
+
+ LGetPropertyCacheV(const LAllocation& object, const LBoxAllocation& id) {
+ setOperand(0, object);
+ setBoxOperand(Id, id);
+ }
+ const MGetPropertyCache* mir() const {
+ return mir_->toGetPropertyCache();
+ }
+};
+
+// Patchable jump to stubs generated for a GetProperty cache, which loads a
+// value of a known type, possibly into an FP register.
+class LGetPropertyCacheT : public LInstructionHelper<1, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(GetPropertyCacheT)
+
+ static const size_t Id = 1;
+
+ LGetPropertyCacheT(const LAllocation& object, const LBoxAllocation& id) {
+ setOperand(0, object);
+ setBoxOperand(Id, id);
+ }
+ const MGetPropertyCache* mir() const {
+ return mir_->toGetPropertyCache();
+ }
+};
+
+// Emit code to load a boxed value from an object's slots if its shape matches
+// one of the shapes observed by the baseline IC, else bails out.
+class LGetPropertyPolymorphicV : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(GetPropertyPolymorphicV)
+
+ explicit LGetPropertyPolymorphicV(const LAllocation& obj) {
+ setOperand(0, obj);
+ }
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+ const MGetPropertyPolymorphic* mir() const {
+ return mir_->toGetPropertyPolymorphic();
+ }
+ virtual const char* extraName() const {
+ return PropertyNameToExtraName(mir()->name());
+ }
+};
+
+// Emit code to load a typed value from an object's slots if its shape matches
+// one of the shapes observed by the baseline IC, else bails out.
+class LGetPropertyPolymorphicT : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(GetPropertyPolymorphicT)
+
+ LGetPropertyPolymorphicT(const LAllocation& obj, const LDefinition& temp) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const MGetPropertyPolymorphic* mir() const {
+ return mir_->toGetPropertyPolymorphic();
+ }
+ virtual const char* extraName() const {
+ return PropertyNameToExtraName(mir()->name());
+ }
+};
+
+// Emit code to store a boxed value to an object's slots if its shape matches
+// one of the shapes observed by the baseline IC, else bails out.
+class LSetPropertyPolymorphicV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(SetPropertyPolymorphicV)
+
+ LSetPropertyPolymorphicV(const LAllocation& obj, const LBoxAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Value = 1;
+
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const MSetPropertyPolymorphic* mir() const {
+ return mir_->toSetPropertyPolymorphic();
+ }
+};
+
+// Emit code to store a typed value to an object's slots if its shape matches
+// one of the shapes observed by the baseline IC, else bails out.
+class LSetPropertyPolymorphicT : public LInstructionHelper<0, 2, 1>
+{
+ MIRType valueType_;
+
+ public:
+ LIR_HEADER(SetPropertyPolymorphicT)
+
+ LSetPropertyPolymorphicT(const LAllocation& obj, const LAllocation& value, MIRType valueType,
+ const LDefinition& temp)
+ : valueType_(valueType)
+ {
+ setOperand(0, obj);
+ setOperand(1, value);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* obj() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MIRType valueType() const {
+ return valueType_;
+ }
+ const MSetPropertyPolymorphic* mir() const {
+ return mir_->toSetPropertyPolymorphic();
+ }
+ const char* extraName() const {
+ return StringFromMIRType(valueType_);
+ }
+};
+
+class LBindNameCache : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(BindNameCache)
+
+ explicit LBindNameCache(const LAllocation& envChain) {
+ setOperand(0, envChain);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ const MBindNameCache* mir() const {
+ return mir_->toBindNameCache();
+ }
+};
+
+class LCallBindVar : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CallBindVar)
+
+ explicit LCallBindVar(const LAllocation& envChain) {
+ setOperand(0, envChain);
+ }
+ const LAllocation* environmentChain() {
+ return getOperand(0);
+ }
+ const MCallBindVar* mir() const {
+ return mir_->toCallBindVar();
+ }
+};
+
+// Load a value from an object's dslots or a slots vector.
+class LLoadSlotV : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadSlotV)
+
+ explicit LLoadSlotV(const LAllocation& in) {
+ setOperand(0, in);
+ }
+ const MLoadSlot* mir() const {
+ return mir_->toLoadSlot();
+ }
+};
+
+// Load a typed value from an object's dslots or a slots vector. Unlike
+// LLoadSlotV, this can bypass extracting a type tag, directly retrieving a
+// pointer, integer, or double.
+class LLoadSlotT : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadSlotT)
+
+ explicit LLoadSlotT(const LAllocation& slots) {
+ setOperand(0, slots);
+ }
+ const LAllocation* slots() {
+ return getOperand(0);
+ }
+ const LDefinition* output() {
+ return this->getDef(0);
+ }
+ const MLoadSlot* mir() const {
+ return mir_->toLoadSlot();
+ }
+};
+
+// Store a value to an object's dslots or a slots vector.
+class LStoreSlotV : public LInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(StoreSlotV)
+
+ LStoreSlotV(const LAllocation& slots, const LBoxAllocation& value) {
+ setOperand(0, slots);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ const MStoreSlot* mir() const {
+ return mir_->toStoreSlot();
+ }
+ const LAllocation* slots() {
+ return getOperand(0);
+ }
+};
+
+// Store a typed value to an object's dslots or a slots vector. This has a
+// few advantages over LStoreSlotV:
+// 1) We can bypass storing the type tag if the slot has the same type as
+// the value.
+// 2) Better register allocation: we can store constants and FP regs directly
+// without requiring a second register for the value.
+class LStoreSlotT : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(StoreSlotT)
+
+ LStoreSlotT(const LAllocation& slots, const LAllocation& value) {
+ setOperand(0, slots);
+ setOperand(1, value);
+ }
+ const MStoreSlot* mir() const {
+ return mir_->toStoreSlot();
+ }
+ const LAllocation* slots() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+};
+
+// Read length field of a JSString*.
+class LStringLength : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(StringLength)
+
+ explicit LStringLength(const LAllocation& string) {
+ setOperand(0, string);
+ }
+
+ const LAllocation* string() {
+ return getOperand(0);
+ }
+};
+
+// Take the floor of a double precision number. Implements Math.floor().
+class LFloor : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Floor)
+
+ explicit LFloor(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Take the floor of a single precision number. Implements Math.floor().
+class LFloorF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(FloorF)
+
+ explicit LFloorF(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Take the ceiling of a double precision number. Implements Math.ceil().
+class LCeil : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(Ceil)
+
+ explicit LCeil(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Take the ceiling of a single precision number. Implements Math.ceil().
+class LCeilF : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CeilF)
+
+ explicit LCeilF(const LAllocation& num) {
+ setOperand(0, num);
+ }
+};
+
+// Round a double precision number. Implements Math.round().
+class LRound : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(Round)
+
+ LRound(const LAllocation& num, const LDefinition& temp) {
+ setOperand(0, num);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MRound* mir() const {
+ return mir_->toRound();
+ }
+};
+
+// Round a single precision number. Implements Math.round().
+class LRoundF : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(RoundF)
+
+ LRoundF(const LAllocation& num, const LDefinition& temp) {
+ setOperand(0, num);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MRound* mir() const {
+ return mir_->toRound();
+ }
+};
+
+// Load a function's call environment.
+class LFunctionEnvironment : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(FunctionEnvironment)
+
+ explicit LFunctionEnvironment(const LAllocation& function) {
+ setOperand(0, function);
+ }
+ const LAllocation* function() {
+ return getOperand(0);
+ }
+};
+
+class LCallGetProperty : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallGetProperty)
+
+ static const size_t Value = 0;
+
+ explicit LCallGetProperty(const LBoxAllocation& val) {
+ setBoxOperand(Value, val);
+ }
+
+ MCallGetProperty* mir() const {
+ return mir_->toCallGetProperty();
+ }
+};
+
+// Call js::GetElement.
+class LCallGetElement : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallGetElement)
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+
+ LCallGetElement(const LBoxAllocation& lhs, const LBoxAllocation& rhs) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ }
+
+ MCallGetElement* mir() const {
+ return mir_->toCallGetElement();
+ }
+};
+
+// Call js::SetElement.
+class LCallSetElement : public LCallInstructionHelper<0, 1 + 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallSetElement)
+
+ static const size_t Index = 1;
+ static const size_t Value = 1 + BOX_PIECES;
+
+ LCallSetElement(const LAllocation& obj, const LBoxAllocation& index,
+ const LBoxAllocation& value) {
+ setOperand(0, obj);
+ setBoxOperand(Index, index);
+ setBoxOperand(Value, value);
+ }
+
+ const MCallSetElement* mir() const {
+ return mir_->toCallSetElement();
+ }
+};
+
+// Call js::InitElementArray.
+class LCallInitElementArray : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+public:
+ LIR_HEADER(CallInitElementArray)
+
+ static const size_t Value = 1;
+
+ LCallInitElementArray(const LAllocation& obj, const LBoxAllocation& value) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ }
+
+ const MCallInitElementArray* mir() const {
+ return mir_->toCallInitElementArray();
+ }
+};
+
+// Call a VM function to perform a property or name assignment of a generic value.
+class LCallSetProperty : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallSetProperty)
+
+ LCallSetProperty(const LAllocation& obj, const LBoxAllocation& value) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ const MCallSetProperty* mir() const {
+ return mir_->toCallSetProperty();
+ }
+};
+
+class LCallDeleteProperty : public LCallInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallDeleteProperty)
+
+ static const size_t Value = 0;
+
+ explicit LCallDeleteProperty(const LBoxAllocation& value) {
+ setBoxOperand(Value, value);
+ }
+
+ MDeleteProperty* mir() const {
+ return mir_->toDeleteProperty();
+ }
+};
+
+class LCallDeleteElement : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallDeleteElement)
+
+ static const size_t Value = 0;
+ static const size_t Index = BOX_PIECES;
+
+ LCallDeleteElement(const LBoxAllocation& value, const LBoxAllocation& index) {
+ setBoxOperand(Value, value);
+ setBoxOperand(Index, index);
+ }
+
+ MDeleteElement* mir() const {
+ return mir_->toDeleteElement();
+ }
+};
+
+// Patchable jump to stubs generated for a SetProperty cache.
+class LSetPropertyCache : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 4>
+{
+ public:
+ LIR_HEADER(SetPropertyCache)
+
+ LSetPropertyCache(const LAllocation& object, const LBoxAllocation& id,
+ const LBoxAllocation& value, const LDefinition& temp,
+ const LDefinition& tempToUnboxIndex, const LDefinition& tempDouble,
+ const LDefinition& tempFloat32) {
+ setOperand(0, object);
+ setBoxOperand(Id, id);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, tempToUnboxIndex);
+ setTemp(2, tempDouble);
+ setTemp(3, tempFloat32);
+ }
+
+ static const size_t Id = 1;
+ static const size_t Value = 1 + BOX_PIECES;
+
+ const MSetPropertyCache* mir() const {
+ return mir_->toSetPropertyCache();
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const LDefinition* tempToUnboxIndex() {
+ return getTemp(1);
+ }
+ const LDefinition* tempDouble() {
+ return getTemp(2);
+ }
+ const LDefinition* tempFloat32() {
+ if (hasUnaliasedDouble())
+ return getTemp(3);
+ return getTemp(2);
+ }
+};
+
+class LCallIteratorStartV : public LCallInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CallIteratorStartV)
+
+ static const size_t Value = 0;
+
+ explicit LCallIteratorStartV(const LBoxAllocation& value) {
+ setBoxOperand(Value, value);
+ }
+ MIteratorStart* mir() const {
+ return mir_->toIteratorStart();
+ }
+};
+
+class LCallIteratorStartO : public LCallInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(CallIteratorStartO)
+
+ explicit LCallIteratorStartO(const LAllocation& object) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ MIteratorStart* mir() const {
+ return mir_->toIteratorStart();
+ }
+};
+
+class LIteratorStartO : public LInstructionHelper<1, 1, 3>
+{
+ public:
+ LIR_HEADER(IteratorStartO)
+
+ LIteratorStartO(const LAllocation& object, const LDefinition& temp1,
+ const LDefinition& temp2, const LDefinition& temp3) {
+ setOperand(0, object);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+ const LDefinition* temp3() {
+ return getTemp(2);
+ }
+ MIteratorStart* mir() const {
+ return mir_->toIteratorStart();
+ }
+};
+
+class LIteratorMore : public LInstructionHelper<BOX_PIECES, 1, 1>
+{
+ public:
+ LIR_HEADER(IteratorMore)
+
+ LIteratorMore(const LAllocation& iterator, const LDefinition& temp) {
+ setOperand(0, iterator);
+ setTemp(0, temp);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ MIteratorMore* mir() const {
+ return mir_->toIteratorMore();
+ }
+};
+
+class LIsNoIterAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(IsNoIterAndBranch)
+
+ LIsNoIterAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse, const LBoxAllocation& input) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+class LIteratorEnd : public LInstructionHelper<0, 1, 3>
+{
+ public:
+ LIR_HEADER(IteratorEnd)
+
+ LIteratorEnd(const LAllocation& iterator, const LDefinition& temp1,
+ const LDefinition& temp2, const LDefinition& temp3) {
+ setOperand(0, iterator);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+ const LDefinition* temp3() {
+ return getTemp(2);
+ }
+ MIteratorEnd* mir() const {
+ return mir_->toIteratorEnd();
+ }
+};
+
+// Read the number of actual arguments.
+class LArgumentsLength : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(ArgumentsLength)
+};
+
+// Load a value from the actual arguments.
+class LGetFrameArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ LIR_HEADER(GetFrameArgument)
+
+ explicit LGetFrameArgument(const LAllocation& index) {
+ setOperand(0, index);
+ }
+ const LAllocation* index() {
+ return getOperand(0);
+ }
+};
+
+// Load a value from the actual arguments.
+class LSetFrameArgumentT : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(SetFrameArgumentT)
+
+ explicit LSetFrameArgumentT(const LAllocation& input) {
+ setOperand(0, input);
+ }
+ MSetFrameArgument* mir() const {
+ return mir_->toSetFrameArgument();
+ }
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+};
+
+// Load a value from the actual arguments.
+class LSetFrameArgumentC : public LInstructionHelper<0, 0, 0>
+{
+ Value val_;
+
+ public:
+ LIR_HEADER(SetFrameArgumentC)
+
+ explicit LSetFrameArgumentC(const Value& val) {
+ val_ = val;
+ }
+ MSetFrameArgument* mir() const {
+ return mir_->toSetFrameArgument();
+ }
+ const Value& val() const {
+ return val_;
+ }
+};
+
+// Load a value from the actual arguments.
+class LSetFrameArgumentV : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(SetFrameArgumentV)
+
+ explicit LSetFrameArgumentV(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MSetFrameArgument* mir() const {
+ return mir_->toSetFrameArgument();
+ }
+};
+
+class LRunOncePrologue : public LCallInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(RunOncePrologue)
+
+ MRunOncePrologue* mir() const {
+ return mir_->toRunOncePrologue();
+ }
+};
+
+// Create the rest parameter.
+class LRest : public LCallInstructionHelper<1, 1, 3>
+{
+ public:
+ LIR_HEADER(Rest)
+
+ LRest(const LAllocation& numActuals, const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ {
+ setOperand(0, numActuals);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+ const LAllocation* numActuals() {
+ return getOperand(0);
+ }
+ MRest* mir() const {
+ return mir_->toRest();
+ }
+};
+
+class LGuardReceiverPolymorphic : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(GuardReceiverPolymorphic)
+
+ LGuardReceiverPolymorphic(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const MGuardReceiverPolymorphic* mir() const {
+ return mir_->toGuardReceiverPolymorphic();
+ }
+};
+
+class LGuardUnboxedExpando : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(GuardUnboxedExpando)
+
+ explicit LGuardUnboxedExpando(const LAllocation& in) {
+ setOperand(0, in);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const MGuardUnboxedExpando* mir() const {
+ return mir_->toGuardUnboxedExpando();
+ }
+};
+
+class LLoadUnboxedExpando : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(LoadUnboxedExpando)
+
+ explicit LLoadUnboxedExpando(const LAllocation& in) {
+ setOperand(0, in);
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const MLoadUnboxedExpando* mir() const {
+ return mir_->toLoadUnboxedExpando();
+ }
+};
+
+// Guard that a value is in a TypeSet.
+class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(TypeBarrierV)
+
+ LTypeBarrierV(const LBoxAllocation& input, const LDefinition& temp) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 0;
+
+ const MTypeBarrier* mir() const {
+ return mir_->toTypeBarrier();
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Guard that a object is in a TypeSet.
+class LTypeBarrierO : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(TypeBarrierO)
+
+ LTypeBarrierO(const LAllocation& obj, const LDefinition& temp) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+ const MTypeBarrier* mir() const {
+ return mir_->toTypeBarrier();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Guard that a value is in a TypeSet.
+class LMonitorTypes : public LInstructionHelper<0, BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(MonitorTypes)
+
+ LMonitorTypes(const LBoxAllocation& input, const LDefinition& temp) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 0;
+
+ const MMonitorTypes* mir() const {
+ return mir_->toMonitorTypes();
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Generational write barrier used when writing an object to another object.
+class LPostWriteBarrierO : public LInstructionHelper<0, 2, 1>
+{
+ public:
+ LIR_HEADER(PostWriteBarrierO)
+
+ LPostWriteBarrierO(const LAllocation& obj, const LAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, obj);
+ setOperand(1, value);
+ setTemp(0, temp);
+ }
+
+ const MPostWriteBarrier* mir() const {
+ return mir_->toPostWriteBarrier();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Generational write barrier used when writing a value to another object.
+class LPostWriteBarrierV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(PostWriteBarrierV)
+
+ LPostWriteBarrierV(const LAllocation& obj, const LBoxAllocation& value,
+ const LDefinition& temp) {
+ setOperand(0, obj);
+ setBoxOperand(Input, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 1;
+
+ const MPostWriteBarrier* mir() const {
+ return mir_->toPostWriteBarrier();
+ }
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Generational write barrier used when writing an object to another object's
+// elements.
+class LPostWriteElementBarrierO : public LInstructionHelper<0, 3, 1>
+{
+ public:
+ LIR_HEADER(PostWriteElementBarrierO)
+
+ LPostWriteElementBarrierO(const LAllocation& obj, const LAllocation& value,
+ const LAllocation& index, const LDefinition& temp) {
+ setOperand(0, obj);
+ setOperand(1, value);
+ setOperand(2, index);
+ setTemp(0, temp);
+ }
+
+ const MPostWriteElementBarrier* mir() const {
+ return mir_->toPostWriteElementBarrier();
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+
+ const LAllocation* index() {
+ return getOperand(2);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Generational write barrier used when writing a value to another object's
+// elements.
+class LPostWriteElementBarrierV : public LInstructionHelper<0, 2 + BOX_PIECES, 1>
+{
+ public:
+ LIR_HEADER(PostWriteElementBarrierV)
+
+ LPostWriteElementBarrierV(const LAllocation& obj, const LAllocation& index,
+ const LBoxAllocation& value, const LDefinition& temp) {
+ setOperand(0, obj);
+ setOperand(1, index);
+ setBoxOperand(Input, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 2;
+
+ const MPostWriteElementBarrier* mir() const {
+ return mir_->toPostWriteElementBarrier();
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+
+ const LAllocation* index() {
+ return getOperand(1);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+};
+
+// Guard against an object's identity.
+class LGuardObjectIdentity : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(GuardObjectIdentity)
+
+ explicit LGuardObjectIdentity(const LAllocation& in, const LAllocation& expected) {
+ setOperand(0, in);
+ setOperand(1, expected);
+ }
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+ const LAllocation* expected() {
+ return getOperand(1);
+ }
+ const MGuardObjectIdentity* mir() const {
+ return mir_->toGuardObjectIdentity();
+ }
+};
+
+// Guard against an object's class.
+class LGuardClass : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(GuardClass)
+
+ LGuardClass(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+ const MGuardClass* mir() const {
+ return mir_->toGuardClass();
+ }
+ const LDefinition* tempInt() {
+ return getTemp(0);
+ }
+};
+
+// Guard against the sharedness of a TypedArray's memory.
+class LGuardSharedTypedArray : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(GuardSharedTypedArray)
+
+ LGuardSharedTypedArray(const LAllocation& in, const LDefinition& temp) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+ const MGuardSharedTypedArray* mir() const {
+ return mir_->toGuardSharedTypedArray();
+ }
+ const LDefinition* tempInt() {
+ return getTemp(0);
+ }
+};
+
+class LIn : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
+{
+ public:
+ LIR_HEADER(In)
+ LIn(const LBoxAllocation& lhs, const LAllocation& rhs) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(LHS);
+ }
+ const LAllocation* rhs() {
+ return getOperand(RHS);
+ }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LInstanceOfO : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(InstanceOfO)
+ explicit LInstanceOfO(const LAllocation& lhs) {
+ setOperand(0, lhs);
+ }
+
+ MInstanceOf* mir() const {
+ return mir_->toInstanceOf();
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+};
+
+class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(InstanceOfV)
+ explicit LInstanceOfV(const LBoxAllocation& lhs) {
+ setBoxOperand(LHS, lhs);
+ }
+
+ MInstanceOf* mir() const {
+ return mir_->toInstanceOf();
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(LHS);
+ }
+
+ static const size_t LHS = 0;
+};
+
+class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
+{
+ public:
+ LIR_HEADER(CallInstanceOf)
+ LCallInstanceOf(const LBoxAllocation& lhs, const LAllocation& rhs) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ }
+
+ const LDefinition* output() {
+ return this->getDef(0);
+ }
+ const LAllocation* lhs() {
+ return getOperand(LHS);
+ }
+ const LAllocation* rhs() {
+ return getOperand(RHS);
+ }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LIsCallable : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(IsCallable);
+ explicit LIsCallable(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ MIsCallable* mir() const {
+ return mir_->toIsCallable();
+ }
+};
+
+class LIsConstructor : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(IsConstructor);
+ explicit LIsConstructor(const LAllocation& object) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() {
+ return getOperand(0);
+ }
+ MIsConstructor* mir() const {
+ return mir_->toIsConstructor();
+ }
+};
+
+class LIsObject : public LInstructionHelper<1, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(IsObject);
+ static const size_t Input = 0;
+
+ explicit LIsObject(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ MIsObject* mir() const {
+ return mir_->toIsObject();
+ }
+};
+
+class LIsObjectAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(IsObjectAndBranch)
+
+ LIsObjectAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse, const LBoxAllocation& input) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MBasicBlock* ifTrue() const {
+ return getSuccessor(0);
+ }
+ MBasicBlock* ifFalse() const {
+ return getSuccessor(1);
+ }
+};
+
+class LHasClass : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(HasClass);
+ explicit LHasClass(const LAllocation& lhs) {
+ setOperand(0, lhs);
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+ MHasClass* mir() const {
+ return mir_->toHasClass();
+ }
+};
+
+template<size_t Defs, size_t Ops>
+class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0>
+{
+ typedef LInstructionHelper<Defs, Ops, 0> Base;
+ public:
+
+ MWasmSelect* mir() const {
+ return Base::mir_->toWasmSelect();
+ }
+};
+
+class LWasmSelect : public LWasmSelectBase<1, 3>
+{
+ public:
+ LIR_HEADER(WasmSelect);
+
+ static const size_t TrueExprIndex = 0;
+ static const size_t FalseExprIndex = 1;
+ static const size_t CondIndex = 2;
+
+ LWasmSelect(const LAllocation& trueExpr, const LAllocation& falseExpr,
+ const LAllocation& cond)
+ {
+ setOperand(TrueExprIndex, trueExpr);
+ setOperand(FalseExprIndex, falseExpr);
+ setOperand(CondIndex, cond);
+ }
+
+ const LAllocation* trueExpr() {
+ return getOperand(TrueExprIndex);
+ }
+ const LAllocation* falseExpr() {
+ return getOperand(FalseExprIndex);
+ }
+ const LAllocation* condExpr() {
+ return getOperand(CondIndex);
+ }
+};
+
+class LWasmSelectI64 : public LWasmSelectBase<INT64_PIECES, 2 * INT64_PIECES + 1>
+{
+ public:
+ LIR_HEADER(WasmSelectI64);
+
+ static const size_t TrueExprIndex = 0;
+ static const size_t FalseExprIndex = INT64_PIECES;
+ static const size_t CondIndex = INT64_PIECES * 2;
+
+ LWasmSelectI64(const LInt64Allocation& trueExpr, const LInt64Allocation& falseExpr,
+ const LAllocation& cond)
+ {
+ setInt64Operand(TrueExprIndex, trueExpr);
+ setInt64Operand(FalseExprIndex, falseExpr);
+ setOperand(CondIndex, cond);
+ }
+
+ const LInt64Allocation trueExpr() {
+ return getInt64Operand(TrueExprIndex);
+ }
+ const LInt64Allocation falseExpr() {
+ return getInt64Operand(FalseExprIndex);
+ }
+ const LAllocation* condExpr() {
+ return getOperand(CondIndex);
+ }
+};
+
+class LWasmAddOffset : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmAddOffset);
+ explicit LWasmAddOffset(const LAllocation& base) {
+ setOperand(0, base);
+ }
+ MWasmAddOffset* mir() const {
+ return mir_->toWasmAddOffset();
+ }
+ const LAllocation* base() {
+ return getOperand(0);
+ }
+};
+
+class LWasmBoundsCheck : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmBoundsCheck);
+ explicit LWasmBoundsCheck(const LAllocation& ptr) {
+ setOperand(0, ptr);
+ }
+ MWasmBoundsCheck* mir() const {
+ return mir_->toWasmBoundsCheck();
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+};
+
+namespace details {
+
+// This is a base class for LWasmLoad/LWasmLoadI64.
+template<size_t Defs, size_t Temp>
+class LWasmLoadBase : public LInstructionHelper<Defs, 1, Temp>
+{
+ public:
+ typedef LInstructionHelper<Defs, 1, Temp> Base;
+ explicit LWasmLoadBase(const LAllocation& ptr) {
+ Base::setOperand(0, ptr);
+ }
+ MWasmLoad* mir() const {
+ return Base::mir_->toWasmLoad();
+ }
+ const LAllocation* ptr() {
+ return Base::getOperand(0);
+ }
+};
+
+} // namespace details
+
+class LWasmLoad : public details::LWasmLoadBase<1, 1>
+{
+ public:
+ explicit LWasmLoad(const LAllocation& ptr)
+ : LWasmLoadBase(ptr)
+ {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ const LDefinition* ptrCopy() {
+ return Base::getTemp(0);
+ }
+
+ LIR_HEADER(WasmLoad);
+};
+
+class LWasmLoadI64 : public details::LWasmLoadBase<INT64_PIECES, 1>
+{
+ public:
+ explicit LWasmLoadI64(const LAllocation& ptr)
+ : LWasmLoadBase(ptr)
+ {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ const LDefinition* ptrCopy() {
+ return Base::getTemp(0);
+ }
+
+ LIR_HEADER(WasmLoadI64);
+};
+
+class LWasmStore : public LInstructionHelper<0, 2, 1>
+{
+ public:
+ LIR_HEADER(WasmStore);
+
+ static const size_t PtrIndex = 0;
+ static const size_t ValueIndex = 1;
+
+ LWasmStore(const LAllocation& ptr, const LAllocation& value) {
+ setOperand(PtrIndex, ptr);
+ setOperand(ValueIndex, value);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ MWasmStore* mir() const {
+ return mir_->toWasmStore();
+ }
+ const LAllocation* ptr() {
+ return getOperand(PtrIndex);
+ }
+ const LDefinition* ptrCopy() {
+ return getTemp(0);
+ }
+ const LAllocation* value() {
+ return getOperand(ValueIndex);
+ }
+};
+
+class LWasmStoreI64 : public LInstructionHelper<0, INT64_PIECES + 1, 1>
+{
+ public:
+ LIR_HEADER(WasmStoreI64);
+
+ static const size_t PtrIndex = 0;
+ static const size_t ValueIndex = 1;
+
+ LWasmStoreI64(const LAllocation& ptr, const LInt64Allocation& value) {
+ setOperand(PtrIndex, ptr);
+ setInt64Operand(ValueIndex, value);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ MWasmStore* mir() const {
+ return mir_->toWasmStore();
+ }
+ const LAllocation* ptr() {
+ return getOperand(PtrIndex);
+ }
+ const LDefinition* ptrCopy() {
+ return getTemp(0);
+ }
+ const LInt64Allocation value() {
+ return getInt64Operand(ValueIndex);
+ }
+};
+
+class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0>
+{
+ public:
+ LIR_HEADER(AsmJSLoadHeap);
+ explicit LAsmJSLoadHeap(const LAllocation& ptr) {
+ setOperand(0, ptr);
+ }
+ MAsmJSLoadHeap* mir() const {
+ return mir_->toAsmJSLoadHeap();
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+};
+
+class LAsmJSStoreHeap : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(AsmJSStoreHeap);
+ LAsmJSStoreHeap(const LAllocation& ptr, const LAllocation& value) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ }
+ MAsmJSStoreHeap* mir() const {
+ return mir_->toAsmJSStoreHeap();
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+};
+
+class LAsmJSCompareExchangeHeap : public LInstructionHelper<1, 3, 4>
+{
+ public:
+ LIR_HEADER(AsmJSCompareExchangeHeap);
+
+ LAsmJSCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue)
+ {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ LAsmJSCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue, const LDefinition& valueTemp,
+ const LDefinition& offsetTemp, const LDefinition& maskTemp)
+ {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* oldValue() {
+ return getOperand(1);
+ }
+ const LAllocation* newValue() {
+ return getOperand(2);
+ }
+ const LDefinition* addrTemp() {
+ return getTemp(0);
+ }
+
+ void setAddrTemp(const LDefinition& addrTemp) {
+ setTemp(0, addrTemp);
+ }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(1);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(3);
+ }
+
+ MAsmJSCompareExchangeHeap* mir() const {
+ return mir_->toAsmJSCompareExchangeHeap();
+ }
+};
+
+class LAsmJSAtomicExchangeHeap : public LInstructionHelper<1, 2, 4>
+{
+ public:
+ LIR_HEADER(AsmJSAtomicExchangeHeap);
+
+ LAsmJSAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value)
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ LAsmJSAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& valueTemp, const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, valueTemp);
+ setTemp(2, offsetTemp);
+ setTemp(3, maskTemp);
+ }
+
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+ const LDefinition* addrTemp() {
+ return getTemp(0);
+ }
+
+ void setAddrTemp(const LDefinition& addrTemp) {
+ setTemp(0, addrTemp);
+ }
+
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(1);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(3);
+ }
+
+ MAsmJSAtomicExchangeHeap* mir() const {
+ return mir_->toAsmJSAtomicExchangeHeap();
+ }
+};
+
+class LAsmJSAtomicBinopHeap : public LInstructionHelper<1, 2, 6>
+{
+ public:
+ LIR_HEADER(AsmJSAtomicBinopHeap);
+
+ static const int32_t valueOp = 1;
+
+ LAsmJSAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& flagTemp = LDefinition::BogusTemp())
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, temp);
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, flagTemp);
+ }
+ LAsmJSAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& temp, const LDefinition& flagTemp,
+ const LDefinition& valueTemp, const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, temp);
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, flagTemp);
+ setTemp(3, valueTemp);
+ setTemp(4, offsetTemp);
+ setTemp(5, maskTemp);
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ MOZ_ASSERT(valueOp == 1);
+ return getOperand(1);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ // Temp that may be used on some platforms to hold a computed address.
+ const LDefinition* addrTemp() {
+ return getTemp(1);
+ }
+ void setAddrTemp(const LDefinition& addrTemp) {
+ setTemp(1, addrTemp);
+ }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() {
+ return getTemp(2);
+ }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(3);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(4);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(5);
+ }
+
+ MAsmJSAtomicBinopHeap* mir() const {
+ return mir_->toAsmJSAtomicBinopHeap();
+ }
+};
+
+// Atomic binary operation where the result is discarded.
+class LAsmJSAtomicBinopHeapForEffect : public LInstructionHelper<0, 2, 5>
+{
+ public:
+ LIR_HEADER(AsmJSAtomicBinopHeapForEffect);
+ LAsmJSAtomicBinopHeapForEffect(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp())
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, flagTemp);
+ }
+ LAsmJSAtomicBinopHeapForEffect(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& flagTemp, const LDefinition& valueTemp,
+ const LDefinition& offsetTemp, const LDefinition& maskTemp)
+ {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, flagTemp);
+ setTemp(2, valueTemp);
+ setTemp(3, offsetTemp);
+ setTemp(4, maskTemp);
+ }
+ const LAllocation* ptr() {
+ return getOperand(0);
+ }
+ const LAllocation* value() {
+ return getOperand(1);
+ }
+
+ // Temp that may be used on some platforms to hold a computed address.
+ const LDefinition* addrTemp() {
+ return getTemp(0);
+ }
+ void setAddrTemp(const LDefinition& addrTemp) {
+ setTemp(0, addrTemp);
+ }
+
+ // Temp that may be used on LL/SC platforms for the flag result of the store.
+ const LDefinition* flagTemp() {
+ return getTemp(1);
+ }
+ // Temp that may be used on LL/SC platforms for extract/insert bits of word.
+ const LDefinition* valueTemp() {
+ return getTemp(2);
+ }
+ const LDefinition* offsetTemp() {
+ return getTemp(3);
+ }
+ const LDefinition* maskTemp() {
+ return getTemp(4);
+ }
+
+ MAsmJSAtomicBinopHeap* mir() const {
+ return mir_->toAsmJSAtomicBinopHeap();
+ }
+};
+
+class LWasmLoadGlobalVar : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(WasmLoadGlobalVar);
+ MWasmLoadGlobalVar* mir() const {
+ return mir_->toWasmLoadGlobalVar();
+ }
+};
+
+class LWasmLoadGlobalVarI64 : public LInstructionHelper<INT64_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(WasmLoadGlobalVarI64);
+ MWasmLoadGlobalVar* mir() const {
+ return mir_->toWasmLoadGlobalVar();
+ }
+};
+
+class LWasmStoreGlobalVar : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmStoreGlobalVar);
+ explicit LWasmStoreGlobalVar(const LAllocation& value) {
+ setOperand(0, value);
+ }
+ MWasmStoreGlobalVar* mir() const {
+ return mir_->toWasmStoreGlobalVar();
+ }
+ const LAllocation* value() {
+ return getOperand(0);
+ }
+};
+
+class LWasmStoreGlobalVarI64 : public LInstructionHelper<0, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(WasmStoreGlobalVarI64);
+ explicit LWasmStoreGlobalVarI64(const LInt64Allocation& value) {
+ setInt64Operand(0, value);
+ }
+ MWasmStoreGlobalVar* mir() const {
+ return mir_->toWasmStoreGlobalVar();
+ }
+ static const uint32_t InputIndex = 0;
+
+ const LInt64Allocation value() {
+ return getInt64Operand(InputIndex);
+ }
+};
+
+class LWasmParameter : public LInstructionHelper<1, 0, 0>
+{
+ public:
+ LIR_HEADER(WasmParameter);
+};
+
+class LWasmParameterI64 : public LInstructionHelper<INT64_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(WasmParameterI64);
+};
+
+class LWasmReturn : public LInstructionHelper<0, 2, 0>
+{
+ public:
+ LIR_HEADER(WasmReturn);
+};
+
+class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0>
+{
+ public:
+ LIR_HEADER(WasmReturnI64)
+
+ explicit LWasmReturnI64(const LInt64Allocation& input) {
+ setInt64Operand(0, input);
+ }
+};
+
+class LWasmReturnVoid : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmReturnVoid);
+};
+
+class LWasmStackArg : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(WasmStackArg);
+ explicit LWasmStackArg(const LAllocation& arg) {
+ setOperand(0, arg);
+ }
+ MWasmStackArg* mir() const {
+ return mirRaw()->toWasmStackArg();
+ }
+ const LAllocation* arg() {
+ return getOperand(0);
+ }
+};
+
+class LWasmStackArgI64 : public LInstructionHelper<0, INT64_PIECES, 0>
+{
+ public:
+ LIR_HEADER(WasmStackArgI64);
+ explicit LWasmStackArgI64(const LInt64Allocation& arg) {
+ setInt64Operand(0, arg);
+ }
+ MWasmStackArg* mir() const {
+ return mirRaw()->toWasmStackArg();
+ }
+ const LInt64Allocation arg() {
+ return getInt64Operand(0);
+ }
+};
+
+class LWasmCallBase : public LInstruction
+{
+ LAllocation* operands_;
+ uint32_t numOperands_;
+
+ public:
+
+ LWasmCallBase(LAllocation* operands, uint32_t numOperands)
+ : operands_(operands),
+ numOperands_(numOperands)
+ {}
+
+ MWasmCall* mir() const {
+ return mir_->toWasmCall();
+ }
+
+ bool isCall() const override {
+ return true;
+ }
+ bool isCallPreserved(AnyRegister reg) const override {
+ // All MWasmCalls preserve the TLS register:
+ // - internal/indirect calls do by the internal wasm ABI
+ // - import calls do by explicitly saving/restoring at the callsite
+ // - builtin calls do because the TLS reg is non-volatile
+ return !reg.isFloat() && reg.gpr() == WasmTlsReg;
+ }
+
+ // LInstruction interface
+ size_t numOperands() const override {
+ return numOperands_;
+ }
+ LAllocation* getOperand(size_t index) override {
+ MOZ_ASSERT(index < numOperands_);
+ return &operands_[index];
+ }
+ void setOperand(size_t index, const LAllocation& a) override {
+ MOZ_ASSERT(index < numOperands_);
+ operands_[index] = a;
+ }
+ size_t numTemps() const override {
+ return 0;
+ }
+ LDefinition* getTemp(size_t index) override {
+ MOZ_CRASH("no temps");
+ }
+ void setTemp(size_t index, const LDefinition& a) override {
+ MOZ_CRASH("no temps");
+ }
+ size_t numSuccessors() const override {
+ return 0;
+ }
+ MBasicBlock* getSuccessor(size_t i) const override {
+ MOZ_CRASH("no successors");
+ }
+ void setSuccessor(size_t i, MBasicBlock*) override {
+ MOZ_CRASH("no successors");
+ }
+};
+
+class LWasmCall : public LWasmCallBase
+{
+ LDefinition def_;
+
+ public:
+ LIR_HEADER(WasmCall);
+
+ LWasmCall(LAllocation* operands, uint32_t numOperands)
+ : LWasmCallBase(operands, numOperands),
+ def_(LDefinition::BogusTemp())
+ {}
+
+ // LInstruction interface
+ size_t numDefs() const {
+ return def_.isBogusTemp() ? 0 : 1;
+ }
+ LDefinition* getDef(size_t index) {
+ MOZ_ASSERT(numDefs() == 1);
+ MOZ_ASSERT(index == 0);
+ return &def_;
+ }
+ void setDef(size_t index, const LDefinition& def) {
+ MOZ_ASSERT(index == 0);
+ def_ = def;
+ }
+};
+
+class LWasmCallI64 : public LWasmCallBase
+{
+ LDefinition defs_[INT64_PIECES];
+
+ public:
+ LIR_HEADER(WasmCallI64);
+
+ LWasmCallI64(LAllocation* operands, uint32_t numOperands)
+ : LWasmCallBase(operands, numOperands)
+ {
+ for (size_t i = 0; i < numDefs(); i++)
+ defs_[i] = LDefinition::BogusTemp();
+ }
+
+ // LInstruction interface
+ size_t numDefs() const {
+ return INT64_PIECES;
+ }
+ LDefinition* getDef(size_t index) {
+ MOZ_ASSERT(index < numDefs());
+ return &defs_[index];
+ }
+ void setDef(size_t index, const LDefinition& def) {
+ MOZ_ASSERT(index < numDefs());
+ defs_[index] = def;
+ }
+};
+
+class LAssertRangeI : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(AssertRangeI)
+
+ explicit LAssertRangeI(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+
+ MAssertRange* mir() {
+ return mir_->toAssertRange();
+ }
+ const Range* range() {
+ return mir()->assertedRange();
+ }
+};
+
+class LAssertRangeD : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(AssertRangeD)
+
+ LAssertRangeD(const LAllocation& input, const LDefinition& temp) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MAssertRange* mir() {
+ return mir_->toAssertRange();
+ }
+ const Range* range() {
+ return mir()->assertedRange();
+ }
+};
+
+class LAssertRangeF : public LInstructionHelper<0, 1, 2>
+{
+ public:
+ LIR_HEADER(AssertRangeF)
+ LAssertRangeF(const LAllocation& input, const LDefinition& temp, const LDefinition& temp2) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const LDefinition* temp2() {
+ return getTemp(1);
+ }
+
+ MAssertRange* mir() {
+ return mir_->toAssertRange();
+ }
+ const Range* range() {
+ return mir()->assertedRange();
+ }
+};
+
+class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3>
+{
+ public:
+ LIR_HEADER(AssertRangeV)
+
+ LAssertRangeV(const LBoxAllocation& input, const LDefinition& temp,
+ const LDefinition& floatTemp1, const LDefinition& floatTemp2)
+ {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ setTemp(1, floatTemp1);
+ setTemp(2, floatTemp2);
+ }
+
+ static const size_t Input = 0;
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+ const LDefinition* floatTemp1() {
+ return getTemp(1);
+ }
+ const LDefinition* floatTemp2() {
+ return getTemp(2);
+ }
+
+ MAssertRange* mir() {
+ return mir_->toAssertRange();
+ }
+ const Range* range() {
+ return mir()->assertedRange();
+ }
+};
+
+class LAssertResultT : public LInstructionHelper<0, 1, 0>
+{
+ public:
+ LIR_HEADER(AssertResultT)
+
+ explicit LAssertResultT(const LAllocation& input) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() {
+ return getOperand(0);
+ }
+};
+
+class LAssertResultV : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(AssertResultV)
+
+ static const size_t Input = 0;
+
+ explicit LAssertResultV(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+};
+
+class LRecompileCheck : public LInstructionHelper<0, 0, 1>
+{
+ public:
+ LIR_HEADER(RecompileCheck)
+
+ explicit LRecompileCheck(const LDefinition& scratch) {
+ setTemp(0, scratch);
+ }
+
+ const LDefinition* scratch() {
+ return getTemp(0);
+ }
+ MRecompileCheck* mir() {
+ return mir_->toRecompileCheck();
+ }
+};
+
+class LLexicalCheck : public LInstructionHelper<0, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(LexicalCheck)
+
+ explicit LLexicalCheck(const LBoxAllocation& input) {
+ setBoxOperand(Input, input);
+ }
+
+ MLexicalCheck* mir() {
+ return mir_->toLexicalCheck();
+ }
+
+ static const size_t Input = 0;
+};
+
+class LThrowRuntimeLexicalError : public LCallInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(ThrowRuntimeLexicalError)
+
+ MThrowRuntimeLexicalError* mir() {
+ return mir_->toThrowRuntimeLexicalError();
+ }
+};
+
+class LGlobalNameConflictsCheck : public LInstructionHelper<0, 0, 0>
+{
+ public:
+ LIR_HEADER(GlobalNameConflictsCheck)
+
+ MGlobalNameConflictsCheck* mir() {
+ return mir_->toGlobalNameConflictsCheck();
+ }
+};
+
+class LMemoryBarrier : public LInstructionHelper<0, 0, 0>
+{
+ private:
+ const MemoryBarrierBits type_;
+
+ public:
+ LIR_HEADER(MemoryBarrier)
+
+ // The parameter 'type' is a bitwise 'or' of the barrier types needed,
+ // see AtomicOp.h.
+ explicit LMemoryBarrier(MemoryBarrierBits type) : type_(type)
+ {
+ MOZ_ASSERT((type_ & ~MembarAllbits) == MembarNobits);
+ }
+
+ MemoryBarrierBits type() const {
+ return type_;
+ }
+};
+
+class LDebugger : public LCallInstructionHelper<0, 0, 2>
+{
+ public:
+ LIR_HEADER(Debugger)
+
+ LDebugger(const LDefinition& temp1, const LDefinition& temp2) {
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+};
+
+class LNewTarget : public LInstructionHelper<BOX_PIECES, 0, 0>
+{
+ public:
+ LIR_HEADER(NewTarget)
+};
+
+class LArrowNewTarget : public LInstructionHelper<BOX_PIECES, 1, 0>
+{
+ public:
+ explicit LArrowNewTarget(const LAllocation& callee) {
+ setOperand(0, callee);
+ }
+
+ LIR_HEADER(ArrowNewTarget)
+
+ const LAllocation* callee() {
+ return getOperand(0);
+ }
+};
+
+// Math.random().
+#ifdef JS_PUNBOX64
+# define LRANDOM_NUM_TEMPS 3
+#else
+# define LRANDOM_NUM_TEMPS 5
+#endif
+
+class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS>
+{
+ public:
+ LIR_HEADER(Random)
+ LRandom(const LDefinition &temp0, const LDefinition &temp1,
+ const LDefinition &temp2
+#ifndef JS_PUNBOX64
+ , const LDefinition &temp3, const LDefinition &temp4
+#endif
+ )
+ {
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+#ifndef JS_PUNBOX64
+ setTemp(3, temp3);
+ setTemp(4, temp4);
+#endif
+ }
+ const LDefinition* temp0() {
+ return getTemp(0);
+ }
+ const LDefinition* temp1() {
+ return getTemp(1);
+ }
+ const LDefinition *temp2() {
+ return getTemp(2);
+ }
+#ifndef JS_PUNBOX64
+ const LDefinition *temp3() {
+ return getTemp(3);
+ }
+ const LDefinition *temp4() {
+ return getTemp(4);
+ }
+#endif
+
+ MRandom* mir() const {
+ return mir_->toRandom();
+ }
+};
+
+class LCheckReturn : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CheckReturn)
+
+ LCheckReturn(const LBoxAllocation& retVal, const LBoxAllocation& thisVal) {
+ setBoxOperand(ReturnValue, retVal);
+ setBoxOperand(ThisValue, thisVal);
+ }
+
+ static const size_t ReturnValue = 0;
+ static const size_t ThisValue = BOX_PIECES;
+};
+
+class LCheckIsObj : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CheckIsObj)
+
+ static const size_t CheckValue = 0;
+
+ explicit LCheckIsObj(const LBoxAllocation& value) {
+ setBoxOperand(CheckValue, value);
+ }
+
+ MCheckIsObj* mir() const {
+ return mir_->toCheckIsObj();
+ }
+};
+
+class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(CheckObjCoercible)
+
+ static const size_t CheckValue = 0;
+
+ explicit LCheckObjCoercible(const LBoxAllocation& value) {
+ setBoxOperand(CheckValue, value);
+ }
+};
+
+class LDebugCheckSelfHosted : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
+{
+ public:
+ LIR_HEADER(DebugCheckSelfHosted)
+
+ static const size_t CheckValue = 0;
+
+ explicit LDebugCheckSelfHosted(const LBoxAllocation& value) {
+ setBoxOperand(CheckValue, value);
+ }
+};
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_shared_LIR_shared_h */