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