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.h8878
1 files changed, 8878 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 0000000000..54e6feb7c0
--- /dev/null
+++ b/js/src/jit/shared/LIR-shared.h
@@ -0,0 +1,8878 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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 "jit/AtomicOp.h"
+#include "jit/shared/Assembler-shared.h"
+#include "util/Memory.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)
+ : LInstructionHelper(classOpcode), 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> {
+ protected:
+ explicit LBinaryMath(LNode::Opcode opcode)
+ : LInstructionHelper<1, 2 + ExtraUses, Temps>(opcode) {}
+
+ public:
+ const LAllocation* lhs() { return this->getOperand(0); }
+ const LAllocation* rhs() { return this->getOperand(1); }
+};
+
+template <size_t Temps, size_t ExtraUses = 0>
+class LUnaryMath : public LInstructionHelper<1, 1 + ExtraUses, Temps> {
+ protected:
+ explicit LUnaryMath(LNode::Opcode opcode)
+ : LInstructionHelper<1, 1 + ExtraUses, Temps>(opcode) {}
+
+ public:
+ const LAllocation* input() { return this->getOperand(0); }
+};
+
+// 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 GC'd.
+class LOsiPoint : public LInstructionHelper<0, 0, 0> {
+ LSafepoint* safepoint_;
+
+ public:
+ LOsiPoint(LSafepoint* safepoint, LSnapshot* snapshot)
+ : LInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode), 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;
+ }
+};
+
+// Constant 32-bit integer.
+class LInteger : public LInstructionHelper<1, 0, 0> {
+ int32_t i32_;
+
+ public:
+ LIR_HEADER(Integer)
+
+ explicit LInteger(int32_t i32) : LInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode), i64_(i64) {}
+
+ int64_t getValue() const { return i64_; }
+};
+
+// Constant pointer.
+class LPointer : public LInstructionHelper<1, 0, 0> {
+ gc::Cell* ptr_;
+
+ public:
+ LIR_HEADER(Pointer)
+
+ explicit LPointer(gc::Cell* ptr)
+ : LInstructionHelper(classOpcode), ptr_(ptr) {}
+
+ gc::Cell* gcptr() const { return ptr_; }
+};
+
+// Constant double.
+class LDouble : public LInstructionHelper<1, 0, 0> {
+ double d_;
+
+ public:
+ LIR_HEADER(Double);
+
+ explicit LDouble(double d) : LInstructionHelper(classOpcode), d_(d) {}
+
+ const double& getDouble() const { return d_; }
+};
+
+// Constant float32.
+class LFloat32 : public LInstructionHelper<1, 0, 0> {
+ float f_;
+
+ public:
+ LIR_HEADER(Float32);
+
+ explicit LFloat32(float f) : LInstructionHelper(classOpcode), f_(f) {}
+
+ const float& getFloat() const { return f_; }
+};
+
+// A constant Value.
+class LValue : public LInstructionHelper<BOX_PIECES, 0, 0> {
+ Value v_;
+
+ public:
+ LIR_HEADER(Value)
+
+ explicit LValue(const Value& v) : LInstructionHelper(classOpcode), v_(v) {}
+
+ Value value() const { return v_; }
+};
+
+class LNurseryObject : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(NurseryObject);
+
+ LNurseryObject() : LInstructionHelper(classOpcode) {}
+
+ MNurseryObject* mir() const { return mir_->toNurseryObject(); }
+};
+
+// 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)
+
+ LParameter() : LInstructionHelper(classOpcode) {}
+};
+
+// Stack offset for a word-sized immutable input value to a frame.
+class LCallee : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(Callee)
+
+ LCallee() : LInstructionHelper(classOpcode) {}
+};
+
+class LIsConstructing : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(IsConstructing)
+
+ LIsConstructing() : LInstructionHelper(classOpcode) {}
+};
+
+// 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_;
+
+ protected:
+ explicit LControlInstructionHelper(LNode::Opcode opcode)
+ : LInstructionHelper<0, Operands, Temps>(opcode) {}
+
+ public:
+ size_t numSuccessors() const { return Succs; }
+ MBasicBlock* getSuccessor(size_t i) const { return successors_[i]; }
+
+ void setSuccessor(size_t i, MBasicBlock* successor) {
+ 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) : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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 LNewArrayDynamicLength : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(NewArrayDynamicLength)
+
+ explicit LNewArrayDynamicLength(const LAllocation& length,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 LNewIterator : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(NewIterator)
+
+ explicit LNewIterator(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MNewIterator* mir() const { return mir_->toNewIterator(); }
+};
+
+class LNewTypedArray : public LInstructionHelper<1, 0, 2> {
+ public:
+ LIR_HEADER(NewTypedArray)
+
+ LNewTypedArray(const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ LNewTypedArrayDynamicLength(const LAllocation& length,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 LNewTypedArrayFromArray : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NewTypedArrayFromArray)
+
+ explicit LNewTypedArrayFromArray(const LAllocation& array)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, array);
+ }
+
+ const LAllocation* array() { return getOperand(0); }
+
+ MNewTypedArrayFromArray* mir() const {
+ return mir_->toNewTypedArrayFromArray();
+ }
+};
+
+class LNewTypedArrayFromArrayBuffer
+ : public LCallInstructionHelper<1, 1 + 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(NewTypedArrayFromArrayBuffer)
+
+ LNewTypedArrayFromArrayBuffer(const LAllocation& arrayBuffer,
+ const LBoxAllocation& byteOffset,
+ const LBoxAllocation& length)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, arrayBuffer);
+ setBoxOperand(ByteOffsetIndex, byteOffset);
+ setBoxOperand(LengthIndex, length);
+ }
+
+ static const size_t ByteOffsetIndex = 1;
+ static const size_t LengthIndex = 1 + BOX_PIECES;
+
+ const LAllocation* arrayBuffer() { return getOperand(0); }
+
+ MNewTypedArrayFromArrayBuffer* mir() const {
+ return mir_->toNewTypedArrayFromArrayBuffer();
+ }
+};
+
+class LNewObject : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(NewObject)
+
+ explicit LNewObject(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ const char* extraName() const {
+ return mir()->isVMCall() ? "VMCall" : nullptr;
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MNewObject* mir() const { return mir_->toNewObject(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MNewCallObject* mir() const { return mir_->toNewCallObject(); }
+};
+
+class LNewStringObject : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(NewStringObject)
+
+ LNewStringObject(const LAllocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 LInitElemGetterSetter
+ : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(InitElemGetterSetter)
+
+ LInitElemGetterSetter(const LAllocation& object, const LBoxAllocation& id,
+ const LAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setBoxOperand(ValueIndex, value);
+ }
+
+ static const size_t ValueIndex = 1;
+
+ const LAllocation* getObject() { return getOperand(0); }
+ const LAllocation* getValue() { return getOperand(1); }
+};
+
+class LInitPropGetterSetter : public LCallInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(InitPropGetterSetter)
+
+ LInitPropGetterSetter(const LAllocation& object, const LAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ 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() : LInstructionHelper(classOpcode) {}
+
+ MCheckOverRecursed* mir() const { return mir_->toCheckOverRecursed(); }
+};
+
+class LWasmTrap : public LInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(WasmTrap);
+
+ LWasmTrap() : LInstructionHelper(classOpcode) {}
+
+ 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;
+
+ protected:
+ explicit LWasmReinterpretBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ 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)
+ : LWasmReinterpretBase(classOpcode) {
+ setOperand(0, input);
+ }
+};
+
+class LWasmReinterpretFromI64 : public LWasmReinterpretBase<1, INT64_PIECES> {
+ public:
+ LIR_HEADER(WasmReinterpretFromI64);
+ explicit LWasmReinterpretFromI64(const LInt64Allocation& input)
+ : LWasmReinterpretBase(classOpcode) {
+ setInt64Operand(0, input);
+ }
+};
+
+class LWasmReinterpretToI64 : public LWasmReinterpretBase<INT64_PIECES, 1> {
+ public:
+ LIR_HEADER(WasmReinterpretToI64);
+ explicit LWasmReinterpretToI64(const LAllocation& input)
+ : LWasmReinterpretBase(classOpcode) {
+ 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;
+
+ protected:
+ explicit RotateBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ public:
+ MRotate* mir() { return Base::mir_->toRotate(); }
+};
+} // namespace details
+
+class LRotate : public details::RotateBase<1, 2, 0> {
+ public:
+ LIR_HEADER(Rotate);
+
+ LRotate() : RotateBase(classOpcode) {}
+
+ 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() : RotateBase(classOpcode) {
+ 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> {
+ public:
+ LIR_HEADER(InterruptCheck)
+
+ LInterruptCheck() : LInstructionHelper(classOpcode) {}
+ MInterruptCheck* mir() const { return mir_->toInterruptCheck(); }
+};
+
+class LWasmInterruptCheck : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(WasmInterruptCheck)
+
+ explicit LWasmInterruptCheck(const LAllocation& tlsData)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, tlsData);
+ }
+ MWasmInterruptCheck* mir() const { return mir_->toWasmInterruptCheck(); }
+ const LAllocation* tlsPtr() { return getOperand(0); }
+};
+
+class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(TypeOfV)
+
+ LTypeOfV(const LBoxAllocation& input, const LDefinition& tempToUnbox)
+ : LInstructionHelper(classOpcode) {
+ 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 LTypeOfO : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(TypeOfO)
+
+ explicit LTypeOfO(const LAllocation& obj) : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+
+ MTypeOf* mir() const { return mir_->toTypeOf(); }
+};
+
+class LToAsyncIter : public LCallInstructionHelper<1, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ToAsyncIter)
+
+ explicit LToAsyncIter(const LAllocation& iterator,
+ const LBoxAllocation& nextMethod)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, iterator);
+ setBoxOperand(NextMethodIndex, nextMethod);
+ }
+
+ static const size_t NextMethodIndex = 1;
+
+ const LAllocation* iterator() { return getOperand(0); }
+};
+
+class LToPropertyKeyCache
+ : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ToPropertyKeyCache)
+
+ explicit LToPropertyKeyCache(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ const MToPropertyKeyCache* mir() const {
+ return mir_->toToPropertyKeyCache();
+ }
+
+ const LAllocation* input() { return getOperand(Input); }
+
+ static const size_t Input = 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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.
+// Always performs object initialization with a fast path.
+class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(CreateThisWithTemplate)
+
+ explicit LCreateThisWithTemplate(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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;
+};
+
+// Load an element from an arguments object.
+class LLoadArgumentsObjectArg : public LInstructionHelper<BOX_PIECES, 2, 1> {
+ public:
+ LIR_HEADER(LoadArgumentsObjectArg)
+
+ LLoadArgumentsObjectArg(const LAllocation& argsObj, const LAllocation& index,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, argsObj);
+ setOperand(1, index);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* getArgsObject() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return this->getTemp(0); }
+};
+
+// Return |arguments.length| unless it has been overridden.
+class LArgumentsObjectLength : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArgumentsObjectLength)
+
+ explicit LArgumentsObjectLength(const LAllocation& argsObj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, argsObj);
+ }
+
+ const LAllocation* getArgsObject() { return getOperand(0); }
+};
+
+// Guard that the arguments object has no overridden iterator.
+class LGuardArgumentsObjectNotOverriddenIterator
+ : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardArgumentsObjectNotOverriddenIterator)
+
+ explicit LGuardArgumentsObjectNotOverriddenIterator(
+ const LAllocation& argsObj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, argsObj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* getArgsObject() { return getOperand(0); }
+ const LDefinition* temp() { return this->getTemp(0); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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 LBoxNonStrictThis : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(BoxNonStrictThis)
+
+ static const size_t ValueIndex = 0;
+
+ explicit LBoxNonStrictThis(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(ValueIndex, value);
+ }
+
+ MBoxNonStrictThis* mir() const { return mir_->toBoxNonStrictThis(); }
+};
+
+class LImplicitThis : public LCallInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(ImplicitThis)
+
+ explicit LImplicitThis(const LAllocation& env)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, env);
+ }
+
+ const LAllocation* env() { return getOperand(0); }
+
+ MImplicitThis* mir() const { return mir_->toImplicitThis(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode), 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> {
+ protected:
+ explicit LJSCallInstructionHelper(LNode::Opcode opcode)
+ : LCallInstructionHelper<Defs, Operands, Temps>(opcode) {}
+
+ 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(); }
+ bool ignoresReturnValue() const { return mir()->ignoresReturnValue(); }
+};
+
+// 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)
+ : LJSCallInstructionHelper(classOpcode) {
+ 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)
+ : LJSCallInstructionHelper(classOpcode) {
+ 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)
+ : LJSCallInstructionHelper(classOpcode) {
+ // 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)
+ : LJSCallInstructionHelper(classOpcode) {
+ 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)
+
+ LBail() : LInstructionHelper(classOpcode) {}
+};
+
+class LUnreachable : public LControlInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(Unreachable)
+
+ LUnreachable() : LControlInstructionHelper(classOpcode) {}
+};
+
+class LEncodeSnapshot : public LInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(EncodeSnapshot)
+
+ LEncodeSnapshot() : LInstructionHelper(classOpcode) {}
+};
+
+class LUnreachableResultV : public LInstructionHelper<BOX_PIECES, 0, 0> {
+ public:
+ LIR_HEADER(UnreachableResultV)
+
+ LUnreachableResultV() : LInstructionHelper(classOpcode) {}
+};
+
+class LUnreachableResultT : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(UnreachableResultT)
+
+ LUnreachableResultT() : LInstructionHelper(classOpcode) {}
+};
+
+template <size_t defs, size_t ops>
+class LDOMPropertyInstructionHelper
+ : public LCallInstructionHelper<defs, 1 + ops, 3> {
+ protected:
+ LDOMPropertyInstructionHelper(LNode::Opcode opcode,
+ const LDefinition& JSContextReg,
+ const LAllocation& ObjectReg,
+ const LDefinition& PrivReg,
+ const LDefinition& ValueReg)
+ : LCallInstructionHelper<defs, 1 + ops, 3>(opcode) {
+ 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>(
+ classOpcode, 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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>(
+ classOpcode, JSContextReg, ObjectReg, PrivReg, ValueReg) {
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ MSetDOMProperty* mir() const { return mir_->toSetDOMProperty(); }
+};
+
+class LLoadDOMExpandoValue : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(LoadDOMExpandoValue)
+
+ explicit LLoadDOMExpandoValue(const LAllocation& proxy)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ }
+
+ const LAllocation* proxy() { return getOperand(0); }
+
+ const MLoadDOMExpandoValue* mir() const {
+ return mir_->toLoadDOMExpandoValue();
+ }
+};
+
+class LLoadDOMExpandoValueGuardGeneration
+ : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(LoadDOMExpandoValueGuardGeneration)
+
+ explicit LLoadDOMExpandoValueGuardGeneration(const LAllocation& proxy)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ }
+
+ const LAllocation* proxy() { return getOperand(0); }
+
+ const MLoadDOMExpandoValueGuardGeneration* mir() const {
+ return mir_->toLoadDOMExpandoValueGuardGeneration();
+ }
+};
+
+class LLoadDOMExpandoValueIgnoreGeneration
+ : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(LoadDOMExpandoValueIgnoreGeneration)
+
+ explicit LLoadDOMExpandoValueIgnoreGeneration(const LAllocation& proxy)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ }
+
+ const LAllocation* proxy() { return getOperand(0); }
+};
+
+class LGuardDOMExpandoMissingOrGuardShape
+ : public LInstructionHelper<0, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(GuardDOMExpandoMissingOrGuardShape)
+
+ explicit LGuardDOMExpandoMissingOrGuardShape(const LBoxAllocation& input,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ static const size_t Input = 0;
+
+ MGuardDOMExpandoMissingOrGuardShape* mir() {
+ return mir_->toGuardDOMExpandoMissingOrGuardShape();
+ }
+};
+
+// 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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 LConstructArrayGeneric
+ : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 3, 1> {
+ public:
+ LIR_HEADER(ConstructArrayGeneric)
+
+ LConstructArrayGeneric(const LAllocation& func, const LAllocation& elements,
+ const LAllocation& newTarget,
+ const LBoxAllocation& thisv,
+ const LDefinition& tmpobjreg)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, func);
+ setOperand(1, elements);
+ setOperand(2, newTarget);
+ setBoxOperand(ThisIndex, thisv);
+ setTemp(0, tmpobjreg);
+ }
+
+ MConstructArray* mir() const { return mir_->toConstructArray(); }
+
+ bool hasSingleTarget() const { return getSingleTarget() != nullptr; }
+ WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); }
+
+ const LAllocation* getFunction() { return getOperand(0); }
+ const LAllocation* getElements() { return getOperand(1); }
+ const LAllocation* getNewTarget() { return getOperand(2); }
+
+ static const size_t ThisIndex = 3;
+
+ const LDefinition* getTempObject() { return getTemp(0); }
+
+ // 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); }
+
+ // tempStackCounter is mapped to the same register as newTarget:
+ // tempStackCounter becomes live as newTarget is dying, all registers are
+ // calltemps.
+ const LAllocation* getTempStackCounter() { return getOperand(2); }
+};
+
+// 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ setSuccessor(0, ifTruthy);
+ setSuccessor(1, ifFalsy);
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ setTemp(2, temp2);
+ }
+
+ 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(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode), 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)
+ : LControlInstructionHelper(classOpcode), 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)
+ : LControlInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode), 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)
+ : LControlInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MCompare* mir() { return mir_->toCompare(); }
+};
+
+class LCompareBigInt : public LInstructionHelper<1, 2, 3> {
+ public:
+ LIR_HEADER(CompareBigInt)
+
+ LCompareBigInt(const LAllocation& left, const LAllocation& right,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+ MCompare* mir() { return mir_->toCompare(); }
+};
+
+class LCompareBigIntInt32 : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CompareBigIntInt32)
+
+ LCompareBigIntInt32(const LAllocation& left, const LAllocation& right,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ MCompare* mir() { return mir_->toCompare(); }
+};
+
+class LCompareBigIntDouble : public LCallInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(CompareBigIntDouble)
+
+ LCompareBigIntDouble(const LAllocation& left, const LAllocation& right,
+ const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ MCompare* mir() { return mir_->toCompare(); }
+};
+
+class LCompareBigIntString : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(CompareBigIntString)
+
+ LCompareBigIntString(const LAllocation& left, const LAllocation& right)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ MCompare* mir() { return mir_->toCompare(); }
+};
+
+class LBitAndAndBranch : public LControlInstructionHelper<2, 2, 0> {
+ Assembler::Condition cond_;
+
+ public:
+ LIR_HEADER(BitAndAndBranch)
+ LBitAndAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ Assembler::Condition cond = Assembler::NonZero)
+ : LControlInstructionHelper(classOpcode), cond_(cond) {
+ 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); }
+ Assembler::Condition cond() const {
+ MOZ_ASSERT(cond_ == Assembler::Zero || cond_ == Assembler::NonZero);
+ return cond_;
+ }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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 pointer and tests whether it is an object that emulates
+// |undefined|, as above.
+class LIsNullOrLikeUndefinedT : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsNullOrLikeUndefinedT)
+
+ explicit LIsNullOrLikeUndefinedT(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode), 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)
+ : LControlInstructionHelper(classOpcode), 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); }
+};
+
+class LSameValueD : public LInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(SameValueD)
+ LSameValueD(const LAllocation& left, const LAllocation& right,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, left);
+ setOperand(1, right);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* left() { return getOperand(0); }
+ const LAllocation* right() { return getOperand(1); }
+ const LDefinition* tempFloat() { return getTemp(0); }
+};
+
+// Not operation on an integer.
+class LNotI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NotI)
+
+ explicit LNotI(const LAllocation& input) : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, input);
+ }
+};
+
+// Not operation on a double.
+class LNotD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NotD)
+
+ explicit LNotD(const LAllocation& input) : LInstructionHelper(classOpcode) {
+ 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) : LInstructionHelper(classOpcode) {
+ 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) : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ LBitNotI() : LInstructionHelper(classOpcode) {}
+};
+
+// 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) : LInstructionHelper(classOpcode), 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) : LInstructionHelper(classOpcode), op_(op) {}
+
+ const char* extraName() const { return CodeName(op_); }
+
+ JSOp bitop() const { return op_; }
+};
+
+// 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) : LBinaryMath(classOpcode), 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) : LInstructionHelper(classOpcode), 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 LSignExtendInt32 : public LInstructionHelper<1, 1, 0> {
+ MSignExtendInt32::Mode mode_;
+
+ public:
+ LIR_HEADER(SignExtendInt32);
+
+ explicit LSignExtendInt32(const LAllocation& num, MSignExtendInt32::Mode mode)
+ : LInstructionHelper(classOpcode), mode_(mode) {
+ setOperand(0, num);
+ }
+
+ MSignExtendInt32::Mode mode() { return mode_; }
+};
+
+class LSignExtendInt64
+ : public LInstructionHelper<INT64_PIECES, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(SignExtendInt64)
+
+ explicit LSignExtendInt64(const LInt64Allocation& input)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, input);
+ }
+
+ const MSignExtendInt64* mir() const { return mir_->toSignExtendInt64(); }
+
+ MSignExtendInt64::Mode mode() const { return mir()->mode(); }
+};
+
+class LUrshD : public LBinaryMath<1> {
+ public:
+ LIR_HEADER(UrshD)
+
+ LUrshD(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp)
+ : LBinaryMath(classOpcode) {
+ 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> {
+ bool isGenerator_;
+
+ public:
+ LIR_HEADER(Return)
+
+ explicit LReturn(bool isGenerator)
+ : LInstructionHelper(classOpcode), isGenerator_(isGenerator) {}
+
+ bool isGenerator() { return isGenerator_; }
+};
+
+class LThrow : public LCallInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(Throw)
+
+ static const size_t Value = 0;
+
+ explicit LThrow(const LBoxAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ }
+};
+
+class LMinMaxBase : public LInstructionHelper<1, 2, 0> {
+ protected:
+ LMinMaxBase(LNode::Opcode opcode, const LAllocation& first,
+ const LAllocation& second)
+ : LInstructionHelper(opcode) {
+ 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(classOpcode, first, second) {}
+};
+
+class LMinMaxD : public LMinMaxBase {
+ public:
+ LIR_HEADER(MinMaxD)
+ LMinMaxD(const LAllocation& first, const LAllocation& second)
+ : LMinMaxBase(classOpcode, first, second) {}
+};
+
+class LMinMaxF : public LMinMaxBase {
+ public:
+ LIR_HEADER(MinMaxF)
+ LMinMaxF(const LAllocation& first, const LAllocation& second)
+ : LMinMaxBase(classOpcode, first, second) {}
+};
+
+// Negative of an integer
+class LNegI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NegI);
+ explicit LNegI(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Negative of a double.
+class LNegD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NegD)
+ explicit LNegD(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Negative of a float32.
+class LNegF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NegF)
+ explicit LNegF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Absolute value of an integer.
+class LAbsI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(AbsI)
+ explicit LAbsI(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+
+ MAbs* mir() const { return mir_->toAbs(); }
+};
+
+// Absolute value of a double.
+class LAbsD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(AbsD)
+ explicit LAbsD(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Absolute value of a float32.
+class LAbsF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(AbsF)
+ explicit LAbsF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Copysign for doubles.
+class LCopySignD : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CopySignD)
+ explicit LCopySignD() : LInstructionHelper(classOpcode) {}
+};
+
+// Copysign for float32.
+class LCopySignF : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CopySignF)
+ explicit LCopySignF() : LInstructionHelper(classOpcode) {}
+};
+
+// Count leading zeroes on an int32.
+class LClzI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ClzI)
+ explicit LClzI(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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) : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Square root of a float32.
+class LSqrtF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(SqrtF)
+ explicit LSqrtF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+class LAtan2D : public LCallInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(Atan2D)
+ LAtan2D(const LAllocation& y, const LAllocation& x, const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode), numOperands_(2) {
+ setOperand(0, x);
+ setOperand(1, y);
+ setTemp(0, temp);
+ }
+
+ LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z,
+ const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode), 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)
+ : LCallInstructionHelper(classOpcode), 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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); }
+};
+
+// Integer raised to an integer power.
+class LPowII : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(PowII)
+ LPowII(const LAllocation& value, const LAllocation& power,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, value);
+ setOperand(1, power);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* value() { return getOperand(0); }
+ const LAllocation* power() { return getOperand(1); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MPow* mir() const { return mir_->toPow(); }
+};
+
+// 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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); }
+};
+
+// Constant of a power of two raised to an integer power.
+class LPowOfTwoI : public LInstructionHelper<1, 1, 0> {
+ uint32_t base_;
+
+ public:
+ LIR_HEADER(PowOfTwoI)
+ LPowOfTwoI(uint32_t base, const LAllocation& power)
+ : LInstructionHelper(classOpcode), base_(base) {
+ setOperand(0, power);
+ }
+
+ uint32_t base() const { return base_; }
+ const LAllocation* power() { return getOperand(0); }
+};
+
+// Sign value of an integer.
+class LSignI : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(SignI)
+ explicit LSignI(const LAllocation& input) : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+};
+
+// Sign value of a double.
+class LSignD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(SignD)
+ explicit LSignD(const LAllocation& input) : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+};
+
+// Sign value of a double with expected int32 result.
+class LSignDI : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(SignDI)
+ explicit LSignDI(const LAllocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LMathFunctionD : public LCallInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(MathFunctionD)
+ LMathFunctionD(const LAllocation& input, const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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() : LBinaryMath(classOpcode), recoversInput_(false) {}
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ 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)
+
+ LAddI64() : LInstructionHelper(classOpcode) {}
+
+ 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() : LBinaryMath(classOpcode), recoversInput_(false) {}
+
+ const char* extraName() const {
+ return snapshot() ? "OverflowCheck" : nullptr;
+ }
+
+ bool recoversInput() const { return recoversInput_; }
+ void setRecoversInput() { recoversInput_ = true; }
+ MSub* mir() const { return mir_->toSub(); }
+};
+
+inline bool LNode::recoversInput() const {
+ switch (op()) {
+ case Opcode::AddI:
+ return toAddI()->recoversInput();
+ case Opcode::SubI:
+ return toSubI()->recoversInput();
+ default:
+ return false;
+ }
+}
+
+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;
+
+ LSubI64() : LInstructionHelper(classOpcode) {}
+};
+
+class LMulI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 1> {
+ public:
+ LIR_HEADER(MulI64)
+
+ explicit LMulI64() : LInstructionHelper(classOpcode) {
+ 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) : LBinaryMath(classOpcode), 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) : LBinaryMath(classOpcode), 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)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp);
+ setIsCall();
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ MMod* mir() const { return mir_->toMod(); }
+};
+
+class LModPowTwoD : public LInstructionHelper<1, 1, 0> {
+ const uint32_t divisor_;
+
+ public:
+ LIR_HEADER(ModPowTwoD)
+
+ LModPowTwoD(const LAllocation& lhs, uint32_t divisor)
+ : LInstructionHelper(classOpcode), divisor_(divisor) {
+ setOperand(0, lhs);
+ }
+
+ uint32_t divisor() const { return divisor_; }
+ const LAllocation* lhs() { return getOperand(0); }
+ MMod* mir() const { return mir_->toMod(); }
+};
+
+class LWasmBuiltinModD : public LInstructionHelper<1, 3, 0> {
+ static const size_t LhsIndex = 0;
+ static const size_t RhsIndex = 1;
+ static const size_t TlsIndex = 2;
+
+ public:
+ LIR_HEADER(WasmBuiltinModD)
+
+ LWasmBuiltinModD(const LAllocation& lhs, const LAllocation& rhs,
+ const LAllocation& tls)
+ : LInstructionHelper(classOpcode) {
+ setOperand(LhsIndex, lhs);
+ setOperand(RhsIndex, rhs);
+ setOperand(TlsIndex, tls);
+ setIsCall();
+ }
+
+ const LAllocation* lhs() { return this->getOperand(LhsIndex); }
+ const LAllocation* rhs() { return this->getOperand(RhsIndex); }
+ const LAllocation* tls() { return this->getOperand(TlsIndex); }
+
+ MWasmBuiltinModD* mir() const { return mir_->toWasmBuiltinModD(); }
+};
+
+class LBigIntAdd : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntAdd)
+
+ LBigIntAdd(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntSub : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntSub)
+
+ LBigIntSub(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntMul : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntMul)
+
+ LBigIntMul(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntDiv : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntDiv)
+
+ LBigIntDiv(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntDiv* mir() const { return mirRaw()->toBigIntDiv(); }
+};
+
+class LBigIntMod : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntMod)
+
+ LBigIntMod(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntMod* mir() const { return mirRaw()->toBigIntMod(); }
+};
+
+class LBigIntPow : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntPow)
+
+ LBigIntPow(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ const MBigIntPow* mir() const { return mirRaw()->toBigIntPow(); }
+};
+
+class LBigIntBitAnd : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitAnd)
+
+ LBigIntBitAnd(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntBitOr : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitOr)
+
+ LBigIntBitOr(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntBitXor : public LBinaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitXor)
+
+ LBigIntBitXor(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntLsh : public LBinaryMath<3> {
+ public:
+ LIR_HEADER(BigIntLsh)
+
+ LBigIntLsh(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+};
+
+class LBigIntRsh : public LBinaryMath<3> {
+ public:
+ LIR_HEADER(BigIntRsh)
+
+ LBigIntRsh(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LBinaryMath(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+};
+
+class LBigIntIncrement : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntIncrement)
+
+ LBigIntIncrement(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntDecrement : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntDecrement)
+
+ LBigIntDecrement(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntNegate : public LUnaryMath<1> {
+ public:
+ LIR_HEADER(BigIntNegate)
+
+ LBigIntNegate(const LAllocation& input, const LDefinition& temp)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LBigIntBitNot : public LUnaryMath<2> {
+ public:
+ LIR_HEADER(BigIntBitNot)
+
+ LBigIntBitNot(const LAllocation& input, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LUnaryMath(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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, 1> {
+ public:
+ LIR_HEADER(CharCodeAt)
+
+ LCharCodeAt(const LAllocation& str, const LAllocation& index,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, str);
+ setOperand(1, index);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* str() { return this->getOperand(0); }
+ const LAllocation* index() { return this->getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+// Convert uint16 character code to a string.
+class LFromCharCode : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(FromCharCode)
+
+ explicit LFromCharCode(const LAllocation& code)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, code);
+ }
+
+ const LAllocation* code() { return this->getOperand(0); }
+};
+
+// Convert uint32 code point to a string.
+class LFromCodePoint : public LInstructionHelper<1, 1, 2> {
+ public:
+ LIR_HEADER(FromCodePoint)
+
+ explicit LFromCodePoint(const LAllocation& codePoint,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, codePoint);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* codePoint() { return this->getOperand(0); }
+
+ const LDefinition* temp1() { return this->getTemp(0); }
+
+ const LDefinition* temp2() { return this->getTemp(1); }
+};
+
+// Calls the ToLowerCase or ToUpperCase case conversion function.
+class LStringConvertCase : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(StringConvertCase)
+
+ explicit LStringConvertCase(const LAllocation& string)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, string);
+ }
+
+ const MStringConvertCase* mir() const { return mir_->toStringConvertCase(); }
+
+ const LAllocation* string() { return this->getOperand(0); }
+};
+
+class LStringSplit : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(StringSplit)
+
+ LStringSplit(const LAllocation& string, const LAllocation& separator)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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, TRUNCATE_NOWRAP };
+
+ private:
+ Mode mode_;
+
+ public:
+ LIR_HEADER(ValueToInt32)
+
+ LValueToInt32(const LBoxAllocation& input, const LDefinition& temp0,
+ const LDefinition& temp1, Mode mode)
+ : LInstructionHelper(classOpcode), mode_(mode) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const char* extraName() const {
+ return mode() == NORMAL ? "Normal"
+ : mode() == TRUNCATE ? "Truncate"
+ : "TruncateNoWrap";
+ }
+
+ static const size_t Input = 0;
+
+ Mode mode() const { return mode_; }
+ const LDefinition* tempFloat() { return getTemp(0); }
+ const LDefinition* temp() { return getTemp(1); }
+ MToNumberInt32* mirNormal() const {
+ MOZ_ASSERT(mode_ == NORMAL);
+ return mir_->toToNumberInt32();
+ }
+ MTruncateToInt32* mirTruncate() const {
+ MOZ_ASSERT(mode_ == TRUNCATE);
+ return mir_->toTruncateToInt32();
+ }
+ MToIntegerInt32* mirTruncateNoWrap() const {
+ MOZ_ASSERT(mode_ == TRUNCATE_NOWRAP);
+ return mir_->toToIntegerInt32();
+ }
+ MInstruction* mir() const { return mir_->toInstruction(); }
+};
+
+// Convert a value to a BigInt.
+class LValueToBigInt : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ValueToBigInt)
+ static const size_t Input = 0;
+
+ explicit LValueToBigInt(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ MToBigInt* mir() const { return mir_->toToBigInt(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+
+ MToNumberInt32* mir() const { return mir_->toToNumberInt32(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+
+ MToNumberInt32* mir() const { return mir_->toToNumberInt32(); }
+};
+
+// Truncates a double to an int32.
+// Input: floating-point register
+// Output: 32-bit integer
+// Bailout: if the double when converted to an integer exceeds the int32
+// bounds. No bailout for NaN or negative zero.
+class LDoubleToIntegerInt32 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(DoubleToIntegerInt32)
+
+ explicit LDoubleToIntegerInt32(const LAllocation& in)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+
+ MToIntegerInt32* mir() const { return mir_->toToIntegerInt32(); }
+};
+
+// Truncates a float to an int32.
+// Input: floating-point register
+// Output: 32-bit integer
+// Bailout: if the double when converted to an integer exceeds the int32
+// bounds. No bailout for NaN or negative zero.
+class LFloat32ToIntegerInt32 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(Float32ToIntegerInt32)
+
+ explicit LFloat32ToIntegerInt32(const LAllocation& in)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+
+ MToIntegerInt32* mir() const { return mir_->toToIntegerInt32(); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempFloat() { return getTemp(0); }
+
+ MTruncateToInt32* mir() const { return mir_->toTruncateToInt32(); }
+};
+
+// Convert a double to a truncated int32 with tls offset because we need it for
+// the slow ool path.
+class LWasmBuiltinTruncateDToInt32 : public LInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(WasmBuiltinTruncateDToInt32)
+
+ LWasmBuiltinTruncateDToInt32(const LAllocation& in, const LAllocation& tls,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setOperand(1, tls);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempFloat() { return getTemp(0); }
+
+ MWasmBuiltinTruncateToInt32* mir() const {
+ return mir_->toWasmBuiltinTruncateToInt32();
+ }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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 with tls offset because we need it for
+// the slow ool path.
+class LWasmBuiltinTruncateFToInt32 : public LInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(WasmBuiltinTruncateFToInt32)
+
+ LWasmBuiltinTruncateFToInt32(const LAllocation& in, const LAllocation& tls,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setOperand(1, tls);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* tempFloat() { return getTemp(0); }
+
+ MWasmBuiltinTruncateToInt32* mir() const {
+ return mir_->toWasmBuiltinTruncateToInt32();
+ }
+};
+
+class LWasmTruncateToInt32 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmTruncateToInt32)
+
+ explicit LWasmTruncateToInt32(const LAllocation& in)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ setTemp(0, tempToUnbox);
+ }
+
+ static const size_t Input = 0;
+
+ const MToString* mir() { return mir_->toToString(); }
+
+ const LDefinition* tempToUnbox() { return getTemp(0); }
+};
+
+// Double raised to a half power.
+class LPowHalfD : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(PowHalfD);
+ explicit LPowHalfD(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* output() { return getDef(0); }
+ MPowHalf* mir() const { return mir_->toPowHalf(); }
+};
+
+class LNaNToZero : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(NaNToZero)
+
+ explicit LNaNToZero(const LAllocation& input, const LDefinition& tempDouble)
+ : LInstructionHelper(classOpcode) {
+ 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 via the IonOsrTempData
+// populated by PrepareOsrTempData.
+//
+// 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)
+ : LInstructionHelper(classOpcode), 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, entry);
+ }
+
+ const MOsrArgumentsObject* mir() { return mir_->toOsrArgumentsObject(); }
+};
+
+class LRegExp : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(RegExp)
+
+ explicit LRegExp(const LDefinition& temp) : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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);
+ LRegExpPrototypeOptimizable(const LAllocation& object,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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);
+ LRegExpInstanceOptimizable(const LAllocation& object,
+ const LAllocation& proto, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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);
+ LGetFirstDollarIndex(const LAllocation& str, const LDefinition& temp0,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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 LBinaryValueCache
+ : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(BinaryValueCache)
+
+ // Takes two temps: these are intendend to be FloatReg0 and FloatReg1
+ // To allow the actual cache code to safely clobber those values without
+ // save and restore.
+ LBinaryValueCache(const LBoxAllocation& lhs, const LBoxAllocation& rhs,
+ const LDefinition& temp0, const LDefinition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const MBinaryCache* mir() const { return mir_->toBinaryCache(); }
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+};
+
+class LBinaryBoolCache : public LInstructionHelper<1, 2 * BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(BinaryBoolCache)
+
+ // Takes two temps: these are intendend to be FloatReg0 and FloatReg1
+ // To allow the actual cache code to safely clobber those values without
+ // save and restore.
+ LBinaryBoolCache(const LBoxAllocation& lhs, const LBoxAllocation& rhs,
+ const LDefinition& temp0, const LDefinition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LhsInput, lhs);
+ setBoxOperand(RhsInput, rhs);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const MBinaryCache* mir() const { return mir_->toBinaryCache(); }
+
+ static const size_t LhsInput = 0;
+ static const size_t RhsInput = BOX_PIECES;
+};
+
+class LUnaryCache : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(UnaryCache)
+
+ explicit LUnaryCache(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ const MUnaryCache* mir() const { return mir_->toUnaryCache(); }
+
+ const LAllocation* input() { return getOperand(Input); }
+
+ static const size_t Input = 0;
+};
+
+class LClassConstructor : public LCallInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(ClassConstructor)
+
+ const MClassConstructor* mir() const { return mir_->toClassConstructor(); }
+
+ LClassConstructor() : LCallInstructionHelper(classOpcode) {}
+};
+
+class LDerivedClassConstructor : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(DerivedClassConstructor)
+
+ explicit LDerivedClassConstructor(const LAllocation& prototype)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, prototype);
+ }
+
+ const LAllocation* prototype() { return getOperand(0); }
+
+ const MDerivedClassConstructor* mir() const {
+ return mir_->toDerivedClassConstructor();
+ }
+};
+
+class LModuleMetadata : public LCallInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(ModuleMetadata)
+
+ const MModuleMetadata* mir() const { return mir_->toModuleMetadata(); }
+
+ LModuleMetadata() : LCallInstructionHelper(classOpcode) {}
+};
+
+class LDynamicImport : public LCallInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(DynamicImport)
+
+ static const size_t SpecifierIndex = 0;
+
+ explicit LDynamicImport(const LBoxAllocation& specifier)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(SpecifierIndex, specifier);
+ }
+
+ const MDynamicImport* mir() const { return mir_->toDynamicImport(); }
+};
+
+class LLambda : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(Lambda)
+
+ LLambda(const LAllocation& envChain, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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, 1> {
+ public:
+ LIR_HEADER(LambdaArrow)
+
+ static const size_t NewTargetValue = 1;
+
+ LLambdaArrow(const LAllocation& envChain, const LBoxAllocation& newTarget,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, envChain);
+ setBoxOperand(NewTargetValue, newTarget);
+ setTemp(0, temp);
+ }
+ const LAllocation* environmentChain() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ const MLambdaArrow* mir() const { return mir_->toLambdaArrow(); }
+};
+
+class LFunctionWithProto : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(FunctionWithProto)
+
+ LFunctionWithProto(const LAllocation& envChain, const LAllocation& prototype)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, envChain);
+ setOperand(1, prototype);
+ }
+ const LAllocation* environmentChain() { return getOperand(0); }
+ const LAllocation* prototype() { return getOperand(1); }
+ const MFunctionWithProto* mir() const { return mir_->toFunctionWithProto(); }
+};
+
+class LSetFunName : public LCallInstructionHelper<1, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(SetFunName)
+
+ static const size_t NameValue = 1;
+
+ LSetFunName(const LAllocation& fun, const LBoxAllocation& name)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, fun);
+ setBoxOperand(NameValue, name);
+ }
+ const LAllocation* fun() { return getOperand(0); }
+ const MSetFunName* mir() const { return mir_->toSetFunName(); }
+};
+
+class LKeepAliveObject : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(KeepAliveObject)
+
+ explicit LKeepAliveObject(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ 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) : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+
+ const MElements* mir() const { return mir_->toElements(); }
+};
+
+// Load the initialized length from an elements header.
+class LInitializedLength : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(InitializedLength)
+
+ explicit LInitializedLength(const LAllocation& elements)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// Load the length from an elements header.
+class LArrayLength : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArrayLength)
+
+ explicit LArrayLength(const LAllocation& elements)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// Load the "length" property of a function.
+class LFunctionLength : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(FunctionLength)
+
+ explicit LFunctionLength(const LAllocation& function)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, function);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+};
+
+// Load the "name" property of a function.
+class LFunctionName : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(FunctionName)
+
+ explicit LFunctionName(const LAllocation& function)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, function);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+};
+
+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)
+ : LInstructionHelper(classOpcode) {
+ 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); }
+};
+
+class LArrayBufferByteLengthInt32 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArrayBufferByteLengthInt32)
+
+ explicit LArrayBufferByteLengthInt32(const LAllocation& obj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+// Read the length of an array buffer view.
+class LArrayBufferViewLength : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArrayBufferViewLength)
+
+ explicit LArrayBufferViewLength(const LAllocation& obj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+// Read the byteOffset of an array buffer view.
+class LArrayBufferViewByteOffset : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArrayBufferViewByteOffset)
+
+ explicit LArrayBufferViewByteOffset(const LAllocation& obj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+// Load an array buffer view's elements vector.
+class LArrayBufferViewElements : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ArrayBufferViewElements)
+
+ explicit LArrayBufferViewElements(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() { return getOperand(0); }
+};
+
+// Return the element shift of a typed array.
+class LTypedArrayElementShift : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(TypedArrayElementShift)
+
+ explicit LTypedArrayElementShift(const LAllocation& obj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+// Double to Int32, eligible for accessing into a TypedArray. If the index isn't
+// exactly representable as an Int32, produce any Int32 which is equivalent to
+// an OOB access into a TypedArray.
+class LTypedArrayIndexToInt32 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(TypedArrayIndexToInt32)
+
+ explicit LTypedArrayIndexToInt32(const LAllocation& obj)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ }
+
+ const LAllocation* index() { return getOperand(0); }
+ const MTypedArrayIndexToInt32* mir() const {
+ return mir_->toTypedArrayIndexToInt32();
+ }
+};
+
+// Bailout if index >= length.
+class LBoundsCheck : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(BoundsCheck)
+
+ LBoundsCheck(const LAllocation& index, const LAllocation& length)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, index);
+ }
+ MBoundsCheckLower* mir() const { return mir_->toBoundsCheckLower(); }
+ const LAllocation* index() { return getOperand(0); }
+};
+
+class LSpectreMaskIndex : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(SpectreMaskIndex)
+
+ LSpectreMaskIndex(const LAllocation& index, const LAllocation& length)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, index);
+ setOperand(1, length);
+ }
+ const LAllocation* index() { return getOperand(0); }
+ const LAllocation* length() { return getOperand(1); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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, 3, 0> {
+ public:
+ LIR_HEADER(InArray)
+
+ LInArray(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& initLength)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, initLength);
+ }
+ 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); }
+};
+
+class LGuardElementNotHole : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(GuardElementNotHole)
+
+ LGuardElementNotHole(const LAllocation& elements, const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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); }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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); }
+};
+
+class LStoreHoleValueElement : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(StoreHoleValueElement)
+
+ LStoreHoleValueElement(const LAllocation& elements, const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+// 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& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setBoxOperand(Value, value);
+ setTemp(0, spectreTemp);
+ }
+
+ 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); }
+ const LDefinition* spectreTemp() { return getTemp(0); }
+};
+
+// 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& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, elements);
+ setOperand(2, index);
+ setOperand(3, value);
+ setTemp(0, spectreTemp);
+ }
+
+ 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); }
+ const LDefinition* spectreTemp() { return getTemp(0); }
+};
+
+class LArrayPopShift : public LInstructionHelper<BOX_PIECES, 1, 2> {
+ public:
+ LIR_HEADER(ArrayPopShift)
+
+ LArrayPopShift(const LAllocation& object, const LDefinition& temp0,
+ const LDefinition& temp1)
+ : LInstructionHelper(classOpcode) {
+ 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 LArrayPush : public LInstructionHelper<1, 1 + BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(ArrayPush)
+
+ LArrayPush(const LAllocation& object, const LBoxAllocation& value,
+ const LDefinition& temp, const LDefinition& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, spectreTemp);
+ }
+
+ 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); }
+ const LDefinition* spectreTemp() { return getTemp(1); }
+};
+
+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)
+ : LCallInstructionHelper(classOpcode) {
+ 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, 1> {
+ public:
+ LIR_HEADER(ArrayJoin)
+
+ LArrayJoin(const LAllocation& array, const LAllocation& sep,
+ const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, array);
+ setOperand(1, sep);
+ setTemp(0, temp);
+ }
+
+ const MArrayJoin* mir() const { return mir_->toArrayJoin(); }
+ const LDefinition* output() { return getDef(0); }
+ const LAllocation* array() { return getOperand(0); }
+ const LAllocation* separator() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LLoadUnboxedScalar : public LInstructionHelper<1, 2, 1> {
+ public:
+ LIR_HEADER(LoadUnboxedScalar)
+
+ LLoadUnboxedScalar(const LAllocation& elements, const LAllocation& index,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 LLoadUnboxedBigInt : public LInstructionHelper<1, 2, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadUnboxedBigInt)
+
+ LLoadUnboxedBigInt(const LAllocation& elements, const LAllocation& index,
+ const LDefinition& temp, const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ 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); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LLoadDataViewElement : public LInstructionHelper<1, 3, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadDataViewElement)
+
+ LLoadDataViewElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& littleEndian, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, littleEndian);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadDataViewElement* mir() const {
+ return mir_->toLoadDataViewElement();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* littleEndian() { return getOperand(2); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LLoadTypedArrayElementHole : public LInstructionHelper<BOX_PIECES, 2, 1> {
+ public:
+ LIR_HEADER(LoadTypedArrayElementHole)
+
+ LLoadTypedArrayElementHole(const LAllocation& object,
+ const LAllocation& index, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp);
+ }
+ const MLoadTypedArrayElementHole* mir() const {
+ return mir_->toLoadTypedArrayElementHole();
+ }
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LLoadTypedArrayElementHoleBigInt
+ : public LInstructionHelper<BOX_PIECES, 2, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(LoadTypedArrayElementHoleBigInt)
+
+ LLoadTypedArrayElementHoleBigInt(const LAllocation& object,
+ const LAllocation& index,
+ const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+ const MLoadTypedArrayElementHole* mir() const {
+ return mir_->toLoadTypedArrayElementHole();
+ }
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LStoreUnboxedScalar : public LInstructionHelper<0, 3, 0> {
+ public:
+ LIR_HEADER(StoreUnboxedScalar)
+
+ LStoreUnboxedScalar(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ 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 LStoreUnboxedBigInt : public LInstructionHelper<0, 3, INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreUnboxedBigInt)
+
+ LStoreUnboxedBigInt(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value, const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setInt64Temp(0, temp);
+ }
+
+ 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); }
+ LInt64Definition temp() { return getInt64Temp(0); }
+};
+
+class LStoreDataViewElement
+ : public LInstructionHelper<0, 4, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreDataViewElement)
+
+ LStoreDataViewElement(const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value,
+ const LAllocation& littleEndian,
+ const LDefinition& temp, const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setOperand(3, littleEndian);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const MStoreDataViewElement* mir() const {
+ return mir_->toStoreDataViewElement();
+ }
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ const LAllocation* littleEndian() { return getOperand(3); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 1> {
+ public:
+ LIR_HEADER(StoreTypedArrayElementHole)
+
+ LStoreTypedArrayElementHole(const LAllocation& elements,
+ const LAllocation& length,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, length);
+ setOperand(2, index);
+ setOperand(3, value);
+ setTemp(0, spectreTemp);
+ }
+
+ 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); }
+ const LDefinition* spectreTemp() { return getTemp(0); }
+};
+
+class LStoreTypedArrayElementHoleBigInt
+ : public LInstructionHelper<0, 4, INT64_PIECES> {
+ public:
+ LIR_HEADER(StoreTypedArrayElementHoleBigInt)
+
+ LStoreTypedArrayElementHoleBigInt(const LAllocation& elements,
+ const LAllocation& length,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LInt64Definition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, length);
+ setOperand(2, index);
+ setOperand(3, value);
+ setInt64Temp(0, temp);
+ }
+
+ 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); }
+ LInt64Definition temp() { return getInt64Temp(0); }
+};
+
+class LAtomicIsLockFree : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(AtomicIsLockFree)
+
+ explicit LAtomicIsLockFree(const LAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, value);
+ }
+ const LAllocation* value() { return getOperand(0); }
+};
+
+class LCompareExchangeTypedArrayElement : public LInstructionHelper<1, 4, 4> {
+ public:
+ LIR_HEADER(CompareExchangeTypedArrayElement)
+
+ // ARM, ARM64, x86, x64
+ LCompareExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& oldval,
+ const LAllocation& newval,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, oldval);
+ setOperand(3, newval);
+ setTemp(0, temp);
+ }
+ // MIPS32, MIPS64
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ // ARM, ARM64, x86, x64
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp);
+ }
+ // MIPS32, MIPS64
+ LAtomicExchangeTypedArrayElement(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ 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;
+
+ // ARM, ARM64, x86, x64
+ LAtomicTypedArrayElementBinop(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+ // MIPS32, MIPS64
+ LAtomicTypedArrayElementBinop(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& temp2,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, LDefinition::BogusTemp());
+ 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)
+
+ // ARM, ARM64, x86, x64
+ LAtomicTypedArrayElementBinopForEffect(
+ const LAllocation& elements, const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LAtomicTypedArrayElementBinopForEffect(const LAllocation& elements,
+ const LAllocation& index,
+ const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ setOperand(2, value);
+ setTemp(0, LDefinition::BogusTemp());
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+};
+
+class LClampDToUint8 : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(ClampDToUint8)
+
+ LClampDToUint8(const LAllocation& in, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+
+ const MLoadFixedSlotAndUnbox* mir() const {
+ return mir_->toLoadFixedSlotAndUnbox();
+ }
+};
+
+class LLoadDynamicSlotAndUnbox : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(LoadDynamicSlotAndUnbox)
+
+ explicit LLoadDynamicSlotAndUnbox(const LAllocation& slots)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, slots);
+ }
+
+ const LAllocation* slots() { return getOperand(0); }
+
+ const MLoadDynamicSlotAndUnbox* mir() const {
+ return mir_->toLoadDynamicSlotAndUnbox();
+ }
+};
+
+class LLoadElementAndUnbox : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(LoadElementAndUnbox)
+
+ LLoadElementAndUnbox(const LAllocation& elements, const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, elements);
+ setOperand(1, index);
+ }
+
+ const LAllocation* elements() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+
+ const MLoadElementAndUnbox* mir() const {
+ return mir_->toLoadElementAndUnbox();
+ }
+};
+
+class LAddAndStoreSlot : public LInstructionHelper<0, 1 + BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(AddAndStoreSlot)
+
+ LAddAndStoreSlot(const LAllocation& obj, const LBoxAllocation& value,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+
+ static const size_t Value = 1;
+
+ const MAddAndStoreSlot* mir() const { return mir_->toAddAndStoreSlot(); }
+};
+
+class LAllocateAndStoreSlot
+ : public LCallInstructionHelper<0, 1 + BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(AllocateAndStoreSlot)
+
+ LAllocateAndStoreSlot(const LAllocation& obj, const LBoxAllocation& value,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(Value, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ static const size_t Value = 1;
+
+ const MAllocateAndStoreSlot* mir() const {
+ return mir_->toAllocateAndStoreSlot();
+ }
+};
+
+// 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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, 1> {
+ public:
+ LIR_HEADER(GetNameCache)
+
+ LGetNameCache(const LAllocation& envObj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, envObj);
+ setTemp(0, temp);
+ }
+ const LAllocation* envObj() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(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();
+ }
+
+ LCallGetIntrinsicValue() : LCallInstructionHelper(classOpcode) {}
+};
+
+class LGetPropSuperCache
+ : public LInstructionHelper<BOX_PIECES, 1 + 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GetPropSuperCache)
+
+ static const size_t Receiver = 1;
+ static const size_t Id = Receiver + BOX_PIECES;
+
+ LGetPropSuperCache(const LAllocation& obj, const LBoxAllocation& receiver,
+ const LBoxAllocation& id)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(Receiver, receiver);
+ setBoxOperand(Id, id);
+ }
+ const LAllocation* obj() { return getOperand(0); }
+ const MGetPropSuperCache* mir() const { return mir_->toGetPropSuperCache(); }
+};
+
+// Patchable jump to stubs generated for a GetProperty cache, which loads a
+// boxed value.
+class LGetPropertyCache
+ : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GetPropertyCache)
+
+ static const size_t Value = 0;
+ static const size_t Id = BOX_PIECES;
+
+ LGetPropertyCache(const LBoxAllocation& value, const LBoxAllocation& id)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ setBoxOperand(Id, id);
+ }
+ const MGetPropertyCache* mir() const { return mir_->toGetPropertyCache(); }
+};
+
+class LBindNameCache : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(BindNameCache)
+
+ LBindNameCache(const LAllocation& envChain, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, envChain);
+ setTemp(0, temp);
+ }
+ const LAllocation* environmentChain() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ const MBindNameCache* mir() const { return mir_->toBindNameCache(); }
+};
+
+class LCallBindVar : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(CallBindVar)
+
+ explicit LCallBindVar(const LAllocation& envChain)
+ : LInstructionHelper(classOpcode) {
+ 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 LLoadDynamicSlotV : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(LoadDynamicSlotV)
+
+ explicit LLoadDynamicSlotV(const LAllocation& in)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ }
+ const MLoadDynamicSlot* mir() const { return mir_->toLoadDynamicSlot(); }
+};
+
+// Store a value to an object's dslots or a slots vector.
+class LStoreDynamicSlotV : public LInstructionHelper<0, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(StoreDynamicSlotV)
+
+ LStoreDynamicSlotV(const LAllocation& slots, const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, slots);
+ setBoxOperand(Value, value);
+ }
+
+ static const size_t Value = 1;
+
+ const MStoreDynamicSlot* mir() const { return mir_->toStoreDynamicSlot(); }
+ 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 LStoreDynamicSlotV:
+// 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 LStoreDynamicSlotT : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(StoreDynamicSlotT)
+
+ LStoreDynamicSlotT(const LAllocation& slots, const LAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, slots);
+ setOperand(1, value);
+ }
+ const MStoreDynamicSlot* mir() const { return mir_->toStoreDynamicSlot(); }
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, string);
+ }
+
+ const LAllocation* string() { return getOperand(0); }
+};
+
+// Take the floor of a double precision number and converts it to an int32.
+// Implements Math.floor().
+class LFloor : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(Floor)
+
+ explicit LFloor(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Take the floor of a single precision number and converts it to an int32.
+// Implements Math.floor().
+class LFloorF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(FloorF)
+
+ explicit LFloorF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Take the ceiling of a double precision number and converts it to an int32.
+// Implements Math.ceil().
+class LCeil : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(Ceil)
+
+ explicit LCeil(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Take the ceiling of a single precision number and converts it to an int32.
+// Implements Math.ceil().
+class LCeilF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(CeilF)
+
+ explicit LCeilF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Round a double precision number and converts it to an int32.
+// Implements Math.round().
+class LRound : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(Round)
+
+ LRound(const LAllocation& num, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+ MRound* mir() const { return mir_->toRound(); }
+};
+
+// Round a single precision number and converts it to an int32.
+// Implements Math.round().
+class LRoundF : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(RoundF)
+
+ LRoundF(const LAllocation& num, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+ MRound* mir() const { return mir_->toRound(); }
+};
+
+// Truncates a double precision number and converts it to an int32.
+// Implements Math.trunc().
+class LTrunc : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(Trunc)
+
+ explicit LTrunc(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Truncates a single precision number and converts it to an int32.
+// Implements Math.trunc().
+class LTruncF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(TruncF)
+
+ explicit LTruncF(const LAllocation& num) : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+};
+
+// Rounds a double precision number accordingly to mir()->roundingMode(),
+// and keeps a double output.
+class LNearbyInt : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NearbyInt)
+
+ explicit LNearbyInt(const LAllocation& num)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+ MNearbyInt* mir() const { return mir_->toNearbyInt(); }
+};
+
+// Rounds a single precision number accordingly to mir()->roundingMode(),
+// and keeps a single output.
+class LNearbyIntF : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NearbyIntF)
+
+ explicit LNearbyIntF(const LAllocation& num)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, num);
+ }
+ MNearbyInt* mir() const { return mir_->toNearbyInt(); }
+};
+
+// Load a function's call environment.
+class LFunctionEnvironment : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(FunctionEnvironment)
+
+ explicit LFunctionEnvironment(const LAllocation& function)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, function);
+ }
+ const LAllocation* function() { return getOperand(0); }
+};
+
+class LHomeObject : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(HomeObject)
+
+ explicit LHomeObject(const LAllocation& function)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, function);
+ }
+ const LAllocation* function() { return getOperand(0); }
+};
+
+class LHomeObjectSuperBase : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(HomeObjectSuperBase)
+
+ explicit LHomeObjectSuperBase(const LAllocation& homeObject)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, homeObject);
+ }
+
+ const LAllocation* homeObject() { return getOperand(0); }
+};
+
+// Allocate a new LexicalEnvironmentObject.
+class LNewLexicalEnvironmentObject : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(NewLexicalEnvironmentObject)
+
+ explicit LNewLexicalEnvironmentObject(const LAllocation& enclosing)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, enclosing);
+ }
+ const LAllocation* enclosing() { return getOperand(0); }
+
+ MNewLexicalEnvironmentObject* mir() const {
+ return mir_->toNewLexicalEnvironmentObject();
+ }
+};
+
+// Copy a LexicalEnvironmentObject.
+class LCopyLexicalEnvironmentObject : public LCallInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(CopyLexicalEnvironmentObject)
+
+ explicit LCopyLexicalEnvironmentObject(const LAllocation& env)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, env);
+ }
+ const LAllocation* env() { return getOperand(0); }
+
+ MCopyLexicalEnvironmentObject* mir() const {
+ return mir_->toCopyLexicalEnvironmentObject();
+ }
+};
+
+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)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(Index, index);
+ setBoxOperand(Value, value);
+ }
+
+ const MCallSetElement* mir() const { return mir_->toCallSetElement(); }
+};
+
+class LCallDeleteProperty : public LCallInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CallDeleteProperty)
+
+ static const size_t Value = 0;
+
+ explicit LCallDeleteProperty(const LBoxAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ 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)
+ : LCallInstructionHelper(classOpcode) {
+ 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, 2> {
+ public:
+ LIR_HEADER(SetPropertyCache)
+
+ // Takes an additional temp: this is intendend to be FloatReg0 to allow the
+ // actual cache code to safely clobber that value without save and restore.
+ LSetPropertyCache(const LAllocation& object, const LBoxAllocation& id,
+ const LBoxAllocation& value, const LDefinition& temp,
+ const LDefinition& tempDouble)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setBoxOperand(Id, id);
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ setTemp(1, tempDouble);
+ }
+
+ 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); }
+};
+
+class LGetIteratorCache : public LInstructionHelper<1, BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(GetIteratorCache)
+
+ static const size_t Value = 0;
+
+ LGetIteratorCache(const LBoxAllocation& value, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+ const MGetIteratorCache* mir() const { return mir_->toGetIteratorCache(); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LOptimizeSpreadCallCache : public LInstructionHelper<1, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(OptimizeSpreadCallCache)
+
+ static const size_t Value = 0;
+
+ LOptimizeSpreadCallCache(const LBoxAllocation& value, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ setTemp(0, temp);
+ }
+ const MOptimizeSpreadCallCache* mir() const {
+ return mir_->toOptimizeSpreadCallCache();
+ }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LIteratorMore : public LInstructionHelper<BOX_PIECES, 1, 1> {
+ public:
+ LIR_HEADER(IteratorMore)
+
+ LIteratorMore(const LAllocation& iterator, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ LArgumentsLength() : LInstructionHelper(classOpcode) {}
+};
+
+// Load a value from the actual arguments.
+class LGetFrameArgument : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(GetFrameArgument)
+
+ explicit LGetFrameArgument(const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, index);
+ }
+ const LAllocation* index() { return getOperand(0); }
+};
+
+// 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)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, numActuals);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+ const LAllocation* numActuals() { return getOperand(0); }
+ MRest* mir() const { return mir_->toRest(); }
+};
+
+// Convert a Boolean to an Int64, following ToBigInt.
+class LBooleanToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(BooleanToInt64)
+
+ explicit LBooleanToInt64(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ const MToInt64* mir() const { return mir_->toToInt64(); }
+};
+
+// Convert a String to an Int64, following ToBigInt.
+class LStringToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(StringToInt64)
+
+ explicit LStringToInt64(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ const MToInt64* mir() const { return mir_->toToInt64(); }
+};
+
+// Simulate ToBigInt on a Value and produce a matching Int64.
+class LValueToInt64 : public LInstructionHelper<INT64_PIECES, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(ValueToInt64)
+
+ explicit LValueToInt64(const LBoxAllocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 0;
+
+ const MToInt64* mir() const { return mir_->toToInt64(); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+// Truncate a BigInt to an unboxed int64.
+class LTruncateBigIntToInt64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(TruncateBigIntToInt64)
+
+ explicit LTruncateBigIntToInt64(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ const MTruncateBigIntToInt64* mir() const {
+ return mir_->toTruncateBigIntToInt64();
+ }
+};
+
+// Create a new BigInt* from an unboxed int64.
+class LInt64ToBigInt : public LInstructionHelper<1, INT64_PIECES, 1> {
+ public:
+ LIR_HEADER(Int64ToBigInt)
+
+ LInt64ToBigInt(const LInt64Allocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(Input, input);
+ setTemp(0, temp);
+ }
+
+ static const size_t Input = 0;
+
+ const MInt64ToBigInt* mir() const { return mir_->toInt64ToBigInt(); }
+ const LInt64Allocation input() { return getInt64Operand(Input); }
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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 string to an object.
+class LPostWriteBarrierS : public LInstructionHelper<0, 2, 1> {
+ public:
+ LIR_HEADER(PostWriteBarrierS)
+
+ LPostWriteBarrierS(const LAllocation& obj, const LAllocation& value,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 BigInt to an object.
+class LPostWriteBarrierBI : public LInstructionHelper<0, 2, 1> {
+ public:
+ LIR_HEADER(PostWriteBarrierBI)
+
+ LPostWriteBarrierBI(const LAllocation& obj, const LAllocation& value,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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 string to an object's
+// elements.
+class LPostWriteElementBarrierS : public LInstructionHelper<0, 3, 1> {
+ public:
+ LIR_HEADER(PostWriteElementBarrierS)
+
+ LPostWriteElementBarrierS(const LAllocation& obj, const LAllocation& value,
+ const LAllocation& index, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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 BigInt to an object's
+// elements.
+class LPostWriteElementBarrierBI : public LInstructionHelper<0, 3, 1> {
+ public:
+ LIR_HEADER(PostWriteElementBarrierBI)
+
+ LPostWriteElementBarrierBI(const LAllocation& obj, const LAllocation& value,
+ const LAllocation& index, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ LGuardObjectIdentity(const LAllocation& in, const LAllocation& expected)
+ : LInstructionHelper(classOpcode) {
+ 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 function's identity.
+class LGuardSpecificFunction : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(GuardSpecificFunction)
+
+ LGuardSpecificFunction(const LAllocation& in, const LAllocation& expected)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setOperand(1, expected);
+ }
+ const LAllocation* input() { return getOperand(0); }
+ const LAllocation* expected() { return getOperand(1); }
+};
+
+class LGuardSpecificAtom : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardSpecificAtom)
+
+ LGuardSpecificAtom(const LAllocation& str, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, str);
+ setTemp(0, temp);
+ }
+ const LAllocation* str() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ const MGuardSpecificAtom* mir() const { return mir_->toGuardSpecificAtom(); }
+};
+
+class LGuardSpecificSymbol : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(GuardSpecificSymbol)
+
+ explicit LGuardSpecificSymbol(const LAllocation& symbol)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, symbol);
+ }
+ const LAllocation* symbol() { return getOperand(0); }
+ const MGuardSpecificSymbol* mir() const {
+ return mir_->toGuardSpecificSymbol();
+ }
+};
+
+class LGuardStringToIndex : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(GuardStringToIndex)
+
+ explicit LGuardStringToIndex(const LAllocation& str)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, str);
+ }
+
+ const LAllocation* string() { return getOperand(0); }
+};
+
+class LGuardStringToInt32 : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(GuardStringToInt32)
+
+ LGuardStringToInt32(const LAllocation& str, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, str);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* string() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardStringToDouble : public LInstructionHelper<1, 1, 2> {
+ public:
+ LIR_HEADER(GuardStringToDouble)
+
+ LGuardStringToDouble(const LAllocation& str, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, str);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* string() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LGuardShape : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(GuardShape)
+
+ LGuardShape(const LAllocation& in, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ const MGuardShape* mir() const { return mir_->toGuardShape(); }
+};
+
+class LGuardProto : public LInstructionHelper<0, 2, 1> {
+ public:
+ LIR_HEADER(GuardProto)
+
+ LGuardProto(const LAllocation& obj, const LAllocation& expected,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setOperand(1, expected);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* expected() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardNullProto : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardNullProto)
+
+ LGuardNullProto(const LAllocation& obj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardIsNativeObject : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsNativeObject)
+
+ LGuardIsNativeObject(const LAllocation& obj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardIsProxy : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsProxy)
+
+ LGuardIsProxy(const LAllocation& obj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardIsNotProxy : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsNotProxy)
+
+ LGuardIsNotProxy(const LAllocation& obj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardIsNotDOMProxy : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsNotDOMProxy)
+
+ LGuardIsNotDOMProxy(const LAllocation& proxy, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* proxy() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LProxyGet : public LCallInstructionHelper<BOX_PIECES, 1, 1> {
+ public:
+ LIR_HEADER(ProxyGet)
+
+ LProxyGet(const LAllocation& proxy, const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* proxy() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ MProxyGet* mir() const { return mir_->toProxyGet(); }
+};
+
+class LProxyGetByValue
+ : public LCallInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ProxyGetByValue)
+
+ LProxyGetByValue(const LAllocation& proxy, const LBoxAllocation& idVal)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setBoxOperand(IdIndex, idVal);
+ }
+
+ static const size_t IdIndex = 1;
+
+ const LAllocation* proxy() { return getOperand(0); }
+};
+
+class LProxyHasProp
+ : public LCallInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ProxyHasProp)
+
+ LProxyHasProp(const LAllocation& proxy, const LBoxAllocation& idVal)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setBoxOperand(IdIndex, idVal);
+ }
+
+ static const size_t IdIndex = 1;
+
+ const LAllocation* proxy() { return getOperand(0); }
+
+ MProxyHasProp* mir() const { return mir_->toProxyHasProp(); }
+};
+
+class LProxySet : public LCallInstructionHelper<0, 1 + BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(ProxySet)
+
+ LProxySet(const LAllocation& proxy, const LBoxAllocation& rhs,
+ const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setBoxOperand(RhsIndex, rhs);
+ setTemp(0, temp);
+ }
+
+ static const size_t RhsIndex = 1;
+
+ const LAllocation* proxy() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ MProxySet* mir() const { return mir_->toProxySet(); }
+};
+
+class LProxySetByValue
+ : public LCallInstructionHelper<0, 1 + 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ProxySetByValue)
+
+ LProxySetByValue(const LAllocation& proxy, const LBoxAllocation& idVal,
+ const LBoxAllocation& rhs)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, proxy);
+ setBoxOperand(IdIndex, idVal);
+ setBoxOperand(RhsIndex, rhs);
+ }
+
+ static const size_t IdIndex = 1;
+ static const size_t RhsIndex = 1 + BOX_PIECES;
+
+ const LAllocation* proxy() { return getOperand(0); }
+
+ MProxySetByValue* mir() const { return mir_->toProxySetByValue(); }
+};
+
+class LCallSetArrayLength
+ : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CallSetArrayLength)
+
+ LCallSetArrayLength(const LAllocation& obj, const LBoxAllocation& rhs)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(RhsIndex, rhs);
+ }
+
+ static const size_t RhsIndex = 1;
+
+ const LAllocation* obj() { return getOperand(0); }
+
+ MCallSetArrayLength* mir() const { return mir_->toCallSetArrayLength(); }
+};
+
+class LMegamorphicLoadSlot : public LCallInstructionHelper<BOX_PIECES, 1, 3> {
+ public:
+ LIR_HEADER(MegamorphicLoadSlot)
+
+ LMegamorphicLoadSlot(const LAllocation& obj, const LDefinition& temp1,
+ const LDefinition& temp2, const LDefinition& temp3)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ 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); }
+
+ MMegamorphicLoadSlot* mir() const { return mir_->toMegamorphicLoadSlot(); }
+};
+
+class LMegamorphicLoadSlotByValue
+ : public LCallInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(MegamorphicLoadSlotByValue)
+
+ LMegamorphicLoadSlotByValue(const LAllocation& obj,
+ const LBoxAllocation& idVal,
+ const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(IdIndex, idVal);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ static const size_t IdIndex = 1;
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MMegamorphicLoadSlotByValue* mir() const {
+ return mir_->toMegamorphicLoadSlotByValue();
+ }
+};
+
+class LMegamorphicStoreSlot
+ : public LCallInstructionHelper<BOX_PIECES, 1 + BOX_PIECES, 3> {
+ public:
+ LIR_HEADER(MegamorphicStoreSlot)
+
+ LMegamorphicStoreSlot(const LAllocation& obj, const LBoxAllocation& rhs,
+ const LDefinition& temp1, const LDefinition& temp2,
+ const LDefinition& temp3)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(RhsIndex, rhs);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ setTemp(2, temp3);
+ }
+
+ static const size_t RhsIndex = 1;
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+ const LDefinition* temp3() { return getTemp(2); }
+
+ MMegamorphicStoreSlot* mir() const { return mir_->toMegamorphicStoreSlot(); }
+};
+
+class LMegamorphicHasProp
+ : public LCallInstructionHelper<1, 1 + BOX_PIECES, 2> {
+ public:
+ LIR_HEADER(MegamorphicHasProp)
+
+ LMegamorphicHasProp(const LAllocation& obj, const LBoxAllocation& idVal,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setBoxOperand(IdIndex, idVal);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ static const size_t IdIndex = 1;
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MMegamorphicHasProp* mir() const { return mir_->toMegamorphicHasProp(); }
+};
+
+class LGuardIsNotArrayBufferMaybeShared : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsNotArrayBufferMaybeShared)
+
+ LGuardIsNotArrayBufferMaybeShared(const LAllocation& obj,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardIsTypedArray : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsTypedArray)
+
+ LGuardIsTypedArray(const LAllocation& obj, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, obj);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardObjectGroup : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(GuardObjectGroup)
+
+ LGuardObjectGroup(const LAllocation& in, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ const MGuardObjectGroup* mir() const { return mir_->toGuardObjectGroup(); }
+};
+
+class LGuardNoDenseElements : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardNoDenseElements)
+
+ LGuardNoDenseElements(const LAllocation& in, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, in);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LInCache : public LInstructionHelper<1, BOX_PIECES + 1, 1> {
+ public:
+ LIR_HEADER(InCache)
+ LInCache(const LBoxAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(LHS); }
+ const LAllocation* rhs() { return getOperand(RHS); }
+ const LDefinition* temp() { return getTemp(0); }
+ const MInCache* mir() const { return mir_->toInCache(); }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LHasOwnCache : public LInstructionHelper<1, 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(HasOwnCache)
+
+ static const size_t Value = 0;
+ static const size_t Id = BOX_PIECES;
+
+ LHasOwnCache(const LBoxAllocation& value, const LBoxAllocation& id)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ setBoxOperand(Id, id);
+ }
+
+ const MHasOwnCache* mir() const { return mir_->toHasOwnCache(); }
+};
+
+class LCheckPrivateFieldCache
+ : public LInstructionHelper<1, 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckPrivateFieldCache)
+
+ static const size_t Value = 0;
+ static const size_t Id = BOX_PIECES;
+
+ LCheckPrivateFieldCache(const LBoxAllocation& value, const LBoxAllocation& id)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ setBoxOperand(Id, id);
+ }
+
+ const MCheckPrivateFieldCache* mir() const {
+ return mir_->toCheckPrivateFieldCache();
+ }
+};
+
+class LInstanceOfO : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(InstanceOfO)
+ explicit LInstanceOfO(const LAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ }
+
+ MInstanceOf* mir() const { return mir_->toInstanceOf(); }
+
+ const LAllocation* lhs() { return getOperand(0); }
+ const LAllocation* rhs() { return getOperand(1); }
+};
+
+class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(InstanceOfV)
+ explicit LInstanceOfV(const LBoxAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ }
+
+ MInstanceOf* mir() const { return mir_->toInstanceOf(); }
+
+ const LAllocation* rhs() { return getOperand(RHS); }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LInstanceOfCache : public LInstructionHelper<1, BOX_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(InstanceOfCache)
+ LInstanceOfCache(const LBoxAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(LHS, lhs);
+ setOperand(RHS, rhs);
+ }
+
+ const LDefinition* output() { return this->getDef(0); }
+ const LAllocation* rhs() { return getOperand(RHS); }
+
+ static const size_t LHS = 0;
+ static const size_t RHS = BOX_PIECES;
+};
+
+class LIsCallableO : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsCallableO);
+ explicit LIsCallableO(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ MIsCallable* mir() const { return mir_->toIsCallable(); }
+};
+
+class LIsCallableV : public LInstructionHelper<1, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(IsCallableV);
+ static const size_t Value = 0;
+
+ LIsCallableV(const LBoxAllocation& value, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(0, value);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ MIsCallable* mir() const { return mir_->toIsCallable(); }
+};
+
+class LIsConstructor : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsConstructor);
+ explicit LIsConstructor(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ MIsConstructor* mir() const { return mir_->toIsConstructor(); }
+};
+
+class LIsCrossRealmArrayConstructor : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsCrossRealmArrayConstructor);
+ explicit LIsCrossRealmArrayConstructor(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+class LIsArrayO : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsArrayO);
+
+ explicit LIsArrayO(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() { return getOperand(0); }
+ MIsArray* mir() const { return mir_->toIsArray(); }
+};
+
+class LIsArrayV : public LInstructionHelper<1, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(IsArrayV);
+ static const size_t Value = 0;
+
+ LIsArrayV(const LBoxAllocation& value, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(0, value);
+ setTemp(0, temp);
+ }
+ const LDefinition* temp() { return getTemp(0); }
+ MIsArray* mir() const { return mir_->toIsArray(); }
+};
+
+class LIsTypedArray : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsTypedArray);
+
+ explicit LIsTypedArray(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+ const LAllocation* object() { return getOperand(0); }
+ MIsTypedArray* mir() const { return mir_->toIsTypedArray(); }
+};
+
+class LIsObject : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(IsObject);
+ static const size_t Input = 0;
+
+ explicit LIsObject(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LControlInstructionHelper(classOpcode) {
+ 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 LIsNullOrUndefined : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(IsNullOrUndefined);
+ static const size_t Input = 0;
+
+ explicit LIsNullOrUndefined(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ MIsNullOrUndefined* mir() const { return mir_->toIsNullOrUndefined(); }
+};
+
+class LIsNullOrUndefinedAndBranch
+ : public LControlInstructionHelper<2, BOX_PIECES, 0> {
+ MIsNullOrUndefined* isNullOrUndefined_;
+
+ public:
+ LIR_HEADER(IsNullOrUndefinedAndBranch)
+ static const size_t Input = 0;
+
+ LIsNullOrUndefinedAndBranch(MIsNullOrUndefined* isNullOrUndefined,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse,
+ const LBoxAllocation& input)
+ : LControlInstructionHelper(classOpcode),
+ isNullOrUndefined_(isNullOrUndefined) {
+ setSuccessor(0, ifTrue);
+ setSuccessor(1, ifFalse);
+ setBoxOperand(Input, input);
+ }
+
+ MBasicBlock* ifTrue() const { return getSuccessor(0); }
+ MBasicBlock* ifFalse() const { return getSuccessor(1); }
+
+ MIsNullOrUndefined* isNullOrUndefinedMir() const {
+ return isNullOrUndefined_;
+ }
+};
+
+class LHasClass : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(HasClass);
+ explicit LHasClass(const LAllocation& lhs) : LInstructionHelper(classOpcode) {
+ setOperand(0, lhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(0); }
+ MHasClass* mir() const { return mir_->toHasClass(); }
+};
+
+class LGuardToClass : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(GuardToClass);
+ explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, lhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(0); }
+
+ const LDefinition* temp() { return getTemp(0); }
+
+ MGuardToClass* mir() const { return mir_->toGuardToClass(); }
+};
+
+class LObjectClassToString : public LCallInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(ObjectClassToString);
+
+ LObjectClassToString(const LAllocation& lhs, const LDefinition& temp)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, lhs);
+ setTemp(0, temp);
+ }
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ MObjectClassToString* mir() const { return mir_->toObjectClassToString(); }
+};
+
+template <size_t Defs, size_t Ops>
+class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0> {
+ typedef LInstructionHelper<Defs, Ops, 0> Base;
+
+ protected:
+ explicit LWasmSelectBase(LNode::Opcode opcode) : Base(opcode) {}
+
+ 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)
+ : LWasmSelectBase(classOpcode) {
+ 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)
+ : LWasmSelectBase(classOpcode) {
+ 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 LWasmCompareAndSelect : public LWasmSelectBase<1, 4> {
+ MCompare::CompareType compareType_;
+ JSOp jsop_;
+
+ public:
+ LIR_HEADER(WasmCompareAndSelect);
+
+ static const size_t LeftExprIndex = 0;
+ static const size_t RightExprIndex = 1;
+ static const size_t IfTrueExprIndex = 2;
+ static const size_t IfFalseExprIndex = 3;
+
+ LWasmCompareAndSelect(const LAllocation& leftExpr,
+ const LAllocation& rightExpr,
+ MCompare::CompareType compareType, JSOp jsop,
+ const LAllocation& ifTrueExpr,
+ const LAllocation& ifFalseExpr)
+ : LWasmSelectBase(classOpcode), compareType_(compareType), jsop_(jsop) {
+ setOperand(LeftExprIndex, leftExpr);
+ setOperand(RightExprIndex, rightExpr);
+ setOperand(IfTrueExprIndex, ifTrueExpr);
+ setOperand(IfFalseExprIndex, ifFalseExpr);
+ }
+
+ const LAllocation* leftExpr() { return getOperand(LeftExprIndex); }
+ const LAllocation* rightExpr() { return getOperand(RightExprIndex); }
+ const LAllocation* ifTrueExpr() { return getOperand(IfTrueExprIndex); }
+ const LAllocation* ifFalseExpr() { return getOperand(IfFalseExprIndex); }
+
+ MCompare::CompareType compareType() { return compareType_; }
+ JSOp jsop() { return jsop_; }
+};
+
+class LWasmAddOffset : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmAddOffset);
+ explicit LWasmAddOffset(const LAllocation& base)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, base);
+ }
+ MWasmAddOffset* mir() const { return mir_->toWasmAddOffset(); }
+ const LAllocation* base() { return getOperand(0); }
+};
+
+class LWasmBoundsCheck : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(WasmBoundsCheck);
+ explicit LWasmBoundsCheck(const LAllocation& ptr,
+ const LAllocation& boundsCheckLimit = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, boundsCheckLimit);
+ }
+ MWasmBoundsCheck* mir() const { return mir_->toWasmBoundsCheck(); }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* boundsCheckLimit() { return getOperand(1); }
+};
+
+class LWasmAlignmentCheck : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(WasmAlignmentCheck);
+ explicit LWasmAlignmentCheck(const LAllocation& ptr)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ }
+ MWasmAlignmentCheck* mir() const { return mir_->toWasmAlignmentCheck(); }
+ const LAllocation* ptr() { return getOperand(0); }
+};
+
+class LWasmLoadTls : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmLoadTls);
+ explicit LWasmLoadTls(const LAllocation& tlsPtr)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, tlsPtr);
+ }
+ MWasmLoadTls* mir() const { return mir_->toWasmLoadTls(); }
+ const LAllocation* tlsPtr() { return getOperand(0); }
+};
+
+class LWasmHeapBase : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmHeapBase);
+ explicit LWasmHeapBase(const LAllocation& tlsPtr)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, tlsPtr);
+ }
+ MWasmHeapBase* mir() const { return mir_->toWasmHeapBase(); }
+ const LAllocation* tlsPtr() { 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, 2, Temp> {
+ public:
+ typedef LInstructionHelper<Defs, 2, Temp> Base;
+ explicit LWasmLoadBase(LNode::Opcode opcode, const LAllocation& ptr,
+ const LAllocation& memoryBase)
+ : Base(opcode) {
+ Base::setOperand(0, ptr);
+ Base::setOperand(1, memoryBase);
+ }
+ MWasmLoad* mir() const { return Base::mir_->toWasmLoad(); }
+ const LAllocation* ptr() { return Base::getOperand(0); }
+ const LAllocation* memoryBase() { return Base::getOperand(1); }
+};
+
+} // namespace details
+
+class LWasmLoad : public details::LWasmLoadBase<1, 1> {
+ public:
+ explicit LWasmLoad(const LAllocation& ptr,
+ const LAllocation& memoryBase = LAllocation())
+ : LWasmLoadBase(classOpcode, ptr, memoryBase) {
+ 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,
+ const LAllocation& memoryBase = LAllocation())
+ : LWasmLoadBase(classOpcode, ptr, memoryBase) {
+ setTemp(0, LDefinition::BogusTemp());
+ }
+
+ const LDefinition* ptrCopy() { return Base::getTemp(0); }
+
+ LIR_HEADER(WasmLoadI64);
+};
+
+class LWasmStore : public LInstructionHelper<0, 3, 1> {
+ public:
+ LIR_HEADER(WasmStore);
+
+ static const size_t PtrIndex = 0;
+ static const size_t ValueIndex = 1;
+ static const size_t MemoryBaseIndex = 2;
+
+ LWasmStore(const LAllocation& ptr, const LAllocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(PtrIndex, ptr);
+ setOperand(ValueIndex, value);
+ setOperand(MemoryBaseIndex, memoryBase);
+ 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); }
+ const LAllocation* memoryBase() { return getOperand(MemoryBaseIndex); }
+};
+
+class LWasmStoreI64 : public LInstructionHelper<0, INT64_PIECES + 2, 1> {
+ public:
+ LIR_HEADER(WasmStoreI64);
+
+ static const size_t PtrIndex = 0;
+ static const size_t MemoryBaseIndex = 1;
+ static const size_t ValueIndex = 2;
+
+ LWasmStoreI64(const LAllocation& ptr, const LInt64Allocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(PtrIndex, ptr);
+ setOperand(MemoryBaseIndex, memoryBase);
+ setInt64Operand(ValueIndex, value);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ MWasmStore* mir() const { return mir_->toWasmStore(); }
+ const LAllocation* ptr() { return getOperand(PtrIndex); }
+ const LAllocation* memoryBase() { return getOperand(MemoryBaseIndex); }
+ const LDefinition* ptrCopy() { return getTemp(0); }
+ const LInt64Allocation value() { return getInt64Operand(ValueIndex); }
+};
+
+class LAsmJSLoadHeap : public LInstructionHelper<1, 3, 0> {
+ public:
+ LIR_HEADER(AsmJSLoadHeap);
+ explicit LAsmJSLoadHeap(const LAllocation& ptr,
+ const LAllocation& boundsCheckLimit,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, boundsCheckLimit);
+ setOperand(2, memoryBase);
+ }
+ MAsmJSLoadHeap* mir() const { return mir_->toAsmJSLoadHeap(); }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* boundsCheckLimit() { return getOperand(1); }
+ const LAllocation* memoryBase() { return getOperand(2); }
+};
+
+class LAsmJSStoreHeap : public LInstructionHelper<0, 4, 0> {
+ public:
+ LIR_HEADER(AsmJSStoreHeap);
+ LAsmJSStoreHeap(const LAllocation& ptr, const LAllocation& value,
+ const LAllocation& boundsCheckLimit,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, boundsCheckLimit);
+ setOperand(3, memoryBase);
+ }
+ MAsmJSStoreHeap* mir() const { return mir_->toAsmJSStoreHeap(); }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* value() { return getOperand(1); }
+ const LAllocation* boundsCheckLimit() { return getOperand(2); }
+ const LAllocation* memoryBase() { return getOperand(3); }
+};
+
+class LWasmCompareExchangeHeap : public LInstructionHelper<1, 4, 4> {
+ public:
+ LIR_HEADER(WasmCompareExchangeHeap);
+
+ // ARM, ARM64, x86, x64
+ LWasmCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setOperand(3, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ // MIPS32, MIPS64
+ LWasmCompareExchangeHeap(const LAllocation& ptr, const LAllocation& oldValue,
+ const LAllocation& newValue,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, oldValue);
+ setOperand(2, newValue);
+ setOperand(3, LAllocation());
+ 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 LAllocation* memoryBase() { return getOperand(3); }
+ 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); }
+
+ MWasmCompareExchangeHeap* mir() const {
+ return mir_->toWasmCompareExchangeHeap();
+ }
+};
+
+class LWasmFence : public LInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(WasmFence);
+ explicit LWasmFence() : LInstructionHelper(classOpcode) {}
+};
+
+class LWasmAtomicExchangeHeap : public LInstructionHelper<1, 3, 4> {
+ public:
+ LIR_HEADER(WasmAtomicExchangeHeap);
+
+ // ARM, ARM64, x86, x64
+ LWasmAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value,
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicExchangeHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ 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 LAllocation* memoryBase() { 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); }
+
+ MWasmAtomicExchangeHeap* mir() const {
+ return mir_->toWasmAtomicExchangeHeap();
+ }
+};
+
+class LWasmAtomicBinopHeap : public LInstructionHelper<1, 3, 6> {
+ public:
+ LIR_HEADER(WasmAtomicBinopHeap);
+
+ static const int32_t valueOp = 1;
+
+ // ARM, ARM64, x86, x64
+ LWasmAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& temp,
+ const LDefinition& flagTemp = LDefinition::BogusTemp(),
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, temp);
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicBinopHeap(const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, LDefinition::BogusTemp());
+ 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 LAllocation* memoryBase() { return getOperand(2); }
+ 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); }
+
+ MWasmAtomicBinopHeap* mir() const { return mir_->toWasmAtomicBinopHeap(); }
+};
+
+// Atomic binary operation where the result is discarded.
+class LWasmAtomicBinopHeapForEffect : public LInstructionHelper<0, 3, 5> {
+ public:
+ LIR_HEADER(WasmAtomicBinopHeapForEffect);
+ // ARM, ARM64, x86, x64
+ LWasmAtomicBinopHeapForEffect(
+ const LAllocation& ptr, const LAllocation& value,
+ const LDefinition& flagTemp = LDefinition::BogusTemp(),
+ const LAllocation& memoryBase = LAllocation())
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, memoryBase);
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, flagTemp);
+ }
+ // MIPS32, MIPS64
+ LWasmAtomicBinopHeapForEffect(const LAllocation& ptr,
+ const LAllocation& value,
+ const LDefinition& valueTemp,
+ const LDefinition& offsetTemp,
+ const LDefinition& maskTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, ptr);
+ setOperand(1, value);
+ setOperand(2, LAllocation());
+ setTemp(0, LDefinition::BogusTemp());
+ setTemp(1, LDefinition::BogusTemp());
+ setTemp(2, valueTemp);
+ setTemp(3, offsetTemp);
+ setTemp(4, maskTemp);
+ }
+ const LAllocation* ptr() { return getOperand(0); }
+ const LAllocation* value() { return getOperand(1); }
+ const LAllocation* memoryBase() { return getOperand(2); }
+
+ // 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); }
+
+ MWasmAtomicBinopHeap* mir() const { return mir_->toWasmAtomicBinopHeap(); }
+};
+
+class LWasmLoadSlot : public LInstructionHelper<1, 1, 0> {
+ size_t offset_;
+ MIRType type_;
+
+ public:
+ LIR_HEADER(WasmLoadSlot);
+ explicit LWasmLoadSlot(const LAllocation& containerRef, size_t offset,
+ MIRType type)
+ : LInstructionHelper(classOpcode), offset_(offset), type_(type) {
+ setOperand(0, containerRef);
+ }
+ const LAllocation* containerRef() { return getOperand(0); }
+ size_t offset() const { return offset_; }
+ MIRType type() const { return type_; }
+};
+
+class LWasmLoadSlotI64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ size_t offset_;
+
+ public:
+ LIR_HEADER(WasmLoadSlotI64);
+ explicit LWasmLoadSlotI64(const LAllocation& containerRef, size_t offset)
+ : LInstructionHelper(classOpcode), offset_(offset) {
+ setOperand(0, containerRef);
+ }
+ const LAllocation* containerRef() { return getOperand(0); }
+ size_t offset() const { return offset_; }
+};
+
+class LWasmStoreSlot : public LInstructionHelper<0, 2, 0> {
+ size_t offset_;
+ MIRType type_;
+
+ public:
+ LIR_HEADER(WasmStoreSlot);
+ LWasmStoreSlot(const LAllocation& value, const LAllocation& containerRef,
+ size_t offset, MIRType type)
+ : LInstructionHelper(classOpcode), offset_(offset), type_(type) {
+ setOperand(0, value);
+ setOperand(1, containerRef);
+ }
+ const LAllocation* value() { return getOperand(0); }
+ const LAllocation* containerRef() { return getOperand(1); }
+ size_t offset() const { return offset_; }
+ MIRType type() const { return type_; }
+};
+
+class LWasmStoreSlotI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0> {
+ size_t offset_;
+
+ public:
+ LIR_HEADER(WasmStoreSlotI64);
+ LWasmStoreSlotI64(const LInt64Allocation& value,
+ const LAllocation& containerRef, size_t offset)
+ : LInstructionHelper(classOpcode), offset_(offset) {
+ setInt64Operand(0, value);
+ setOperand(INT64_PIECES, containerRef);
+ }
+ const LInt64Allocation value() { return getInt64Operand(0); }
+ const LAllocation* containerRef() { return getOperand(INT64_PIECES); }
+ size_t offset() const { return offset_; }
+};
+
+class LWasmDerivedPointer : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmDerivedPointer);
+ explicit LWasmDerivedPointer(const LAllocation& base)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, base);
+ }
+ const LAllocation* base() { return getOperand(0); }
+ size_t offset() { return mirRaw()->toWasmDerivedPointer()->offset(); }
+};
+
+class LWasmStoreRef : public LInstructionHelper<0, 3, 1> {
+ public:
+ LIR_HEADER(WasmStoreRef);
+ LWasmStoreRef(const LAllocation& tls, const LAllocation& valueAddr,
+ const LAllocation& value, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, tls);
+ setOperand(1, valueAddr);
+ setOperand(2, value);
+ setTemp(0, temp);
+ }
+ MWasmStoreRef* mir() const { return mirRaw()->toWasmStoreRef(); }
+ const LAllocation* tls() { return getOperand(0); }
+ const LAllocation* valueAddr() { return getOperand(1); }
+ const LAllocation* value() { return getOperand(2); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LWasmParameter : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(WasmParameter);
+
+ LWasmParameter() : LInstructionHelper(classOpcode) {}
+};
+
+class LWasmParameterI64 : public LInstructionHelper<INT64_PIECES, 0, 0> {
+ public:
+ LIR_HEADER(WasmParameterI64);
+
+ LWasmParameterI64() : LInstructionHelper(classOpcode) {}
+};
+
+class LWasmReturn : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(WasmReturn);
+
+ LWasmReturn() : LInstructionHelper(classOpcode) {}
+};
+
+// +1 for tls.
+class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(WasmReturnI64)
+
+ LWasmReturnI64(const LInt64Allocation& input, const LAllocation& tls)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, input);
+ setOperand(INT64_PIECES, tls);
+ }
+};
+
+class LWasmReturnVoid : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(WasmReturnVoid);
+
+ LWasmReturnVoid() : LInstructionHelper(classOpcode) {}
+};
+
+class LWasmStackArg : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(WasmStackArg);
+ explicit LWasmStackArg(const LAllocation& arg)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(0, arg);
+ }
+ MWasmStackArg* mir() const { return mirRaw()->toWasmStackArg(); }
+ const LInt64Allocation arg() { return getInt64Operand(0); }
+};
+
+class LWasmNullConstant : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(WasmNullConstant);
+ explicit LWasmNullConstant() : LInstructionHelper(classOpcode) {}
+};
+
+class LWasmCall : public LVariadicInstruction<0, 0> {
+ bool needsBoundsCheck_;
+
+ public:
+ LIR_HEADER(WasmCall);
+
+ LWasmCall(uint32_t numOperands, bool needsBoundsCheck)
+ : LVariadicInstruction(classOpcode, numOperands),
+ needsBoundsCheck_(needsBoundsCheck) {
+ this->setIsCall();
+ }
+
+ MWasmCall* mir() const { return mir_->toWasmCall(); }
+
+ static bool isCallPreserved(AnyRegister reg) {
+ // 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
+ // See also CodeGeneratorShared::emitWasmCall.
+ return !reg.isFloat() && reg.gpr() == WasmTlsReg;
+ }
+
+ bool needsBoundsCheck() const { return needsBoundsCheck_; }
+};
+
+class LWasmRegisterResult : public LInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(WasmRegisterResult);
+
+ LWasmRegisterResult() : LInstructionHelper(classOpcode) {}
+
+ MWasmRegisterResult* mir() const {
+ if (!mir_->isWasmRegisterResult()) {
+ return nullptr;
+ }
+ return mir_->toWasmRegisterResult();
+ }
+};
+
+class LWasmRegisterPairResult : public LInstructionHelper<2, 0, 0> {
+ public:
+ LIR_HEADER(WasmRegisterPairResult);
+
+ LWasmRegisterPairResult() : LInstructionHelper(classOpcode) {}
+
+ MDefinition* mir() const { return mirRaw(); }
+};
+
+class LWasmStackResultArea : public LInstructionHelper<1, 0, 1> {
+ public:
+ LIR_HEADER(WasmStackResultArea);
+
+ explicit LWasmStackResultArea(const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp);
+ }
+
+ MWasmStackResultArea* mir() const { return mir_->toWasmStackResultArea(); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+inline uint32_t LStackArea::base() const {
+ return ins()->toWasmStackResultArea()->mir()->base();
+}
+inline void LStackArea::setBase(uint32_t base) {
+ ins()->toWasmStackResultArea()->mir()->setBase(base);
+}
+inline uint32_t LStackArea::size() const {
+ return ins()->toWasmStackResultArea()->mir()->byteSize();
+}
+
+inline bool LStackArea::ResultIterator::done() const {
+ return idx_ == alloc_.ins()->toWasmStackResultArea()->mir()->resultCount();
+}
+inline void LStackArea::ResultIterator::next() {
+ MOZ_ASSERT(!done());
+ idx_++;
+}
+inline LAllocation LStackArea::ResultIterator::alloc() const {
+ MOZ_ASSERT(!done());
+ MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir();
+ return LStackSlot(area->base() - area->result(idx_).offset());
+}
+inline bool LStackArea::ResultIterator::isGcPointer() const {
+ MOZ_ASSERT(!done());
+ MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir();
+ MIRType type = area->result(idx_).type();
+#ifndef JS_PUNBOX64
+ // LDefinition::TypeFrom isn't defined for MIRType::Int64 values on
+ // this platform, so here we have a special case.
+ if (type == MIRType::Int64) {
+ return false;
+ }
+#endif
+ return LDefinition::TypeFrom(type) == LDefinition::OBJECT;
+}
+
+class LWasmStackResult : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmStackResult);
+
+ LWasmStackResult() : LInstructionHelper(classOpcode) {}
+
+ MWasmStackResult* mir() const { return mir_->toWasmStackResult(); }
+ LStackSlot result(uint32_t base) const {
+ return LStackSlot(base - mir()->result().offset());
+ }
+};
+
+class LWasmStackResult64 : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(WasmStackResult64);
+
+ LWasmStackResult64() : LInstructionHelper(classOpcode) {}
+
+ MWasmStackResult* mir() const { return mir_->toWasmStackResult(); }
+ LStackSlot result(uint32_t base, LDefinition* def) {
+ uint32_t offset = base - mir()->result().offset();
+#if defined(JS_NUNBOX32)
+ if (def == getDef(INT64LOW_INDEX)) {
+ offset -= INT64LOW_OFFSET;
+ } else {
+ MOZ_ASSERT(def == getDef(INT64HIGH_INDEX));
+ offset -= INT64HIGH_OFFSET;
+ }
+#else
+ MOZ_ASSERT(def == getDef(0));
+#endif
+ return LStackSlot(offset);
+ }
+};
+
+inline LStackSlot LStackArea::resultAlloc(LInstruction* lir,
+ LDefinition* def) const {
+ if (lir->isWasmStackResult64()) {
+ return lir->toWasmStackResult64()->result(base(), def);
+ }
+ MOZ_ASSERT(def == lir->getDef(0));
+ return lir->toWasmStackResult()->result(base());
+}
+
+inline bool LNode::isCallPreserved(AnyRegister reg) const {
+ return isWasmCall() && LWasmCall::isCallPreserved(reg);
+}
+
+class LAssertRangeI : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(AssertRangeI)
+
+ explicit LAssertRangeI(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ 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 LAssertClass : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(AssertClass)
+
+ explicit LAssertClass(const LAllocation& input, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+
+ MAssertClass* mir() { return mir_->toAssertClass(); }
+};
+
+class LAssertShape : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(AssertShape)
+
+ explicit LAssertShape(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+
+ MAssertShape* mir() { return mir_->toAssertShape(); }
+};
+
+class LAssertResultT : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(AssertResultT)
+
+ explicit LAssertResultT(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ 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)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+};
+
+class LGuardValue : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GuardValue)
+
+ explicit LGuardValue(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MGuardValue* mir() { return mir_->toGuardValue(); }
+};
+
+class LGuardNotOptimizedArguments
+ : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GuardNotOptimizedArguments)
+
+ explicit LGuardNotOptimizedArguments(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+};
+
+class LGuardNullOrUndefined : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(GuardNullOrUndefined)
+
+ explicit LGuardNullOrUndefined(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+
+ MGuardNullOrUndefined* mir() { return mir_->toGuardNullOrUndefined(); }
+};
+
+class LGuardFunctionFlags : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(GuardFunctionFlags)
+
+ explicit LGuardFunctionFlags(const LAllocation& fun)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, fun);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+
+ MGuardFunctionFlags* mir() { return mir_->toGuardFunctionFlags(); }
+};
+
+class LGuardFunctionIsNonBuiltinCtor : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardFunctionIsNonBuiltinCtor)
+
+ LGuardFunctionIsNonBuiltinCtor(const LAllocation& fun,
+ const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, fun);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardFunctionKind : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardFunctionKind)
+
+ explicit LGuardFunctionKind(const LAllocation& fun, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, fun);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+
+ MGuardFunctionKind* mir() { return mir_->toGuardFunctionKind(); }
+};
+
+class LGuardFunctionScript : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(GuardFunctionScript)
+
+ explicit LGuardFunctionScript(const LAllocation& fun)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, fun);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+
+ MGuardFunctionScript* mir() { return mir_->toGuardFunctionScript(); }
+};
+
+class LIncrementWarmUpCounter : public LInstructionHelper<0, 0, 1> {
+ public:
+ LIR_HEADER(IncrementWarmUpCounter)
+
+ explicit LIncrementWarmUpCounter(const LDefinition& scratch)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, scratch);
+ }
+
+ const LDefinition* scratch() { return getTemp(0); }
+ MIncrementWarmUpCounter* mir() { return mir_->toIncrementWarmUpCounter(); }
+};
+
+class LLexicalCheck : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(LexicalCheck)
+
+ explicit LLexicalCheck(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ 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)
+
+ LThrowRuntimeLexicalError() : LCallInstructionHelper(classOpcode) {}
+
+ MThrowRuntimeLexicalError* mir() {
+ return mir_->toThrowRuntimeLexicalError();
+ }
+};
+
+class LThrowMsg : public LCallInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(ThrowMsg)
+
+ LThrowMsg() : LCallInstructionHelper(classOpcode) {}
+
+ MThrowMsg* mir() { return mir_->toThrowMsg(); }
+};
+
+class LGlobalDeclInstantiation : public LInstructionHelper<0, 0, 0> {
+ public:
+ LIR_HEADER(GlobalDeclInstantiation)
+
+ LGlobalDeclInstantiation() : LInstructionHelper(classOpcode) {}
+
+ MGlobalDeclInstantiation* mir() { return mir_->toGlobalDeclInstantiation(); }
+};
+
+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)
+ : LInstructionHelper(classOpcode), 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)
+ : LCallInstructionHelper(classOpcode) {
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+};
+
+class LNewTarget : public LInstructionHelper<BOX_PIECES, 0, 0> {
+ public:
+ LIR_HEADER(NewTarget)
+
+ LNewTarget() : LInstructionHelper(classOpcode) {}
+};
+
+class LArrowNewTarget : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ explicit LArrowNewTarget(const LAllocation& callee)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, callee);
+ }
+
+ LIR_HEADER(ArrowNewTarget)
+
+ const LAllocation* callee() { return getOperand(0); }
+};
+
+// Math.random().
+class LRandom : public LInstructionHelper<1, 0, 1 + 2 * INT64_PIECES> {
+ public:
+ LIR_HEADER(Random)
+ LRandom(const LDefinition& temp0, const LInt64Definition& temp1,
+ const LInt64Definition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setTemp(0, temp0);
+ setInt64Temp(1, temp1);
+ setInt64Temp(1 + INT64_PIECES, temp2);
+ }
+ const LDefinition* temp0() { return getTemp(0); }
+ LInt64Definition temp1() { return getInt64Temp(1); }
+ LInt64Definition temp2() { return getInt64Temp(1 + INT64_PIECES); }
+
+ MRandom* mir() const { return mir_->toRandom(); }
+};
+
+class LCheckReturn : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckReturn)
+
+ LCheckReturn(const LBoxAllocation& retVal, const LBoxAllocation& thisVal)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(ReturnValue, retVal);
+ setBoxOperand(ThisValue, thisVal);
+ }
+
+ static const size_t ReturnValue = 0;
+ static const size_t ThisValue = BOX_PIECES;
+};
+
+class LCheckIsObj : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckIsObj)
+
+ static const size_t ValueIndex = 0;
+
+ explicit LCheckIsObj(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(ValueIndex, value);
+ }
+
+ MCheckIsObj* mir() const { return mir_->toCheckIsObj(); }
+};
+
+class LCheckObjCoercible : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckObjCoercible)
+
+ static const size_t CheckValue = 0;
+
+ explicit LCheckObjCoercible(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(CheckValue, value);
+ }
+};
+
+class LCheckClassHeritage : public LInstructionHelper<0, BOX_PIECES, 1> {
+ public:
+ LIR_HEADER(CheckClassHeritage)
+
+ static const size_t Heritage = 0;
+
+ LCheckClassHeritage(const LBoxAllocation& value, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Heritage, value);
+ setTemp(0, temp);
+ }
+
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LCheckThis : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckThis)
+
+ static const size_t ThisValue = 0;
+
+ explicit LCheckThis(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(ThisValue, value);
+ }
+};
+
+class LCheckThisReinit : public LInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CheckThisReinit)
+
+ static const size_t ThisValue = 0;
+
+ explicit LCheckThisReinit(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(ThisValue, value);
+ }
+};
+
+class LGenerator
+ : public LCallInstructionHelper</* defs = */ 1, /* operands = */ 3,
+ /* temps = */ 0> {
+ public:
+ LIR_HEADER(Generator)
+
+ static const size_t CalleeInput = 0;
+ static const size_t EnvInput = 1;
+ static const size_t ArgsInput = 2;
+
+ LGenerator(const LAllocation& callee, const LAllocation& environmentChain,
+ const LAllocation& argsObject)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(CalleeInput, callee);
+ setOperand(EnvInput, environmentChain);
+ setOperand(ArgsInput, argsObject);
+ }
+
+ MGenerator* mir() const { return mir_->toGenerator(); }
+ const LAllocation* callee() { return getOperand(CalleeInput); }
+ const LAllocation* environmentChain() { return getOperand(EnvInput); }
+ const LAllocation* argsObject() { return getOperand(ArgsInput); }
+};
+
+class LAsyncResolve : public LCallInstructionHelper<1, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(AsyncResolve)
+
+ static const size_t GeneratorInput = 0;
+ static const size_t ValueOrReasonInput = 1;
+
+ LAsyncResolve(const LAllocation& generator,
+ const LBoxAllocation& valueOrReason)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(GeneratorInput, generator);
+ setBoxOperand(ValueOrReasonInput, valueOrReason);
+ }
+
+ MAsyncResolve* mir() const { return mir_->toAsyncResolve(); }
+ const LAllocation* generator() { return getOperand(GeneratorInput); }
+};
+
+class LAsyncAwait
+ : public LCallInstructionHelper</* defs= */ 1,
+ /*operands = */ BOX_PIECES + 1,
+ /* temps = */ 0> {
+ public:
+ LIR_HEADER(AsyncAwait)
+
+ static const size_t ValueInput = 0;
+ static const size_t GenInput = BOX_PIECES;
+
+ explicit LAsyncAwait(const LBoxAllocation& value,
+ const LAllocation& generator)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(ValueInput, value);
+ setOperand(GenInput, generator);
+ }
+
+ MAsyncAwait* mir() { return mir_->toAsyncAwait(); }
+ const LAllocation* generator() { return getOperand(GenInput); }
+};
+
+class LCanSkipAwait
+ : public LCallInstructionHelper</* defs= */ 1, /* defs= */ BOX_PIECES,
+ /* temps = */ 0> {
+ public:
+ LIR_HEADER(CanSkipAwait)
+
+ static const size_t ValueInput = 0;
+
+ explicit LCanSkipAwait(const LBoxAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(ValueInput, value);
+ }
+
+ MCanSkipAwait* mir() { return mir_->toCanSkipAwait(); }
+};
+
+class LMaybeExtractAwaitValue
+ : public LCallInstructionHelper</* defs= */ BOX_PIECES,
+ /* defs= */ BOX_PIECES + 1,
+ /* temps = */ 0> {
+ public:
+ LIR_HEADER(MaybeExtractAwaitValue);
+
+ static const size_t ValueInput = 0;
+ static const size_t CanSkipInput = BOX_PIECES;
+
+ explicit LMaybeExtractAwaitValue(const LBoxAllocation& value,
+ const LAllocation& canSkip)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(ValueInput, value);
+ setOperand(CanSkipInput, canSkip);
+ }
+
+ MMaybeExtractAwaitValue* mir() { return mir_->toMaybeExtractAwaitValue(); }
+ const LAllocation* canSkip() { return getOperand(CanSkipInput); }
+};
+
+class LDebugCheckSelfHosted : public LCallInstructionHelper<0, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(DebugCheckSelfHosted)
+
+ static const size_t CheckValue = 0;
+
+ explicit LDebugCheckSelfHosted(const LBoxAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(CheckValue, value);
+ }
+};
+
+class LFinishBoundFunctionInit : public LInstructionHelper<0, 3, 2> {
+ public:
+ LIR_HEADER(FinishBoundFunctionInit)
+
+ LFinishBoundFunctionInit(const LAllocation& bound, const LAllocation& target,
+ const LAllocation& argCount,
+ const LDefinition& temp1, const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, bound);
+ setOperand(1, target);
+ setOperand(2, argCount);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* bound() { return getOperand(0); }
+ const LAllocation* target() { return getOperand(1); }
+ const LAllocation* argCount() { return getOperand(2); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LIsPackedArray : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(IsPackedArray)
+
+ LIsPackedArray(const LAllocation& object, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardArrayIsPacked : public LInstructionHelper<0, 1, 2> {
+ public:
+ LIR_HEADER(GuardArrayIsPacked)
+
+ explicit LGuardArrayIsPacked(const LAllocation& array,
+ const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, array);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* array() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MGuardArrayIsPacked* mir() { return mir_->toGuardArrayIsPacked(); }
+};
+
+class LGetPrototypeOf : public LInstructionHelper<BOX_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(GetPrototypeOf)
+
+ explicit LGetPrototypeOf(const LAllocation& target)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, target);
+ }
+
+ const LAllocation* target() { return getOperand(0); }
+};
+
+class LObjectWithProto : public LCallInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(ObjectWithProto)
+
+ static const size_t PrototypeValue = 0;
+
+ explicit LObjectWithProto(const LBoxAllocation& prototype)
+ : LCallInstructionHelper(classOpcode) {
+ setBoxOperand(PrototypeValue, prototype);
+ }
+};
+
+class LObjectStaticProto : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(ObjectStaticProto)
+
+ explicit LObjectStaticProto(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+};
+
+class LBuiltinObject : public LCallInstructionHelper<1, 0, 0> {
+ public:
+ LIR_HEADER(BuiltinObject)
+
+ LBuiltinObject() : LCallInstructionHelper(classOpcode) {}
+
+ MBuiltinObject* mir() const { return mir_->toBuiltinObject(); }
+};
+
+class LSuperFunction : public LInstructionHelper<BOX_PIECES, 1, 1> {
+ public:
+ LIR_HEADER(SuperFunction)
+
+ explicit LSuperFunction(const LAllocation& callee, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, callee);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* callee() { return getOperand(0); }
+ const LDefinition* temp() { return this->getTemp(0); }
+};
+
+class LInitHomeObject : public LInstructionHelper<0, 1 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(InitHomeObject)
+
+ static const size_t HomeObjectValue = 1;
+
+ LInitHomeObject(const LAllocation& function, const LBoxAllocation& homeObject)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, function);
+ setBoxOperand(HomeObjectValue, homeObject);
+ }
+
+ const LAllocation* function() { return getOperand(0); }
+};
+
+class LIsTypedArrayConstructor : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(IsTypedArrayConstructor)
+
+ explicit LIsTypedArrayConstructor(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+class LLoadValueTag : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(LoadValueTag)
+
+ static const size_t Value = 0;
+
+ explicit LLoadValueTag(const LBoxAllocation& value)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Value, value);
+ }
+};
+
+class LGuardTagNotEqual : public LInstructionHelper<0, 2, 0> {
+ public:
+ LIR_HEADER(GuardTagNotEqual)
+
+ LGuardTagNotEqual(const LAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, lhs);
+ setOperand(1, rhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(0); }
+ const LAllocation* rhs() { return getOperand(1); }
+};
+
+class LLoadWrapperTarget : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(LoadWrapperTarget)
+
+ explicit LLoadWrapperTarget(const LAllocation& object)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+};
+
+class LGuardHasGetterSetter : public LCallInstructionHelper<0, 1, 2> {
+ public:
+ LIR_HEADER(GuardHasGetterSetter)
+
+ LGuardHasGetterSetter(const LAllocation& object, const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+
+ MGuardHasGetterSetter* mir() const { return mir_->toGuardHasGetterSetter(); }
+};
+
+class LGuardIsExtensible : public LInstructionHelper<0, 1, 1> {
+ public:
+ LIR_HEADER(GuardIsExtensible)
+
+ LGuardIsExtensible(const LAllocation& object, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+class LGuardInt32IsNonNegative : public LInstructionHelper<0, 1, 0> {
+ public:
+ LIR_HEADER(GuardInt32IsNonNegative)
+
+ explicit LGuardInt32IsNonNegative(const LAllocation& index)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, index);
+ }
+
+ const LAllocation* index() { return getOperand(0); }
+};
+
+class LGuardIndexGreaterThanDenseInitLength
+ : public LInstructionHelper<0, 2, 2> {
+ public:
+ LIR_HEADER(GuardIndexGreaterThanDenseInitLength)
+
+ LGuardIndexGreaterThanDenseInitLength(const LAllocation& object,
+ const LAllocation& index,
+ const LDefinition& temp,
+ const LDefinition& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setTemp(1, spectreTemp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* spectreTemp() { return getTemp(1); }
+};
+
+class LGuardIndexIsValidUpdateOrAdd : public LInstructionHelper<0, 2, 2> {
+ public:
+ LIR_HEADER(GuardIndexIsValidUpdateOrAdd)
+
+ LGuardIndexIsValidUpdateOrAdd(const LAllocation& object,
+ const LAllocation& index,
+ const LDefinition& temp,
+ const LDefinition& spectreTemp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp);
+ setTemp(1, spectreTemp);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp() { return getTemp(0); }
+ const LDefinition* spectreTemp() { return getTemp(1); }
+};
+
+class LCallAddOrUpdateSparseElement
+ : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(CallAddOrUpdateSparseElement)
+
+ LCallAddOrUpdateSparseElement(const LAllocation& object,
+ const LAllocation& index,
+ const LBoxAllocation& value)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setBoxOperand(ValueIndex, value);
+ }
+
+ static const size_t ValueIndex = 2;
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+
+ MCallAddOrUpdateSparseElement* mir() const {
+ return mir_->toCallAddOrUpdateSparseElement();
+ }
+};
+
+class LCallGetSparseElement : public LCallInstructionHelper<BOX_PIECES, 2, 0> {
+ public:
+ LIR_HEADER(CallGetSparseElement)
+
+ LCallGetSparseElement(const LAllocation& object, const LAllocation& index)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+class LCallNativeGetElement : public LCallInstructionHelper<BOX_PIECES, 2, 0> {
+ public:
+ LIR_HEADER(CallNativeGetElement)
+
+ LCallNativeGetElement(const LAllocation& object, const LAllocation& index)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+};
+
+class LCallObjectHasSparseElement : public LCallInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(CallObjectHasSparseElement)
+
+ LCallObjectHasSparseElement(const LAllocation& object,
+ const LAllocation& index,
+ const LDefinition& temp1,
+ const LDefinition& temp2)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, object);
+ setOperand(1, index);
+ setTemp(0, temp1);
+ setTemp(1, temp2);
+ }
+
+ const LAllocation* object() { return getOperand(0); }
+ const LAllocation* index() { return getOperand(1); }
+ const LDefinition* temp1() { return getTemp(0); }
+ const LDefinition* temp2() { return getTemp(1); }
+};
+
+class LBigIntAsIntN : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(BigIntAsIntN)
+
+ LBigIntAsIntN(const LAllocation& bits, const LAllocation& input)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, bits);
+ setOperand(1, input);
+ }
+
+ const LAllocation* bits() { return getOperand(0); }
+ const LAllocation* input() { return getOperand(1); }
+};
+
+class LBigIntAsIntN64 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsIntN64)
+
+ LBigIntAsIntN64(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsIntN32 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsIntN32)
+
+ LBigIntAsIntN32(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsUintN : public LCallInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(BigIntAsUintN)
+
+ LBigIntAsUintN(const LAllocation& bits, const LAllocation& input)
+ : LCallInstructionHelper(classOpcode) {
+ setOperand(0, bits);
+ setOperand(1, input);
+ }
+
+ const LAllocation* bits() { return getOperand(0); }
+ const LAllocation* input() { return getOperand(1); }
+};
+
+class LBigIntAsUintN64 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsUintN64)
+
+ LBigIntAsUintN64(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+class LBigIntAsUintN32 : public LInstructionHelper<1, 1, 1 + INT64_PIECES> {
+ public:
+ LIR_HEADER(BigIntAsUintN32)
+
+ LBigIntAsUintN32(const LAllocation& input, const LDefinition& temp,
+ const LInt64Definition& temp64)
+ : LInstructionHelper(classOpcode) {
+ setOperand(0, input);
+ setTemp(0, temp);
+ setInt64Temp(1, temp64);
+ }
+
+ const LAllocation* input() { return getOperand(0); }
+ const LDefinition* temp() { return getTemp(0); }
+ LInt64Definition temp64() { return getInt64Temp(1); }
+};
+
+template <size_t NumDefs>
+class LIonToWasmCallBase : public LVariadicInstruction<NumDefs, 2> {
+ using Base = LVariadicInstruction<NumDefs, 2>;
+
+ public:
+ explicit LIonToWasmCallBase(LNode::Opcode classOpcode, uint32_t numOperands,
+ const LDefinition& temp, const LDefinition& fp)
+ : Base(classOpcode, numOperands) {
+ this->setIsCall();
+ this->setTemp(0, temp);
+ this->setTemp(1, fp);
+ }
+ MIonToWasmCall* mir() const { return this->mir_->toIonToWasmCall(); }
+ const LDefinition* temp() { return this->getTemp(0); }
+};
+
+class LIonToWasmCall : public LIonToWasmCallBase<1> {
+ public:
+ LIR_HEADER(IonToWasmCall);
+ LIonToWasmCall(uint32_t numOperands, const LDefinition& temp,
+ const LDefinition& fp)
+ : LIonToWasmCallBase<1>(classOpcode, numOperands, temp, fp) {}
+};
+
+class LIonToWasmCallV : public LIonToWasmCallBase<BOX_PIECES> {
+ public:
+ LIR_HEADER(IonToWasmCallV);
+ LIonToWasmCallV(uint32_t numOperands, const LDefinition& temp,
+ const LDefinition& fp)
+ : LIonToWasmCallBase<BOX_PIECES>(classOpcode, numOperands, temp, fp) {}
+};
+
+class LIonToWasmCallI64 : public LIonToWasmCallBase<INT64_PIECES> {
+ public:
+ LIR_HEADER(IonToWasmCallI64);
+ LIonToWasmCallI64(uint32_t numOperands, const LDefinition& temp,
+ const LDefinition& fp)
+ : LIonToWasmCallBase<INT64_PIECES>(classOpcode, numOperands, temp, fp) {}
+};
+
+class LWasmBoxValue : public LInstructionHelper<1, BOX_PIECES, 0> {
+ public:
+ LIR_HEADER(WasmBoxValue)
+
+ explicit LWasmBoxValue(const LBoxAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setBoxOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+};
+
+class LWasmAnyRefFromJSObject : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmAnyRefFromJSObject)
+
+ explicit LWasmAnyRefFromJSObject(const LAllocation& input)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Input, input);
+ }
+
+ static const size_t Input = 0;
+};
+
+// Wasm SIMD.
+
+// Constant Simd128
+class LSimd128 : public LInstructionHelper<1, 0, 0> {
+ SimdConstant v_;
+
+ public:
+ LIR_HEADER(Simd128);
+
+ explicit LSimd128(SimdConstant v) : LInstructionHelper(classOpcode), v_(v) {}
+
+ const SimdConstant& getSimd128() const { return v_; }
+};
+
+// (v128, v128, v128) -> v128 effect-free operation.
+// temp is FPR (and always in use).
+class LWasmBitselectSimd128 : public LInstructionHelper<1, 3, 1> {
+ public:
+ LIR_HEADER(WasmBitselectSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+ static constexpr uint32_t Control = 2;
+
+ LWasmBitselectSimd128(const LAllocation& lhs, const LAllocation& rhs,
+ const LAllocation& control, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setOperand(Control, control);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ const LAllocation* control() { return getOperand(Control); }
+ const LDefinition* temp() { return getTemp(0); }
+};
+
+// (v128, v128) -> v128 effect-free operations
+// lhs and dest are the same.
+// temps (if in use) are FPR.
+// The op may differ from the MIR node's op.
+class LWasmBinarySimd128 : public LInstructionHelper<1, 2, 2> {
+ wasm::SimdOp op_;
+
+ public:
+ LIR_HEADER(WasmBinarySimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmBinarySimd128(wasm::SimdOp op, const LAllocation& lhs,
+ const LAllocation& rhs, const LDefinition& temp0,
+ const LDefinition& temp1)
+ : LInstructionHelper(classOpcode), op_(op) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ wasm::SimdOp simdOp() const { return op_; }
+
+ static bool SpecializeForConstantRhs(wasm::SimdOp op);
+};
+
+class LWasmBinarySimd128WithConstant : public LInstructionHelper<1, 1, 0> {
+ SimdConstant rhs_;
+
+ public:
+ LIR_HEADER(WasmBinarySimd128WithConstant)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+
+ LWasmBinarySimd128WithConstant(const LAllocation& lhs,
+ const SimdConstant& rhs)
+ : LInstructionHelper(classOpcode), rhs_(rhs) {
+ setOperand(Lhs, lhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const SimdConstant& rhs() { return rhs_; }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmBinarySimd128WithConstant()->simdOp();
+ }
+};
+
+// (v128, i32) -> v128 effect-free variable-width shift operations
+// lhs and dest are the same.
+// temp0 is a GPR (if in use).
+// temp1 is an FPR (if in use).
+class LWasmVariableShiftSimd128 : public LInstructionHelper<1, 2, 2> {
+ public:
+ LIR_HEADER(WasmVariableShiftSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmVariableShiftSimd128(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp0, const LDefinition& temp1)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp0);
+ setTemp(1, temp1);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmShiftSimd128()->simdOp(); }
+};
+
+// (v128, i32) -> v128 effect-free constant-width shift operations
+class LWasmConstantShiftSimd128 : public LInstructionHelper<1, 1, 1> {
+ int32_t shift_;
+
+ public:
+ LIR_HEADER(WasmConstantShiftSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmConstantShiftSimd128(const LAllocation& src, const LDefinition& temp,
+ int32_t shift)
+ : LInstructionHelper(classOpcode), shift_(shift) {
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ const LDefinition* temp() { return getTemp(0); }
+ int32_t shift() { return shift_; }
+ wasm::SimdOp simdOp() const { return mir_->toWasmShiftSimd128()->simdOp(); }
+};
+
+// (v128, v128, imm_simd) -> v128 effect-free operation.
+// temp is FPR (and always in use).
+class LWasmShuffleSimd128 : public LInstructionHelper<1, 2, 1> {
+ public:
+ // Shuffle operations. NOTE: these may still be x86-centric, but the set can
+ // accomodate operations from other architectures.
+ enum Op {
+ // Blend bytes. control_ has the blend mask as an I8x16: 0 to select from
+ // the lhs, -1 to select from the rhs.
+ BLEND_8x16,
+
+ // Blend words. control_ has the blend mask as an I16x8: 0 to select from
+ // the lhs, -1 to select from the rhs.
+ BLEND_16x8,
+
+ // Concat the lhs in front of the rhs and shift right by bytes, extracting
+ // the low 16 bytes; control_[0] has the shift count.
+ CONCAT_RIGHT_SHIFT_8x16,
+
+ // Interleave qwords/dwords/words/bytes from high/low halves of operands.
+ // The low-order item in the result comes from the lhs, then the next from
+ // the rhs, and so on. control_ is ignored.
+ INTERLEAVE_HIGH_8x16,
+ INTERLEAVE_HIGH_16x8,
+ INTERLEAVE_HIGH_32x4,
+ INTERLEAVE_HIGH_64x2,
+ INTERLEAVE_LOW_8x16,
+ INTERLEAVE_LOW_16x8,
+ INTERLEAVE_LOW_32x4,
+ INTERLEAVE_LOW_64x2,
+
+ // Fully general shuffle+blend. control_ has the shuffle mask.
+ SHUFFLE_BLEND_8x16,
+ };
+
+ private:
+ Op op_;
+ SimdConstant control_;
+
+ public:
+ LIR_HEADER(WasmShuffleSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmShuffleSimd128(const LAllocation& lhs, const LAllocation& rhs,
+ const LDefinition& temp, Op op, SimdConstant control)
+ : LInstructionHelper(classOpcode), op_(op), control_(control) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ const LDefinition* temp() { return getTemp(0); }
+ Op op() { return op_; }
+ SimdConstant control() { return control_; }
+};
+
+// (v128, imm_simd) -> v128 effect-free operation.
+class LWasmPermuteSimd128 : public LInstructionHelper<1, 1, 0> {
+ public:
+ // Permutation operations. NOTE: these may still be x86-centric, but the set
+ // can accomodate operations from other architectures.
+ //
+ // The "low-order" byte is in lane 0 of an 8x16 datum, the "high-order" byte
+ // in lane 15. The low-order byte is also the "rightmost". In wasm, the
+ // constant (v128.const i8x16 0 1 2 ... 15) has 0 in the low-order byte and 15
+ // in the high-order byte.
+ enum Op {
+ // A single byte lane is copied into all the other byte lanes. control_[0]
+ // has the source lane.
+ BROADCAST_8x16,
+
+ // A single word lane is copied into all the other word lanes. control_[0]
+ // has the source lane.
+ BROADCAST_16x8,
+
+ // Copy input to output.
+ MOVE,
+
+ // control_ has bytes in range 0..15 s.t. control_[i] holds the source lane
+ // for output lane i.
+ PERMUTE_8x16,
+
+ // control_ has int16s in range 0..7, as for 8x16. In addition, the high
+ // byte of control_[0] has flags detailing the operation, values taken
+ // from the Perm16x8Action enum below.
+ PERMUTE_16x8,
+
+ // control_ has int32s in range 0..3, as for 8x16.
+ PERMUTE_32x4,
+
+ // control_[0] has the number of places to rotate by.
+ ROTATE_RIGHT_8x16,
+
+ // Zeroes are shifted into high-order bytes and low-order bytes are lost.
+ // control_[0] has the number of places to shift by.
+ SHIFT_RIGHT_8x16,
+
+ // Zeroes are shifted into low-order bytes and high-order bytes are lost.
+ // control_[0] has the number of places to shift by.
+ SHIFT_LEFT_8x16,
+ };
+
+ enum Perm16x8Action {
+ SWAP_QWORDS = 1, // Swap qwords first
+ PERM_LOW = 2, // Permute low qword by control_[0..3]
+ PERM_HIGH = 4 // Permute high qword by control_[4..7]
+ };
+
+ private:
+ Op op_;
+ SimdConstant control_;
+
+ public:
+ LIR_HEADER(WasmPermuteSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmPermuteSimd128(const LAllocation& src, Op op, SimdConstant control)
+ : LInstructionHelper(classOpcode), op_(op), control_(control) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ Op op() { return op_; }
+ SimdConstant control() { return control_; }
+};
+
+class LWasmReplaceLaneSimd128 : public LInstructionHelper<1, 2, 0> {
+ public:
+ LIR_HEADER(WasmReplaceLaneSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmReplaceLaneSimd128(const LAllocation& lhs, const LAllocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setOperand(Rhs, rhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LAllocation* rhs() { return getOperand(Rhs); }
+ uint32_t laneIndex() const {
+ return mir_->toWasmReplaceLaneSimd128()->laneIndex();
+ }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmReplaceLaneSimd128()->simdOp();
+ }
+};
+
+class LWasmReplaceInt64LaneSimd128
+ : public LInstructionHelper<1, INT64_PIECES + 1, 0> {
+ public:
+ LIR_HEADER(WasmReplaceInt64LaneSimd128)
+
+ static constexpr uint32_t Lhs = 0;
+ static constexpr uint32_t LhsDest = 0;
+ static constexpr uint32_t Rhs = 1;
+
+ LWasmReplaceInt64LaneSimd128(const LAllocation& lhs,
+ const LInt64Allocation& rhs)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Lhs, lhs);
+ setInt64Operand(Rhs, rhs);
+ }
+
+ const LAllocation* lhs() { return getOperand(Lhs); }
+ const LAllocation* lhsDest() { return getOperand(LhsDest); }
+ const LInt64Allocation rhs() { return getInt64Operand(Rhs); }
+ uint32_t laneIndex() const {
+ return mir_->toWasmReplaceLaneSimd128()->laneIndex();
+ }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmReplaceLaneSimd128()->simdOp();
+ }
+};
+
+// (scalar) -> v128 effect-free operations, scalar != int64
+class LWasmScalarToSimd128 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmScalarToSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmScalarToSimd128(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmScalarToSimd128()->simdOp();
+ }
+};
+
+// (int64) -> v128 effect-free operations
+class LWasmInt64ToSimd128 : public LInstructionHelper<1, INT64_PIECES, 0> {
+ public:
+ LIR_HEADER(WasmInt64ToSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmInt64ToSimd128(const LInt64Allocation& src)
+ : LInstructionHelper(classOpcode) {
+ setInt64Operand(Src, src);
+ }
+
+ const LInt64Allocation src() { return getInt64Operand(Src); }
+ wasm::SimdOp simdOp() const {
+ return mir_->toWasmScalarToSimd128()->simdOp();
+ }
+};
+
+// (v128) -> v128 effect-free operations
+// temp is FPR (if in use).
+class LWasmUnarySimd128 : public LInstructionHelper<1, 1, 1> {
+ public:
+ LIR_HEADER(WasmUnarySimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ LWasmUnarySimd128(const LAllocation& src, const LDefinition& temp)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ const LDefinition* temp() { return getTemp(0); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmUnarySimd128()->simdOp(); }
+};
+
+// (v128, imm) -> scalar effect-free operations.
+class LWasmReduceSimd128 : public LInstructionHelper<1, 1, 0> {
+ public:
+ LIR_HEADER(WasmReduceSimd128)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmReduceSimd128(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ uint32_t imm() const { return mir_->toWasmReduceSimd128()->imm(); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmReduceSimd128()->simdOp(); }
+};
+
+// (v128, onTrue, onFalse) test-and-branch operations.
+class LWasmReduceAndBranchSimd128 : public LControlInstructionHelper<2, 1, 0> {
+ wasm::SimdOp op_;
+
+ public:
+ LIR_HEADER(WasmReduceAndBranchSimd128)
+
+ static constexpr uint32_t Src = 0;
+ static constexpr uint32_t IfTrue = 0;
+ static constexpr uint32_t IfFalse = 1;
+
+ LWasmReduceAndBranchSimd128(const LAllocation& src, wasm::SimdOp op,
+ MBasicBlock* ifTrue, MBasicBlock* ifFalse)
+ : LControlInstructionHelper(classOpcode), op_(op) {
+ setOperand(Src, src);
+ setSuccessor(IfTrue, ifTrue);
+ setSuccessor(IfFalse, ifFalse);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ wasm::SimdOp simdOp() const { return op_; }
+ MBasicBlock* ifTrue() const { return getSuccessor(IfTrue); }
+ MBasicBlock* ifFalse() const { return getSuccessor(IfFalse); }
+};
+
+// (v128, imm) -> i64 effect-free operations
+class LWasmReduceSimd128ToInt64
+ : public LInstructionHelper<INT64_PIECES, 1, 0> {
+ public:
+ LIR_HEADER(WasmReduceSimd128ToInt64)
+
+ static constexpr uint32_t Src = 0;
+
+ explicit LWasmReduceSimd128ToInt64(const LAllocation& src)
+ : LInstructionHelper(classOpcode) {
+ setOperand(Src, src);
+ }
+
+ const LAllocation* src() { return getOperand(Src); }
+ uint32_t imm() const { return mir_->toWasmReduceSimd128()->imm(); }
+ wasm::SimdOp simdOp() const { return mir_->toWasmReduceSimd128()->simdOp(); }
+};
+
+// End Wasm SIMD
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_shared_LIR_shared_h */