mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-08 20:29:36 +00:00
7415 lines
172 KiB
C++
7415 lines
172 KiB
C++
/* -*- 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 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);
|
|
}
|
|
|
|
MSimdSplatX4* mir() const {
|
|
return mir_->toSimdSplatX4();
|
|
}
|
|
};
|
|
|
|
// 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);
|
|
}
|
|
SimdLane lane() const {
|
|
return mir_->toSimdExtractElement()->lane();
|
|
}
|
|
const char* extraName() const {
|
|
switch (lane()) {
|
|
case LaneX: return "lane x";
|
|
case LaneY: return "lane y";
|
|
case LaneZ: return "lane z";
|
|
case LaneW: return "lane w";
|
|
}
|
|
return "unknown lane";
|
|
}
|
|
};
|
|
|
|
// 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)
|
|
{}
|
|
};
|
|
|
|
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);
|
|
}
|
|
SimdLane lane() const {
|
|
return mir_->toSimdInsertElement()->lane();
|
|
}
|
|
const char* extraName() const {
|
|
return MSimdInsertElement::LaneName(lane());
|
|
}
|
|
};
|
|
|
|
// Replace an element from a given SIMD int32x4 lane with a given value.
|
|
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)
|
|
{}
|
|
};
|
|
|
|
class LSimdSignMaskX4 : public LInstructionHelper<1, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(SimdSignMaskX4);
|
|
|
|
explicit LSimdSignMaskX4(const LAllocation& input) {
|
|
setOperand(0, input);
|
|
}
|
|
};
|
|
|
|
// Base class for both int32x4 and float32x4 shuffle instructions.
|
|
class LSimdSwizzleBase : public LInstructionHelper<1, 1, 0>
|
|
{
|
|
public:
|
|
explicit LSimdSwizzleBase(const LAllocation& base)
|
|
{
|
|
setOperand(0, base);
|
|
}
|
|
|
|
const LAllocation* getBase() {
|
|
return getOperand(0);
|
|
}
|
|
|
|
uint32_t laneX() const { return mir_->toSimdSwizzle()->laneX(); }
|
|
uint32_t laneY() const { return mir_->toSimdSwizzle()->laneY(); }
|
|
uint32_t laneZ() const { return mir_->toSimdSwizzle()->laneZ(); }
|
|
uint32_t laneW() const { return mir_->toSimdSwizzle()->laneW(); }
|
|
|
|
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 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);
|
|
}
|
|
|
|
uint32_t laneX() const { return mir_->toSimdShuffle()->laneX(); }
|
|
uint32_t laneY() const { return mir_->toSimdShuffle()->laneY(); }
|
|
uint32_t laneZ() const { return mir_->toSimdShuffle()->laneZ(); }
|
|
uint32_t laneW() const { return mir_->toSimdShuffle()->laneW(); }
|
|
|
|
bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
|
|
return mir_->toSimdShuffle()->lanesMatch(x, y, z, w);
|
|
}
|
|
};
|
|
|
|
// 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 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 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() {}
|
|
};
|
|
|
|
// 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 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 int32x4 or float32x4 operands
|
|
class LSimdBinaryBitwiseX4 : public LInstructionHelper<1, 2, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(SimdBinaryBitwiseX4);
|
|
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();
|
|
}
|
|
};
|
|
|
|
class LSimdShift : public LInstructionHelper<1, 2, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(SimdShift)
|
|
LSimdShift(const LAllocation& vec, const LAllocation& val) {
|
|
setOperand(0, vec);
|
|
setOperand(1, val);
|
|
}
|
|
const LAllocation* vector() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* value() {
|
|
return getOperand(1);
|
|
}
|
|
MSimdShift::Operation operation() const {
|
|
return mir_->toSimdShift()->operation();
|
|
}
|
|
const char* extraName() const {
|
|
return MSimdShift::OperationName(operation());
|
|
}
|
|
MSimdShift* mir() const {
|
|
return mir_->toSimdShift();
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
|
|
// 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 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>
|
|
{
|
|
double d_;
|
|
public:
|
|
LIR_HEADER(Double);
|
|
|
|
explicit LDouble(double d) : d_(d)
|
|
{ }
|
|
double getDouble() const {
|
|
return d_;
|
|
}
|
|
};
|
|
|
|
// Constant float32.
|
|
class LFloat32 : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
float f_;
|
|
public:
|
|
LIR_HEADER(Float32);
|
|
|
|
explicit LFloat32(float f)
|
|
: f_(f)
|
|
{ }
|
|
|
|
float getFloat() const {
|
|
return f_;
|
|
}
|
|
};
|
|
|
|
// Constant SIMD int32x4
|
|
class LInt32x4 : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(Int32x4);
|
|
|
|
explicit LInt32x4() {}
|
|
const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
|
|
};
|
|
|
|
// Constant SIMD float32x4
|
|
class LFloat32x4 : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(Float32x4);
|
|
|
|
explicit LFloat32x4() {}
|
|
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()->shouldUseVM() ? "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 LNewObject : public LInstructionHelper<1, 0, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(NewObject)
|
|
|
|
explicit LNewObject(const LDefinition& temp) {
|
|
setTemp(0, temp);
|
|
}
|
|
|
|
const char* extraName() const {
|
|
return mir()->shouldUseVM() ? "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 DeclEnvObject.
|
|
//
|
|
// 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 LNewDeclEnvObject : public LInstructionHelper<1, 0, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(NewDeclEnvObject);
|
|
|
|
explicit LNewDeclEnvObject(const LDefinition& temp) {
|
|
setTemp(0, temp);
|
|
}
|
|
|
|
const LDefinition* temp() {
|
|
return getTemp(0);
|
|
}
|
|
|
|
MNewDeclEnvObject* mir() const {
|
|
return mir_->toNewDeclEnvObject();
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
|
|
// Allocates a new CallObject with singleton type.
|
|
//
|
|
// 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 LNewSingletonCallObject : public LInstructionHelper<1, 0, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(NewSingletonCallObject)
|
|
|
|
explicit LNewSingletonCallObject(const LDefinition& temp) {
|
|
setTemp(0, temp);
|
|
}
|
|
|
|
const LDefinition* temp() {
|
|
return getTemp(0);
|
|
}
|
|
|
|
MNewCallObjectBase* mir() const {
|
|
MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject());
|
|
return static_cast<MNewCallObjectBase*>(mir_);
|
|
}
|
|
};
|
|
|
|
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)
|
|
|
|
explicit LInitElem(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
|
|
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 LAllocation& value) {
|
|
setOperand(0, object);
|
|
setOperand(1, value);
|
|
}
|
|
|
|
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)
|
|
|
|
explicit LMutateProto(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
|
|
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)
|
|
|
|
explicit LInitProp(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
|
|
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 LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
|
|
{
|
|
Label* interruptExit_;
|
|
const wasm::CallSiteDesc& funcDesc_;
|
|
|
|
public:
|
|
LIR_HEADER(AsmJSInterruptCheck);
|
|
|
|
LAsmJSInterruptCheck(Label* interruptExit, const wasm::CallSiteDesc& funcDesc)
|
|
: interruptExit_(interruptExit), funcDesc_(funcDesc)
|
|
{
|
|
}
|
|
|
|
bool isCall() const {
|
|
return true;
|
|
}
|
|
|
|
Label* interruptExit() const {
|
|
return interruptExit_;
|
|
}
|
|
const wasm::CallSiteDesc& funcDesc() const {
|
|
return funcDesc_;
|
|
}
|
|
};
|
|
|
|
class LInterruptCheck : public LInstructionHelper<0, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(InterruptCheck)
|
|
};
|
|
|
|
// Alternative to LInterruptCheck which does not emit an explicit check of the
|
|
// interrupt flag but relies on the loop backedge being patched via a signal
|
|
// handler.
|
|
class LInterruptCheckImplicit : public LInstructionHelper<0, 0, 0>
|
|
{
|
|
Label* oolEntry_;
|
|
|
|
public:
|
|
LIR_HEADER(InterruptCheckImplicit)
|
|
|
|
LInterruptCheckImplicit()
|
|
: oolEntry_(nullptr)
|
|
{}
|
|
|
|
Label* oolEntry() {
|
|
return oolEntry_;
|
|
}
|
|
|
|
void setOolEntry(Label* oolEntry) {
|
|
oolEntry_ = oolEntry;
|
|
}
|
|
MInterruptCheck* mir() const {
|
|
return mir_->toInterruptCheck();
|
|
}
|
|
};
|
|
|
|
class LDefVar : public LCallInstructionHelper<0, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(DefVar)
|
|
|
|
explicit LDefVar(const LAllocation& scopeChain)
|
|
{
|
|
setOperand(0, scopeChain);
|
|
}
|
|
|
|
const LAllocation* scopeChain() {
|
|
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& scopeChain)
|
|
{
|
|
setOperand(0, fun);
|
|
setOperand(1, scopeChain);
|
|
}
|
|
|
|
const LAllocation* fun() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
return getOperand(1);
|
|
}
|
|
MDefFun* mir() const {
|
|
return mir_->toDefFun();
|
|
}
|
|
};
|
|
|
|
class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(TypeOfV)
|
|
|
|
explicit LTypeOfV(const LDefinition& tempToUnbox) {
|
|
setTemp(0, tempToUnbox);
|
|
}
|
|
|
|
static const size_t Input = 0;
|
|
|
|
const LDefinition* tempToUnbox() {
|
|
return getTemp(0);
|
|
}
|
|
|
|
MTypeOf* mir() const {
|
|
return mir_->toTypeOf();
|
|
}
|
|
};
|
|
|
|
class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(ToIdV)
|
|
|
|
explicit LToIdV(const LDefinition& temp)
|
|
{
|
|
setTemp(0, temp);
|
|
}
|
|
|
|
static const size_t Index = 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, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(CreateArgumentsObject)
|
|
|
|
LCreateArgumentsObject(const LAllocation& callObj, const LDefinition& temp)
|
|
{
|
|
setOperand(0, callObj);
|
|
setTemp(0, temp);
|
|
}
|
|
|
|
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 LDefinition& temp)
|
|
{
|
|
setOperand(0, argsObj);
|
|
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)
|
|
|
|
explicit LReturnFromCtor(const LAllocation& object)
|
|
{
|
|
// Value set by useBox() during lowering.
|
|
setOperand(LReturnFromCtor::ObjectIndex, object);
|
|
}
|
|
|
|
const LAllocation* getObject() {
|
|
return getOperand(LReturnFromCtor::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;
|
|
|
|
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)
|
|
|
|
explicit LStackArgV(uint32_t argslot)
|
|
: argslot_(argslot)
|
|
{ }
|
|
|
|
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;
|
|
}
|
|
JSFunction* 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 LDefinition& PrivReg, const LDefinition& ValueReg)
|
|
: LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg,
|
|
PrivReg, ValueReg)
|
|
{ }
|
|
|
|
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 LDefinition& tmpobjreg, const LDefinition& tmpcopy)
|
|
{
|
|
setOperand(0, func);
|
|
setOperand(1, argc);
|
|
setTemp(0, tmpobjreg);
|
|
setTemp(1, tmpcopy);
|
|
}
|
|
|
|
MApplyArgs* mir() const {
|
|
return mir_->toApplyArgs();
|
|
}
|
|
|
|
bool hasSingleTarget() const {
|
|
return getSingleTarget() != nullptr;
|
|
}
|
|
JSFunction* 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 LDefinition& tmpobjreg, const LDefinition& tmpcopy)
|
|
{
|
|
setOperand(0, func);
|
|
setOperand(1, elements);
|
|
setTemp(0, tmpobjreg);
|
|
setTemp(1, tmpcopy);
|
|
}
|
|
|
|
MApplyArray* mir() const {
|
|
return mir_->toApplyArray();
|
|
}
|
|
|
|
bool hasSingleTarget() const {
|
|
return getSingleTarget() != nullptr;
|
|
}
|
|
JSFunction* 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& scopeChain, const LAllocation& name,
|
|
const LDefinition& temp1, const LDefinition& temp2, const LDefinition& temp3)
|
|
{
|
|
setOperand(0, scopeChain);
|
|
setOperand(1, name);
|
|
setTemp(0, temp1);
|
|
setTemp(1, temp2);
|
|
setTemp(2, temp3);
|
|
}
|
|
|
|
MGetDynamicName* mir() const {
|
|
return mir_->toGetDynamicName();
|
|
}
|
|
|
|
const LAllocation* getScopeChain() {
|
|
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 + (2 * BOX_PIECES), 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(CallDirectEval)
|
|
|
|
LCallDirectEval(const LAllocation& scopeChain, const LAllocation& string)
|
|
{
|
|
setOperand(0, scopeChain);
|
|
setOperand(1, string);
|
|
}
|
|
|
|
static const size_t ThisValue = 2;
|
|
static const size_t NewTarget = 2 + BOX_PIECES;
|
|
|
|
MCallDirectEval* mir() const {
|
|
return mir_->toCallDirectEval();
|
|
}
|
|
|
|
const LAllocation* getScopeChain() {
|
|
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 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 LDefinition& temp0,
|
|
const LDefinition& temp1, const LDefinition& temp2)
|
|
{
|
|
setSuccessor(0, ifTruthy);
|
|
setSuccessor(1, ifFalsy);
|
|
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_];
|
|
}
|
|
};
|
|
|
|
// 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 LAllocation& rhs, const LDefinition& temp) {
|
|
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)
|
|
|
|
explicit LCompareB(const LAllocation& rhs) {
|
|
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 LAllocation& rhs,
|
|
MBasicBlock* ifTrue, MBasicBlock* ifFalse)
|
|
: cmpMir_(cmpMir)
|
|
{
|
|
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;
|
|
|
|
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)
|
|
: cmpMir_(cmpMir)
|
|
{
|
|
setSuccessor(0, ifTrue);
|
|
setSuccessor(1, ifFalse);
|
|
}
|
|
|
|
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;
|
|
|
|
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 LDefinition& temp, const LDefinition& tempToUnbox)
|
|
{
|
|
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 LDefinition& temp, const LDefinition& tempToUnbox)
|
|
: cmpMir_(cmpMir)
|
|
{
|
|
setSuccessor(0, ifTrue);
|
|
setSuccessor(1, ifFalse);
|
|
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 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 LDefinition& temp0, const LDefinition& temp1, const LDefinition& temp2)
|
|
{
|
|
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;
|
|
};
|
|
|
|
// 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_;
|
|
}
|
|
};
|
|
|
|
// Call a VM function to perform a bitwise operation.
|
|
class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
|
|
{
|
|
JSOp jsop_;
|
|
|
|
public:
|
|
LIR_HEADER(BitOpV)
|
|
|
|
explicit LBitOpV(JSOp jsop)
|
|
: jsop_(jsop)
|
|
{ }
|
|
|
|
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 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;
|
|
};
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
// Count leading zeroes
|
|
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();
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
|
|
// 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)
|
|
|
|
explicit LBinaryV(JSOp jsop)
|
|
: jsop_(jsop)
|
|
{ }
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
// 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;
|
|
|
|
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;
|
|
|
|
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 LDefinition& temp0, const LDefinition& temp1, Mode mode)
|
|
: mode_(mode)
|
|
{
|
|
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();
|
|
}
|
|
};
|
|
|
|
// 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)
|
|
|
|
explicit LValueToString(const LDefinition& tempToUnbox)
|
|
{
|
|
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()
|
|
{}
|
|
|
|
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();
|
|
}
|
|
};
|
|
|
|
// 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)
|
|
};
|
|
|
|
// 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 scope chain stored in an interpreter frame for OSR.
|
|
class LOsrScopeChain : public LInstructionHelper<1, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(OsrScopeChain)
|
|
|
|
explicit LOsrScopeChain(const LAllocation& entry)
|
|
{
|
|
setOperand(0, entry);
|
|
}
|
|
|
|
const MOsrScopeChain* mir() {
|
|
return mir_->toOsrScopeChain();
|
|
}
|
|
};
|
|
|
|
// Materialize a JSObject scope 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 LRegExpExec : public LCallInstructionHelper<BOX_PIECES, 2, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(RegExpExec)
|
|
|
|
LRegExpExec(const LAllocation& regexp, const LAllocation& string)
|
|
{
|
|
setOperand(0, regexp);
|
|
setOperand(1, string);
|
|
}
|
|
|
|
const LAllocation* regexp() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* string() {
|
|
return getOperand(1);
|
|
}
|
|
|
|
const MRegExpExec* mir() const {
|
|
return mir_->toRegExpExec();
|
|
}
|
|
};
|
|
|
|
class LRegExpTest : public LCallInstructionHelper<1, 2, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(RegExpTest)
|
|
|
|
LRegExpTest(const LAllocation& regexp, const LAllocation& string)
|
|
{
|
|
setOperand(0, regexp);
|
|
setOperand(1, string);
|
|
}
|
|
|
|
const LAllocation* regexp() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* string() {
|
|
return getOperand(1);
|
|
}
|
|
|
|
const MRegExpTest* mir() const {
|
|
return mir_->toRegExpTest();
|
|
}
|
|
};
|
|
|
|
|
|
class LStrReplace : public LCallInstructionHelper<1, 3, 0>
|
|
{
|
|
public:
|
|
LStrReplace(const LAllocation& string, const LAllocation& pattern,
|
|
const LAllocation& replacement)
|
|
{
|
|
setOperand(0, string);
|
|
setOperand(1, pattern);
|
|
setOperand(2, replacement);
|
|
}
|
|
|
|
const LAllocation* string() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* pattern() {
|
|
return getOperand(1);
|
|
}
|
|
const LAllocation* replacement() {
|
|
return getOperand(2);
|
|
}
|
|
};
|
|
|
|
class LRegExpReplace: public LStrReplace
|
|
{
|
|
public:
|
|
LIR_HEADER(RegExpReplace);
|
|
|
|
LRegExpReplace(const LAllocation& string, const LAllocation& pattern,
|
|
const LAllocation& replacement)
|
|
: LStrReplace(string, pattern, replacement)
|
|
{
|
|
}
|
|
|
|
const MRegExpReplace* mir() const {
|
|
return mir_->toRegExpReplace();
|
|
}
|
|
};
|
|
|
|
class LStringReplace: public LStrReplace
|
|
{
|
|
public:
|
|
LIR_HEADER(StringReplace);
|
|
|
|
LStringReplace(const LAllocation& string, const LAllocation& pattern,
|
|
const LAllocation& replacement)
|
|
: LStrReplace(string, pattern, replacement)
|
|
{
|
|
}
|
|
|
|
const MStringReplace* mir() const {
|
|
return mir_->toStringReplace();
|
|
}
|
|
};
|
|
|
|
class LBinarySharedStub : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(BinarySharedStub)
|
|
|
|
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)
|
|
|
|
const MUnarySharedStub* mir() const {
|
|
return mir_->toUnarySharedStub();
|
|
}
|
|
|
|
static const size_t Input = 0;
|
|
};
|
|
|
|
class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(LambdaForSingleton)
|
|
|
|
explicit LLambdaForSingleton(const LAllocation& scopeChain)
|
|
{
|
|
setOperand(0, scopeChain);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
return getOperand(0);
|
|
}
|
|
const MLambda* mir() const {
|
|
return mir_->toLambda();
|
|
}
|
|
};
|
|
|
|
class LLambda : public LInstructionHelper<1, 1, 1>
|
|
{
|
|
public:
|
|
LIR_HEADER(Lambda)
|
|
|
|
LLambda(const LAllocation& scopeChain, const LDefinition& temp) {
|
|
setOperand(0, scopeChain);
|
|
setTemp(0, temp);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
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;
|
|
|
|
explicit LLambdaArrow(const LAllocation& scopeChain) {
|
|
setOperand(0, scopeChain);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
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);
|
|
}
|
|
};
|
|
|
|
// 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) {
|
|
setOperand(0, elements);
|
|
setOperand(1, index);
|
|
}
|
|
|
|
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 LDefinition& temp) {
|
|
setOperand(0, object);
|
|
setOperand(1, elements);
|
|
setOperand(2, index);
|
|
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);
|
|
}
|
|
};
|
|
|
|
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 LDefinition& temp) {
|
|
setOperand(0, object);
|
|
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 LArrayConcat : public LCallInstructionHelper<1, 2, 2>
|
|
{
|
|
public:
|
|
LIR_HEADER(ArrayConcat)
|
|
|
|
LArrayConcat(const LAllocation& lhs, const LAllocation& rhs,
|
|
const LDefinition& temp1, const LDefinition& temp2) {
|
|
setOperand(0, lhs);
|
|
setOperand(1, rhs);
|
|
setTemp(0, temp1);
|
|
setTemp(1, temp2);
|
|
}
|
|
const MArrayConcat* mir() const {
|
|
return mir_->toArrayConcat();
|
|
}
|
|
const LAllocation* lhs() {
|
|
return getOperand(0);
|
|
}
|
|
const LAllocation* rhs() {
|
|
return getOperand(1);
|
|
}
|
|
const LDefinition* temp1() {
|
|
return getTemp(0);
|
|
}
|
|
const LDefinition* temp2() {
|
|
return getTemp(1);
|
|
}
|
|
};
|
|
|
|
class LArraySlice : public LCallInstructionHelper<1, 3, 2>
|
|
{
|
|
public:
|
|
LIR_HEADER(ArraySlice)
|
|
|
|
LArraySlice(const LAllocation& obj, const LAllocation& begin, const LAllocation& end,
|
|
const LDefinition& temp1, const LDefinition& temp2) {
|
|
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)
|
|
|
|
explicit LClampVToUint8(const LDefinition& tempFloat) {
|
|
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)
|
|
|
|
explicit LStoreFixedSlotV(const LAllocation& obj) {
|
|
setOperand(0, obj);
|
|
}
|
|
|
|
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& scopeObj) {
|
|
setOperand(0, scopeObj);
|
|
}
|
|
const LAllocation* scopeObj() {
|
|
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;
|
|
|
|
explicit LGetPropertyCacheV(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
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;
|
|
|
|
explicit LGetPropertyCacheT(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
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();
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
};
|
|
|
|
// 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 LDefinition& temp) {
|
|
setOperand(0, obj);
|
|
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& scopeChain) {
|
|
setOperand(0, scopeChain);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
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& scopeChain) {
|
|
setOperand(0, scopeChain);
|
|
}
|
|
const LAllocation* scopeChain() {
|
|
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)
|
|
|
|
explicit LStoreSlotV(const LAllocation& slots) {
|
|
setOperand(0, slots);
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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)
|
|
|
|
explicit LCallSetProperty(const LAllocation& obj) {
|
|
setOperand(0, obj);
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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 LDefinition& temp,
|
|
const LDefinition& tempToUnboxIndex, const LDefinition& tempDouble,
|
|
const LDefinition& tempFloat32) {
|
|
setOperand(0, object);
|
|
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 LCallIteratorStart : public LCallInstructionHelper<1, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(CallIteratorStart)
|
|
|
|
explicit LCallIteratorStart(const LAllocation& object) {
|
|
setOperand(0, object);
|
|
}
|
|
const LAllocation* object() {
|
|
return getOperand(0);
|
|
}
|
|
MIteratorStart* mir() const {
|
|
return mir_->toIteratorStart();
|
|
}
|
|
};
|
|
|
|
class LIteratorStart : public LInstructionHelper<1, 1, 3>
|
|
{
|
|
public:
|
|
LIR_HEADER(IteratorStart)
|
|
|
|
LIteratorStart(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) {
|
|
setSuccessor(0, ifTrue);
|
|
setSuccessor(1, ifFalse);
|
|
}
|
|
|
|
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)
|
|
|
|
LSetFrameArgumentV() {}
|
|
|
|
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)
|
|
|
|
explicit LTypeBarrierV(const LDefinition& temp) {
|
|
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)
|
|
|
|
explicit LMonitorTypes(const LDefinition& temp) {
|
|
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 LDefinition& temp) {
|
|
setOperand(0, obj);
|
|
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);
|
|
}
|
|
};
|
|
|
|
// 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)
|
|
explicit LIn(const LAllocation& rhs) {
|
|
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)
|
|
LInstanceOfV() {
|
|
}
|
|
|
|
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)
|
|
explicit LCallInstanceOf(const LAllocation& rhs) {
|
|
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 LIsObject : public LInstructionHelper<1, BOX_PIECES, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(IsObject);
|
|
static const size_t Input = 0;
|
|
MIsObject* mir() const {
|
|
return mir_->toIsObject();
|
|
}
|
|
};
|
|
|
|
class LIsObjectAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(IsObjectAndBranch)
|
|
|
|
LIsObjectAndBranch(MBasicBlock* ifTrue, MBasicBlock* ifFalse) {
|
|
setSuccessor(0, ifTrue);
|
|
setSuccessor(1, ifFalse);
|
|
}
|
|
|
|
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();
|
|
}
|
|
};
|
|
|
|
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 LAsmJSLoadGlobalVar : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSLoadGlobalVar);
|
|
MAsmJSLoadGlobalVar* mir() const {
|
|
return mir_->toAsmJSLoadGlobalVar();
|
|
}
|
|
};
|
|
|
|
class LAsmJSStoreGlobalVar : public LInstructionHelper<0, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSStoreGlobalVar);
|
|
explicit LAsmJSStoreGlobalVar(const LAllocation& value) {
|
|
setOperand(0, value);
|
|
}
|
|
MAsmJSStoreGlobalVar* mir() const {
|
|
return mir_->toAsmJSStoreGlobalVar();
|
|
}
|
|
const LAllocation* value() {
|
|
return getOperand(0);
|
|
}
|
|
};
|
|
|
|
class LAsmJSLoadFFIFunc : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSLoadFFIFunc);
|
|
MAsmJSLoadFFIFunc* mir() const {
|
|
return mir_->toAsmJSLoadFFIFunc();
|
|
}
|
|
};
|
|
|
|
class LAsmJSParameter : public LInstructionHelper<1, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSParameter);
|
|
};
|
|
|
|
class LAsmJSReturn : public LInstructionHelper<0, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSReturn);
|
|
};
|
|
|
|
class LAsmJSVoidReturn : public LInstructionHelper<0, 0, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSVoidReturn);
|
|
};
|
|
|
|
class LAsmJSPassStackArg : public LInstructionHelper<0, 1, 0>
|
|
{
|
|
public:
|
|
LIR_HEADER(AsmJSPassStackArg);
|
|
explicit LAsmJSPassStackArg(const LAllocation& arg) {
|
|
setOperand(0, arg);
|
|
}
|
|
MAsmJSPassStackArg* mir() const {
|
|
return mirRaw()->toAsmJSPassStackArg();
|
|
}
|
|
const LAllocation* arg() {
|
|
return getOperand(0);
|
|
}
|
|
};
|
|
|
|
class LAsmJSCall final : public LInstruction
|
|
{
|
|
LAllocation* operands_;
|
|
uint32_t numOperands_;
|
|
LDefinition def_;
|
|
|
|
public:
|
|
LIR_HEADER(AsmJSCall);
|
|
|
|
LAsmJSCall(LAllocation* operands, uint32_t numOperands)
|
|
: operands_(operands),
|
|
numOperands_(numOperands),
|
|
def_(LDefinition::BogusTemp())
|
|
{}
|
|
|
|
MAsmJSCall* mir() const {
|
|
return mir_->toAsmJSCall();
|
|
}
|
|
|
|
bool isCall() const {
|
|
return true;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
size_t numOperands() const {
|
|
return numOperands_;
|
|
}
|
|
LAllocation* getOperand(size_t index) {
|
|
MOZ_ASSERT(index < numOperands_);
|
|
return &operands_[index];
|
|
}
|
|
void setOperand(size_t index, const LAllocation& a) {
|
|
MOZ_ASSERT(index < numOperands_);
|
|
operands_[index] = a;
|
|
}
|
|
size_t numTemps() const {
|
|
return 0;
|
|
}
|
|
LDefinition* getTemp(size_t index) {
|
|
MOZ_CRASH("no temps");
|
|
}
|
|
void setTemp(size_t index, const LDefinition& a) {
|
|
MOZ_CRASH("no temps");
|
|
}
|
|
size_t numSuccessors() const {
|
|
return 0;
|
|
}
|
|
MBasicBlock* getSuccessor(size_t i) const {
|
|
MOZ_CRASH("no successors");
|
|
}
|
|
void setSuccessor(size_t i, MBasicBlock*) {
|
|
MOZ_CRASH("no successors");
|
|
}
|
|
};
|
|
|
|
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& armtemp) {
|
|
setOperand(0, input);
|
|
setTemp(0, temp);
|
|
setTemp(1, armtemp);
|
|
}
|
|
const LDefinition* armtemp() {
|
|
return getTemp(1);
|
|
}
|
|
|
|
const LAllocation* input() {
|
|
return getOperand(0);
|
|
}
|
|
|
|
const LDefinition* temp() {
|
|
return getTemp(0);
|
|
}
|
|
|
|
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 LDefinition& temp, const LDefinition& floatTemp1,
|
|
const LDefinition& floatTemp2)
|
|
{
|
|
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;
|
|
};
|
|
|
|
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)
|
|
|
|
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_;
|
|
}
|
|
|
|
const MMemoryBarrier* mir() const {
|
|
return mir_->toMemoryBarrier();
|
|
}
|
|
};
|
|
|
|
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:
|
|
static const size_t ReturnValue = 0;
|
|
static const size_t ThisValue = BOX_PIECES;
|
|
|
|
LIR_HEADER(CheckReturn)
|
|
};
|
|
|
|
class LCheckObjCoercible : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
|
|
{
|
|
public:
|
|
static const size_t CheckValue = 0;
|
|
|
|
LIR_HEADER(CheckObjCoercible)
|
|
};
|
|
|
|
} // namespace jit
|
|
} // namespace js
|
|
|
|
#endif /* jit_shared_LIR_shared_h */
|