michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_LIR_Common_h michael@0: #define jit_LIR_Common_h michael@0: michael@0: #include "jit/shared/Assembler-shared.h" michael@0: michael@0: // This file declares LIR instructions that are common to every platform. michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class Range; michael@0: michael@0: template michael@0: class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps> michael@0: { michael@0: public: michael@0: const LAllocation *lhs() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return this->getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Simplifies register allocation since the first instruction of a block is michael@0: // guaranteed to have no uses. michael@0: class LLabel : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Label) michael@0: }; michael@0: michael@0: class LNop : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Nop) michael@0: }; michael@0: michael@0: // An LOsiPoint captures a snapshot after a call and ensures enough space to michael@0: // patch in a call to the invalidation mechanism. michael@0: // michael@0: // Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the michael@0: // corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it michael@0: // gets CG'd. michael@0: class LOsiPoint : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: LSafepoint *safepoint_; michael@0: michael@0: public: michael@0: LOsiPoint(LSafepoint *safepoint, LSnapshot *snapshot) michael@0: : safepoint_(safepoint) michael@0: { michael@0: JS_ASSERT(safepoint && snapshot); michael@0: assignSnapshot(snapshot); michael@0: } michael@0: michael@0: LSafepoint *associatedSafepoint() { michael@0: return safepoint_; michael@0: } michael@0: michael@0: LIR_HEADER(OsiPoint) michael@0: }; michael@0: michael@0: class LMove michael@0: { michael@0: LAllocation *from_; michael@0: LAllocation *to_; michael@0: LDefinition::Type type_; michael@0: michael@0: public: michael@0: LMove(LAllocation *from, LAllocation *to, LDefinition::Type type) michael@0: : from_(from), michael@0: to_(to), michael@0: type_(type) michael@0: { } michael@0: michael@0: LAllocation *from() { michael@0: return from_; michael@0: } michael@0: const LAllocation *from() const { michael@0: return from_; michael@0: } michael@0: LAllocation *to() { michael@0: return to_; michael@0: } michael@0: const LAllocation *to() const { michael@0: return to_; michael@0: } michael@0: LDefinition::Type type() const { michael@0: return type_; michael@0: } michael@0: }; michael@0: michael@0: class LMoveGroup : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: js::Vector moves_; michael@0: michael@0: LMoveGroup(TempAllocator &alloc) michael@0: : moves_(alloc) michael@0: { } michael@0: michael@0: public: michael@0: LIR_HEADER(MoveGroup) michael@0: michael@0: static LMoveGroup *New(TempAllocator &alloc) { michael@0: return new(alloc) LMoveGroup(alloc); michael@0: } michael@0: michael@0: void printOperands(FILE *fp); michael@0: michael@0: // Add a move which takes place simultaneously with all others in the group. michael@0: bool add(LAllocation *from, LAllocation *to, LDefinition::Type type); michael@0: michael@0: // Add a move which takes place after existing moves in the group. michael@0: bool addAfter(LAllocation *from, LAllocation *to, LDefinition::Type type); michael@0: michael@0: size_t numMoves() const { michael@0: return moves_.length(); michael@0: } michael@0: const LMove &getMove(size_t i) const { michael@0: return moves_[i]; michael@0: } michael@0: }; michael@0: michael@0: // Constant 32-bit integer. michael@0: class LInteger : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: int32_t i32_; michael@0: michael@0: public: michael@0: LIR_HEADER(Integer) michael@0: michael@0: LInteger(int32_t i32) michael@0: : i32_(i32) michael@0: { } michael@0: michael@0: int32_t getValue() const { michael@0: return i32_; michael@0: } michael@0: }; michael@0: michael@0: // Constant pointer. michael@0: class LPointer : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: enum Kind { michael@0: GC_THING, michael@0: NON_GC_THING michael@0: }; michael@0: michael@0: private: michael@0: void *ptr_; michael@0: Kind kind_; michael@0: michael@0: public: michael@0: LIR_HEADER(Pointer) michael@0: michael@0: LPointer(gc::Cell *ptr) michael@0: : ptr_(ptr), kind_(GC_THING) michael@0: { } michael@0: michael@0: LPointer(void *ptr, Kind kind) michael@0: : ptr_(ptr), kind_(kind) michael@0: { } michael@0: michael@0: void *ptr() const { michael@0: return ptr_; michael@0: } michael@0: Kind kind() const { michael@0: return kind_; michael@0: } michael@0: const char *extraName() const { michael@0: return kind_ == GC_THING ? "GC_THING" : "NON_GC_THING"; michael@0: } michael@0: michael@0: gc::Cell *gcptr() const { michael@0: JS_ASSERT(kind() == GC_THING); michael@0: return (gc::Cell *) ptr_; michael@0: } michael@0: }; michael@0: michael@0: // Constant double. michael@0: class LDouble : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: double d_; michael@0: public: michael@0: LIR_HEADER(Double); michael@0: michael@0: LDouble(double d) : d_(d) michael@0: { } michael@0: double getDouble() const { michael@0: return d_; michael@0: } michael@0: }; michael@0: michael@0: // Constant float32. michael@0: class LFloat32 : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: float f_; michael@0: public: michael@0: LIR_HEADER(Float32); michael@0: michael@0: LFloat32(float f) michael@0: : f_(f) michael@0: { } michael@0: michael@0: float getFloat() const { michael@0: return f_; michael@0: } michael@0: }; michael@0: michael@0: // A constant Value. michael@0: class LValue : public LInstructionHelper michael@0: { michael@0: Value v_; michael@0: michael@0: public: michael@0: LIR_HEADER(Value) michael@0: michael@0: LValue(const Value &v) michael@0: : v_(v) michael@0: { } michael@0: michael@0: Value value() const { michael@0: return v_; michael@0: } michael@0: }; michael@0: michael@0: // Clone an object literal such as we are not modifying the object contained in michael@0: // the sources. michael@0: class LCloneLiteral : public LCallInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CloneLiteral) michael@0: michael@0: LCloneLiteral(const LAllocation &obj) michael@0: { michael@0: setOperand(0, obj); michael@0: } michael@0: michael@0: const LAllocation *getObjectLiteral() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MCloneLiteral *mir() const { michael@0: return mir_->toCloneLiteral(); michael@0: } michael@0: }; michael@0: michael@0: // Formal argument for a function, returning a box. Formal arguments are michael@0: // initially read from the stack. michael@0: class LParameter : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(Parameter) michael@0: }; michael@0: michael@0: // Stack offset for a word-sized immutable input value to a frame. michael@0: class LCallee : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Callee) michael@0: }; michael@0: michael@0: // Base class for control instructions (goto, branch, etc.) michael@0: template michael@0: class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> { michael@0: michael@0: mozilla::Array successors_; michael@0: michael@0: public: michael@0: virtual size_t numSuccessors() const MOZ_FINAL MOZ_OVERRIDE { return Succs; } michael@0: michael@0: virtual MBasicBlock *getSuccessor(size_t i) const MOZ_FINAL MOZ_OVERRIDE { michael@0: return successors_[i]; michael@0: } michael@0: michael@0: virtual void setSuccessor(size_t i, MBasicBlock *successor) MOZ_FINAL MOZ_OVERRIDE { michael@0: successors_[i] = successor; michael@0: } michael@0: }; michael@0: michael@0: // Jumps to the start of a basic block. michael@0: class LGoto : public LControlInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Goto) michael@0: michael@0: LGoto(MBasicBlock *block) michael@0: { michael@0: setSuccessor(0, block); michael@0: } michael@0: michael@0: MBasicBlock *target() const { michael@0: return getSuccessor(0); michael@0: } michael@0: }; michael@0: michael@0: class LNewSlots : public LCallInstructionHelper<1, 0, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewSlots) michael@0: michael@0: LNewSlots(const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) { michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: michael@0: MNewSlots *mir() const { michael@0: return mir_->toNewSlots(); michael@0: } michael@0: }; michael@0: michael@0: class LNewArray : public LInstructionHelper<1, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewArray) michael@0: michael@0: LNewArray(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->shouldUseVM() ? "VMCall" : nullptr; michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MNewArray *mir() const { michael@0: return mir_->toNewArray(); michael@0: } michael@0: }; michael@0: michael@0: class LNewObject : public LInstructionHelper<1, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewObject) michael@0: michael@0: LNewObject(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->shouldUseVM() ? "VMCall" : nullptr; michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MNewObject *mir() const { michael@0: return mir_->toNewObject(); michael@0: } michael@0: }; michael@0: michael@0: class LNewPar : public LInstructionHelper<1, 1, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewPar); michael@0: michael@0: LNewPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) { michael@0: setOperand(0, cx); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: } michael@0: michael@0: MNewPar *mir() const { michael@0: return mir_->toNewPar(); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LDefinition *getTemp0() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *getTemp1() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LNewDenseArrayPar : public LCallInstructionHelper<1, 2, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewDenseArrayPar); michael@0: michael@0: LNewDenseArrayPar(const LAllocation &cx, const LAllocation &length, michael@0: const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) michael@0: { michael@0: setOperand(0, cx); michael@0: setOperand(1, length); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: michael@0: MNewDenseArrayPar *mir() const { michael@0: return mir_->toNewDenseArrayPar(); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *length() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LDefinition *getTemp0() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *getTemp1() { michael@0: return getTemp(1); michael@0: } michael@0: michael@0: const LDefinition *getTemp2() { michael@0: return getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: // Allocates a new DeclEnvObject. michael@0: // michael@0: // This instruction generates two possible instruction sets: michael@0: // (1) An inline allocation of the call object is attempted. michael@0: // (2) Otherwise, a callVM create a new object. michael@0: // michael@0: class LNewDeclEnvObject : public LInstructionHelper<1, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewDeclEnvObject); michael@0: michael@0: LNewDeclEnvObject(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MNewDeclEnvObject *mir() const { michael@0: return mir_->toNewDeclEnvObject(); michael@0: } michael@0: }; michael@0: michael@0: // Allocates a new CallObject. The inputs are: michael@0: // slots: either a reg representing a HeapSlot *, or a placeholder michael@0: // meaning that no slots pointer is needed. michael@0: // michael@0: // This instruction generates two possible instruction sets: michael@0: // (1) If the call object is extensible, this is a callVM to create the michael@0: // call object. michael@0: // (2) Otherwise, an inline allocation of the call object is attempted. michael@0: // michael@0: class LNewCallObject : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewCallObject) michael@0: michael@0: LNewCallObject(const LAllocation &slots, const LDefinition &temp) { michael@0: setOperand(0, slots); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LAllocation *slots() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MNewCallObject *mir() const { michael@0: return mir_->toNewCallObject(); michael@0: } michael@0: }; michael@0: michael@0: // Allocates a new CallObject with singleton type through an out-of-line VM michael@0: // call. The inputs are: michael@0: // slots: either a reg representing a HeapSlot *, or a placeholder michael@0: // meaning that no slots pointer is needed. michael@0: // michael@0: class LNewSingletonCallObject : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewSingletonCallObject) michael@0: michael@0: LNewSingletonCallObject(const LAllocation &slots) { michael@0: setOperand(0, slots); michael@0: } michael@0: michael@0: const LAllocation *slots() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MNewCallObjectBase * mir() const { michael@0: MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject()); michael@0: return static_cast(mir_); michael@0: } michael@0: }; michael@0: michael@0: class LNewCallObjectPar : public LInstructionHelper<1, 2, 2> michael@0: { michael@0: LNewCallObjectPar(const LAllocation &cx, const LAllocation &slots, michael@0: const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: setOperand(0, cx); michael@0: setOperand(1, slots); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: } michael@0: michael@0: public: michael@0: LIR_HEADER(NewCallObjectPar); michael@0: michael@0: static LNewCallObjectPar *NewWithSlots(TempAllocator &alloc, michael@0: const LAllocation &cx, const LAllocation &slots, michael@0: const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2); michael@0: } michael@0: michael@0: static LNewCallObjectPar *NewSansSlots(TempAllocator &alloc, michael@0: const LAllocation &cx, michael@0: const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: LAllocation slots = LConstantIndex::Bogus(); michael@0: return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *slots() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const bool hasDynamicSlots() { michael@0: // TO INVESTIGATE: Felix tried using isRegister() method here, michael@0: // but for useFixed(_, CallTempN), isRegister() is false (and michael@0: // isUse() is true). So for now ignore that and try to match michael@0: // the LConstantIndex::Bogus() generated above instead. michael@0: return slots() && ! slots()->isConstant(); michael@0: } michael@0: michael@0: const MNewCallObjectPar *mir() const { michael@0: return mir_->toNewCallObjectPar(); michael@0: } michael@0: michael@0: const LDefinition *getTemp0() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *getTemp1() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewDerivedTypedObject); michael@0: michael@0: LNewDerivedTypedObject(const LAllocation &type, michael@0: const LAllocation &owner, michael@0: const LAllocation &offset) { michael@0: setOperand(0, type); michael@0: setOperand(1, owner); michael@0: setOperand(2, offset); michael@0: } michael@0: michael@0: const LAllocation *type() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *owner() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LAllocation *offset() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: class LNewStringObject : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NewStringObject) michael@0: michael@0: LNewStringObject(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *input() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MNewStringObject *mir() const { michael@0: return mir_->toNewStringObject(); michael@0: } michael@0: }; michael@0: michael@0: class LAbortPar : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AbortPar); michael@0: }; michael@0: michael@0: class LInitElem : public LCallInstructionHelper<0, 1 + 2*BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InitElem) michael@0: michael@0: LInitElem(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: static const size_t IdIndex = 1; michael@0: static const size_t ValueIndex = 1 + BOX_PIECES; michael@0: michael@0: const LAllocation *getObject() { michael@0: return getOperand(0); michael@0: } michael@0: MInitElem *mir() const { michael@0: return mir_->toInitElem(); michael@0: } michael@0: }; michael@0: michael@0: class LInitElemGetterSetter : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InitElemGetterSetter) michael@0: michael@0: LInitElemGetterSetter(const LAllocation &object, const LAllocation &value) { michael@0: setOperand(0, object); michael@0: setOperand(1, value); michael@0: } michael@0: michael@0: static const size_t IdIndex = 2; michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: MInitElemGetterSetter *mir() const { michael@0: return mir_->toInitElemGetterSetter(); michael@0: } michael@0: }; michael@0: michael@0: // Takes in an Object and a Value. michael@0: class LMutateProto : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(MutateProto) michael@0: michael@0: LMutateProto(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: static const size_t ValueIndex = 1; michael@0: michael@0: const LAllocation *getObject() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getValue() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Takes in an Object and a Value. michael@0: class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InitProp) michael@0: michael@0: LInitProp(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: static const size_t ValueIndex = 1; michael@0: michael@0: const LAllocation *getObject() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getValue() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: MInitProp *mir() const { michael@0: return mir_->toInitProp(); michael@0: } michael@0: }; michael@0: michael@0: class LInitPropGetterSetter : public LCallInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InitPropGetterSetter) michael@0: michael@0: LInitPropGetterSetter(const LAllocation &object, const LAllocation &value) { michael@0: setOperand(0, object); michael@0: setOperand(1, value); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: MInitPropGetterSetter *mir() const { michael@0: return mir_->toInitPropGetterSetter(); michael@0: } michael@0: }; michael@0: michael@0: class LCheckOverRecursed : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CheckOverRecursed) michael@0: michael@0: LCheckOverRecursed() michael@0: { } michael@0: }; michael@0: michael@0: class LCheckOverRecursedPar : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(CheckOverRecursedPar); michael@0: michael@0: LCheckOverRecursedPar(const LAllocation &cx, const LDefinition &tempReg) { michael@0: setOperand(0, cx); michael@0: setTemp(0, tempReg); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LDefinition *getTempReg() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Alternative to LInterruptCheck which does not emit an explicit check of the michael@0: // interrupt flag but relies on the loop backedge being patched via a signal michael@0: // handler. michael@0: class LInterruptCheckImplicit : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: Label *oolEntry_; michael@0: michael@0: public: michael@0: LIR_HEADER(InterruptCheckImplicit) michael@0: michael@0: LInterruptCheckImplicit() michael@0: : oolEntry_(nullptr) michael@0: {} michael@0: michael@0: Label *oolEntry() { michael@0: return oolEntry_; michael@0: } michael@0: michael@0: void setOolEntry(Label *oolEntry) { michael@0: oolEntry_ = oolEntry; michael@0: } michael@0: }; michael@0: michael@0: class LInterruptCheckPar : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(InterruptCheckPar); michael@0: michael@0: LInterruptCheckPar(const LAllocation &cx, const LDefinition &tempReg) { michael@0: setOperand(0, cx); michael@0: setTemp(0, tempReg); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LDefinition *getTempReg() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class LDefVar : public LCallInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(DefVar) michael@0: michael@0: LDefVar(const LAllocation &scopeChain) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: } michael@0: michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: MDefVar *mir() const { michael@0: return mir_->toDefVar(); michael@0: } michael@0: }; michael@0: michael@0: class LDefFun : public LCallInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(DefFun) michael@0: michael@0: LDefFun(const LAllocation &scopeChain) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: } michael@0: michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: MDefFun *mir() const { michael@0: return mir_->toDefFun(); michael@0: } michael@0: }; michael@0: michael@0: class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypeOfV) michael@0: michael@0: LTypeOfV(const LDefinition &tempToUnbox) { michael@0: setTemp(0, tempToUnbox); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const LDefinition *tempToUnbox() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MTypeOf *mir() const { michael@0: return mir_->toTypeOf(); michael@0: } michael@0: }; michael@0: michael@0: class LToIdV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(ToIdV) michael@0: michael@0: LToIdV(const LDefinition &temp) michael@0: { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Object = 0; michael@0: static const size_t Index = BOX_PIECES; michael@0: michael@0: MToId *mir() const { michael@0: return mir_->toToId(); michael@0: } michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Allocate an object for |new| on the caller-side, michael@0: // when there is no templateObject or prototype known michael@0: class LCreateThis : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CreateThis) michael@0: michael@0: LCreateThis(const LAllocation &callee) michael@0: { michael@0: setOperand(0, callee); michael@0: } michael@0: michael@0: const LAllocation *getCallee() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MCreateThis *mir() const { michael@0: return mir_->toCreateThis(); michael@0: } michael@0: }; michael@0: michael@0: // Allocate an object for |new| on the caller-side, michael@0: // when the prototype is known. michael@0: class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CreateThisWithProto) michael@0: michael@0: LCreateThisWithProto(const LAllocation &callee, const LAllocation &prototype) michael@0: { michael@0: setOperand(0, callee); michael@0: setOperand(1, prototype); michael@0: } michael@0: michael@0: const LAllocation *getCallee() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getPrototype() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: MCreateThis *mir() const { michael@0: return mir_->toCreateThis(); michael@0: } michael@0: }; michael@0: michael@0: // Allocate an object for |new| on the caller-side. michael@0: // Always performs object initialization with a fast path. michael@0: class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(CreateThisWithTemplate) michael@0: michael@0: LCreateThisWithTemplate(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: MCreateThisWithTemplate *mir() const { michael@0: return mir_->toCreateThisWithTemplate(); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Allocate a new arguments object for the frame. michael@0: class LCreateArgumentsObject : public LCallInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(CreateArgumentsObject) michael@0: michael@0: LCreateArgumentsObject(const LAllocation &callObj, const LDefinition &temp) michael@0: { michael@0: setOperand(0, callObj); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *getCallObject() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MCreateArgumentsObject *mir() const { michael@0: return mir_->toCreateArgumentsObject(); michael@0: } michael@0: }; michael@0: michael@0: // Get argument from arguments object. michael@0: class LGetArgumentsObjectArg : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetArgumentsObjectArg) michael@0: michael@0: LGetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp) michael@0: { michael@0: setOperand(0, argsObj); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *getArgsObject() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MGetArgumentsObjectArg *mir() const { michael@0: return mir_->toGetArgumentsObjectArg(); michael@0: } michael@0: }; michael@0: michael@0: // Set argument on arguments object. michael@0: class LSetArgumentsObjectArg : public LInstructionHelper<0, 1 + BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetArgumentsObjectArg) michael@0: michael@0: LSetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp) michael@0: { michael@0: setOperand(0, argsObj); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *getArgsObject() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MSetArgumentsObjectArg *mir() const { michael@0: return mir_->toSetArgumentsObjectArg(); michael@0: } michael@0: michael@0: static const size_t ValueIndex = 1; michael@0: }; michael@0: michael@0: // If the Value is an Object, return unbox(Value). michael@0: // Otherwise, return the other Object. michael@0: class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ReturnFromCtor) michael@0: michael@0: LReturnFromCtor(const LAllocation &object) michael@0: { michael@0: // Value set by useBox() during lowering. michael@0: setOperand(LReturnFromCtor::ObjectIndex, object); michael@0: } michael@0: michael@0: const LAllocation *getObject() { michael@0: return getOperand(LReturnFromCtor::ObjectIndex); michael@0: } michael@0: michael@0: static const size_t ValueIndex = 0; michael@0: static const size_t ObjectIndex = BOX_PIECES; michael@0: }; michael@0: michael@0: class LComputeThis : public LInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ComputeThis) michael@0: michael@0: static const size_t ValueIndex = 0; michael@0: michael@0: const LDefinition *output() { michael@0: return getDef(0); michael@0: } michael@0: michael@0: MComputeThis *mir() const { michael@0: return mir_->toComputeThis(); michael@0: } michael@0: }; michael@0: michael@0: class LLoadArrowThis : public LInstructionHelper michael@0: { michael@0: public: michael@0: LLoadArrowThis(const LAllocation &callee) { michael@0: setOperand(0, callee); michael@0: } michael@0: michael@0: LIR_HEADER(LoadArrowThis) michael@0: michael@0: const LAllocation *callee() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Writes a typed argument for a function call to the frame's argument vector. michael@0: class LStackArgT : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: uint32_t argslot_; // Index into frame-scope argument vector. michael@0: MIRType type_; michael@0: michael@0: public: michael@0: LIR_HEADER(StackArgT) michael@0: michael@0: LStackArgT(uint32_t argslot, MIRType type, const LAllocation &arg) michael@0: : argslot_(argslot), michael@0: type_(type) michael@0: { michael@0: setOperand(0, arg); michael@0: } michael@0: uint32_t argslot() const { michael@0: return argslot_; michael@0: } michael@0: MIRType type() const { michael@0: return type_; michael@0: } michael@0: const LAllocation *getArgument() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Writes an untyped argument for a function call to the frame's argument vector. michael@0: class LStackArgV : public LInstructionHelper<0, BOX_PIECES, 0> michael@0: { michael@0: uint32_t argslot_; // Index into frame-scope argument vector. michael@0: michael@0: public: michael@0: LIR_HEADER(StackArgV) michael@0: michael@0: LStackArgV(uint32_t argslot) michael@0: : argslot_(argslot) michael@0: { } michael@0: michael@0: uint32_t argslot() const { michael@0: return argslot_; michael@0: } michael@0: }; michael@0: michael@0: // Common code for LIR descended from MCall. michael@0: template michael@0: class LJSCallInstructionHelper : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: uint32_t argslot() const { michael@0: return mir()->numStackArgs(); michael@0: } michael@0: MCall *mir() const { michael@0: return this->mir_->toCall(); michael@0: } michael@0: michael@0: bool hasSingleTarget() const { michael@0: return getSingleTarget() != nullptr; michael@0: } michael@0: JSFunction *getSingleTarget() const { michael@0: return mir()->getSingleTarget(); michael@0: } michael@0: michael@0: // The number of stack arguments is the max between the number of formal michael@0: // arguments and the number of actual arguments. The number of stack michael@0: // argument includes the |undefined| padding added in case of underflow. michael@0: // Does not include |this|. michael@0: uint32_t numStackArgs() const { michael@0: JS_ASSERT(mir()->numStackArgs() >= 1); michael@0: return mir()->numStackArgs() - 1; // |this| is not a formal argument. michael@0: } michael@0: // Does not include |this|. michael@0: uint32_t numActualArgs() const { michael@0: return mir()->numActualArgs(); michael@0: } michael@0: }; michael@0: michael@0: // Generates a polymorphic callsite, wherein the function being called is michael@0: // unknown and anticipated to vary. michael@0: class LCallGeneric : public LJSCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallGeneric) michael@0: michael@0: LCallGeneric(const LAllocation &func, const LDefinition &nargsreg, michael@0: const LDefinition &tmpobjreg) michael@0: { michael@0: setOperand(0, func); michael@0: setTemp(0, nargsreg); michael@0: setTemp(1, tmpobjreg); michael@0: } michael@0: michael@0: const LAllocation *getFunction() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *getNargsReg() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *getTempObject() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: // Generates a hardcoded callsite for a known, non-native target. michael@0: class LCallKnown : public LJSCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallKnown) michael@0: michael@0: LCallKnown(const LAllocation &func, const LDefinition &tmpobjreg) michael@0: { michael@0: setOperand(0, func); michael@0: setTemp(0, tmpobjreg); michael@0: } michael@0: michael@0: const LAllocation *getFunction() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *getTempObject() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Generates a hardcoded callsite for a known, native target. michael@0: class LCallNative : public LJSCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallNative) michael@0: michael@0: LCallNative(const LDefinition &argContext, const LDefinition &argUintN, michael@0: const LDefinition &argVp, const LDefinition &tmpreg) michael@0: { michael@0: // Registers used for callWithABI(). michael@0: setTemp(0, argContext); michael@0: setTemp(1, argUintN); michael@0: setTemp(2, argVp); michael@0: michael@0: // Temporary registers. michael@0: setTemp(3, tmpreg); michael@0: } michael@0: michael@0: const LDefinition *getArgContextReg() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *getArgUintNReg() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *getArgVpReg() { michael@0: return getTemp(2); michael@0: } michael@0: const LDefinition *getTempReg() { michael@0: return getTemp(3); michael@0: } michael@0: }; michael@0: michael@0: // Generates a hardcoded callsite for a known, DOM-native target. michael@0: class LCallDOMNative : public LJSCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallDOMNative) michael@0: michael@0: LCallDOMNative(const LDefinition &argJSContext, const LDefinition &argObj, michael@0: const LDefinition &argPrivate, const LDefinition &argArgs) michael@0: { michael@0: setTemp(0, argJSContext); michael@0: setTemp(1, argObj); michael@0: setTemp(2, argPrivate); michael@0: setTemp(3, argArgs); michael@0: } michael@0: michael@0: const LDefinition *getArgJSContext() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *getArgObj() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *getArgPrivate() { michael@0: return getTemp(2); michael@0: } michael@0: const LDefinition *getArgArgs() { michael@0: return getTemp(3); michael@0: } michael@0: }; michael@0: michael@0: class LBail : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Bail) michael@0: }; michael@0: michael@0: template michael@0: class LDOMPropertyInstructionHelper : public LCallInstructionHelper michael@0: { michael@0: protected: michael@0: LDOMPropertyInstructionHelper(const LDefinition &JSContextReg, const LAllocation &ObjectReg, michael@0: const LDefinition &PrivReg, const LDefinition &ValueReg) michael@0: { michael@0: this->setOperand(0, ObjectReg); michael@0: this->setTemp(0, JSContextReg); michael@0: this->setTemp(1, PrivReg); michael@0: this->setTemp(2, ValueReg); michael@0: } michael@0: michael@0: public: michael@0: const LDefinition *getJSContextReg() { michael@0: return this->getTemp(0); michael@0: } michael@0: const LAllocation *getObjectReg() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LDefinition *getPrivReg() { michael@0: return this->getTemp(1); michael@0: } michael@0: const LDefinition *getValueReg() { michael@0: return this->getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: michael@0: class LGetDOMProperty : public LDOMPropertyInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetDOMProperty) michael@0: michael@0: LGetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg, michael@0: const LDefinition &PrivReg, const LDefinition &ValueReg) michael@0: : LDOMPropertyInstructionHelper(JSContextReg, ObjectReg, michael@0: PrivReg, ValueReg) michael@0: { } michael@0: michael@0: MGetDOMProperty *mir() const { michael@0: return mir_->toGetDOMProperty(); michael@0: } michael@0: }; michael@0: michael@0: class LGetDOMMember : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetDOMMember); michael@0: LGetDOMMember(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MGetDOMMember *mir() const { michael@0: return mir_->toGetDOMMember(); michael@0: } michael@0: }; michael@0: michael@0: class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetDOMProperty) michael@0: michael@0: LSetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg, michael@0: const LDefinition &PrivReg, const LDefinition &ValueReg) michael@0: : LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg, michael@0: PrivReg, ValueReg) michael@0: { } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: MSetDOMProperty *mir() const { michael@0: return mir_->toSetDOMProperty(); michael@0: } michael@0: }; michael@0: michael@0: // Generates a polymorphic callsite, wherein the function being called is michael@0: // unknown and anticipated to vary. michael@0: class LApplyArgsGeneric : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(ApplyArgsGeneric) michael@0: michael@0: LApplyArgsGeneric(const LAllocation &func, const LAllocation &argc, michael@0: const LDefinition &tmpobjreg, const LDefinition &tmpcopy) michael@0: { michael@0: setOperand(0, func); michael@0: setOperand(1, argc); michael@0: setTemp(0, tmpobjreg); michael@0: setTemp(1, tmpcopy); michael@0: } michael@0: michael@0: MApplyArgs *mir() const { michael@0: return mir_->toApplyArgs(); michael@0: } michael@0: michael@0: bool hasSingleTarget() const { michael@0: return getSingleTarget() != nullptr; michael@0: } michael@0: JSFunction *getSingleTarget() const { michael@0: return mir()->getSingleTarget(); michael@0: } michael@0: michael@0: const LAllocation *getFunction() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getArgc() { michael@0: return getOperand(1); michael@0: } michael@0: static const size_t ThisIndex = 2; michael@0: michael@0: const LDefinition *getTempObject() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *getTempCopy() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LArraySplice : public LCallInstructionHelper<0, 3, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArraySplice) michael@0: michael@0: LArraySplice(const LAllocation &object, const LAllocation &start, michael@0: const LAllocation &deleteCount) michael@0: { michael@0: setOperand(0, object); michael@0: setOperand(1, start); michael@0: setOperand(2, deleteCount); michael@0: } michael@0: michael@0: MArraySplice *mir() const { michael@0: return mir_->toArraySplice(); michael@0: } michael@0: michael@0: const LAllocation *getObject() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getStart() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *getDeleteCount() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: class LGetDynamicName : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetDynamicName) michael@0: michael@0: LGetDynamicName(const LAllocation &scopeChain, const LAllocation &name, michael@0: const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: setOperand(1, name); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: michael@0: MGetDynamicName *mir() const { michael@0: return mir_->toGetDynamicName(); michael@0: } michael@0: michael@0: const LAllocation *getScopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getName() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: class LFilterArgumentsOrEvalS : public LCallInstructionHelper<0, 1, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(FilterArgumentsOrEvalS) michael@0: michael@0: LFilterArgumentsOrEvalS(const LAllocation &string, const LDefinition &temp1, michael@0: const LDefinition &temp2) michael@0: { michael@0: setOperand(0, string); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: } michael@0: michael@0: MFilterArgumentsOrEval *mir() const { michael@0: return mir_->toFilterArgumentsOrEval(); michael@0: } michael@0: michael@0: const LAllocation *getString() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LFilterArgumentsOrEvalV : public LCallInstructionHelper<0, BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(FilterArgumentsOrEvalV) michael@0: michael@0: LFilterArgumentsOrEvalV(const LDefinition &temp1, const LDefinition &temp2, michael@0: const LDefinition &temp3) michael@0: { michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: MFilterArgumentsOrEval *mir() const { michael@0: return mir_->toFilterArgumentsOrEval(); michael@0: } michael@0: michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: class LCallDirectEvalS : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallDirectEvalS) michael@0: michael@0: LCallDirectEvalS(const LAllocation &scopeChain, const LAllocation &string) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: setOperand(1, string); michael@0: } michael@0: michael@0: static const size_t ThisValue = 2; michael@0: michael@0: MCallDirectEval *mir() const { michael@0: return mir_->toCallDirectEval(); michael@0: } michael@0: michael@0: const LAllocation *getScopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *getString() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LCallDirectEvalV : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallDirectEvalV) michael@0: michael@0: LCallDirectEvalV(const LAllocation &scopeChain) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: } michael@0: michael@0: static const size_t Argument = 1; michael@0: static const size_t ThisValue = 1 + BOX_PIECES; michael@0: michael@0: MCallDirectEval *mir() const { michael@0: return mir_->toCallDirectEval(); michael@0: } michael@0: michael@0: const LAllocation *getScopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Takes in either an integer or boolean input and tests it for truthiness. michael@0: class LTestIAndBranch : public LControlInstructionHelper<2, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TestIAndBranch) michael@0: michael@0: LTestIAndBranch(const LAllocation &in, MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: { michael@0: setOperand(0, in); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: }; michael@0: michael@0: // Takes in either an integer or boolean input and tests it for truthiness. michael@0: class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TestDAndBranch) michael@0: michael@0: LTestDAndBranch(const LAllocation &in, MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: { michael@0: setOperand(0, in); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: }; michael@0: michael@0: // Takes in either an integer or boolean input and tests it for truthiness. michael@0: class LTestFAndBranch : public LControlInstructionHelper<2, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TestFAndBranch) michael@0: michael@0: LTestFAndBranch(const LAllocation &in, MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: { michael@0: setOperand(0, in); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: }; michael@0: michael@0: // Takes an object and tests it for truthiness. An object is falsy iff it michael@0: // emulates |undefined|; see js::EmulatesUndefined. michael@0: class LTestOAndBranch : public LControlInstructionHelper<2, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TestOAndBranch) michael@0: michael@0: LTestOAndBranch(const LAllocation &input, MBasicBlock *ifTruthy, MBasicBlock *ifFalsy, michael@0: const LDefinition &temp) michael@0: { michael@0: setOperand(0, input); michael@0: setSuccessor(0, ifTruthy); michael@0: setSuccessor(1, ifFalsy); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MBasicBlock *ifTruthy() { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalsy() { michael@0: return getSuccessor(1); michael@0: } michael@0: michael@0: MTest *mir() { michael@0: return mir_->toTest(); michael@0: } michael@0: }; michael@0: michael@0: // Takes in a boxed value and tests it for truthiness. michael@0: class LTestVAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(TestVAndBranch) michael@0: michael@0: LTestVAndBranch(MBasicBlock *ifTruthy, MBasicBlock *ifFalsy, const LDefinition &temp0, michael@0: const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: setSuccessor(0, ifTruthy); michael@0: setSuccessor(1, ifFalsy); michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: setTemp(2, temp2); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->operandMightEmulateUndefined() ? "MightEmulateUndefined" : nullptr; michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *temp1() { michael@0: return getTemp(1); michael@0: } michael@0: michael@0: const LDefinition *temp2() { michael@0: return getTemp(2); michael@0: } michael@0: michael@0: MBasicBlock *ifTruthy() { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalsy() { michael@0: return getSuccessor(1); michael@0: } michael@0: michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: }; michael@0: michael@0: // Dispatches control flow to a successor based on incoming JSFunction*. michael@0: // Used to implemenent polymorphic inlining. michael@0: class LFunctionDispatch : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: // Dispatch is performed based on a function -> block map michael@0: // stored in the MIR. michael@0: michael@0: public: michael@0: LIR_HEADER(FunctionDispatch); michael@0: michael@0: LFunctionDispatch(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: michael@0: MFunctionDispatch *mir() { michael@0: return mir_->toFunctionDispatch(); michael@0: } michael@0: }; michael@0: michael@0: class LTypeObjectDispatch : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: // Dispatch is performed based on a TypeObject -> block michael@0: // map inferred by the MIR. michael@0: michael@0: public: michael@0: LIR_HEADER(TypeObjectDispatch); michael@0: michael@0: LTypeObjectDispatch(const LAllocation &in, const LDefinition &temp) { michael@0: setOperand(0, in); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MTypeObjectDispatch *mir() { michael@0: return mir_->toTypeObjectDispatch(); michael@0: } michael@0: }; michael@0: michael@0: // Compares two integral values of the same JS type, either integer or object. michael@0: // For objects, both operands are in registers. michael@0: class LCompare : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(Compare) michael@0: LCompare(JSOp jsop, const LAllocation &left, const LAllocation &right) michael@0: : jsop_(jsop) michael@0: { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: }; michael@0: michael@0: // Compares two integral values of the same JS type, either integer or object. michael@0: // For objects, both operands are in registers. michael@0: class LCompareAndBranch : public LControlInstructionHelper<2, 2, 0> michael@0: { michael@0: MCompare *cmpMir_; michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(CompareAndBranch) michael@0: LCompareAndBranch(MCompare *cmpMir, JSOp jsop, michael@0: const LAllocation &left, const LAllocation &right, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: : cmpMir_(cmpMir), jsop_(jsop) michael@0: { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: }; michael@0: michael@0: class LCompareD : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareD) michael@0: LCompareD(const LAllocation &left, const LAllocation &right) { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: } michael@0: michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LCompareF : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareF) michael@0: LCompareF(const LAllocation &left, const LAllocation &right) { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: } michael@0: michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(CompareDAndBranch) michael@0: LCompareDAndBranch(MCompare *cmpMir, const LAllocation &left, const LAllocation &right, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: }; michael@0: michael@0: class LCompareFAndBranch : public LControlInstructionHelper<2, 2, 0> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(CompareFAndBranch) michael@0: LCompareFAndBranch(MCompare *cmpMir, const LAllocation &left, const LAllocation &right, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: }; michael@0: michael@0: class LCompareS : public LInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareS) michael@0: LCompareS(const LAllocation &left, const LAllocation &right, michael@0: const LDefinition &temp) { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: // strict-equality between value and string. michael@0: class LCompareStrictS : public LInstructionHelper<1, BOX_PIECES + 1, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareStrictS) michael@0: LCompareStrictS(const LAllocation &rhs, const LDefinition &temp0, michael@0: const LDefinition &temp1) { michael@0: setOperand(BOX_PIECES, rhs); michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: } michael@0: michael@0: static const size_t Lhs = 0; michael@0: michael@0: const LAllocation *right() { michael@0: return getOperand(BOX_PIECES); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *tempToUnbox() { michael@0: return getTemp(1); michael@0: } michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: // Used for strict-equality comparisons where one side is a boolean michael@0: // and the other is a value. Note that CompareI is used to compare michael@0: // two booleans. michael@0: class LCompareB : public LInstructionHelper<1, BOX_PIECES + 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareB) michael@0: michael@0: LCompareB(const LAllocation &rhs) { michael@0: setOperand(BOX_PIECES, rhs); michael@0: } michael@0: michael@0: static const size_t Lhs = 0; michael@0: michael@0: const LAllocation *rhs() { michael@0: return getOperand(BOX_PIECES); michael@0: } michael@0: michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LCompareBAndBranch : public LControlInstructionHelper<2, BOX_PIECES + 1, 0> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(CompareBAndBranch) michael@0: michael@0: LCompareBAndBranch(MCompare *cmpMir, const LAllocation &rhs, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setOperand(BOX_PIECES, rhs); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: static const size_t Lhs = 0; michael@0: michael@0: const LAllocation *rhs() { michael@0: return getOperand(BOX_PIECES); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: }; michael@0: michael@0: class LCompareV : public LInstructionHelper<1, 2 * BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareV) michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: michael@0: MCompare *mir() const { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LCompareVAndBranch : public LControlInstructionHelper<2, 2 * BOX_PIECES, 0> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(CompareVAndBranch) michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: michael@0: LCompareVAndBranch(MCompare *cmpMir, MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: }; michael@0: michael@0: class LCompareVM : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CompareVM) michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: michael@0: MCompare *mir() const { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LBitAndAndBranch : public LControlInstructionHelper<2, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BitAndAndBranch) michael@0: LBitAndAndBranch(MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: { michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: const LAllocation *left() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *right() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LIsNullOrLikeUndefined : public LInstructionHelper<1, BOX_PIECES, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(IsNullOrLikeUndefined) michael@0: michael@0: LIsNullOrLikeUndefined(const LDefinition &temp, const LDefinition &tempToUnbox) michael@0: { michael@0: setTemp(0, temp); michael@0: setTemp(1, tempToUnbox); michael@0: } michael@0: michael@0: static const size_t Value = 0; michael@0: michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *tempToUnbox() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LIsNullOrLikeUndefinedAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 2> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(IsNullOrLikeUndefinedAndBranch) michael@0: michael@0: LIsNullOrLikeUndefinedAndBranch(MCompare *cmpMir, MBasicBlock *ifTrue, MBasicBlock *ifFalse, michael@0: const LDefinition &temp, const LDefinition &tempToUnbox) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: setTemp(0, temp); michael@0: setTemp(1, tempToUnbox); michael@0: } michael@0: michael@0: static const size_t Value = 0; michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *tempToUnbox() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: // Takes an object and tests whether it emulates |undefined|, as determined by michael@0: // the JSCLASS_EMULATES_UNDEFINED class flag on unwrapped objects. See also michael@0: // js::EmulatesUndefined. michael@0: class LEmulatesUndefined : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(EmulatesUndefined) michael@0: michael@0: LEmulatesUndefined(const LAllocation &input) michael@0: { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: MCompare *mir() { michael@0: return mir_->toCompare(); michael@0: } michael@0: }; michael@0: michael@0: class LEmulatesUndefinedAndBranch : public LControlInstructionHelper<2, 1, 1> michael@0: { michael@0: MCompare *cmpMir_; michael@0: michael@0: public: michael@0: LIR_HEADER(EmulatesUndefinedAndBranch) michael@0: michael@0: LEmulatesUndefinedAndBranch(MCompare *cmpMir, const LAllocation &input, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse, michael@0: const LDefinition &temp) michael@0: : cmpMir_(cmpMir) michael@0: { michael@0: setOperand(0, input); michael@0: setSuccessor(0, ifTrue); michael@0: setSuccessor(1, ifFalse); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: MBasicBlock *ifTrue() const { michael@0: return getSuccessor(0); michael@0: } michael@0: MBasicBlock *ifFalse() const { michael@0: return getSuccessor(1); michael@0: } michael@0: MTest *mir() const { michael@0: return mir_->toTest(); michael@0: } michael@0: MCompare *cmpMir() const { michael@0: return cmpMir_; michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Not operation on an integer. michael@0: class LNotI : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NotI) michael@0: michael@0: LNotI(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: }; michael@0: michael@0: // Not operation on a double. michael@0: class LNotD : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NotD) michael@0: michael@0: LNotD(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: MNot *mir() { michael@0: return mir_->toNot(); michael@0: } michael@0: }; michael@0: michael@0: // Not operation on a float32. michael@0: class LNotF : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NotF) michael@0: michael@0: LNotF(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: MNot *mir() { michael@0: return mir_->toNot(); michael@0: } michael@0: }; michael@0: michael@0: // Boolean complement operation on an object. michael@0: class LNotO : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NotO) michael@0: michael@0: LNotO(const LAllocation &input) michael@0: { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: MNot *mir() { michael@0: return mir_->toNot(); michael@0: } michael@0: }; michael@0: michael@0: // Boolean complement operation on a value. michael@0: class LNotV : public LInstructionHelper<1, BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(NotV) michael@0: michael@0: static const size_t Input = 0; michael@0: LNotV(const LDefinition &temp0, const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: setTemp(2, temp2); michael@0: } michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *temp1() { michael@0: return getTemp(1); michael@0: } michael@0: michael@0: const LDefinition *temp2() { michael@0: return getTemp(2); michael@0: } michael@0: michael@0: MNot *mir() { michael@0: return mir_->toNot(); michael@0: } michael@0: }; michael@0: michael@0: // Bitwise not operation, takes a 32-bit integer as input and returning michael@0: // a 32-bit integer result as an output. michael@0: class LBitNotI : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BitNotI) michael@0: }; michael@0: michael@0: // Call a VM function to perform a BITNOT operation. michael@0: class LBitNotV : public LCallInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BitNotV) michael@0: michael@0: static const size_t Input = 0; michael@0: }; michael@0: michael@0: // Binary bitwise operation, taking two 32-bit integers as inputs and returning michael@0: // a 32-bit integer result as an output. michael@0: class LBitOpI : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: JSOp op_; michael@0: michael@0: public: michael@0: LIR_HEADER(BitOpI) michael@0: michael@0: LBitOpI(JSOp op) michael@0: : op_(op) michael@0: { } michael@0: michael@0: const char *extraName() const { michael@0: if (bitop() == JSOP_URSH && mir_->toUrsh()->bailoutsDisabled()) michael@0: return "ursh:BailoutsDisabled"; michael@0: return js_CodeName[op_]; michael@0: } michael@0: michael@0: JSOp bitop() const { michael@0: return op_; michael@0: } michael@0: }; michael@0: michael@0: // Call a VM function to perform a bitwise operation. michael@0: class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> michael@0: { michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(BitOpV) michael@0: michael@0: LBitOpV(JSOp jsop) michael@0: : jsop_(jsop) michael@0: { } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: }; michael@0: michael@0: // Shift operation, taking two 32-bit integers as inputs and returning michael@0: // a 32-bit integer result as an output. michael@0: class LShiftI : public LBinaryMath<0> michael@0: { michael@0: JSOp op_; michael@0: michael@0: public: michael@0: LIR_HEADER(ShiftI) michael@0: michael@0: LShiftI(JSOp op) michael@0: : op_(op) michael@0: { } michael@0: michael@0: JSOp bitop() { michael@0: return op_; michael@0: } michael@0: michael@0: MInstruction *mir() { michael@0: return mir_->toInstruction(); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return js_CodeName[op_]; michael@0: } michael@0: }; michael@0: michael@0: class LUrshD : public LBinaryMath<1> michael@0: { michael@0: public: michael@0: LIR_HEADER(UrshD) michael@0: michael@0: LUrshD(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) { michael@0: setOperand(0, lhs); michael@0: setOperand(1, rhs); michael@0: setTemp(0, temp); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Returns from the function being compiled (not used in inlined frames). The michael@0: // input must be a box. michael@0: class LReturn : public LInstructionHelper<0, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Return) michael@0: }; michael@0: michael@0: class LThrow : public LCallInstructionHelper<0, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Throw) michael@0: michael@0: static const size_t Value = 0; michael@0: }; michael@0: michael@0: class LMinMaxI : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(MinMaxI) michael@0: LMinMaxI(const LAllocation &first, const LAllocation &second) michael@0: { michael@0: setOperand(0, first); michael@0: setOperand(1, second); michael@0: } michael@0: michael@0: const LAllocation *first() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *second() { michael@0: return this->getOperand(1); michael@0: } michael@0: const LDefinition *output() { michael@0: return this->getDef(0); michael@0: } michael@0: MMinMax *mir() const { michael@0: return mir_->toMinMax(); michael@0: } michael@0: const char *extraName() const { michael@0: return mir()->isMax() ? "Max" : "Min"; michael@0: } michael@0: }; michael@0: michael@0: class LMinMaxD : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(MinMaxD) michael@0: LMinMaxD(const LAllocation &first, const LAllocation &second) michael@0: { michael@0: setOperand(0, first); michael@0: setOperand(1, second); michael@0: } michael@0: michael@0: const LAllocation *first() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *second() { michael@0: return this->getOperand(1); michael@0: } michael@0: const LDefinition *output() { michael@0: return this->getDef(0); michael@0: } michael@0: MMinMax *mir() const { michael@0: return mir_->toMinMax(); michael@0: } michael@0: const char *extraName() const { michael@0: return mir()->isMax() ? "Max" : "Min"; michael@0: } michael@0: }; michael@0: michael@0: // Negative of an integer michael@0: class LNegI : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NegI); michael@0: LNegI(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Negative of a double. michael@0: class LNegD : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NegD) michael@0: LNegD(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Negative of a float32. michael@0: class LNegF : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(NegF) michael@0: LNegF(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Absolute value of an integer. michael@0: class LAbsI : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AbsI) michael@0: LAbsI(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Absolute value of a double. michael@0: class LAbsD : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AbsD) michael@0: LAbsD(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Absolute value of a float32. michael@0: class LAbsF : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AbsF) michael@0: LAbsF(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Square root of a double. michael@0: class LSqrtD : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SqrtD) michael@0: LSqrtD(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Square root of a float32. michael@0: class LSqrtF : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SqrtF) michael@0: LSqrtF(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: class LAtan2D : public LCallInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(Atan2D) michael@0: LAtan2D(const LAllocation &y, const LAllocation &x, const LDefinition &temp) { michael@0: setOperand(0, y); michael@0: setOperand(1, x); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *y() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *x() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *output() { michael@0: return getDef(0); michael@0: } michael@0: }; michael@0: michael@0: class LHypot : public LCallInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(Hypot) michael@0: LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp) { michael@0: setOperand(0, x); michael@0: setOperand(1, y); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *x() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *y() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: const LDefinition *output() { michael@0: return getDef(0); michael@0: } michael@0: }; michael@0: michael@0: // Double raised to an integer power. michael@0: class LPowI : public LCallInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(PowI) michael@0: LPowI(const LAllocation &value, const LAllocation &power, const LDefinition &temp) { michael@0: setOperand(0, value); michael@0: setOperand(1, power); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *value() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *power() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Double raised to a double power. michael@0: class LPowD : public LCallInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(PowD) michael@0: LPowD(const LAllocation &value, const LAllocation &power, const LDefinition &temp) { michael@0: setOperand(0, value); michael@0: setOperand(1, power); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *value() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *power() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Math.random(). michael@0: class LRandom : public LCallInstructionHelper<1, 0, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(Random) michael@0: LRandom(const LDefinition &temp, const LDefinition &temp2) { michael@0: setTemp(0, temp); michael@0: setTemp(1, temp2); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LMathFunctionD : public LCallInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(MathFunctionD) michael@0: LMathFunctionD(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MMathFunction *mir() const { michael@0: return mir_->toMathFunction(); michael@0: } michael@0: const char *extraName() const { michael@0: return MMathFunction::FunctionName(mir()->function()); michael@0: } michael@0: }; michael@0: michael@0: class LMathFunctionF : public LCallInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(MathFunctionF) michael@0: LMathFunctionF(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MMathFunction *mir() const { michael@0: return mir_->toMathFunction(); michael@0: } michael@0: const char *extraName() const { michael@0: return MMathFunction::FunctionName(mir()->function()); michael@0: } michael@0: }; michael@0: michael@0: // Adds two integers, returning an integer value. michael@0: class LAddI : public LBinaryMath<0> michael@0: { michael@0: bool recoversInput_; michael@0: michael@0: public: michael@0: LIR_HEADER(AddI) michael@0: michael@0: LAddI() michael@0: : recoversInput_(false) michael@0: { } michael@0: michael@0: const char *extraName() const { michael@0: return snapshot() ? "OverflowCheck" : nullptr; michael@0: } michael@0: michael@0: virtual bool recoversInput() const { michael@0: return recoversInput_; michael@0: } michael@0: void setRecoversInput() { michael@0: recoversInput_ = true; michael@0: } michael@0: }; michael@0: michael@0: // Subtracts two integers, returning an integer value. michael@0: class LSubI : public LBinaryMath<0> michael@0: { michael@0: bool recoversInput_; michael@0: michael@0: public: michael@0: LIR_HEADER(SubI) michael@0: michael@0: LSubI() michael@0: : recoversInput_(false) michael@0: { } michael@0: michael@0: const char *extraName() const { michael@0: return snapshot() ? "OverflowCheck" : nullptr; michael@0: } michael@0: michael@0: virtual bool recoversInput() const { michael@0: return recoversInput_; michael@0: } michael@0: void setRecoversInput() { michael@0: recoversInput_ = true; michael@0: } michael@0: }; michael@0: michael@0: // Performs an add, sub, mul, or div on two double values. michael@0: class LMathD : public LBinaryMath<0> michael@0: { michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(MathD) michael@0: michael@0: LMathD(JSOp jsop) michael@0: : jsop_(jsop) michael@0: { } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: }; michael@0: michael@0: // Performs an add, sub, mul, or div on two double values. michael@0: class LMathF: public LBinaryMath<0> michael@0: { michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(MathF) michael@0: michael@0: LMathF(JSOp jsop) michael@0: : jsop_(jsop) michael@0: { } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: }; michael@0: michael@0: class LModD : public LBinaryMath<1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ModD) michael@0: michael@0: LModD(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) { michael@0: setOperand(0, lhs); michael@0: setOperand(1, rhs); michael@0: setTemp(0, temp); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: bool isCall() const { michael@0: return true; michael@0: } michael@0: }; michael@0: michael@0: // Call a VM function to perform a binary operation. michael@0: class LBinaryV : public LCallInstructionHelper michael@0: { michael@0: JSOp jsop_; michael@0: michael@0: public: michael@0: LIR_HEADER(BinaryV) michael@0: michael@0: LBinaryV(JSOp jsop) michael@0: : jsop_(jsop) michael@0: { } michael@0: michael@0: JSOp jsop() const { michael@0: return jsop_; michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return js_CodeName[jsop_]; michael@0: } michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: }; michael@0: michael@0: // Adds two string, returning a string. michael@0: class LConcat : public LInstructionHelper<1, 2, 5> michael@0: { michael@0: public: michael@0: LIR_HEADER(Concat) michael@0: michael@0: LConcat(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, michael@0: const LDefinition &temp2, const LDefinition &temp3, const LDefinition &temp4, michael@0: const LDefinition &temp5) michael@0: { michael@0: setOperand(0, lhs); michael@0: setOperand(1, rhs); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: setTemp(3, temp4); michael@0: setTemp(4, temp5); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return this->getOperand(1); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return this->getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return this->getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return this->getTemp(2); michael@0: } michael@0: const LDefinition *temp4() { michael@0: return this->getTemp(3); michael@0: } michael@0: const LDefinition *temp5() { michael@0: return this->getTemp(4); michael@0: } michael@0: }; michael@0: michael@0: class LConcatPar : public LInstructionHelper<1, 3, 4> michael@0: { michael@0: public: michael@0: LIR_HEADER(ConcatPar) michael@0: michael@0: LConcatPar(const LAllocation &cx, const LAllocation &lhs, const LAllocation &rhs, michael@0: const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3, michael@0: const LDefinition &temp4) michael@0: { michael@0: setOperand(0, cx); michael@0: setOperand(1, lhs); michael@0: setOperand(2, rhs); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: setTemp(3, temp4); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *lhs() { michael@0: return this->getOperand(1); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return this->getOperand(2); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return this->getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return this->getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return this->getTemp(2); michael@0: } michael@0: const LDefinition *temp4() { michael@0: return this->getTemp(3); michael@0: } michael@0: }; michael@0: michael@0: // Get uint16 character code from a string. michael@0: class LCharCodeAt : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CharCodeAt) michael@0: michael@0: LCharCodeAt(const LAllocation &str, const LAllocation &index) { michael@0: setOperand(0, str); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const LAllocation *str() { michael@0: return this->getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return this->getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Convert uint16 character code to a string. michael@0: class LFromCharCode : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(FromCharCode) michael@0: michael@0: LFromCharCode(const LAllocation &code) { michael@0: setOperand(0, code); michael@0: } michael@0: michael@0: const LAllocation *code() { michael@0: return this->getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LStringSplit : public LCallInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StringSplit) michael@0: michael@0: LStringSplit(const LAllocation &string, const LAllocation &separator) { michael@0: setOperand(0, string); michael@0: setOperand(1, separator); michael@0: } michael@0: const LAllocation *string() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *separator() { michael@0: return getOperand(1); michael@0: } michael@0: const MStringSplit *mir() const { michael@0: return mir_->toStringSplit(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a 32-bit integer to a double. michael@0: class LInt32ToDouble : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Int32ToDouble) michael@0: michael@0: LInt32ToDouble(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: }; michael@0: michael@0: // Convert a 32-bit float to a double. michael@0: class LFloat32ToDouble : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Float32ToDouble) michael@0: michael@0: LFloat32ToDouble(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: }; michael@0: michael@0: // Convert a double to a 32-bit float. michael@0: class LDoubleToFloat32 : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(DoubleToFloat32) michael@0: michael@0: LDoubleToFloat32(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: }; michael@0: michael@0: // Convert a 32-bit integer to a float32. michael@0: class LInt32ToFloat32 : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Int32ToFloat32) michael@0: michael@0: LInt32ToFloat32(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: }; michael@0: michael@0: // Convert a value to a double. michael@0: class LValueToDouble : public LInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ValueToDouble) michael@0: static const size_t Input = 0; michael@0: michael@0: MToDouble *mir() { michael@0: return mir_->toToDouble(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a value to a float32. michael@0: class LValueToFloat32 : public LInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ValueToFloat32) michael@0: static const size_t Input = 0; michael@0: michael@0: MToFloat32 *mir() { michael@0: return mir_->toToFloat32(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a value to an int32. michael@0: // Input: components of a Value michael@0: // Output: 32-bit integer michael@0: // Bailout: undefined, string, object, or non-int32 double michael@0: // Temps: one float register, one GP register michael@0: // michael@0: // This instruction requires a temporary float register. michael@0: class LValueToInt32 : public LInstructionHelper<1, BOX_PIECES, 2> michael@0: { michael@0: public: michael@0: enum Mode { michael@0: NORMAL, michael@0: TRUNCATE michael@0: }; michael@0: michael@0: private: michael@0: Mode mode_; michael@0: michael@0: public: michael@0: LIR_HEADER(ValueToInt32) michael@0: michael@0: LValueToInt32(const LDefinition &temp0, const LDefinition &temp1, Mode mode) michael@0: : mode_(mode) michael@0: { michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mode() == NORMAL ? "Normal" : "Truncate"; michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: Mode mode() const { michael@0: return mode_; michael@0: } michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(1); michael@0: } michael@0: MToInt32 *mirNormal() const { michael@0: JS_ASSERT(mode_ == NORMAL); michael@0: return mir_->toToInt32(); michael@0: } michael@0: MTruncateToInt32 *mirTruncate() const { michael@0: JS_ASSERT(mode_ == TRUNCATE); michael@0: return mir_->toTruncateToInt32(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a double to an int32. michael@0: // Input: floating-point register michael@0: // Output: 32-bit integer michael@0: // Bailout: if the double cannot be converted to an integer. michael@0: class LDoubleToInt32 : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(DoubleToInt32) michael@0: michael@0: LDoubleToInt32(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: michael@0: MToInt32 *mir() const { michael@0: return mir_->toToInt32(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a float32 to an int32. michael@0: // Input: floating-point register michael@0: // Output: 32-bit integer michael@0: // Bailout: if the float32 cannot be converted to an integer. michael@0: class LFloat32ToInt32 : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Float32ToInt32) michael@0: michael@0: LFloat32ToInt32(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: michael@0: MToInt32 *mir() const { michael@0: return mir_->toToInt32(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a double to a truncated int32. michael@0: // Input: floating-point register michael@0: // Output: 32-bit integer michael@0: class LTruncateDToInt32 : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TruncateDToInt32) michael@0: michael@0: LTruncateDToInt32(const LAllocation &in, const LDefinition &temp) { michael@0: setOperand(0, in); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Convert a float32 to a truncated int32. michael@0: // Input: floating-point register michael@0: // Output: 32-bit integer michael@0: class LTruncateFToInt32 : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TruncateFToInt32) michael@0: michael@0: LTruncateFToInt32(const LAllocation &in, const LDefinition &temp) { michael@0: setOperand(0, in); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Convert a boolean value to a string. michael@0: class LBooleanToString : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BooleanToString) michael@0: michael@0: LBooleanToString(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: const MToString *mir() { michael@0: return mir_->toToString(); michael@0: } michael@0: }; michael@0: michael@0: // Convert an integer hosted on one definition to a string with a function call. michael@0: class LIntToString : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(IntToString) michael@0: michael@0: LIntToString(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: const MToString *mir() { michael@0: return mir_->toToString(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a double hosted on one definition to a string with a function call. michael@0: class LDoubleToString : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(DoubleToString) michael@0: michael@0: LDoubleToString(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *tempInt() { michael@0: return getTemp(0); michael@0: } michael@0: const MToString *mir() { michael@0: return mir_->toToString(); michael@0: } michael@0: }; michael@0: michael@0: // Convert a primitive to a string with a function call. michael@0: class LPrimitiveToString : public LInstructionHelper<1, BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(PrimitiveToString) michael@0: michael@0: LPrimitiveToString(const LDefinition &tempToUnbox) michael@0: { michael@0: setTemp(0, tempToUnbox); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const MToString *mir() { michael@0: return mir_->toToString(); michael@0: } michael@0: michael@0: const LDefinition *tempToUnbox() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // No-op instruction that is used to hold the entry snapshot. This simplifies michael@0: // register allocation as it doesn't need to sniff the snapshot out of the michael@0: // LIRGraph. michael@0: class LStart : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Start) michael@0: }; michael@0: michael@0: // Passed the BaselineFrame address in the OsrFrameReg by SideCannon(). michael@0: // Forwards this object to the LOsrValues for Value materialization. michael@0: class LOsrEntry : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: protected: michael@0: Label label_; michael@0: uint32_t frameDepth_; michael@0: michael@0: public: michael@0: LIR_HEADER(OsrEntry) michael@0: michael@0: LOsrEntry() michael@0: : frameDepth_(0) michael@0: { } michael@0: michael@0: void setFrameDepth(uint32_t depth) { michael@0: frameDepth_ = depth; michael@0: } michael@0: uint32_t getFrameDepth() { michael@0: return frameDepth_; michael@0: } michael@0: Label *label() { michael@0: return &label_; michael@0: } michael@0: michael@0: }; michael@0: michael@0: // Materialize a Value stored in an interpreter frame for OSR. michael@0: class LOsrValue : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(OsrValue) michael@0: michael@0: LOsrValue(const LAllocation &entry) michael@0: { michael@0: setOperand(0, entry); michael@0: } michael@0: michael@0: const MOsrValue *mir() { michael@0: return mir_->toOsrValue(); michael@0: } michael@0: }; michael@0: michael@0: // Materialize a JSObject scope chain stored in an interpreter frame for OSR. michael@0: class LOsrScopeChain : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(OsrScopeChain) michael@0: michael@0: LOsrScopeChain(const LAllocation &entry) michael@0: { michael@0: setOperand(0, entry); michael@0: } michael@0: michael@0: const MOsrScopeChain *mir() { michael@0: return mir_->toOsrScopeChain(); michael@0: } michael@0: }; michael@0: michael@0: // Materialize a JSObject scope chain stored in an interpreter frame for OSR. michael@0: class LOsrReturnValue : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(OsrReturnValue) michael@0: michael@0: LOsrReturnValue(const LAllocation &entry) michael@0: { michael@0: setOperand(0, entry); michael@0: } michael@0: michael@0: const MOsrReturnValue *mir() { michael@0: return mir_->toOsrReturnValue(); michael@0: } michael@0: }; michael@0: michael@0: // Materialize a JSObject ArgumentsObject stored in an interpreter frame for OSR. michael@0: class LOsrArgumentsObject : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(OsrArgumentsObject) michael@0: michael@0: LOsrArgumentsObject(const LAllocation &entry) michael@0: { michael@0: setOperand(0, entry); michael@0: } michael@0: michael@0: const MOsrArgumentsObject *mir() { michael@0: return mir_->toOsrArgumentsObject(); michael@0: } michael@0: }; michael@0: michael@0: class LRegExp : public LCallInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(RegExp) michael@0: michael@0: const MRegExp *mir() const { michael@0: return mir_->toRegExp(); michael@0: } michael@0: }; michael@0: michael@0: class LRegExpExec : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(RegExpExec) michael@0: michael@0: LRegExpExec(const LAllocation ®exp, const LAllocation &string) michael@0: { michael@0: setOperand(0, regexp); michael@0: setOperand(1, string); michael@0: } michael@0: michael@0: const LAllocation *regexp() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *string() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const MRegExpExec *mir() const { michael@0: return mir_->toRegExpExec(); michael@0: } michael@0: }; michael@0: michael@0: class LRegExpTest : public LCallInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(RegExpTest) michael@0: michael@0: LRegExpTest(const LAllocation ®exp, const LAllocation &string) michael@0: { michael@0: setOperand(0, regexp); michael@0: setOperand(1, string); michael@0: } michael@0: michael@0: const LAllocation *regexp() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *string() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const MRegExpTest *mir() const { michael@0: return mir_->toRegExpTest(); michael@0: } michael@0: }; michael@0: michael@0: michael@0: class LStrReplace : public LCallInstructionHelper<1, 3, 0> michael@0: { michael@0: public: michael@0: LStrReplace(const LAllocation &string, const LAllocation &pattern, michael@0: const LAllocation &replacement) michael@0: { michael@0: setOperand(0, string); michael@0: setOperand(1, pattern); michael@0: setOperand(2, replacement); michael@0: } michael@0: michael@0: const LAllocation *string() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *pattern() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *replacement() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: class LRegExpReplace: public LStrReplace michael@0: { michael@0: public: michael@0: LIR_HEADER(RegExpReplace); michael@0: michael@0: LRegExpReplace(const LAllocation &string, const LAllocation &pattern, michael@0: const LAllocation &replacement) michael@0: : LStrReplace(string, pattern, replacement) michael@0: { michael@0: } michael@0: michael@0: const MRegExpReplace *mir() const { michael@0: return mir_->toRegExpReplace(); michael@0: } michael@0: }; michael@0: michael@0: class LStringReplace: public LStrReplace michael@0: { michael@0: public: michael@0: LIR_HEADER(StringReplace); michael@0: michael@0: LStringReplace(const LAllocation &string, const LAllocation &pattern, michael@0: const LAllocation &replacement) michael@0: : LStrReplace(string, pattern, replacement) michael@0: { michael@0: } michael@0: michael@0: const MStringReplace *mir() const { michael@0: return mir_->toStringReplace(); michael@0: } michael@0: }; michael@0: michael@0: class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(LambdaForSingleton) michael@0: michael@0: LLambdaForSingleton(const LAllocation &scopeChain) michael@0: { michael@0: setOperand(0, scopeChain); michael@0: } michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const MLambda *mir() const { michael@0: return mir_->toLambda(); michael@0: } michael@0: }; michael@0: michael@0: class LLambda : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(Lambda) michael@0: michael@0: LLambda(const LAllocation &scopeChain, const LDefinition &temp) { michael@0: setOperand(0, scopeChain); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MLambda *mir() const { michael@0: return mir_->toLambda(); michael@0: } michael@0: }; michael@0: michael@0: class LLambdaArrow : public LInstructionHelper<1, 1 + BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(LambdaArrow) michael@0: michael@0: static const size_t ThisValue = 1; michael@0: michael@0: LLambdaArrow(const LAllocation &scopeChain, const LDefinition &temp) { michael@0: setOperand(0, scopeChain); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MLambdaArrow *mir() const { michael@0: return mir_->toLambdaArrow(); michael@0: } michael@0: }; michael@0: michael@0: class LLambdaPar : public LInstructionHelper<1, 2, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(LambdaPar); michael@0: michael@0: LLambdaPar(const LAllocation &cx, const LAllocation &scopeChain, michael@0: const LDefinition &temp1, const LDefinition &temp2) michael@0: { michael@0: setOperand(0, cx); michael@0: setOperand(1, scopeChain); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: } michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(1); michael@0: } michael@0: const MLambdaPar *mir() const { michael@0: return mir_->toLambdaPar(); michael@0: } michael@0: const LDefinition *getTemp0() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *getTemp1() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: // Determines the implicit |this| value for function calls. michael@0: class LImplicitThis : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(ImplicitThis) michael@0: michael@0: LImplicitThis(const LAllocation &callee) { michael@0: setOperand(0, callee); michael@0: } michael@0: michael@0: const MImplicitThis *mir() const { michael@0: return mir_->toImplicitThis(); michael@0: } michael@0: const LAllocation *callee() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load the "slots" member out of a JSObject. michael@0: // Input: JSObject pointer michael@0: // Output: slots pointer michael@0: class LSlots : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Slots) michael@0: michael@0: LSlots(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load the "elements" member out of a JSObject. michael@0: // Input: JSObject pointer michael@0: // Output: elements pointer michael@0: class LElements : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Elements) michael@0: michael@0: LElements(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // If necessary, convert any int32 elements in a vector into doubles. michael@0: class LConvertElementsToDoubles : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ConvertElementsToDoubles) michael@0: michael@0: LConvertElementsToDoubles(const LAllocation &elements) { michael@0: setOperand(0, elements); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // If |elements| has the CONVERT_DOUBLE_ELEMENTS flag, convert int32 value to michael@0: // double. Else return the original value. michael@0: class LMaybeToDoubleElement : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(MaybeToDoubleElement) michael@0: michael@0: LMaybeToDoubleElement(const LAllocation &elements, const LAllocation &value, michael@0: const LDefinition &tempFloat) { michael@0: setOperand(0, elements); michael@0: setOperand(1, value); michael@0: setTemp(0, tempFloat); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Load the initialized length from an elements header. michael@0: class LInitializedLength : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InitializedLength) michael@0: michael@0: LInitializedLength(const LAllocation &elements) { michael@0: setOperand(0, elements); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Store to the initialized length in an elements header. Note the input is an michael@0: // *index*, one less than the desired initialized length. michael@0: class LSetInitializedLength : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetInitializedLength) michael@0: michael@0: LSetInitializedLength(const LAllocation &elements, const LAllocation &index) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Load the length from an elements header. michael@0: class LArrayLength : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayLength) michael@0: michael@0: LArrayLength(const LAllocation &elements) { michael@0: setOperand(0, elements); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Store to the length in an elements header. Note the input is an *index*, michael@0: // one less than the desired length. michael@0: class LSetArrayLength : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetArrayLength) michael@0: michael@0: LSetArrayLength(const LAllocation &elements, const LAllocation &index) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Read the length of a typed array. michael@0: class LTypedArrayLength : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypedArrayLength) michael@0: michael@0: LTypedArrayLength(const LAllocation &obj) { michael@0: setOperand(0, obj); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed array's elements vector. michael@0: class LTypedArrayElements : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypedArrayElements) michael@0: michael@0: LTypedArrayElements(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed array's elements vector. michael@0: class LTypedObjectElements : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypedObjectElements) michael@0: michael@0: LTypedObjectElements(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const MTypedObjectElements *mir() const { michael@0: return mir_->toTypedObjectElements(); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed array's elements vector. michael@0: class LSetTypedObjectOffset : public LInstructionHelper<0, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetTypedObjectOffset) michael@0: michael@0: LSetTypedObjectOffset(const LAllocation &object, michael@0: const LAllocation &offset, michael@0: const LDefinition &temp0) michael@0: { michael@0: setOperand(0, object); michael@0: setOperand(1, offset); michael@0: setTemp(0, temp0); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *offset() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp0() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Check whether a typed object has a neutered owner buffer. michael@0: class LNeuterCheck : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(NeuterCheck) michael@0: michael@0: LNeuterCheck(const LAllocation &object, const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Bailout if index >= length. michael@0: class LBoundsCheck : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BoundsCheck) michael@0: michael@0: LBoundsCheck(const LAllocation &index, const LAllocation &length) { michael@0: setOperand(0, index); michael@0: setOperand(1, length); michael@0: } michael@0: const MBoundsCheck *mir() const { michael@0: return mir_->toBoundsCheck(); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *length() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Bailout if index + minimum < 0 or index + maximum >= length. michael@0: class LBoundsCheckRange : public LInstructionHelper<0, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(BoundsCheckRange) michael@0: michael@0: LBoundsCheckRange(const LAllocation &index, const LAllocation &length, michael@0: const LDefinition &temp) michael@0: { michael@0: setOperand(0, index); michael@0: setOperand(1, length); michael@0: setTemp(0, temp); michael@0: } michael@0: const MBoundsCheck *mir() const { michael@0: return mir_->toBoundsCheck(); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *length() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Bailout if index < minimum. michael@0: class LBoundsCheckLower : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BoundsCheckLower) michael@0: michael@0: LBoundsCheckLower(const LAllocation &index) michael@0: { michael@0: setOperand(0, index); michael@0: } michael@0: MBoundsCheckLower *mir() const { michael@0: return mir_->toBoundsCheckLower(); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load a value from a dense array's elements vector. Bail out if it's the hole value. michael@0: class LLoadElementV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadElementV) michael@0: michael@0: LLoadElementV(const LAllocation &elements, const LAllocation &index) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; michael@0: } michael@0: michael@0: const MLoadElement *mir() const { michael@0: return mir_->toLoadElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LInArray : public LInstructionHelper<1, 4, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InArray) michael@0: michael@0: LInArray(const LAllocation &elements, const LAllocation &index, michael@0: const LAllocation &initLength, const LAllocation &object) michael@0: { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: setOperand(2, initLength); michael@0: setOperand(3, object); michael@0: } michael@0: const MInArray *mir() const { michael@0: return mir_->toInArray(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *initLength() { michael@0: return getOperand(2); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(3); michael@0: } michael@0: }; michael@0: michael@0: michael@0: // Load a value from a dense array's elements vector. Bail out if it's the hole value. michael@0: class LLoadElementHole : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadElementHole) michael@0: michael@0: LLoadElementHole(const LAllocation &elements, const LAllocation &index, const LAllocation &initLength) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: setOperand(2, initLength); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; michael@0: } michael@0: michael@0: const MLoadElementHole *mir() const { michael@0: return mir_->toLoadElementHole(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *initLength() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed value from a dense array's elements vector. The array must be michael@0: // known to be packed, so that we don't have to check for the hole value. michael@0: // This instruction does not load the type tag and can directly load into a michael@0: // FP register. michael@0: class LLoadElementT : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadElementT) michael@0: michael@0: LLoadElementT(const LAllocation &elements, const LAllocation &index) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->needsHoleCheck() ? "HoleCheck" michael@0: : (mir()->loadDoubles() ? "Doubles" : nullptr); michael@0: } michael@0: michael@0: const MLoadElement *mir() const { michael@0: return mir_->toLoadElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Store a boxed value to a dense array's element vector. michael@0: class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreElementV) michael@0: michael@0: LStoreElementV(const LAllocation &elements, const LAllocation &index) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; michael@0: } michael@0: michael@0: static const size_t Value = 2; michael@0: michael@0: const MStoreElement *mir() const { michael@0: return mir_->toStoreElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Store a typed value to a dense array's elements vector. Compared to michael@0: // LStoreElementV, this instruction can store doubles and constants directly, michael@0: // and does not store the type tag if the array is monomorphic and known to michael@0: // be packed. michael@0: class LStoreElementT : public LInstructionHelper<0, 3, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreElementT) michael@0: michael@0: LStoreElementT(const LAllocation &elements, const LAllocation &index, const LAllocation &value) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: setOperand(2, value); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; michael@0: } michael@0: michael@0: const MStoreElement *mir() const { michael@0: return mir_->toStoreElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: // Like LStoreElementV, but supports indexes >= initialized length. michael@0: class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreElementHoleV) michael@0: michael@0: LStoreElementHoleV(const LAllocation &object, const LAllocation &elements, michael@0: const LAllocation &index) { michael@0: setOperand(0, object); michael@0: setOperand(1, elements); michael@0: setOperand(2, index); michael@0: } michael@0: michael@0: static const size_t Value = 3; michael@0: michael@0: const MStoreElementHole *mir() const { michael@0: return mir_->toStoreElementHole(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: // Like LStoreElementT, but supports indexes >= initialized length. michael@0: class LStoreElementHoleT : public LInstructionHelper<0, 4, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreElementHoleT) michael@0: michael@0: LStoreElementHoleT(const LAllocation &object, const LAllocation &elements, michael@0: const LAllocation &index, const LAllocation &value) { michael@0: setOperand(0, object); michael@0: setOperand(1, elements); michael@0: setOperand(2, index); michael@0: setOperand(3, value); michael@0: } michael@0: michael@0: const MStoreElementHole *mir() const { michael@0: return mir_->toStoreElementHole(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(2); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(3); michael@0: } michael@0: }; michael@0: michael@0: class LArrayPopShiftV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayPopShiftV) michael@0: michael@0: LArrayPopShiftV(const LAllocation &object, const LDefinition &temp0, const LDefinition &temp1) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift"; michael@0: } michael@0: michael@0: const MArrayPopShift *mir() const { michael@0: return mir_->toArrayPopShift(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp0() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LArrayPopShiftT : public LInstructionHelper<1, 1, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayPopShiftT) michael@0: michael@0: LArrayPopShiftT(const LAllocation &object, const LDefinition &temp0, const LDefinition &temp1) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp0); michael@0: setTemp(1, temp1); michael@0: } michael@0: michael@0: const char *extraName() const { michael@0: return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift"; michael@0: } michael@0: michael@0: const MArrayPopShift *mir() const { michael@0: return mir_->toArrayPopShift(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp0() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LArrayPushV : public LInstructionHelper<1, 1 + BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayPushV) michael@0: michael@0: LArrayPushV(const LAllocation &object, const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MArrayPush *mir() const { michael@0: return mir_->toArrayPush(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class LArrayPushT : public LInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayPushT) michael@0: michael@0: LArrayPushT(const LAllocation &object, const LAllocation &value, const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setOperand(1, value); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const MArrayPush *mir() const { michael@0: return mir_->toArrayPush(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class LArrayConcat : public LCallInstructionHelper<1, 2, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArrayConcat) michael@0: michael@0: LArrayConcat(const LAllocation &lhs, const LAllocation &rhs, michael@0: const LDefinition &temp1, const LDefinition &temp2) { michael@0: setOperand(0, lhs); michael@0: setOperand(1, rhs); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: } michael@0: const MArrayConcat *mir() const { michael@0: return mir_->toArrayConcat(); michael@0: } michael@0: const LAllocation *lhs() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed value from a typed array's elements vector. michael@0: class LLoadTypedArrayElement : public LInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadTypedArrayElement) michael@0: michael@0: LLoadTypedArrayElement(const LAllocation &elements, const LAllocation &index, michael@0: const LDefinition &temp) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: setTemp(0, temp); michael@0: } michael@0: const MLoadTypedArrayElement *mir() const { michael@0: return mir_->toLoadTypedArrayElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class LLoadTypedArrayElementHole : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadTypedArrayElementHole) michael@0: michael@0: LLoadTypedArrayElementHole(const LAllocation &object, const LAllocation &index) { michael@0: setOperand(0, object); michael@0: setOperand(1, index); michael@0: } michael@0: const MLoadTypedArrayElementHole *mir() const { michael@0: return mir_->toLoadTypedArrayElementHole(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LLoadTypedArrayElementStatic : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadTypedArrayElementStatic); michael@0: LLoadTypedArrayElementStatic(const LAllocation &ptr) { michael@0: setOperand(0, ptr); michael@0: } michael@0: MLoadTypedArrayElementStatic *mir() const { michael@0: return mir_->toLoadTypedArrayElementStatic(); michael@0: } michael@0: const LAllocation *ptr() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LStoreTypedArrayElement : public LInstructionHelper<0, 3, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreTypedArrayElement) michael@0: michael@0: LStoreTypedArrayElement(const LAllocation &elements, const LAllocation &index, michael@0: const LAllocation &value) { michael@0: setOperand(0, elements); michael@0: setOperand(1, index); michael@0: setOperand(2, value); michael@0: } michael@0: michael@0: const MStoreTypedArrayElement *mir() const { michael@0: return mir_->toStoreTypedArrayElement(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(2); michael@0: } michael@0: }; michael@0: michael@0: class LStoreTypedArrayElementHole : public LInstructionHelper<0, 4, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreTypedArrayElementHole) michael@0: michael@0: LStoreTypedArrayElementHole(const LAllocation &elements, const LAllocation &length, michael@0: const LAllocation &index, const LAllocation &value) michael@0: { michael@0: setOperand(0, elements); michael@0: setOperand(1, length); michael@0: setOperand(2, index); michael@0: setOperand(3, value); michael@0: } michael@0: michael@0: const MStoreTypedArrayElementHole *mir() const { michael@0: return mir_->toStoreTypedArrayElementHole(); michael@0: } michael@0: const LAllocation *elements() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *length() { michael@0: return getOperand(1); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(2); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(3); michael@0: } michael@0: }; michael@0: michael@0: class LStoreTypedArrayElementStatic : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreTypedArrayElementStatic); michael@0: LStoreTypedArrayElementStatic(const LAllocation &ptr, const LAllocation &value) { michael@0: setOperand(0, ptr); michael@0: setOperand(1, value); michael@0: } michael@0: MStoreTypedArrayElementStatic *mir() const { michael@0: return mir_->toStoreTypedArrayElementStatic(); michael@0: } michael@0: const LAllocation *ptr() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LEffectiveAddress : public LInstructionHelper<1, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(EffectiveAddress); michael@0: michael@0: LEffectiveAddress(const LAllocation &base, const LAllocation &index) { michael@0: setOperand(0, base); michael@0: setOperand(1, index); michael@0: } michael@0: const MEffectiveAddress *mir() const { michael@0: return mir_->toEffectiveAddress(); michael@0: } michael@0: const LAllocation *base() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LClampIToUint8 : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ClampIToUint8) michael@0: michael@0: LClampIToUint8(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: }; michael@0: michael@0: class LClampDToUint8 : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ClampDToUint8) michael@0: michael@0: LClampDToUint8(const LAllocation &in, const LDefinition &temp) { michael@0: setOperand(0, in); michael@0: setTemp(0, temp); michael@0: } michael@0: }; michael@0: michael@0: class LClampVToUint8 : public LInstructionHelper<1, BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ClampVToUint8) michael@0: michael@0: LClampVToUint8(const LDefinition &tempFloat) { michael@0: setTemp(0, tempFloat); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(0); michael@0: } michael@0: const MClampToUint8 *mir() const { michael@0: return mir_->toClampToUint8(); michael@0: } michael@0: }; michael@0: michael@0: // Load a boxed value from an object's fixed slot. michael@0: class LLoadFixedSlotV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadFixedSlotV) michael@0: michael@0: LLoadFixedSlotV(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const MLoadFixedSlot *mir() const { michael@0: return mir_->toLoadFixedSlot(); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed value from an object's fixed slot. michael@0: class LLoadFixedSlotT : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadFixedSlotT) michael@0: michael@0: LLoadFixedSlotT(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const MLoadFixedSlot *mir() const { michael@0: return mir_->toLoadFixedSlot(); michael@0: } michael@0: }; michael@0: michael@0: // Store a boxed value to an object's fixed slot. michael@0: class LStoreFixedSlotV : public LInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreFixedSlotV) michael@0: michael@0: LStoreFixedSlotV(const LAllocation &obj) { michael@0: setOperand(0, obj); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MStoreFixedSlot *mir() const { michael@0: return mir_->toStoreFixedSlot(); michael@0: } michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Store a typed value to an object's fixed slot. michael@0: class LStoreFixedSlotT : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreFixedSlotT) michael@0: michael@0: LStoreFixedSlotT(const LAllocation &obj, const LAllocation &value) michael@0: { michael@0: setOperand(0, obj); michael@0: setOperand(1, value); michael@0: } michael@0: const MStoreFixedSlot *mir() const { michael@0: return mir_->toStoreFixedSlot(); michael@0: } michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Note, Name ICs always return a Value. There are no V/T variants. michael@0: class LGetNameCache : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetNameCache) michael@0: michael@0: LGetNameCache(const LAllocation &scopeObj) { michael@0: setOperand(0, scopeObj); michael@0: } michael@0: const LAllocation *scopeObj() { michael@0: return getOperand(0); michael@0: } michael@0: const MGetNameCache *mir() const { michael@0: return mir_->toGetNameCache(); michael@0: } michael@0: }; michael@0: michael@0: class LCallGetIntrinsicValue : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallGetIntrinsicValue) michael@0: michael@0: const MCallGetIntrinsicValue *mir() const { michael@0: return mir_->toCallGetIntrinsicValue(); michael@0: } michael@0: }; michael@0: michael@0: class LCallsiteCloneCache : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallsiteCloneCache); michael@0: michael@0: LCallsiteCloneCache(const LAllocation &callee) { michael@0: setOperand(0, callee); michael@0: } michael@0: const LAllocation *callee() { michael@0: return getOperand(0); michael@0: } michael@0: const MCallsiteCloneCache *mir() const { michael@0: return mir_->toCallsiteCloneCache(); michael@0: } michael@0: }; michael@0: michael@0: // Patchable jump to stubs generated for a GetProperty cache, which loads a michael@0: // boxed value. michael@0: class LGetPropertyCacheV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetPropertyCacheV) michael@0: michael@0: LGetPropertyCacheV(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const MGetPropertyCache *mir() const { michael@0: return mir_->toGetPropertyCache(); michael@0: } michael@0: }; michael@0: michael@0: // Patchable jump to stubs generated for a GetProperty cache, which loads a michael@0: // value of a known type, possibly into an FP register. michael@0: class LGetPropertyCacheT : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(GetPropertyCacheT) michael@0: michael@0: LGetPropertyCacheT(const LAllocation &object, const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MGetPropertyCache *mir() const { michael@0: return mir_->toGetPropertyCache(); michael@0: } michael@0: }; michael@0: michael@0: // Emit code to load a boxed value from an object's slots if its shape matches michael@0: // one of the shapes observed by the baseline IC, else bails out. michael@0: class LGetPropertyPolymorphicV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetPropertyPolymorphicV) michael@0: michael@0: LGetPropertyPolymorphicV(const LAllocation &obj) { michael@0: setOperand(0, obj); michael@0: } michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: const MGetPropertyPolymorphic *mir() const { michael@0: return mir_->toGetPropertyPolymorphic(); michael@0: } michael@0: }; michael@0: michael@0: // Emit code to load a typed value from an object's slots if its shape matches michael@0: // one of the shapes observed by the baseline IC, else bails out. michael@0: class LGetPropertyPolymorphicT : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(GetPropertyPolymorphicT) michael@0: michael@0: LGetPropertyPolymorphicT(const LAllocation &obj, const LDefinition &temp) { michael@0: setOperand(0, obj); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MGetPropertyPolymorphic *mir() const { michael@0: return mir_->toGetPropertyPolymorphic(); michael@0: } michael@0: }; michael@0: michael@0: // Emit code to store a boxed value to an object's slots if its shape matches michael@0: // one of the shapes observed by the baseline IC, else bails out. michael@0: class LSetPropertyPolymorphicV : public LInstructionHelper<0, 1 + BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetPropertyPolymorphicV) michael@0: michael@0: LSetPropertyPolymorphicV(const LAllocation &obj, const LDefinition &temp) { michael@0: setOperand(0, obj); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MSetPropertyPolymorphic *mir() const { michael@0: return mir_->toSetPropertyPolymorphic(); michael@0: } michael@0: }; michael@0: michael@0: // Emit code to store a typed value to an object's slots if its shape matches michael@0: // one of the shapes observed by the baseline IC, else bails out. michael@0: class LSetPropertyPolymorphicT : public LInstructionHelper<0, 2, 1> michael@0: { michael@0: MIRType valueType_; michael@0: michael@0: public: michael@0: LIR_HEADER(SetPropertyPolymorphicT) michael@0: michael@0: LSetPropertyPolymorphicT(const LAllocation &obj, const LAllocation &value, MIRType valueType, michael@0: const LDefinition &temp) michael@0: : valueType_(valueType) michael@0: { michael@0: setOperand(0, obj); michael@0: setOperand(1, value); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *obj() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MIRType valueType() const { michael@0: return valueType_; michael@0: } michael@0: const MSetPropertyPolymorphic *mir() const { michael@0: return mir_->toSetPropertyPolymorphic(); michael@0: } michael@0: const char *extraName() const { michael@0: return StringFromMIRType(valueType_); michael@0: } michael@0: }; michael@0: michael@0: class LGetElementCacheV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetElementCacheV) michael@0: michael@0: static const size_t Index = 1; michael@0: michael@0: LGetElementCacheV(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const MGetElementCache *mir() const { michael@0: return mir_->toGetElementCache(); michael@0: } michael@0: }; michael@0: michael@0: class LGetElementCacheT : public LInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(GetElementCacheT) michael@0: michael@0: LGetElementCacheT(const LAllocation &object, const LAllocation &index, michael@0: const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setOperand(1, index); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *output() { michael@0: return getDef(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const MGetElementCache *mir() const { michael@0: return mir_->toGetElementCache(); michael@0: } michael@0: }; michael@0: michael@0: class LBindNameCache : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(BindNameCache) michael@0: michael@0: LBindNameCache(const LAllocation &scopeChain) { michael@0: setOperand(0, scopeChain); michael@0: } michael@0: const LAllocation *scopeChain() { michael@0: return getOperand(0); michael@0: } michael@0: const MBindNameCache *mir() const { michael@0: return mir_->toBindNameCache(); michael@0: } michael@0: }; michael@0: michael@0: // Load a value from an object's dslots or a slots vector. michael@0: class LLoadSlotV : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadSlotV) michael@0: michael@0: LLoadSlotV(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: const MLoadSlot *mir() const { michael@0: return mir_->toLoadSlot(); michael@0: } michael@0: }; michael@0: michael@0: // Load a typed value from an object's dslots or a slots vector. Unlike michael@0: // LLoadSlotV, this can bypass extracting a type tag, directly retrieving a michael@0: // pointer, integer, or double. michael@0: class LLoadSlotT : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(LoadSlotT) michael@0: michael@0: LLoadSlotT(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: const MLoadSlot *mir() const { michael@0: return mir_->toLoadSlot(); michael@0: } michael@0: }; michael@0: michael@0: // Store a value to an object's dslots or a slots vector. michael@0: class LStoreSlotV : public LInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreSlotV) michael@0: michael@0: LStoreSlotV(const LAllocation &slots) { michael@0: setOperand(0, slots); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MStoreSlot *mir() const { michael@0: return mir_->toStoreSlot(); michael@0: } michael@0: const LAllocation *slots() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Store a typed value to an object's dslots or a slots vector. This has a michael@0: // few advantages over LStoreSlotV: michael@0: // 1) We can bypass storing the type tag if the slot has the same type as michael@0: // the value. michael@0: // 2) Better register allocation: we can store constants and FP regs directly michael@0: // without requiring a second register for the value. michael@0: class LStoreSlotT : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StoreSlotT) michael@0: michael@0: LStoreSlotT(const LAllocation &slots, const LAllocation &value) { michael@0: setOperand(0, slots); michael@0: setOperand(1, value); michael@0: } michael@0: const MStoreSlot *mir() const { michael@0: return mir_->toStoreSlot(); michael@0: } michael@0: const LAllocation *slots() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: // Read length field of a JSString*. michael@0: class LStringLength : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(StringLength) michael@0: michael@0: LStringLength(const LAllocation &string) { michael@0: setOperand(0, string); michael@0: } michael@0: michael@0: const LAllocation *string() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Take the floor of a double precision number. Implements Math.floor(). michael@0: class LFloor : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(Floor) michael@0: michael@0: LFloor(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Take the floor of a single precision number. Implements Math.floor(). michael@0: class LFloorF : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(FloorF) michael@0: michael@0: LFloorF(const LAllocation &num) { michael@0: setOperand(0, num); michael@0: } michael@0: }; michael@0: michael@0: // Round a double precision number. Implements Math.round(). michael@0: class LRound : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(Round) michael@0: michael@0: LRound(const LAllocation &num, const LDefinition &temp) { michael@0: setOperand(0, num); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MRound *mir() const { michael@0: return mir_->toRound(); michael@0: } michael@0: }; michael@0: michael@0: // Round a single precision number. Implements Math.round(). michael@0: class LRoundF : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(RoundF) michael@0: michael@0: LRoundF(const LAllocation &num, const LDefinition &temp) { michael@0: setOperand(0, num); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MRound *mir() const { michael@0: return mir_->toRound(); michael@0: } michael@0: }; michael@0: michael@0: // Load a function's call environment. michael@0: class LFunctionEnvironment : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(FunctionEnvironment) michael@0: michael@0: LFunctionEnvironment(const LAllocation &function) { michael@0: setOperand(0, function); michael@0: } michael@0: const LAllocation *function() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LForkJoinContext : public LCallInstructionHelper<1, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ForkJoinContext); michael@0: michael@0: LForkJoinContext(const LDefinition &temp1) { michael@0: setTemp(0, temp1); michael@0: } michael@0: michael@0: const LDefinition *getTempReg() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class LForkJoinGetSlice : public LInstructionHelper<1, 1, 4> michael@0: { michael@0: public: michael@0: LIR_HEADER(ForkJoinGetSlice); michael@0: michael@0: LForkJoinGetSlice(const LAllocation &cx, michael@0: const LDefinition &temp1, const LDefinition &temp2, michael@0: const LDefinition &temp3, const LDefinition &temp4) { michael@0: setOperand(0, cx); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: setTemp(3, temp4); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: const LDefinition *temp4() { michael@0: return getTemp(3); michael@0: } michael@0: }; michael@0: michael@0: class LCallGetProperty : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallGetProperty) michael@0: michael@0: static const size_t Value = 0; michael@0: michael@0: MCallGetProperty *mir() const { michael@0: return mir_->toCallGetProperty(); michael@0: } michael@0: }; michael@0: michael@0: // Call js::GetElement. michael@0: class LCallGetElement : public LCallInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(CallGetElement) michael@0: michael@0: static const size_t LhsInput = 0; michael@0: static const size_t RhsInput = BOX_PIECES; michael@0: michael@0: MCallGetElement *mir() const { michael@0: return mir_->toCallGetElement(); michael@0: } michael@0: }; michael@0: michael@0: // Call js::SetElement. michael@0: class LCallSetElement : public LCallInstructionHelper<0, 1 + 2 * BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallSetElement) michael@0: michael@0: static const size_t Index = 1; michael@0: static const size_t Value = 1 + BOX_PIECES; michael@0: }; michael@0: michael@0: // Call js::InitElementArray. michael@0: class LCallInitElementArray : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallInitElementArray) michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MCallInitElementArray *mir() const { michael@0: return mir_->toCallInitElementArray(); michael@0: } michael@0: }; michael@0: michael@0: // Call a VM function to perform a property or name assignment of a generic value. michael@0: class LCallSetProperty : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallSetProperty) michael@0: michael@0: LCallSetProperty(const LAllocation &obj) { michael@0: setOperand(0, obj); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MCallSetProperty *mir() const { michael@0: return mir_->toCallSetProperty(); michael@0: } michael@0: }; michael@0: michael@0: class LCallDeleteProperty : public LCallInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallDeleteProperty) michael@0: michael@0: static const size_t Value = 0; michael@0: michael@0: MDeleteProperty *mir() const { michael@0: return mir_->toDeleteProperty(); michael@0: } michael@0: }; michael@0: michael@0: class LCallDeleteElement : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallDeleteElement) michael@0: michael@0: static const size_t Value = 0; michael@0: static const size_t Index = BOX_PIECES; michael@0: michael@0: MDeleteElement *mir() const { michael@0: return mir_->toDeleteElement(); michael@0: } michael@0: }; michael@0: michael@0: // Patchable jump to stubs generated for a SetProperty cache, which stores a michael@0: // boxed value. michael@0: class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 2> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetPropertyCacheV) michael@0: michael@0: LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots, michael@0: const LDefinition &temp) { michael@0: setOperand(0, object); michael@0: setTemp(0, slots); michael@0: setTemp(1, temp); michael@0: } michael@0: michael@0: static const size_t Value = 1; michael@0: michael@0: const MSetPropertyCache *mir() const { michael@0: return mir_->toSetPropertyCache(); michael@0: } michael@0: michael@0: const LDefinition *tempForDispatchCache() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: // Patchable jump to stubs generated for a SetProperty cache, which stores a michael@0: // value of a known type. michael@0: class LSetPropertyCacheT : public LInstructionHelper<0, 2, 2> michael@0: { michael@0: MIRType valueType_; michael@0: michael@0: public: michael@0: LIR_HEADER(SetPropertyCacheT) michael@0: michael@0: LSetPropertyCacheT(const LAllocation &object, const LDefinition &slots, michael@0: const LAllocation &value, const LDefinition &temp, michael@0: MIRType valueType) michael@0: : valueType_(valueType) michael@0: { michael@0: setOperand(0, object); michael@0: setOperand(1, value); michael@0: setTemp(0, slots); michael@0: setTemp(1, temp); michael@0: } michael@0: michael@0: const MSetPropertyCache *mir() const { michael@0: return mir_->toSetPropertyCache(); michael@0: } michael@0: MIRType valueType() { michael@0: return valueType_; michael@0: } michael@0: const char *extraName() const { michael@0: return StringFromMIRType(valueType_); michael@0: } michael@0: michael@0: const LDefinition *tempForDispatchCache() { michael@0: return getTemp(1); michael@0: } michael@0: }; michael@0: michael@0: class LSetElementCacheV : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetElementCacheV); michael@0: michael@0: static const size_t Index = 1; michael@0: static const size_t Value = 1 + BOX_PIECES; michael@0: michael@0: LSetElementCacheV(const LAllocation &object, const LDefinition &tempToUnboxIndex, michael@0: const LDefinition &temp, const LDefinition &tempFloat) michael@0: { michael@0: setOperand(0, object); michael@0: setTemp(0, tempToUnboxIndex); michael@0: setTemp(1, temp); michael@0: setTemp(2, tempFloat); michael@0: } michael@0: const MSetElementCache *mir() const { michael@0: return mir_->toSetElementCache(); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *tempToUnboxIndex() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: class LSetElementCacheT : public LInstructionHelper<0, 2 + BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetElementCacheT); michael@0: michael@0: static const size_t Index = 2; michael@0: michael@0: LSetElementCacheT(const LAllocation &object, const LAllocation &value, michael@0: const LDefinition &tempToUnboxIndex, michael@0: const LDefinition &temp, const LDefinition &tempFloat) { michael@0: setOperand(0, object); michael@0: setOperand(1, value); michael@0: setTemp(0, tempToUnboxIndex); michael@0: setTemp(1, temp); michael@0: setTemp(2, tempFloat); michael@0: } michael@0: const MSetElementCache *mir() const { michael@0: return mir_->toSetElementCache(); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *tempToUnboxIndex() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *tempFloat() { michael@0: return getTemp(2); michael@0: } michael@0: }; michael@0: michael@0: class LCallIteratorStart : public LCallInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallIteratorStart) michael@0: michael@0: LCallIteratorStart(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: MIteratorStart *mir() const { michael@0: return mir_->toIteratorStart(); michael@0: } michael@0: }; michael@0: michael@0: class LIteratorStart : public LInstructionHelper<1, 1, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(IteratorStart) michael@0: michael@0: LIteratorStart(const LAllocation &object, const LDefinition &temp1, michael@0: const LDefinition &temp2, const LDefinition &temp3) { michael@0: setOperand(0, object); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: MIteratorStart *mir() const { michael@0: return mir_->toIteratorStart(); michael@0: } michael@0: }; michael@0: michael@0: class LIteratorNext : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(IteratorNext) michael@0: michael@0: LIteratorNext(const LAllocation &iterator, const LDefinition &temp) { michael@0: setOperand(0, iterator); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MIteratorNext *mir() const { michael@0: return mir_->toIteratorNext(); michael@0: } michael@0: }; michael@0: michael@0: class LIteratorMore : public LInstructionHelper<1, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(IteratorMore) michael@0: michael@0: LIteratorMore(const LAllocation &iterator, const LDefinition &temp) { michael@0: setOperand(0, iterator); michael@0: setTemp(0, temp); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: MIteratorMore *mir() const { michael@0: return mir_->toIteratorMore(); michael@0: } michael@0: }; michael@0: michael@0: class LIteratorEnd : public LInstructionHelper<0, 1, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(IteratorEnd) michael@0: michael@0: LIteratorEnd(const LAllocation &iterator, const LDefinition &temp1, michael@0: const LDefinition &temp2, const LDefinition &temp3) { michael@0: setOperand(0, iterator); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp1() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *temp2() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *temp3() { michael@0: return getTemp(2); michael@0: } michael@0: MIteratorEnd *mir() const { michael@0: return mir_->toIteratorEnd(); michael@0: } michael@0: }; michael@0: michael@0: // Read the number of actual arguments. michael@0: class LArgumentsLength : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(ArgumentsLength) michael@0: }; michael@0: michael@0: // Load a value from the actual arguments. michael@0: class LGetFrameArgument : public LInstructionHelper michael@0: { michael@0: public: michael@0: LIR_HEADER(GetFrameArgument) michael@0: michael@0: LGetFrameArgument(const LAllocation &index) { michael@0: setOperand(0, index); michael@0: } michael@0: const LAllocation *index() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load a value from the actual arguments. michael@0: class LSetFrameArgumentT : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetFrameArgumentT) michael@0: michael@0: LSetFrameArgumentT(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: MSetFrameArgument *mir() const { michael@0: return mir_->toSetFrameArgument(); michael@0: } michael@0: const LAllocation *input() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: // Load a value from the actual arguments. michael@0: class LSetFrameArgumentC : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: Value val_; michael@0: michael@0: public: michael@0: LIR_HEADER(SetFrameArgumentC) michael@0: michael@0: LSetFrameArgumentC(const Value &val) { michael@0: val_ = val; michael@0: } michael@0: MSetFrameArgument *mir() const { michael@0: return mir_->toSetFrameArgument(); michael@0: } michael@0: const Value &val() const { michael@0: return val_; michael@0: } michael@0: }; michael@0: michael@0: // Load a value from the actual arguments. michael@0: class LSetFrameArgumentV : public LInstructionHelper<0, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(SetFrameArgumentV) michael@0: michael@0: LSetFrameArgumentV() {} michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: MSetFrameArgument *mir() const { michael@0: return mir_->toSetFrameArgument(); michael@0: } michael@0: }; michael@0: michael@0: class LRunOncePrologue : public LCallInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(RunOncePrologue) michael@0: michael@0: MRunOncePrologue *mir() const { michael@0: return mir_->toRunOncePrologue(); michael@0: } michael@0: }; michael@0: michael@0: // Create the rest parameter. michael@0: class LRest : public LCallInstructionHelper<1, 1, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(Rest) michael@0: michael@0: LRest(const LAllocation &numActuals, const LDefinition &temp1, const LDefinition &temp2, michael@0: const LDefinition &temp3) michael@0: { michael@0: setOperand(0, numActuals); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: const LAllocation *numActuals() { michael@0: return getOperand(0); michael@0: } michael@0: MRest *mir() const { michael@0: return mir_->toRest(); michael@0: } michael@0: }; michael@0: michael@0: class LRestPar : public LCallInstructionHelper<1, 2, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(RestPar); michael@0: michael@0: LRestPar(const LAllocation &cx, const LAllocation &numActuals, michael@0: const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) michael@0: { michael@0: setOperand(0, cx); michael@0: setOperand(1, numActuals); michael@0: setTemp(0, temp1); michael@0: setTemp(1, temp2); michael@0: setTemp(2, temp3); michael@0: } michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *numActuals() { michael@0: return getOperand(1); michael@0: } michael@0: MRestPar *mir() const { michael@0: return mir_->toRestPar(); michael@0: } michael@0: }; michael@0: michael@0: class LGuardThreadExclusive : public LCallInstructionHelper<0, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(GuardThreadExclusive); michael@0: michael@0: LGuardThreadExclusive(const LAllocation &cx, const LAllocation &object, const LDefinition &temp1) { michael@0: setOperand(0, cx); michael@0: setOperand(1, object); michael@0: setTemp(0, temp1); michael@0: } michael@0: michael@0: const LAllocation *forkJoinContext() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(1); michael@0: } michael@0: michael@0: const LDefinition *getTempReg() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Guard that a value is in a TypeSet. michael@0: class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypeBarrierV) michael@0: michael@0: LTypeBarrierV(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const MTypeBarrier *mir() const { michael@0: return mir_->toTypeBarrier(); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Guard that a object is in a TypeSet. michael@0: class LTypeBarrierO : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(TypeBarrierO) michael@0: michael@0: LTypeBarrierO(const LAllocation &obj, const LDefinition &temp) { michael@0: setOperand(0, obj); michael@0: setTemp(0, temp); michael@0: } michael@0: const MTypeBarrier *mir() const { michael@0: return mir_->toTypeBarrier(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Guard that a value is in a TypeSet. michael@0: class LMonitorTypes : public LInstructionHelper<0, BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(MonitorTypes) michael@0: michael@0: LMonitorTypes(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const MMonitorTypes *mir() const { michael@0: return mir_->toMonitorTypes(); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Generational write barrier used when writing an object to another object. michael@0: class LPostWriteBarrierO : public LInstructionHelper<0, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(PostWriteBarrierO) michael@0: michael@0: LPostWriteBarrierO(const LAllocation &obj, const LAllocation &value, michael@0: const LDefinition &temp) { michael@0: setOperand(0, obj); michael@0: setOperand(1, value); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const MPostWriteBarrier *mir() const { michael@0: return mir_->toPostWriteBarrier(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Generational write barrier used when writing a value to another object. michael@0: class LPostWriteBarrierV : public LInstructionHelper<0, 1 + BOX_PIECES, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(PostWriteBarrierV) michael@0: michael@0: LPostWriteBarrierV(const LAllocation &obj, const LDefinition &temp) { michael@0: setOperand(0, obj); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: static const size_t Input = 1; michael@0: michael@0: const MPostWriteBarrier *mir() const { michael@0: return mir_->toPostWriteBarrier(); michael@0: } michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: // Guard against an object's identity. michael@0: class LGuardObjectIdentity : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(GuardObjectIdentity) michael@0: michael@0: LGuardObjectIdentity(const LAllocation &in) { michael@0: setOperand(0, in); michael@0: } michael@0: const MGuardObjectIdentity *mir() const { michael@0: return mir_->toGuardObjectIdentity(); michael@0: } michael@0: }; michael@0: michael@0: // Guard against an object's class. michael@0: class LGuardClass : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(GuardClass) michael@0: michael@0: LGuardClass(const LAllocation &in, const LDefinition &temp) { michael@0: setOperand(0, in); michael@0: setTemp(0, temp); michael@0: } michael@0: const MGuardClass *mir() const { michael@0: return mir_->toGuardClass(); michael@0: } michael@0: const LDefinition *tempInt() { michael@0: return getTemp(0); michael@0: } michael@0: }; michael@0: michael@0: class MPhi; michael@0: michael@0: // Phi is a pseudo-instruction that emits no code, and is an annotation for the michael@0: // register allocator. Like its equivalent in MIR, phis are collected at the michael@0: // top of blocks and are meant to be executed in parallel, choosing the input michael@0: // corresponding to the predecessor taken in the control flow graph. michael@0: class LPhi MOZ_FINAL : public LInstruction michael@0: { michael@0: LAllocation *inputs_; michael@0: LDefinition def_; michael@0: michael@0: LPhi() michael@0: { } michael@0: michael@0: public: michael@0: LIR_HEADER(Phi) michael@0: michael@0: static LPhi *New(MIRGenerator *gen, MPhi *phi); michael@0: michael@0: size_t numDefs() const { michael@0: return 1; michael@0: } michael@0: LDefinition *getDef(size_t index) { michael@0: JS_ASSERT(index == 0); michael@0: return &def_; michael@0: } michael@0: void setDef(size_t index, const LDefinition &def) { michael@0: JS_ASSERT(index == 0); michael@0: def_ = def; michael@0: } michael@0: size_t numOperands() const { michael@0: return mir_->toPhi()->numOperands(); michael@0: } michael@0: LAllocation *getOperand(size_t index) { michael@0: JS_ASSERT(index < numOperands()); michael@0: return &inputs_[index]; michael@0: } michael@0: void setOperand(size_t index, const LAllocation &a) { michael@0: JS_ASSERT(index < numOperands()); michael@0: inputs_[index] = a; michael@0: } michael@0: size_t numTemps() const { michael@0: return 0; michael@0: } michael@0: LDefinition *getTemp(size_t index) { michael@0: MOZ_ASSUME_UNREACHABLE("no temps"); michael@0: } michael@0: void setTemp(size_t index, const LDefinition &temp) { michael@0: MOZ_ASSUME_UNREACHABLE("no temps"); michael@0: } michael@0: size_t numSuccessors() const { michael@0: return 0; michael@0: } michael@0: MBasicBlock *getSuccessor(size_t i) const { michael@0: MOZ_ASSUME_UNREACHABLE("no successors"); michael@0: } michael@0: void setSuccessor(size_t i, MBasicBlock *) { michael@0: MOZ_ASSUME_UNREACHABLE("no successors"); michael@0: } michael@0: michael@0: virtual void printInfo(FILE *fp) { michael@0: printOperands(fp); michael@0: } michael@0: }; michael@0: michael@0: class LIn : public LCallInstructionHelper<1, BOX_PIECES+1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(In) michael@0: LIn(const LAllocation &rhs) { michael@0: setOperand(RHS, rhs); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return getOperand(LHS); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return getOperand(RHS); michael@0: } michael@0: michael@0: static const size_t LHS = 0; michael@0: static const size_t RHS = BOX_PIECES; michael@0: }; michael@0: michael@0: class LInstanceOfO : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InstanceOfO) michael@0: LInstanceOfO(const LAllocation &lhs) { michael@0: setOperand(0, lhs); michael@0: } michael@0: michael@0: MInstanceOf *mir() const { michael@0: return mir_->toInstanceOf(); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LInstanceOfV : public LInstructionHelper<1, BOX_PIECES, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(InstanceOfV) michael@0: LInstanceOfV() { michael@0: } michael@0: michael@0: MInstanceOf *mir() const { michael@0: return mir_->toInstanceOf(); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return getOperand(LHS); michael@0: } michael@0: michael@0: static const size_t LHS = 0; michael@0: }; michael@0: michael@0: class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(CallInstanceOf) michael@0: LCallInstanceOf(const LAllocation &rhs) { michael@0: setOperand(RHS, rhs); michael@0: } michael@0: michael@0: const LDefinition *output() { michael@0: return this->getDef(0); michael@0: } michael@0: const LAllocation *lhs() { michael@0: return getOperand(LHS); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return getOperand(RHS); michael@0: } michael@0: michael@0: static const size_t LHS = 0; michael@0: static const size_t RHS = BOX_PIECES; michael@0: }; michael@0: michael@0: class LProfilerStackOp : public LInstructionHelper<0, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(ProfilerStackOp) michael@0: michael@0: LProfilerStackOp(const LDefinition &temp) { michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: JSScript *script() { michael@0: return mir_->toProfilerStackOp()->script(); michael@0: } michael@0: michael@0: MProfilerStackOp::Type type() { michael@0: return mir_->toProfilerStackOp()->type(); michael@0: } michael@0: michael@0: unsigned inlineLevel() { michael@0: return mir_->toProfilerStackOp()->inlineLevel(); michael@0: } michael@0: }; michael@0: michael@0: class LIsCallable : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(IsCallable); michael@0: LIsCallable(const LAllocation &object) { michael@0: setOperand(0, object); michael@0: } michael@0: michael@0: const LAllocation *object() { michael@0: return getOperand(0); michael@0: } michael@0: MIsCallable *mir() const { michael@0: return mir_->toIsCallable(); michael@0: } michael@0: }; michael@0: michael@0: class LHaveSameClass : public LInstructionHelper<1, 2, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(HaveSameClass); michael@0: LHaveSameClass(const LAllocation &left, const LAllocation &right, michael@0: const LDefinition &temp) { michael@0: setOperand(0, left); michael@0: setOperand(1, right); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *rhs() { michael@0: return getOperand(1); michael@0: } michael@0: MHaveSameClass *mir() const { michael@0: return mir_->toHaveSameClass(); michael@0: } michael@0: }; michael@0: michael@0: class LHasClass : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(HasClass); michael@0: LHasClass(const LAllocation &lhs) { michael@0: setOperand(0, lhs); michael@0: } michael@0: michael@0: const LAllocation *lhs() { michael@0: return getOperand(0); michael@0: } michael@0: MHasClass *mir() const { michael@0: return mir_->toHasClass(); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSLoadHeap : public LInstructionHelper<1, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSLoadHeap); michael@0: LAsmJSLoadHeap(const LAllocation &ptr) { michael@0: setOperand(0, ptr); michael@0: } michael@0: MAsmJSLoadHeap *mir() const { michael@0: return mir_->toAsmJSLoadHeap(); michael@0: } michael@0: const LAllocation *ptr() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSStoreHeap : public LInstructionHelper<0, 2, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSStoreHeap); michael@0: LAsmJSStoreHeap(const LAllocation &ptr, const LAllocation &value) { michael@0: setOperand(0, ptr); michael@0: setOperand(1, value); michael@0: } michael@0: MAsmJSStoreHeap *mir() const { michael@0: return mir_->toAsmJSStoreHeap(); michael@0: } michael@0: const LAllocation *ptr() { michael@0: return getOperand(0); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(1); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSLoadGlobalVar : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSLoadGlobalVar); michael@0: MAsmJSLoadGlobalVar *mir() const { michael@0: return mir_->toAsmJSLoadGlobalVar(); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSStoreGlobalVar : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSStoreGlobalVar); michael@0: LAsmJSStoreGlobalVar(const LAllocation &value) { michael@0: setOperand(0, value); michael@0: } michael@0: MAsmJSStoreGlobalVar *mir() const { michael@0: return mir_->toAsmJSStoreGlobalVar(); michael@0: } michael@0: const LAllocation *value() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSLoadFFIFunc : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSLoadFFIFunc); michael@0: MAsmJSLoadFFIFunc *mir() const { michael@0: return mir_->toAsmJSLoadFFIFunc(); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSParameter : public LInstructionHelper<1, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSParameter); michael@0: }; michael@0: michael@0: class LAsmJSReturn : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSReturn); michael@0: }; michael@0: michael@0: class LAsmJSVoidReturn : public LInstructionHelper<0, 0, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSVoidReturn); michael@0: }; michael@0: michael@0: class LAsmJSPassStackArg : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AsmJSPassStackArg); michael@0: LAsmJSPassStackArg(const LAllocation &arg) { michael@0: setOperand(0, arg); michael@0: } michael@0: MAsmJSPassStackArg *mir() const { michael@0: return mirRaw()->toAsmJSPassStackArg(); michael@0: } michael@0: const LAllocation *arg() { michael@0: return getOperand(0); michael@0: } michael@0: }; michael@0: michael@0: class LAsmJSCall MOZ_FINAL : public LInstruction michael@0: { michael@0: LAllocation *operands_; michael@0: uint32_t numOperands_; michael@0: LDefinition def_; michael@0: michael@0: public: michael@0: LIR_HEADER(AsmJSCall); michael@0: michael@0: LAsmJSCall(LAllocation *operands, uint32_t numOperands) michael@0: : operands_(operands), michael@0: numOperands_(numOperands), michael@0: def_(LDefinition::BogusTemp()) michael@0: {} michael@0: michael@0: MAsmJSCall *mir() const { michael@0: return mir_->toAsmJSCall(); michael@0: } michael@0: michael@0: bool isCall() const { michael@0: return true; michael@0: } michael@0: michael@0: // LInstruction interface michael@0: size_t numDefs() const { michael@0: return def_.isBogusTemp() ? 0 : 1; michael@0: } michael@0: LDefinition *getDef(size_t index) { michael@0: JS_ASSERT(numDefs() == 1); michael@0: JS_ASSERT(index == 0); michael@0: return &def_; michael@0: } michael@0: void setDef(size_t index, const LDefinition &def) { michael@0: JS_ASSERT(index == 0); michael@0: def_ = def; michael@0: } michael@0: size_t numOperands() const { michael@0: return numOperands_; michael@0: } michael@0: LAllocation *getOperand(size_t index) { michael@0: JS_ASSERT(index < numOperands_); michael@0: return &operands_[index]; michael@0: } michael@0: void setOperand(size_t index, const LAllocation &a) { michael@0: JS_ASSERT(index < numOperands_); michael@0: operands_[index] = a; michael@0: } michael@0: size_t numTemps() const { michael@0: return 0; michael@0: } michael@0: LDefinition *getTemp(size_t index) { michael@0: MOZ_ASSUME_UNREACHABLE("no temps"); michael@0: } michael@0: void setTemp(size_t index, const LDefinition &a) { michael@0: MOZ_ASSUME_UNREACHABLE("no temps"); michael@0: } michael@0: size_t numSuccessors() const { michael@0: return 0; michael@0: } michael@0: MBasicBlock *getSuccessor(size_t i) const { michael@0: MOZ_ASSUME_UNREACHABLE("no successors"); michael@0: } michael@0: void setSuccessor(size_t i, MBasicBlock *) { michael@0: MOZ_ASSUME_UNREACHABLE("no successors"); michael@0: } michael@0: }; michael@0: michael@0: class LAssertRangeI : public LInstructionHelper<0, 1, 0> michael@0: { michael@0: public: michael@0: LIR_HEADER(AssertRangeI) michael@0: michael@0: LAssertRangeI(const LAllocation &input) { michael@0: setOperand(0, input); michael@0: } michael@0: michael@0: const LAllocation *input() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: MAssertRange *mir() { michael@0: return mir_->toAssertRange(); michael@0: } michael@0: const Range *range() { michael@0: return mir()->assertedRange(); michael@0: } michael@0: }; michael@0: michael@0: class LAssertRangeD : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(AssertRangeD) michael@0: michael@0: LAssertRangeD(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *input() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MAssertRange *mir() { michael@0: return mir_->toAssertRange(); michael@0: } michael@0: const Range *range() { michael@0: return mir()->assertedRange(); michael@0: } michael@0: }; michael@0: michael@0: class LAssertRangeF : public LInstructionHelper<0, 1, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(AssertRangeF) michael@0: michael@0: LAssertRangeF(const LAllocation &input, const LDefinition &temp) { michael@0: setOperand(0, input); michael@0: setTemp(0, temp); michael@0: } michael@0: michael@0: const LAllocation *input() { michael@0: return getOperand(0); michael@0: } michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: michael@0: MAssertRange *mir() { michael@0: return mir_->toAssertRange(); michael@0: } michael@0: const Range *range() { michael@0: return mir()->assertedRange(); michael@0: } michael@0: }; michael@0: michael@0: class LAssertRangeV : public LInstructionHelper<0, BOX_PIECES, 3> michael@0: { michael@0: public: michael@0: LIR_HEADER(AssertRangeV) michael@0: michael@0: LAssertRangeV(const LDefinition &temp, const LDefinition &floatTemp1, michael@0: const LDefinition &floatTemp2) michael@0: { michael@0: setTemp(0, temp); michael@0: setTemp(1, floatTemp1); michael@0: setTemp(2, floatTemp2); michael@0: } michael@0: michael@0: static const size_t Input = 0; michael@0: michael@0: const LDefinition *temp() { michael@0: return getTemp(0); michael@0: } michael@0: const LDefinition *floatTemp1() { michael@0: return getTemp(1); michael@0: } michael@0: const LDefinition *floatTemp2() { michael@0: return getTemp(2); michael@0: } michael@0: michael@0: MAssertRange *mir() { michael@0: return mir_->toAssertRange(); michael@0: } michael@0: const Range *range() { michael@0: return mir()->assertedRange(); michael@0: } michael@0: }; michael@0: michael@0: class LRecompileCheck : public LInstructionHelper<0, 0, 1> michael@0: { michael@0: public: michael@0: LIR_HEADER(RecompileCheck) michael@0: michael@0: LRecompileCheck(const LDefinition &scratch) { michael@0: setTemp(0, scratch); michael@0: } michael@0: michael@0: const LDefinition *scratch() { michael@0: return getTemp(0); michael@0: } michael@0: MRecompileCheck *mir() { michael@0: return mir_->toRecompileCheck(); michael@0: } michael@0: }; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_LIR_Common_h */