blob: 877cb2713e565bfb9acff063131a191dc9f80212 [file] [log] [blame]
/* -*- 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 &regexp, const LAllocation &string)
{
setOperand(0, regexp);
setOperand(1, string);
}
const LAllocation *regexp() {
return getOperand(0);
}
const LAllocation *string() {
return getOperand(1);
}
const MRegExpTest *mir() const {
return mir_->toRegExpTest();
}
};
class 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);
}