| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jit_LIR_Common_h |
| #define jit_LIR_Common_h |
| |
| #include "jit/shared/Assembler-shared.h" |
| |
| // This file declares LIR instructions that are common to every platform. |
| |
| namespace js { |
| namespace jit { |
| |
| template <size_t Temps, size_t ExtraUses = 0> |
| class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps> |
| { |
| public: |
| const LAllocation *lhs() { |
| return this->getOperand(0); |
| } |
| const LAllocation *rhs() { |
| return this->getOperand(1); |
| } |
| }; |
| |
| // Used for jumps from other blocks. Also simplifies register allocation since |
| // the first instruction of a block is guaranteed to have no uses. |
| class LLabel : public LInstructionHelper<0, 0, 0> |
| { |
| Label label_; |
| |
| public: |
| LIR_HEADER(Label) |
| |
| Label *label() { |
| return &label_; |
| } |
| }; |
| |
| class LNop : public LInstructionHelper<0, 0, 0> |
| { |
| public: |
| LIR_HEADER(Nop) |
| }; |
| |
| class LMop : public LInstructionHelper<0, 0, 0> |
| { |
| public: |
| LIR_HEADER(Mop) |
| }; |
| |
| // An LOsiPoint captures a snapshot after a call and ensures enough space to |
| // patch in a call to the invalidation mechanism. |
| // |
| // Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the |
| // corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it |
| // gets CG'd. |
| class LOsiPoint : public LInstructionHelper<0, 0, 0> |
| { |
| LSafepoint *safepoint_; |
| |
| public: |
| LOsiPoint(LSafepoint *safepoint, LSnapshot *snapshot) |
| : safepoint_(safepoint) |
| { |
| JS_ASSERT(safepoint && snapshot); |
| assignSnapshot(snapshot); |
| } |
| |
| LSafepoint *associatedSafepoint() { |
| return safepoint_; |
| } |
| |
| LIR_HEADER(OsiPoint) |
| }; |
| |
| class LMove |
| { |
| LAllocation *from_; |
| LAllocation *to_; |
| |
| public: |
| LMove(LAllocation *from, LAllocation *to) |
| : from_(from), |
| to_(to) |
| { } |
| |
| LAllocation *from() { |
| return from_; |
| } |
| const LAllocation *from() const { |
| return from_; |
| } |
| LAllocation *to() { |
| return to_; |
| } |
| const LAllocation *to() const { |
| return to_; |
| } |
| }; |
| |
| class LMoveGroup : public LInstructionHelper<0, 0, 0> |
| { |
| js::Vector<LMove, 2, IonAllocPolicy> moves_; |
| |
| public: |
| LIR_HEADER(MoveGroup) |
| |
| void printOperands(FILE *fp); |
| |
| // Add a move which takes place simultaneously with all others in the group. |
| bool add(LAllocation *from, LAllocation *to); |
| |
| // Add a move which takes place after existing moves in the group. |
| bool addAfter(LAllocation *from, LAllocation *to); |
| |
| size_t numMoves() const { |
| return moves_.length(); |
| } |
| const LMove &getMove(size_t i) const { |
| return moves_[i]; |
| } |
| }; |
| |
| // Constant 32-bit integer. |
| class LInteger : public LInstructionHelper<1, 0, 0> |
| { |
| int32_t i32_; |
| |
| public: |
| LIR_HEADER(Integer) |
| |
| LInteger(int32_t i32) |
| : i32_(i32) |
| { } |
| |
| int32_t getValue() const { |
| return i32_; |
| } |
| }; |
| |
| // Constant pointer. |
| class LPointer : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| enum Kind { |
| GC_THING, |
| NON_GC_THING |
| }; |
| |
| private: |
| void *ptr_; |
| Kind kind_; |
| |
| public: |
| LIR_HEADER(Pointer) |
| |
| LPointer(gc::Cell *ptr) |
| : ptr_(ptr), kind_(GC_THING) |
| { } |
| |
| LPointer(void *ptr, Kind kind) |
| : ptr_(ptr), kind_(kind) |
| { } |
| |
| void *ptr() const { |
| return ptr_; |
| } |
| Kind kind() const { |
| return kind_; |
| } |
| |
| gc::Cell *gcptr() const { |
| JS_ASSERT(kind() == GC_THING); |
| return (gc::Cell *) ptr_; |
| } |
| }; |
| |
| // Constant double. |
| class LDouble : public LInstructionHelper<1, 0, 0> |
| { |
| double d_; |
| public: |
| LIR_HEADER(Double); |
| |
| LDouble(double d) : d_(d) |
| { } |
| double getDouble() const { |
| return d_; |
| } |
| }; |
| |
| // A constant Value. |
| class LValue : public LInstructionHelper<BOX_PIECES, 0, 0> |
| { |
| Value v_; |
| |
| public: |
| LIR_HEADER(Value) |
| |
| LValue(const Value &v) |
| : v_(v) |
| { } |
| |
| Value value() const { |
| return v_; |
| } |
| }; |
| |
| // Formal argument for a function, returning a box. Formal arguments are |
| // initially read from the stack. |
| class LParameter : public LInstructionHelper<BOX_PIECES, 0, 0> |
| { |
| public: |
| LIR_HEADER(Parameter) |
| }; |
| |
| // Stack offset for a word-sized immutable input value to a frame. |
| class LCallee : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(Callee) |
| }; |
| |
| // Base class for control instructions (goto, branch, etc.) |
| template <size_t Succs, size_t Operands, size_t Temps> |
| class LControlInstructionHelper : public LInstructionHelper<0, Operands, Temps> { |
| |
| MBasicBlock *successors_[Succs]; |
| |
| public: |
| size_t numSuccessors() const { return Succs; } |
| |
| MBasicBlock *getSuccessor(size_t i) const { return successors_[i]; } |
| |
| void setSuccessor(size_t i, MBasicBlock *successor) { |
| successors_[i] = successor; |
| } |
| }; |
| |
| // Jumps to the start of a basic block. |
| class LGoto : public LControlInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(Goto) |
| |
| LGoto(MBasicBlock *block) |
| { |
| setSuccessor(0, block); |
| } |
| |
| MBasicBlock *target() const { |
| return getSuccessor(0); |
| } |
| }; |
| |
| class LNewSlots : public LCallInstructionHelper<1, 0, 3> |
| { |
| public: |
| LIR_HEADER(NewSlots) |
| |
| LNewSlots(const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) { |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| setTemp(2, temp3); |
| } |
| |
| const LDefinition *temp1() { |
| return getTemp(0); |
| } |
| const LDefinition *temp2() { |
| return getTemp(1); |
| } |
| const LDefinition *temp3() { |
| return getTemp(2); |
| } |
| |
| MNewSlots *mir() const { |
| return mir_->toNewSlots(); |
| } |
| }; |
| |
| class LNewParallelArray : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(NewParallelArray); |
| |
| MNewParallelArray *mir() const { |
| return mir_->toNewParallelArray(); |
| } |
| }; |
| |
| class LNewArray : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(NewArray) |
| |
| const char *extraName() const { |
| return mir()->shouldUseVM() ? "VMCall" : NULL; |
| } |
| |
| MNewArray *mir() const { |
| return mir_->toNewArray(); |
| } |
| }; |
| |
| class LNewObject : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(NewObject) |
| |
| const char *extraName() const { |
| return mir()->shouldUseVM() ? "VMCall" : NULL; |
| } |
| |
| MNewObject *mir() const { |
| return mir_->toNewObject(); |
| } |
| }; |
| |
| class LParNew : public LInstructionHelper<1, 1, 2> |
| { |
| public: |
| LIR_HEADER(ParNew); |
| |
| LParNew(const LAllocation &parSlice, |
| const LDefinition &temp1, |
| const LDefinition &temp2) |
| { |
| setOperand(0, parSlice); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| } |
| |
| MParNew *mir() const { |
| return mir_->toParNew(); |
| } |
| |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| |
| const LAllocation *getTemp0() { |
| return getTemp(0)->output(); |
| } |
| |
| const LAllocation *getTemp1() { |
| return getTemp(1)->output(); |
| } |
| }; |
| |
| class LParNewDenseArray : public LCallInstructionHelper<1, 2, 3> |
| { |
| public: |
| LIR_HEADER(ParNewDenseArray); |
| |
| LParNewDenseArray(const LAllocation &parSlice, |
| const LAllocation &length, |
| const LDefinition &temp1, |
| const LDefinition &temp2, |
| const LDefinition &temp3) { |
| setOperand(0, parSlice); |
| setOperand(1, length); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| setTemp(2, temp3); |
| } |
| |
| MParNewDenseArray *mir() const { |
| return mir_->toParNewDenseArray(); |
| } |
| |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| |
| const LAllocation *length() { |
| return getOperand(1); |
| } |
| |
| const LAllocation *getTemp0() { |
| return getTemp(0)->output(); |
| } |
| |
| const LAllocation *getTemp1() { |
| return getTemp(1)->output(); |
| } |
| |
| const LAllocation *getTemp2() { |
| return getTemp(2)->output(); |
| } |
| }; |
| |
| // Allocates a new DeclEnvObject. |
| // |
| // This instruction generates two possible instruction sets: |
| // (1) An inline allocation of the call object is attempted. |
| // (2) Otherwise, a callVM create a new object. |
| // |
| class LNewDeclEnvObject : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(NewDeclEnvObject); |
| |
| MNewDeclEnvObject *mir() const { |
| return mir_->toNewDeclEnvObject(); |
| } |
| }; |
| |
| // Allocates a new CallObject. The inputs are: |
| // slots: either a reg representing a HeapSlot *, or a placeholder |
| // meaning that no slots pointer is needed. |
| // |
| // This instruction generates two possible instruction sets: |
| // (1) If the call object is extensible, this is a callVM to create the |
| // call object. |
| // (2) Otherwise, an inline allocation of the call object is attempted. |
| // |
| class LNewCallObject : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NewCallObject) |
| |
| LNewCallObject(const LAllocation &slots) { |
| setOperand(0, slots); |
| } |
| |
| const LAllocation *slots() { |
| return getOperand(0); |
| } |
| MNewCallObject *mir() const { |
| return mir_->toNewCallObject(); |
| } |
| }; |
| |
| class LParNewCallObject : public LInstructionHelper<1, 2, 2> |
| { |
| LParNewCallObject(const LAllocation &parSlice, |
| const LAllocation &slots, |
| const LDefinition &temp1, |
| const LDefinition &temp2) { |
| setOperand(0, parSlice); |
| setOperand(1, slots); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| } |
| |
| public: |
| LIR_HEADER(ParNewCallObject); |
| |
| static LParNewCallObject *NewWithSlots(const LAllocation &parSlice, |
| const LAllocation &slots, |
| const LDefinition &temp1, |
| const LDefinition &temp2) { |
| return new LParNewCallObject(parSlice, slots, temp1, temp2); |
| } |
| |
| static LParNewCallObject *NewSansSlots(const LAllocation &parSlice, |
| const LDefinition &temp1, |
| const LDefinition &temp2) { |
| LAllocation slots = LConstantIndex::Bogus(); |
| return new LParNewCallObject(parSlice, slots, temp1, temp2); |
| } |
| |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| |
| const LAllocation *slots() { |
| return getOperand(1); |
| } |
| |
| const bool hasDynamicSlots() { |
| // TO INVESTIGATE: Felix tried using isRegister() method here, |
| // but for useFixed(_, CallTempN), isRegister() is false (and |
| // isUse() is true). So for now ignore that and try to match |
| // the LConstantIndex::Bogus() generated above instead. |
| return slots() && ! slots()->isConstant(); |
| } |
| |
| const MParNewCallObject *mir() const { |
| return mir_->toParNewCallObject(); |
| } |
| |
| const LAllocation *getTemp0() { |
| return getTemp(0)->output(); |
| } |
| |
| const LAllocation *getTemp1() { |
| return getTemp(1)->output(); |
| } |
| }; |
| |
| class LNewStringObject : public LInstructionHelper<1, 1, 1> |
| { |
| public: |
| LIR_HEADER(NewStringObject) |
| |
| LNewStringObject(const LAllocation &input, const LDefinition &temp) { |
| setOperand(0, input); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *input() { |
| return getOperand(0); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| MNewStringObject *mir() const { |
| return mir_->toNewStringObject(); |
| } |
| }; |
| |
| class LParBailout : public LInstructionHelper<0, 0, 0> |
| { |
| public: |
| LIR_HEADER(ParBailout); |
| }; |
| |
| class LInitElem : public LCallInstructionHelper<0, 1 + 2*BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(InitElem) |
| |
| LInitElem(const LAllocation &object) { |
| setOperand(0, object); |
| } |
| |
| static const size_t IdIndex = 1; |
| static const size_t ValueIndex = 1 + BOX_PIECES; |
| |
| const LAllocation *getObject() { |
| return getOperand(0); |
| } |
| MInitElem *mir() const { |
| return mir_->toInitElem(); |
| } |
| }; |
| |
| // Takes in an Object and a Value. |
| class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(InitProp) |
| |
| LInitProp(const LAllocation &object) { |
| setOperand(0, object); |
| } |
| |
| static const size_t ValueIndex = 1; |
| |
| const LAllocation *getObject() { |
| return getOperand(0); |
| } |
| const LAllocation *getValue() { |
| return getOperand(1); |
| } |
| |
| MInitProp *mir() const { |
| return mir_->toInitProp(); |
| } |
| }; |
| |
| class LCheckOverRecursed : public LInstructionHelper<0, 0, 0> |
| { |
| public: |
| LIR_HEADER(CheckOverRecursed) |
| |
| LCheckOverRecursed() |
| { } |
| }; |
| |
| class LParCheckOverRecursed : public LInstructionHelper<0, 1, 1> |
| { |
| public: |
| LIR_HEADER(ParCheckOverRecursed); |
| |
| LParCheckOverRecursed(const LAllocation &parSlice, |
| const LDefinition &tempReg) |
| { |
| setOperand(0, parSlice); |
| setTemp(0, tempReg); |
| } |
| |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| |
| const LDefinition *getTempReg() { |
| return getTemp(0); |
| } |
| }; |
| |
| class LParCheckInterrupt : public LInstructionHelper<0, 1, 1> |
| { |
| public: |
| LIR_HEADER(ParCheckInterrupt); |
| |
| LParCheckInterrupt(const LAllocation &parSlice, |
| const LDefinition &tempReg) |
| { |
| setOperand(0, parSlice); |
| setTemp(0, tempReg); |
| } |
| |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| |
| const LDefinition *getTempReg() { |
| return getTemp(0); |
| } |
| }; |
| |
| class LDefVar : public LCallInstructionHelper<0, 1, 0> |
| { |
| public: |
| LIR_HEADER(DefVar) |
| |
| LDefVar(const LAllocation &scopeChain) |
| { |
| setOperand(0, scopeChain); |
| } |
| |
| const LAllocation *scopeChain() { |
| return getOperand(0); |
| } |
| MDefVar *mir() const { |
| return mir_->toDefVar(); |
| } |
| }; |
| |
| class LDefFun : public LCallInstructionHelper<0, 1, 0> |
| { |
| public: |
| LIR_HEADER(DefFun) |
| |
| LDefFun(const LAllocation &scopeChain) |
| { |
| setOperand(0, scopeChain); |
| } |
| |
| const LAllocation *scopeChain() { |
| return getOperand(0); |
| } |
| MDefFun *mir() const { |
| return mir_->toDefFun(); |
| } |
| }; |
| |
| class LTypeOfV : public LInstructionHelper<1, BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(TypeOfV) |
| |
| static const size_t Input = 0; |
| |
| MTypeOf *mir() const { |
| return mir_->toTypeOf(); |
| } |
| }; |
| |
| class LToIdV : public LInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 1> |
| { |
| public: |
| LIR_HEADER(ToIdV) |
| BOX_OUTPUT_ACCESSORS() |
| |
| LToIdV(const LDefinition &temp) |
| { |
| setTemp(0, temp); |
| } |
| |
| static const size_t Object = 0; |
| static const size_t Index = BOX_PIECES; |
| |
| MToId *mir() const { |
| return mir_->toToId(); |
| } |
| |
| const LDefinition *tempFloat() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Allocate an object for |new| on the caller-side, |
| // when there is no templateObject or prototype known |
| class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0> |
| { |
| public: |
| LIR_HEADER(CreateThis) |
| |
| LCreateThis(const LAllocation &callee) |
| { |
| setOperand(0, callee); |
| } |
| |
| const LAllocation *getCallee() { |
| return getOperand(0); |
| } |
| |
| MCreateThis *mir() const { |
| return mir_->toCreateThis(); |
| } |
| }; |
| |
| // Allocate an object for |new| on the caller-side, |
| // when the prototype is known. |
| class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(CreateThisWithProto) |
| |
| LCreateThisWithProto(const LAllocation &callee, const LAllocation &prototype) |
| { |
| setOperand(0, callee); |
| setOperand(1, prototype); |
| } |
| |
| const LAllocation *getCallee() { |
| return getOperand(0); |
| } |
| const LAllocation *getPrototype() { |
| return getOperand(1); |
| } |
| |
| MCreateThis *mir() const { |
| return mir_->toCreateThis(); |
| } |
| }; |
| |
| // Allocate an object for |new| on the caller-side. |
| // Always performs object initialization with a fast path. |
| class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(CreateThisWithTemplate) |
| |
| LCreateThisWithTemplate() |
| { } |
| |
| MCreateThisWithTemplate *mir() const { |
| return mir_->toCreateThisWithTemplate(); |
| } |
| }; |
| |
| // Allocate a new arguments object for the frame. |
| class LCreateArgumentsObject : public LCallInstructionHelper<1, 1, 1> |
| { |
| public: |
| LIR_HEADER(CreateArgumentsObject) |
| |
| LCreateArgumentsObject(const LAllocation &callObj, const LDefinition &temp) |
| { |
| setOperand(0, callObj); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *getCallObject() { |
| return getOperand(0); |
| } |
| |
| MCreateArgumentsObject *mir() const { |
| return mir_->toCreateArgumentsObject(); |
| } |
| }; |
| |
| // Get argument from arguments object. |
| class LGetArgumentsObjectArg : public LInstructionHelper<BOX_PIECES, 1, 1> |
| { |
| public: |
| LIR_HEADER(GetArgumentsObjectArg) |
| |
| LGetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp) |
| { |
| setOperand(0, argsObj); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *getArgsObject() { |
| return getOperand(0); |
| } |
| |
| MGetArgumentsObjectArg *mir() const { |
| return mir_->toGetArgumentsObjectArg(); |
| } |
| }; |
| |
| // Set argument on arguments object. |
| class LSetArgumentsObjectArg : public LInstructionHelper<0, 1 + BOX_PIECES, 1> |
| { |
| public: |
| LIR_HEADER(SetArgumentsObjectArg) |
| |
| LSetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp) |
| { |
| setOperand(0, argsObj); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *getArgsObject() { |
| return getOperand(0); |
| } |
| |
| MSetArgumentsObjectArg *mir() const { |
| return mir_->toSetArgumentsObjectArg(); |
| } |
| |
| static const size_t ValueIndex = 1; |
| }; |
| |
| // If the Value is an Object, return unbox(Value). |
| // Otherwise, return the other Object. |
| class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0> |
| { |
| public: |
| LIR_HEADER(ReturnFromCtor) |
| |
| LReturnFromCtor(const LAllocation &object) |
| { |
| // Value set by useBox() during lowering. |
| setOperand(LReturnFromCtor::ObjectIndex, object); |
| } |
| |
| const LAllocation *getObject() { |
| return getOperand(LReturnFromCtor::ObjectIndex); |
| } |
| |
| static const size_t ValueIndex = 0; |
| static const size_t ObjectIndex = BOX_PIECES; |
| }; |
| |
| // Writes a typed argument for a function call to the frame's argument vector. |
| class LStackArgT : public LInstructionHelper<0, 1, 0> |
| { |
| uint32_t argslot_; // Index into frame-scope argument vector. |
| |
| public: |
| LIR_HEADER(StackArgT) |
| |
| LStackArgT(uint32_t argslot, const LAllocation &arg) |
| : argslot_(argslot) |
| { |
| setOperand(0, arg); |
| } |
| |
| MPassArg *mir() const { |
| return this->mir_->toPassArg(); |
| } |
| uint32_t argslot() const { |
| return argslot_; |
| } |
| const LAllocation *getArgument() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Writes an untyped argument for a function call to the frame's argument vector. |
| class LStackArgV : public LInstructionHelper<0, BOX_PIECES, 0> |
| { |
| uint32_t argslot_; // Index into frame-scope argument vector. |
| |
| public: |
| LIR_HEADER(StackArgV) |
| |
| LStackArgV(uint32_t argslot) |
| : argslot_(argslot) |
| { } |
| |
| uint32_t argslot() const { |
| return argslot_; |
| } |
| }; |
| |
| // Common code for LIR descended from MCall. |
| template <size_t Defs, size_t Operands, size_t Temps> |
| class LJSCallInstructionHelper : public LCallInstructionHelper<Defs, Operands, Temps> |
| { |
| // Slot below which %esp should be adjusted to make the call. |
| // Zero for a function without arguments. |
| uint32_t argslot_; |
| |
| public: |
| LJSCallInstructionHelper(uint32_t argslot) |
| : argslot_(argslot) |
| { } |
| |
| uint32_t argslot() const { |
| return argslot_; |
| } |
| MCall *mir() const { |
| return this->mir_->toCall(); |
| } |
| |
| bool hasSingleTarget() const { |
| return getSingleTarget() != NULL; |
| } |
| JSFunction *getSingleTarget() const { |
| return mir()->getSingleTarget(); |
| } |
| |
| // The number of stack arguments is the max between the number of formal |
| // arguments and the number of actual arguments. The number of stack |
| // argument includes the |undefined| padding added in case of underflow. |
| // Does not include |this|. |
| uint32_t numStackArgs() const { |
| JS_ASSERT(mir()->numStackArgs() >= 1); |
| return mir()->numStackArgs() - 1; // |this| is not a formal argument. |
| } |
| // Does not include |this|. |
| uint32_t numActualArgs() const { |
| return mir()->numActualArgs(); |
| } |
| |
| typedef LJSCallInstructionHelper<Defs, Operands, Temps> JSCallHelper; |
| }; |
| |
| // Generates a polymorphic callsite, wherein the function being called is |
| // unknown and anticipated to vary. |
| class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2> |
| { |
| public: |
| LIR_HEADER(CallGeneric) |
| |
| LCallGeneric(const LAllocation &func, uint32_t argslot, |
| const LDefinition &nargsreg, const LDefinition &tmpobjreg) |
| : JSCallHelper(argslot) |
| { |
| setOperand(0, func); |
| setTemp(0, nargsreg); |
| setTemp(1, tmpobjreg); |
| } |
| |
| const LAllocation *getFunction() { |
| return getOperand(0); |
| } |
| const LAllocation *getNargsReg() { |
| return getTemp(0)->output(); |
| } |
| const LAllocation *getTempObject() { |
| return getTemp(1)->output(); |
| } |
| }; |
| |
| // Generates a hardcoded callsite for a known, non-native target. |
| class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1> |
| { |
| public: |
| LIR_HEADER(CallKnown) |
| |
| LCallKnown(const LAllocation &func, uint32_t argslot, const LDefinition &tmpobjreg) |
| : JSCallHelper(argslot) |
| { |
| setOperand(0, func); |
| setTemp(0, tmpobjreg); |
| } |
| |
| const LAllocation *getFunction() { |
| return getOperand(0); |
| } |
| const LAllocation *getTempObject() { |
| return getTemp(0)->output(); |
| } |
| }; |
| |
| // Generates a hardcoded callsite for a known, native target. |
| class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> |
| { |
| public: |
| LIR_HEADER(CallNative) |
| |
| LCallNative(uint32_t argslot, |
| const LDefinition &argJSContext, const LDefinition &argUintN, |
| const LDefinition &argVp, const LDefinition &tmpreg) |
| : JSCallHelper(argslot) |
| { |
| // Registers used for callWithABI(). |
| setTemp(0, argJSContext); |
| setTemp(1, argUintN); |
| setTemp(2, argVp); |
| |
| // Temporary registers. |
| setTemp(3, tmpreg); |
| } |
| |
| const LAllocation *getArgJSContextReg() { |
| return getTemp(0)->output(); |
| } |
| const LAllocation *getArgUintNReg() { |
| return getTemp(1)->output(); |
| } |
| const LAllocation *getArgVpReg() { |
| return getTemp(2)->output(); |
| } |
| const LAllocation *getTempReg() { |
| return getTemp(3)->output(); |
| } |
| }; |
| |
| // Generates a hardcoded callsite for a known, DOM-native target. |
| class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> |
| { |
| public: |
| LIR_HEADER(CallDOMNative) |
| |
| LCallDOMNative(uint32_t argslot, |
| const LDefinition &argJSContext, const LDefinition &argObj, |
| const LDefinition &argPrivate, const LDefinition &argArgs) |
| : JSCallHelper(argslot) |
| { |
| setTemp(0, argJSContext); |
| setTemp(1, argObj); |
| setTemp(2, argPrivate); |
| setTemp(3, argArgs); |
| } |
| |
| const LAllocation *getArgJSContext() { |
| return getTemp(0)->output(); |
| } |
| const LAllocation *getArgObj() { |
| return getTemp(1)->output(); |
| } |
| const LAllocation *getArgPrivate() { |
| return getTemp(2)->output(); |
| } |
| const LAllocation *getArgArgs() { |
| return getTemp(3)->output(); |
| } |
| }; |
| |
| template <size_t defs, size_t ops> |
| class LDOMPropertyInstructionHelper : public LCallInstructionHelper<defs, 1 + ops, 3> |
| { |
| protected: |
| LDOMPropertyInstructionHelper(const LDefinition &JSContextReg, const LAllocation &ObjectReg, |
| const LDefinition &PrivReg, const LDefinition &ValueReg) |
| { |
| this->setOperand(0, ObjectReg); |
| this->setTemp(0, JSContextReg); |
| this->setTemp(1, PrivReg); |
| this->setTemp(2, ValueReg); |
| } |
| |
| public: |
| const LAllocation *getJSContextReg() { |
| return this->getTemp(0)->output(); |
| } |
| const LAllocation *getObjectReg() { |
| return this->getOperand(0); |
| } |
| const LAllocation *getPrivReg() { |
| return this->getTemp(1)->output(); |
| } |
| const LAllocation *getValueReg() { |
| return this->getTemp(2)->output(); |
| } |
| }; |
| |
| |
| class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(GetDOMProperty) |
| |
| LGetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg, |
| const LDefinition &PrivReg, const LDefinition &ValueReg) |
| : LDOMPropertyInstructionHelper<BOX_PIECES, 0>(JSContextReg, ObjectReg, |
| PrivReg, ValueReg) |
| { } |
| |
| MGetDOMProperty *mir() const { |
| return mir_->toGetDOMProperty(); |
| } |
| }; |
| |
| class LSetDOMProperty : public LDOMPropertyInstructionHelper<0, BOX_PIECES> |
| { |
| public: |
| LIR_HEADER(SetDOMProperty) |
| |
| LSetDOMProperty(const LDefinition &JSContextReg, const LAllocation &ObjectReg, |
| const LDefinition &PrivReg, const LDefinition &ValueReg) |
| : LDOMPropertyInstructionHelper<0, BOX_PIECES>(JSContextReg, ObjectReg, |
| PrivReg, ValueReg) |
| { } |
| |
| static const size_t Value = 1; |
| |
| MSetDOMProperty *mir() const { |
| return mir_->toSetDOMProperty(); |
| } |
| }; |
| |
| // Generates a polymorphic callsite, wherein the function being called is |
| // unknown and anticipated to vary. |
| class LApplyArgsGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> |
| { |
| public: |
| LIR_HEADER(ApplyArgsGeneric) |
| |
| LApplyArgsGeneric(const LAllocation &func, const LAllocation &argc, |
| const LDefinition &tmpobjreg, const LDefinition &tmpcopy) |
| { |
| setOperand(0, func); |
| setOperand(1, argc); |
| setTemp(0, tmpobjreg); |
| setTemp(1, tmpcopy); |
| } |
| |
| MApplyArgs *mir() const { |
| return mir_->toApplyArgs(); |
| } |
| |
| bool hasSingleTarget() const { |
| return getSingleTarget() != NULL; |
| } |
| JSFunction *getSingleTarget() const { |
| return mir()->getSingleTarget(); |
| } |
| |
| const LAllocation *getFunction() { |
| return getOperand(0); |
| } |
| const LAllocation *getArgc() { |
| return getOperand(1); |
| } |
| static const size_t ThisIndex = 2; |
| |
| const LAllocation *getTempObject() { |
| return getTemp(0)->output(); |
| } |
| const LAllocation *getTempCopy() { |
| return getTemp(1)->output(); |
| } |
| }; |
| |
| class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3> |
| { |
| public: |
| LIR_HEADER(GetDynamicName) |
| |
| LGetDynamicName(const LAllocation &scopeChain, const LAllocation &name, |
| const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) |
| { |
| setOperand(0, scopeChain); |
| setOperand(1, name); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| setTemp(2, temp3); |
| } |
| |
| MGetDynamicName *mir() const { |
| return mir_->toGetDynamicName(); |
| } |
| |
| const LAllocation *getScopeChain() { |
| return getOperand(0); |
| } |
| const LAllocation *getName() { |
| return getOperand(1); |
| } |
| |
| const LDefinition *temp1() { |
| return getTemp(0); |
| } |
| const LDefinition *temp2() { |
| return getTemp(1); |
| } |
| const LDefinition *temp3() { |
| return getTemp(2); |
| } |
| }; |
| |
| class LFilterArguments : public LCallInstructionHelper<0, 1, 2> |
| { |
| public: |
| LIR_HEADER(FilterArguments) |
| |
| LFilterArguments(const LAllocation &string, const LDefinition &temp1, const LDefinition &temp2) |
| { |
| setOperand(0, string); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| } |
| |
| MFilterArguments *mir() const { |
| return mir_->toFilterArguments(); |
| } |
| |
| const LAllocation *getString() { |
| return getOperand(0); |
| } |
| const LDefinition *temp1() { |
| return getTemp(0); |
| } |
| const LDefinition *temp2() { |
| return getTemp(1); |
| } |
| }; |
| |
| class LCallDirectEval : public LCallInstructionHelper<BOX_PIECES, 2 + BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(CallDirectEval) |
| |
| LCallDirectEval(const LAllocation &scopeChain, const LAllocation &string) |
| { |
| setOperand(0, scopeChain); |
| setOperand(1, string); |
| } |
| |
| static const size_t ThisValueInput = 2; |
| |
| MCallDirectEval *mir() const { |
| return mir_->toCallDirectEval(); |
| } |
| |
| const LAllocation *getScopeChain() { |
| return getOperand(0); |
| } |
| const LAllocation *getString() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Takes in either an integer or boolean input and tests it for truthiness. |
| class LTestIAndBranch : public LControlInstructionHelper<2, 1, 0> |
| { |
| public: |
| LIR_HEADER(TestIAndBranch) |
| |
| LTestIAndBranch(const LAllocation &in, MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| setOperand(0, in); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| }; |
| |
| // Takes in either an integer or boolean input and tests it for truthiness. |
| class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0> |
| { |
| public: |
| LIR_HEADER(TestDAndBranch) |
| |
| LTestDAndBranch(const LAllocation &in, MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| setOperand(0, in); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| }; |
| |
| // Takes an object and tests it for truthiness. An object is falsy iff it |
| // emulates |undefined|; see js::EmulatesUndefined. |
| class LTestOAndBranch : public LControlInstructionHelper<2, 1, 1> |
| { |
| public: |
| LIR_HEADER(TestOAndBranch) |
| |
| LTestOAndBranch(const LAllocation &input, MBasicBlock *ifTruthy, MBasicBlock *ifFalsy, |
| const LDefinition &temp) |
| { |
| setOperand(0, input); |
| setSuccessor(0, ifTruthy); |
| setSuccessor(1, ifFalsy); |
| setTemp(0, temp); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| |
| Label *ifTruthy() { |
| return getSuccessor(0)->lir()->label(); |
| } |
| Label *ifFalsy() { |
| return getSuccessor(1)->lir()->label(); |
| } |
| |
| MTest *mir() { |
| return mir_->toTest(); |
| } |
| }; |
| |
| // Takes in a boxed value and tests it for truthiness. |
| class LTestVAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 3> |
| { |
| public: |
| LIR_HEADER(TestVAndBranch) |
| |
| LTestVAndBranch(MBasicBlock *ifTruthy, MBasicBlock *ifFalsy, const LDefinition &temp0, |
| const LDefinition &temp1, const LDefinition &temp2) |
| { |
| setSuccessor(0, ifTruthy); |
| setSuccessor(1, ifFalsy); |
| setTemp(0, temp0); |
| setTemp(1, temp1); |
| setTemp(2, temp2); |
| } |
| |
| const char *extraName() const { |
| return mir()->operandMightEmulateUndefined() ? "MightEmulateUndefined" : NULL; |
| } |
| |
| static const size_t Input = 0; |
| |
| const LAllocation *tempFloat() { |
| return getTemp(0)->output(); |
| } |
| |
| const LDefinition *temp1() { |
| return getTemp(1); |
| } |
| |
| const LDefinition *temp2() { |
| return getTemp(2); |
| } |
| |
| Label *ifTruthy() { |
| return getSuccessor(0)->lir()->label(); |
| } |
| Label *ifFalsy() { |
| return getSuccessor(1)->lir()->label(); |
| } |
| |
| MTest *mir() const { |
| return mir_->toTest(); |
| } |
| }; |
| |
| // Dispatches control flow to a successor based on incoming JSFunction*. |
| // Used to implemenent polymorphic inlining. |
| class LFunctionDispatch : public LInstructionHelper<0, 1, 0> |
| { |
| // Dispatch is performed based on a function -> block map |
| // stored in the MIR. |
| |
| public: |
| LIR_HEADER(FunctionDispatch); |
| |
| LFunctionDispatch(const LAllocation &in) { |
| setOperand(0, in); |
| } |
| |
| MFunctionDispatch *mir() { |
| return mir_->toFunctionDispatch(); |
| } |
| }; |
| |
| class LTypeObjectDispatch : public LInstructionHelper<0, 1, 1> |
| { |
| // Dispatch is performed based on a TypeObject -> block |
| // map inferred by the MIR. |
| |
| public: |
| LIR_HEADER(TypeObjectDispatch); |
| |
| LTypeObjectDispatch(const LAllocation &in, const LDefinition &temp) { |
| setOperand(0, in); |
| setTemp(0, temp); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| |
| MTypeObjectDispatch *mir() { |
| return mir_->toTypeObjectDispatch(); |
| } |
| }; |
| |
| class LPolyInlineDispatch : public LInstructionHelper<0, 1, 1> |
| { |
| // Accesses function/block table from MIR instruction. |
| public: |
| LIR_HEADER(PolyInlineDispatch) |
| |
| LPolyInlineDispatch(const LAllocation &in, const LDefinition &temp) { |
| setOperand(0, in); |
| setTemp(0, temp); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| |
| MPolyInlineDispatch *mir() { |
| return mir_->toPolyInlineDispatch(); |
| } |
| }; |
| |
| // Compares two integral values of the same JS type, either integer or object. |
| // For objects, both operands are in registers. |
| class LCompare : public LInstructionHelper<1, 2, 0> |
| { |
| JSOp jsop_; |
| |
| public: |
| LIR_HEADER(Compare) |
| LCompare(JSOp jsop, const LAllocation &left, const LAllocation &right) |
| : jsop_(jsop) |
| { |
| setOperand(0, left); |
| setOperand(1, right); |
| } |
| |
| JSOp jsop() const { |
| return jsop_; |
| } |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| // Compares two integral values of the same JS type, either integer or object. |
| // For objects, both operands are in registers. |
| class LCompareAndBranch : public LControlInstructionHelper<2, 2, 0> |
| { |
| JSOp jsop_; |
| |
| public: |
| LIR_HEADER(CompareAndBranch) |
| LCompareAndBranch(JSOp jsop, const LAllocation &left, const LAllocation &right, |
| MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| : jsop_(jsop) |
| { |
| setOperand(0, left); |
| setOperand(1, right); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| JSOp jsop() const { |
| return jsop_; |
| } |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LCompareD : public LInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(CompareD) |
| LCompareD(const LAllocation &left, const LAllocation &right) { |
| setOperand(0, left); |
| setOperand(1, right); |
| } |
| |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| #if defined(JS_CPU_MIPS) |
| class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> |
| { |
| MCompare *cmpMir_; |
| |
| public: |
| LIR_HEADER(CompareDAndBranch) |
| LCompareDAndBranch(MCompare *cmpMir, const LAllocation &left, const LAllocation &right, |
| MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| : cmpMir_(cmpMir) |
| { |
| setOperand(0, left); |
| setOperand(1, right); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| MTest *mir() const { |
| return mir_->toTest(); |
| } |
| MCompare *cmpMir() const { |
| return cmpMir_; |
| } |
| }; |
| #else // defined(JS_CPU_MIPS) |
| class LCompareDAndBranch : public LControlInstructionHelper<2, 2, 0> |
| { |
| public: |
| LIR_HEADER(CompareDAndBranch) |
| LCompareDAndBranch(const LAllocation &left, const LAllocation &right, |
| MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| setOperand(0, left); |
| setOperand(1, right); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| #endif // defined(JS_CPU_MIPS) |
| |
| class LCompareS : public LInstructionHelper<1, 2, 1> |
| { |
| public: |
| LIR_HEADER(CompareS) |
| LCompareS(const LAllocation &left, const LAllocation &right, |
| const LDefinition &temp) { |
| setOperand(0, left); |
| setOperand(1, right); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *left() { |
| return getOperand(0); |
| } |
| const LAllocation *right() { |
| return getOperand(1); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| // strict-equality between value and string. |
| class LCompareStrictS : public LInstructionHelper<1, BOX_PIECES + 1, 2> |
| { |
| public: |
| LIR_HEADER(CompareStrictS) |
| LCompareStrictS(const LAllocation &rhs, const LDefinition &temp0, |
| const LDefinition &temp1) { |
| setOperand(BOX_PIECES, rhs); |
| setTemp(0, temp0); |
| setTemp(1, temp1); |
| } |
| |
| static const size_t Lhs = 0; |
| |
| const LAllocation *right() { |
| return getOperand(BOX_PIECES); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| const LDefinition *tempToUnbox() { |
| return getTemp(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| // Used for strict-equality comparisons where one side is a boolean |
| // and the other is a value. Note that CompareI is used to compare |
| // two booleans. |
| class LCompareB : public LInstructionHelper<1, BOX_PIECES + 1, 0> |
| { |
| public: |
| LIR_HEADER(CompareB) |
| |
| LCompareB(const LAllocation &rhs) { |
| setOperand(BOX_PIECES, rhs); |
| } |
| |
| static const size_t Lhs = 0; |
| |
| const LAllocation *rhs() { |
| return getOperand(BOX_PIECES); |
| } |
| |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LCompareBAndBranch : public LControlInstructionHelper<2, BOX_PIECES + 1, 0> |
| { |
| public: |
| LIR_HEADER(CompareBAndBranch) |
| |
| LCompareBAndBranch(const LAllocation &rhs, MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| setOperand(BOX_PIECES, rhs); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| static const size_t Lhs = 0; |
| |
| const LAllocation *rhs() { |
| return getOperand(BOX_PIECES); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LCompareV : public LInstructionHelper<1, 2 * BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(CompareV) |
| |
| static const size_t LhsInput = 0; |
| static const size_t RhsInput = BOX_PIECES; |
| |
| MCompare *mir() const { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LCompareVAndBranch : public LControlInstructionHelper<2, 2 * BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(CompareVAndBranch) |
| |
| static const size_t LhsInput = 0; |
| static const size_t RhsInput = BOX_PIECES; |
| |
| LCompareVAndBranch(MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LCompareVM : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(CompareVM) |
| |
| static const size_t LhsInput = 0; |
| static const size_t RhsInput = BOX_PIECES; |
| |
| MCompare *mir() const { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LIsNullOrLikeUndefined : public LInstructionHelper<1, BOX_PIECES, 2> |
| { |
| public: |
| LIR_HEADER(IsNullOrLikeUndefined) |
| |
| LIsNullOrLikeUndefined(const LDefinition &temp, const LDefinition &tempToUnbox) |
| { |
| setTemp(0, temp); |
| setTemp(1, tempToUnbox); |
| } |
| |
| static const size_t Value = 0; |
| |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| |
| const LDefinition *tempToUnbox() { |
| return getTemp(1); |
| } |
| }; |
| |
| class LIsNullOrLikeUndefinedAndBranch : public LControlInstructionHelper<2, BOX_PIECES, 2> |
| { |
| public: |
| LIR_HEADER(IsNullOrLikeUndefinedAndBranch) |
| |
| LIsNullOrLikeUndefinedAndBranch(MBasicBlock *ifTrue, MBasicBlock *ifFalse, const LDefinition &temp, const LDefinition &tempToUnbox) |
| { |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| setTemp(0, temp); |
| setTemp(1, tempToUnbox); |
| } |
| |
| static const size_t Value = 0; |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| const LDefinition *tempToUnbox() { |
| return getTemp(1); |
| } |
| }; |
| |
| // Takes an object and tests whether it emulates |undefined|, as determined by |
| // the JSCLASS_EMULATES_UNDEFINED class flag on unwrapped objects. See also |
| // js::EmulatesUndefined. |
| class LEmulatesUndefined : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(EmulatesUndefined) |
| |
| LEmulatesUndefined(const LAllocation &input) |
| { |
| setOperand(0, input); |
| } |
| |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| }; |
| |
| class LEmulatesUndefinedAndBranch : public LControlInstructionHelper<2, 1, 1> |
| { |
| public: |
| LIR_HEADER(EmulatesUndefinedAndBranch) |
| |
| LEmulatesUndefinedAndBranch(const LAllocation &input, MBasicBlock *ifTrue, MBasicBlock *ifFalse, const LDefinition &temp) |
| { |
| setOperand(0, input); |
| setSuccessor(0, ifTrue); |
| setSuccessor(1, ifFalse); |
| setTemp(0, temp); |
| } |
| |
| MBasicBlock *ifTrue() const { |
| return getSuccessor(0); |
| } |
| MBasicBlock *ifFalse() const { |
| return getSuccessor(1); |
| } |
| MCompare *mir() { |
| return mir_->toCompare(); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Not operation on an integer. |
| class LNotI : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NotI) |
| |
| LNotI(const LAllocation &input) { |
| setOperand(0, input); |
| } |
| }; |
| |
| // Not operation on a double. |
| class LNotD : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NotD) |
| |
| LNotD(const LAllocation &input) { |
| setOperand(0, input); |
| } |
| }; |
| |
| // Boolean complement operation on an object. |
| class LNotO : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NotO) |
| |
| LNotO(const LAllocation &input) |
| { |
| setOperand(0, input); |
| } |
| |
| MNot *mir() { |
| return mir_->toNot(); |
| } |
| }; |
| |
| // Boolean complement operation on a value. |
| class LNotV : public LInstructionHelper<1, BOX_PIECES, 3> |
| { |
| public: |
| LIR_HEADER(NotV) |
| |
| static const size_t Input = 0; |
| LNotV(const LDefinition &temp0, const LDefinition &temp1, const LDefinition &temp2) |
| { |
| setTemp(0, temp0); |
| setTemp(1, temp1); |
| setTemp(2, temp2); |
| } |
| |
| const LAllocation *tempFloat() { |
| return getTemp(0)->output(); |
| } |
| |
| const LDefinition *temp1() { |
| return getTemp(1); |
| } |
| |
| const LDefinition *temp2() { |
| return getTemp(2); |
| } |
| |
| MNot *mir() { |
| return mir_->toNot(); |
| } |
| }; |
| |
| // Bitwise not operation, takes a 32-bit integer as input and returning |
| // a 32-bit integer result as an output. |
| class LBitNotI : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(BitNotI) |
| }; |
| |
| // Call a VM function to perform a BITNOT operation. |
| class LBitNotV : public LCallInstructionHelper<1, BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(BitNotV) |
| |
| static const size_t Input = 0; |
| }; |
| |
| // Binary bitwise operation, taking two 32-bit integers as inputs and returning |
| // a 32-bit integer result as an output. |
| class LBitOpI : public LInstructionHelper<1, 2, 0> |
| { |
| JSOp op_; |
| |
| public: |
| LIR_HEADER(BitOpI) |
| |
| LBitOpI(JSOp op) |
| : op_(op) |
| { } |
| |
| const char *extraName() const { |
| if (bitop() == JSOP_URSH && mir_->toUrsh()->canOverflow()) |
| return "UrshCanOverflow"; |
| return NULL; |
| } |
| |
| JSOp bitop() const { |
| return op_; |
| } |
| }; |
| |
| // Call a VM function to perform a bitwise operation. |
| class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> |
| { |
| JSOp jsop_; |
| |
| public: |
| LIR_HEADER(BitOpV) |
| |
| LBitOpV(JSOp jsop) |
| : jsop_(jsop) |
| { } |
| |
| JSOp jsop() const { |
| return jsop_; |
| } |
| |
| static const size_t LhsInput = 0; |
| static const size_t RhsInput = BOX_PIECES; |
| }; |
| |
| // Shift operation, taking two 32-bit integers as inputs and returning |
| // a 32-bit integer result as an output. |
| class LShiftI : public LBinaryMath<0> |
| { |
| JSOp op_; |
| |
| public: |
| LIR_HEADER(ShiftI) |
| |
| LShiftI(JSOp op) |
| : op_(op) |
| { } |
| |
| JSOp bitop() { |
| return op_; |
| } |
| |
| MInstruction *mir() { |
| return mir_->toInstruction(); |
| } |
| }; |
| |
| class LUrshD : public LBinaryMath<1> |
| { |
| public: |
| LIR_HEADER(UrshD) |
| |
| LUrshD(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) { |
| setOperand(0, lhs); |
| setOperand(1, rhs); |
| setTemp(0, temp); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Returns from the function being compiled (not used in inlined frames). The |
| // input must be a box. |
| class LReturn : public LInstructionHelper<0, BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(Return) |
| }; |
| |
| class LThrow : public LCallInstructionHelper<0, BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(Throw) |
| |
| static const size_t Value = 0; |
| }; |
| |
| class LMinMaxI : public LInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(MinMaxI) |
| LMinMaxI(const LAllocation &first, const LAllocation &second) |
| { |
| setOperand(0, first); |
| setOperand(1, second); |
| } |
| |
| const LAllocation *first() { |
| return this->getOperand(0); |
| } |
| const LAllocation *second() { |
| return this->getOperand(1); |
| } |
| const LDefinition *output() { |
| return this->getDef(0); |
| } |
| MMinMax *mir() const { |
| return mir_->toMinMax(); |
| } |
| }; |
| |
| class LMinMaxD : public LInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(MinMaxD) |
| LMinMaxD(const LAllocation &first, const LAllocation &second) |
| { |
| setOperand(0, first); |
| setOperand(1, second); |
| } |
| |
| const LAllocation *first() { |
| return this->getOperand(0); |
| } |
| const LAllocation *second() { |
| return this->getOperand(1); |
| } |
| const LDefinition *output() { |
| return this->getDef(0); |
| } |
| MMinMax *mir() const { |
| return mir_->toMinMax(); |
| } |
| }; |
| |
| // Negative of an integer |
| class LNegI : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NegI); |
| LNegI(const LAllocation &num) { |
| setOperand(0, num); |
| } |
| }; |
| |
| // Negative of a double. |
| class LNegD : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(NegD) |
| LNegD(const LAllocation &num) { |
| setOperand(0, num); |
| } |
| }; |
| |
| // Absolute value of an integer. |
| class LAbsI : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(AbsI) |
| LAbsI(const LAllocation &num) { |
| setOperand(0, num); |
| } |
| }; |
| |
| // Absolute value of a double. |
| class LAbsD : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(AbsD) |
| LAbsD(const LAllocation &num) { |
| setOperand(0, num); |
| } |
| }; |
| |
| // Square root of a double. |
| class LSqrtD : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(SqrtD) |
| LSqrtD(const LAllocation &num) { |
| setOperand(0, num); |
| } |
| }; |
| |
| class LAtan2D : public LCallInstructionHelper<1, 2, 1> |
| { |
| public: |
| LIR_HEADER(Atan2D) |
| LAtan2D(const LAllocation &y, const LAllocation &x, const LDefinition &temp) { |
| setOperand(0, y); |
| setOperand(1, x); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *y() { |
| return getOperand(0); |
| } |
| |
| const LAllocation *x() { |
| return getOperand(1); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| |
| const LDefinition *output() { |
| return getDef(0); |
| } |
| }; |
| |
| // Double raised to an integer power. |
| class LPowI : public LCallInstructionHelper<1, 2, 1> |
| { |
| public: |
| LIR_HEADER(PowI) |
| LPowI(const LAllocation &value, const LAllocation &power, const LDefinition &temp) { |
| setOperand(0, value); |
| setOperand(1, power); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *value() { |
| return getOperand(0); |
| } |
| const LAllocation *power() { |
| return getOperand(1); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Double raised to a double power. |
| class LPowD : public LCallInstructionHelper<1, 2, 1> |
| { |
| public: |
| LIR_HEADER(PowD) |
| LPowD(const LAllocation &value, const LAllocation &power, const LDefinition &temp) { |
| setOperand(0, value); |
| setOperand(1, power); |
| setTemp(0, temp); |
| } |
| |
| const LAllocation *value() { |
| return getOperand(0); |
| } |
| const LAllocation *power() { |
| return getOperand(1); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Math.random(). |
| class LRandom : public LCallInstructionHelper<1, 0, 2> |
| { |
| public: |
| LIR_HEADER(Random) |
| LRandom(const LDefinition &temp, const LDefinition &temp2) { |
| setTemp(0, temp); |
| setTemp(1, temp2); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| const LDefinition *temp2() { |
| return getTemp(1); |
| } |
| }; |
| |
| class LMathFunctionD : public LCallInstructionHelper<1, 1, 1> |
| { |
| public: |
| LIR_HEADER(MathFunctionD) |
| LMathFunctionD(const LAllocation &input, const LDefinition &temp) { |
| setOperand(0, input); |
| setTemp(0, temp); |
| } |
| |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| MMathFunction *mir() const { |
| return mir_->toMathFunction(); |
| } |
| }; |
| |
| // Adds two integers, returning an integer value. |
| class LAddI : public LBinaryMath<0> |
| { |
| bool recoversInput_; |
| |
| public: |
| LIR_HEADER(AddI) |
| |
| LAddI() |
| : recoversInput_(false) |
| { } |
| |
| const char *extraName() const { |
| return snapshot() ? "OverflowCheck" : NULL; |
| } |
| |
| virtual bool recoversInput() const { |
| return recoversInput_; |
| } |
| void setRecoversInput() { |
| recoversInput_ = true; |
| } |
| }; |
| |
| // Subtracts two integers, returning an integer value. |
| class LSubI : public LBinaryMath<0> |
| { |
| bool recoversInput_; |
| |
| public: |
| LIR_HEADER(SubI) |
| |
| LSubI() |
| : recoversInput_(false) |
| { } |
| |
| const char *extraName() const { |
| return snapshot() ? "OverflowCheck" : NULL; |
| } |
| |
| virtual bool recoversInput() const { |
| return recoversInput_; |
| } |
| void setRecoversInput() { |
| recoversInput_ = true; |
| } |
| }; |
| |
| // Performs an add, sub, mul, or div on two double values. |
| class LMathD : public LBinaryMath<0> |
| { |
| JSOp jsop_; |
| |
| public: |
| LIR_HEADER(MathD) |
| |
| LMathD(JSOp jsop) |
| : jsop_(jsop) |
| { } |
| |
| JSOp jsop() const { |
| return jsop_; |
| } |
| }; |
| |
| class LModD : public LBinaryMath<1> |
| { |
| public: |
| LIR_HEADER(ModD) |
| |
| LModD(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) { |
| setOperand(0, lhs); |
| setOperand(1, rhs); |
| setTemp(0, temp); |
| } |
| const LDefinition *temp() { |
| return getTemp(0); |
| } |
| bool isCall() const { |
| return true; |
| } |
| }; |
| |
| // Call a VM function to perform a binary operation. |
| class LBinaryV : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0> |
| { |
| JSOp jsop_; |
| |
| public: |
| LIR_HEADER(BinaryV) |
| BOX_OUTPUT_ACCESSORS() |
| |
| LBinaryV(JSOp jsop) |
| : jsop_(jsop) |
| { } |
| |
| JSOp jsop() const { |
| return jsop_; |
| } |
| |
| static const size_t LhsInput = 0; |
| static const size_t RhsInput = BOX_PIECES; |
| }; |
| |
| // Adds two string, returning a string. |
| class LConcat : public LInstructionHelper<1, 2, 4> |
| { |
| public: |
| LIR_HEADER(Concat) |
| |
| LConcat(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, |
| const LDefinition &temp2, const LDefinition &temp3, const LDefinition &temp4) { |
| setOperand(0, lhs); |
| setOperand(1, rhs); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| setTemp(2, temp3); |
| setTemp(3, temp4); |
| } |
| |
| const LAllocation *lhs() { |
| return this->getOperand(0); |
| } |
| const LAllocation *rhs() { |
| return this->getOperand(1); |
| } |
| const LDefinition *temp1() { |
| return this->getTemp(0); |
| } |
| const LDefinition *temp2() { |
| return this->getTemp(1); |
| } |
| const LDefinition *temp3() { |
| return this->getTemp(2); |
| } |
| const LDefinition *temp4() { |
| return this->getTemp(3); |
| } |
| }; |
| |
| // Get uint16 character code from a string. |
| class LCharCodeAt : public LInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(CharCodeAt) |
| |
| LCharCodeAt(const LAllocation &str, const LAllocation &index) { |
| setOperand(0, str); |
| setOperand(1, index); |
| } |
| |
| const LAllocation *str() { |
| return this->getOperand(0); |
| } |
| const LAllocation *index() { |
| return this->getOperand(1); |
| } |
| }; |
| |
| // Convert uint16 character code to a string. |
| class LFromCharCode : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(FromCharCode) |
| |
| LFromCharCode(const LAllocation &code) { |
| setOperand(0, code); |
| } |
| |
| const LAllocation *code() { |
| return this->getOperand(0); |
| } |
| }; |
| |
| // Convert a 32-bit integer to a double. |
| class LInt32ToDouble : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(Int32ToDouble) |
| |
| LInt32ToDouble(const LAllocation &input) { |
| setOperand(0, input); |
| } |
| }; |
| |
| // Convert a value to a double. |
| class LValueToDouble : public LInstructionHelper<1, BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(ValueToDouble) |
| static const size_t Input = 0; |
| |
| MToDouble *mir() { |
| return mir_->toToDouble(); |
| } |
| }; |
| |
| // Convert a value to an int32. |
| // Input: components of a Value |
| // Output: 32-bit integer |
| // Bailout: undefined, string, object, or non-int32 double |
| // Temps: one float register |
| // |
| // This instruction requires a temporary float register. |
| class LValueToInt32 : public LInstructionHelper<1, BOX_PIECES, 1> |
| { |
| public: |
| enum Mode { |
| NORMAL, |
| TRUNCATE |
| }; |
| |
| private: |
| Mode mode_; |
| |
| public: |
| LIR_HEADER(ValueToInt32) |
| |
| LValueToInt32(const LDefinition &temp, Mode mode) |
| : mode_(mode) |
| { |
| setTemp(0, temp); |
| } |
| |
| const char *extraName() const { |
| return mode() == NORMAL ? "Normal" : "Truncate"; |
| } |
| |
| static const size_t Input = 0; |
| |
| Mode mode() const { |
| return mode_; |
| } |
| const LDefinition *tempFloat() { |
| return getTemp(0); |
| } |
| MToInt32 *mir() const { |
| return mir_->toToInt32(); |
| } |
| }; |
| |
| // Convert a double to an int32. |
| // Input: floating-point register |
| // Output: 32-bit integer |
| // Bailout: if the double cannot be converted to an integer. |
| class LDoubleToInt32 : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(DoubleToInt32) |
| |
| LDoubleToInt32(const LAllocation &in) { |
| setOperand(0, in); |
| } |
| |
| MToInt32 *mir() const { |
| return mir_->toToInt32(); |
| } |
| }; |
| |
| |
| // Convert a double to a truncated int32. |
| // Input: floating-point register |
| // Output: 32-bit integer |
| class LTruncateDToInt32 : public LInstructionHelper<1, 1, 1> |
| { |
| public: |
| LIR_HEADER(TruncateDToInt32) |
| |
| LTruncateDToInt32(const LAllocation &in, const LDefinition &temp) { |
| setOperand(0, in); |
| setTemp(0, temp); |
| } |
| |
| const LDefinition *tempFloat() { |
| return getTemp(0); |
| } |
| }; |
| |
| // Convert a any input type hosted on one definition to a string with a function |
| // call. |
| class LIntToString : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(IntToString) |
| |
| LIntToString(const LAllocation &input) { |
| setOperand(0, input); |
| } |
| |
| const MToString *mir() { |
| return mir_->toToString(); |
| } |
| }; |
| |
| // No-op instruction that is used to hold the entry snapshot. This simplifies |
| // register allocation as it doesn't need to sniff the snapshot out of the |
| // LIRGraph. |
| class LStart : public LInstructionHelper<0, 0, 0> |
| { |
| public: |
| LIR_HEADER(Start) |
| }; |
| |
| // Passed the StackFrame address in the OsrFrameReg by SideCannon(). |
| // Forwards this object to the LOsrValues for Value materialization. |
| class LOsrEntry : public LInstructionHelper<1, 0, 0> |
| { |
| protected: |
| Label label_; |
| uint32_t frameDepth_; |
| |
| public: |
| LIR_HEADER(OsrEntry) |
| |
| LOsrEntry() |
| : frameDepth_(0) |
| { } |
| |
| void setFrameDepth(uint32_t depth) { |
| frameDepth_ = depth; |
| } |
| uint32_t getFrameDepth() { |
| return frameDepth_; |
| } |
| Label *label() { |
| return &label_; |
| } |
| |
| }; |
| |
| // Materialize a Value stored in an interpreter frame for OSR. |
| class LOsrValue : public LInstructionHelper<BOX_PIECES, 1, 0> |
| { |
| public: |
| LIR_HEADER(OsrValue) |
| |
| LOsrValue(const LAllocation &entry) |
| { |
| setOperand(0, entry); |
| } |
| |
| const MOsrValue *mir() { |
| return mir_->toOsrValue(); |
| } |
| }; |
| |
| // Materialize a JSObject scope chain stored in an interpreter frame for OSR. |
| class LOsrScopeChain : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(OsrScopeChain) |
| |
| LOsrScopeChain(const LAllocation &entry) |
| { |
| setOperand(0, entry); |
| } |
| |
| const MOsrScopeChain *mir() { |
| return mir_->toOsrScopeChain(); |
| } |
| }; |
| |
| class LRegExp : public LCallInstructionHelper<1, 0, 0> |
| { |
| public: |
| LIR_HEADER(RegExp) |
| |
| const MRegExp *mir() const { |
| return mir_->toRegExp(); |
| } |
| }; |
| |
| class LRegExpTest : public LCallInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(RegExpTest) |
| |
| LRegExpTest(const LAllocation ®exp, const LAllocation &string) |
| { |
| setOperand(0, regexp); |
| setOperand(1, string); |
| } |
| |
| const LAllocation *regexp() { |
| return getOperand(0); |
| } |
| const LAllocation *string() { |
| return getOperand(1); |
| } |
| |
| const MRegExpTest *mir() const { |
| return mir_->toRegExpTest(); |
| } |
| }; |
| |
| class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(LambdaForSingleton) |
| |
| LLambdaForSingleton(const LAllocation &scopeChain) |
| { |
| setOperand(0, scopeChain); |
| } |
| const LAllocation *scopeChain() { |
| return getOperand(0); |
| } |
| const MLambda *mir() const { |
| return mir_->toLambda(); |
| } |
| }; |
| |
| class LLambda : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(Lambda) |
| |
| LLambda(const LAllocation &scopeChain) { |
| setOperand(0, scopeChain); |
| } |
| const LAllocation *scopeChain() { |
| return getOperand(0); |
| } |
| const MLambda *mir() const { |
| return mir_->toLambda(); |
| } |
| }; |
| |
| class LParLambda : public LInstructionHelper<1, 2, 2> |
| { |
| public: |
| LIR_HEADER(ParLambda); |
| |
| LParLambda(const LAllocation &parSlice, |
| const LAllocation &scopeChain, |
| const LDefinition &temp1, |
| const LDefinition &temp2) { |
| setOperand(0, parSlice); |
| setOperand(1, scopeChain); |
| setTemp(0, temp1); |
| setTemp(1, temp2); |
| } |
| const LAllocation *parSlice() { |
| return getOperand(0); |
| } |
| const LAllocation *scopeChain() { |
| return getOperand(1); |
| } |
| const MParLambda *mir() const { |
| return mir_->toParLambda(); |
| } |
| const LAllocation *getTemp0() { |
| return getTemp(0)->output(); |
| } |
| const LAllocation *getTemp1() { |
| return getTemp(1)->output(); |
| } |
| }; |
| |
| // Determines the implicit |this| value for function calls. |
| class LImplicitThis : public LInstructionHelper<BOX_PIECES, 1, 0> |
| { |
| public: |
| LIR_HEADER(ImplicitThis) |
| BOX_OUTPUT_ACCESSORS() |
| |
| LImplicitThis(const LAllocation &callee) { |
| setOperand(0, callee); |
| } |
| |
| const MImplicitThis *mir() const { |
| return mir_->toImplicitThis(); |
| } |
| const LAllocation *callee() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Load the "slots" member out of a JSObject. |
| // Input: JSObject pointer |
| // Output: slots pointer |
| class LSlots : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(Slots) |
| |
| LSlots(const LAllocation &object) { |
| setOperand(0, object); |
| } |
| |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Load the "elements" member out of a JSObject. |
| // Input: JSObject pointer |
| // Output: elements pointer |
| class LElements : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(Elements) |
| |
| LElements(const LAllocation &object) { |
| setOperand(0, object); |
| } |
| |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| }; |
| |
| // If necessary, convert any int32 elements in a vector into doubles. |
| class LConvertElementsToDoubles : public LInstructionHelper<0, 1, 0> |
| { |
| public: |
| LIR_HEADER(ConvertElementsToDoubles) |
| |
| LConvertElementsToDoubles(const LAllocation &elements) { |
| setOperand(0, elements); |
| } |
| |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Load a dense array's initialized length from an elements vector. |
| class LInitializedLength : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(InitializedLength) |
| |
| LInitializedLength(const LAllocation &elements) { |
| setOperand(0, elements); |
| } |
| |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Set a dense array's initialized length to an elements vector. |
| class LSetInitializedLength : public LInstructionHelper<0, 2, 0> |
| { |
| public: |
| LIR_HEADER(SetInitializedLength) |
| |
| LSetInitializedLength(const LAllocation &elements, const LAllocation &index) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| } |
| |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Read length field of an object element. |
| class LArrayLength : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(ArrayLength) |
| |
| LArrayLength(const LAllocation &elements) { |
| setOperand(0, elements); |
| } |
| |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Read the length of a typed array. |
| class LTypedArrayLength : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(TypedArrayLength) |
| |
| LTypedArrayLength(const LAllocation &obj) { |
| setOperand(0, obj); |
| } |
| |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Load a typed array's elements vector. |
| class LTypedArrayElements : public LInstructionHelper<1, 1, 0> |
| { |
| public: |
| LIR_HEADER(TypedArrayElements) |
| |
| LTypedArrayElements(const LAllocation &object) { |
| setOperand(0, object); |
| } |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Bailout if index >= length. |
| class LBoundsCheck : public LInstructionHelper<0, 2, 0> |
| { |
| public: |
| LIR_HEADER(BoundsCheck) |
| |
| LBoundsCheck(const LAllocation &index, const LAllocation &length) { |
| setOperand(0, index); |
| setOperand(1, length); |
| } |
| const MBoundsCheck *mir() const { |
| return mir_->toBoundsCheck(); |
| } |
| const LAllocation *index() { |
| return getOperand(0); |
| } |
| const LAllocation *length() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Bailout if index + minimum < 0 or index + maximum >= length. |
| class LBoundsCheckRange : public LInstructionHelper<0, 2, 1> |
| { |
| public: |
| LIR_HEADER(BoundsCheckRange) |
| |
| LBoundsCheckRange(const LAllocation &index, const LAllocation &length, |
| const LDefinition &temp) |
| { |
| setOperand(0, index); |
| setOperand(1, length); |
| setTemp(0, temp); |
| } |
| const MBoundsCheck *mir() const { |
| return mir_->toBoundsCheck(); |
| } |
| const LAllocation *index() { |
| return getOperand(0); |
| } |
| const LAllocation *length() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Bailout if index < minimum. |
| class LBoundsCheckLower : public LInstructionHelper<0, 1, 0> |
| { |
| public: |
| LIR_HEADER(BoundsCheckLower) |
| |
| LBoundsCheckLower(const LAllocation &index) |
| { |
| setOperand(0, index); |
| } |
| MBoundsCheckLower *mir() const { |
| return mir_->toBoundsCheckLower(); |
| } |
| const LAllocation *index() { |
| return getOperand(0); |
| } |
| }; |
| |
| // Load a value from a dense array's elements vector. Bail out if it's the hole value. |
| class LLoadElementV : public LInstructionHelper<BOX_PIECES, 2, 0> |
| { |
| public: |
| LIR_HEADER(LoadElementV) |
| BOX_OUTPUT_ACCESSORS() |
| |
| LLoadElementV(const LAllocation &elements, const LAllocation &index) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| } |
| |
| const char *extraName() const { |
| return mir()->needsHoleCheck() ? "HoleCheck" : NULL; |
| } |
| |
| const MLoadElement *mir() const { |
| return mir_->toLoadElement(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| }; |
| |
| class LInArray : public LInstructionHelper<1, 4, 0> |
| { |
| public: |
| LIR_HEADER(InArray) |
| |
| LInArray(const LAllocation &elements, const LAllocation &index, |
| const LAllocation &initLength, const LAllocation &object) |
| { |
| setOperand(0, elements); |
| setOperand(1, index); |
| setOperand(2, initLength); |
| setOperand(3, object); |
| } |
| const MInArray *mir() const { |
| return mir_->toInArray(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| const LAllocation *initLength() { |
| return getOperand(2); |
| } |
| const LAllocation *object() { |
| return getOperand(3); |
| } |
| }; |
| |
| |
| // Load a value from a dense array's elements vector. Bail out if it's the hole value. |
| class LLoadElementHole : public LInstructionHelper<BOX_PIECES, 3, 0> |
| { |
| public: |
| LIR_HEADER(LoadElementHole) |
| BOX_OUTPUT_ACCESSORS() |
| |
| LLoadElementHole(const LAllocation &elements, const LAllocation &index, const LAllocation &initLength) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| setOperand(2, initLength); |
| } |
| |
| const char *extraName() const { |
| return mir()->needsHoleCheck() ? "HoleCheck" : NULL; |
| } |
| |
| const MLoadElementHole *mir() const { |
| return mir_->toLoadElementHole(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| const LAllocation *initLength() { |
| return getOperand(2); |
| } |
| }; |
| |
| // Load a typed value from a dense array's elements vector. The array must be |
| // known to be packed, so that we don't have to check for the hole value. |
| // This instruction does not load the type tag and can directly load into a |
| // FP register. |
| class LLoadElementT : public LInstructionHelper<1, 2, 0> |
| { |
| public: |
| LIR_HEADER(LoadElementT) |
| |
| LLoadElementT(const LAllocation &elements, const LAllocation &index) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| } |
| |
| const char *extraName() const { |
| return mir()->needsHoleCheck() ? "HoleCheck" : (mir()->loadDoubles() ? "Doubles" : NULL); |
| } |
| |
| const MLoadElement *mir() const { |
| return mir_->toLoadElement(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Store a boxed value to a dense array's element vector. |
| class LStoreElementV : public LInstructionHelper<0, 2 + BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(StoreElementV) |
| |
| LStoreElementV(const LAllocation &elements, const LAllocation &index) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| } |
| |
| const char *extraName() const { |
| return mir()->needsHoleCheck() ? "HoleCheck" : NULL; |
| } |
| |
| static const size_t Value = 2; |
| |
| const MStoreElement *mir() const { |
| return mir_->toStoreElement(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| }; |
| |
| // Store a typed value to a dense array's elements vector. Compared to |
| // LStoreElementV, this instruction can store doubles and constants directly, |
| // and does not store the type tag if the array is monomorphic and known to |
| // be packed. |
| class LStoreElementT : public LInstructionHelper<0, 3, 0> |
| { |
| public: |
| LIR_HEADER(StoreElementT) |
| |
| LStoreElementT(const LAllocation &elements, const LAllocation &index, const LAllocation &value) { |
| setOperand(0, elements); |
| setOperand(1, index); |
| setOperand(2, value); |
| } |
| |
| const char *extraName() const { |
| return mir()->needsHoleCheck() ? "HoleCheck" : NULL; |
| } |
| |
| const MStoreElement *mir() const { |
| return mir_->toStoreElement(); |
| } |
| const LAllocation *elements() { |
| return getOperand(0); |
| } |
| const LAllocation *index() { |
| return getOperand(1); |
| } |
| const LAllocation *value() { |
| return getOperand(2); |
| } |
| }; |
| |
| // Like LStoreElementV, but supports indexes >= initialized length. |
| class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0> |
| { |
| public: |
| LIR_HEADER(StoreElementHoleV) |
| |
| LStoreElementHoleV(const LAllocation &object, const LAllocation &elements, |
| const LAllocation &index) { |
| setOperand(0, object); |
| setOperand(1, elements); |
| setOperand(2, index); |
| } |
| |
| static const size_t Value = 3; |
| |
| const MStoreElementHole *mir() const { |
| return mir_->toStoreElementHole(); |
| } |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| const LAllocation *elements() { |
| return getOperand(1); |
| } |
| const LAllocation *index() { |
| return getOperand(2); |
| } |
| }; |
| |
| // Like LStoreElementT, but supports indexes >= initialized length. |
| class LStoreElementHoleT : public LInstructionHelper<0, 4, 0> |
| { |
| public: |
| LIR_HEADER(StoreElementHoleT) |
| |
| LStoreElementHoleT(const LAllocation &object, const LAllocation &elements, |
| const LAllocation &index, const LAllocation &value) { |
| setOperand(0, object); |
| setOperand(1, elements); |
| setOperand(2, index); |
| setOperand(3, value); |
| } |
| |
| const MStoreElementHole *mir() const { |
| return mir_->toStoreElementHole(); |
| } |
| const LAllocation *object() { |
| return getOperand(0); |
| } |
| const LAllocation *elements() { |
| return getOperand(1); |
| } |
|