DFGSpeculativeJIT.h [plain text]
#ifndef DFGSpeculativeJIT_h
#define DFGSpeculativeJIT_h
#if ENABLE(DFG_JIT)
#include "DFGAbstractState.h"
#include "DFGGenerationInfo.h"
#include "DFGJITCompiler.h"
#include "DFGOSRExit.h"
#include "DFGOperations.h"
#include "ValueRecovery.h"
namespace JSC { namespace DFG {
class JSValueOperand;
class SpeculativeJIT;
class SpeculateIntegerOperand;
class SpeculateStrictInt32Operand;
class SpeculateDoubleOperand;
class SpeculateCellOperand;
class SpeculateBooleanOperand;
enum ValueSourceKind {
SourceNotSet,
ValueInRegisterFile,
Int32InRegisterFile,
CellInRegisterFile,
BooleanInRegisterFile,
HaveNode
};
class ValueSource {
public:
ValueSource()
: m_nodeIndex(nodeIndexFromKind(SourceNotSet))
{
}
explicit ValueSource(ValueSourceKind valueSourceKind)
: m_nodeIndex(nodeIndexFromKind(valueSourceKind))
{
ASSERT(kind() != SourceNotSet);
ASSERT(kind() != HaveNode);
}
explicit ValueSource(NodeIndex nodeIndex)
: m_nodeIndex(nodeIndex)
{
ASSERT(kind() == HaveNode);
}
static ValueSource forPrediction(PredictedType prediction)
{
if (isInt32Prediction(prediction))
return ValueSource(Int32InRegisterFile);
if (isArrayPrediction(prediction) || isByteArrayPrediction(prediction))
return ValueSource(CellInRegisterFile);
if (isBooleanPrediction(prediction))
return ValueSource(BooleanInRegisterFile);
return ValueSource(ValueInRegisterFile);
}
bool isSet() const
{
return kindFromNodeIndex(m_nodeIndex) != SourceNotSet;
}
ValueSourceKind kind() const
{
return kindFromNodeIndex(m_nodeIndex);
}
NodeIndex nodeIndex() const
{
ASSERT(kind() == HaveNode);
return m_nodeIndex;
}
#ifndef NDEBUG
void dump(FILE* out) const;
#endif
private:
static NodeIndex nodeIndexFromKind(ValueSourceKind kind)
{
ASSERT(kind >= SourceNotSet && kind < HaveNode);
return NoNode - kind;
}
static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex)
{
unsigned kind = static_cast<unsigned>(NoNode - nodeIndex);
if (kind >= static_cast<unsigned>(HaveNode))
return HaveNode;
return static_cast<ValueSourceKind>(kind);
}
NodeIndex m_nodeIndex;
};
class SpeculativeJIT {
friend struct OSRExit;
private:
typedef JITCompiler::TrustedImm32 TrustedImm32;
typedef JITCompiler::Imm32 Imm32;
typedef JITCompiler::TrustedImmPtr TrustedImmPtr;
typedef JITCompiler::ImmPtr ImmPtr;
#if USE(JSVALUE64)
enum SpillOrder {
SpillOrderConstant = 1, SpillOrderSpilled = 2, SpillOrderJS = 4, SpillOrderCell = 4, SpillOrderStorage = 4, SpillOrderInteger = 5, SpillOrderBoolean = 5, SpillOrderDouble = 6, };
#elif USE(JSVALUE32_64)
enum SpillOrder {
SpillOrderConstant = 1, SpillOrderSpilled = 2, SpillOrderJS = 4, SpillOrderStorage = 4, SpillOrderDouble = 4, SpillOrderInteger = 5, SpillOrderCell = 5, SpillOrderBoolean = 5, };
#endif
enum UseChildrenMode { CallUseChildren, UseChildrenCalledExplicitly };
public:
SpeculativeJIT(JITCompiler&);
bool compile();
void linkOSREntries(LinkBuffer&);
Node& at(NodeIndex nodeIndex)
{
return m_jit.graph()[nodeIndex];
}
GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
FPRReg fillDouble(NodeIndex);
#if USE(JSVALUE64)
GPRReg fillJSValue(NodeIndex);
#elif USE(JSVALUE32_64)
bool fillJSValue(NodeIndex, GPRReg&, GPRReg&, FPRReg&);
#endif
GPRReg fillStorage(NodeIndex);
void lock(GPRReg reg)
{
m_gprs.lock(reg);
}
void lock(FPRReg reg)
{
m_fprs.lock(reg);
}
void unlock(GPRReg reg)
{
m_gprs.unlock(reg);
}
void unlock(FPRReg reg)
{
m_fprs.unlock(reg);
}
bool canReuse(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = at(nodeIndex).virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.canReuse();
}
GPRReg reuse(GPRReg reg)
{
m_gprs.lock(reg);
return reg;
}
FPRReg reuse(FPRReg reg)
{
m_fprs.lock(reg);
return reg;
}
GPRReg allocate()
{
VirtualRegister spillMe;
GPRReg gpr = m_gprs.allocate(spillMe);
if (spillMe != InvalidVirtualRegister) {
#if USE(JSVALUE32_64)
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatJSDouble);
if ((info.registerFormat() & DataFormatJS))
m_gprs.release(info.tagGPR() == gpr ? info.payloadGPR() : info.tagGPR());
#endif
spill(spillMe);
}
return gpr;
}
GPRReg allocate(GPRReg specific)
{
VirtualRegister spillMe = m_gprs.allocateSpecific(specific);
if (spillMe != InvalidVirtualRegister) {
#if USE(JSVALUE32_64)
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatJSDouble);
if ((info.registerFormat() & DataFormatJS))
m_gprs.release(info.tagGPR() == specific ? info.payloadGPR() : info.tagGPR());
#endif
spill(spillMe);
}
return specific;
}
GPRReg tryAllocate()
{
return m_gprs.tryAllocate();
}
FPRReg fprAllocate()
{
VirtualRegister spillMe;
FPRReg fpr = m_fprs.allocate(spillMe);
if (spillMe != InvalidVirtualRegister)
spill(spillMe);
return fpr;
}
bool isFilled(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = at(nodeIndex).virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.registerFormat() != DataFormatNone;
}
bool isFilledDouble(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = at(nodeIndex).virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.registerFormat() == DataFormatDouble;
}
void use(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = at(nodeIndex).virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (!info.use())
return;
DataFormat registerFormat = info.registerFormat();
#if USE(JSVALUE64)
if (registerFormat == DataFormatDouble)
m_fprs.release(info.fpr());
else if (registerFormat != DataFormatNone)
m_gprs.release(info.gpr());
#elif USE(JSVALUE32_64)
if (registerFormat == DataFormatDouble || registerFormat == DataFormatJSDouble)
m_fprs.release(info.fpr());
else if (registerFormat & DataFormatJS) {
m_gprs.release(info.tagGPR());
m_gprs.release(info.payloadGPR());
} else if (registerFormat != DataFormatNone)
m_gprs.release(info.gpr());
#endif
}
static void markCellCard(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR1, GPRReg scratchGPR2);
static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, WriteBarrierUseKind);
void writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg);
void writeBarrier(GPRReg ownerGPR, JSCell* value, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg, GPRReg scratchGPR2 = InvalidGPRReg);
void writeBarrier(JSCell* owner, GPRReg valueGPR, NodeIndex valueIndex, WriteBarrierUseKind, GPRReg scratchGPR1 = InvalidGPRReg);
static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg)
{
if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0)
return GPRInfo::regT0;
if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1)
return GPRInfo::regT1;
if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2)
return GPRInfo::regT2;
if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3)
return GPRInfo::regT3;
return GPRInfo::regT4;
}
GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat);
GPRReg fillSpeculateIntStrict(NodeIndex);
FPRReg fillSpeculateDouble(NodeIndex);
GPRReg fillSpeculateCell(NodeIndex);
GPRReg fillSpeculateBoolean(NodeIndex);
private:
void compile(Node&);
void compileMovHint(Node&);
void compile(BasicBlock&);
void checkArgumentTypes();
void clearGenerationInfo();
void silentSpillGPR(VirtualRegister spillMe, GPRReg source)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatNone);
ASSERT(info.registerFormat() != DataFormatDouble);
if (!info.needsSpill())
return;
DataFormat registerFormat = info.registerFormat();
#if USE(JSVALUE64)
ASSERT(info.gpr() == source);
if (registerFormat == DataFormatInteger)
m_jit.store32(source, JITCompiler::addressFor(spillMe));
else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage);
m_jit.storePtr(source, JITCompiler::addressFor(spillMe));
}
#elif USE(JSVALUE32_64)
if (registerFormat & DataFormatJS) {
ASSERT(info.tagGPR() == source || info.payloadGPR() == source);
m_jit.store32(source, source == info.tagGPR() ? JITCompiler::tagFor(spillMe) : JITCompiler::payloadFor(spillMe));
} else {
ASSERT(info.gpr() == source);
m_jit.store32(source, JITCompiler::payloadFor(spillMe));
}
#endif
}
void silentSpillFPR(VirtualRegister spillMe, FPRReg source)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() == DataFormatDouble);
if (!info.needsSpill()) {
ASSERT(at(info.nodeIndex()).hasConstant() || info.spillFormat() != DataFormatNone);
return;
}
ASSERT(!at(info.nodeIndex()).hasConstant());
ASSERT(info.spillFormat() == DataFormatNone);
ASSERT(info.fpr() == source);
m_jit.storeDouble(source, JITCompiler::addressFor(spillMe));
}
void silentFillGPR(VirtualRegister spillMe, GPRReg target)
{
GenerationInfo& info = m_generationInfo[spillMe];
NodeIndex nodeIndex = info.nodeIndex();
Node& node = at(nodeIndex);
ASSERT(info.registerFormat() != DataFormatNone);
ASSERT(info.registerFormat() != DataFormatDouble);
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatInteger) {
ASSERT(info.gpr() == target);
ASSERT(isJSInteger(info.registerFormat()));
if (node.hasConstant()) {
ASSERT(isInt32Constant(nodeIndex));
m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), target);
} else
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
return;
}
if (registerFormat == DataFormatBoolean) {
#if USE(JSVALUE64)
ASSERT_NOT_REACHED();
#elif USE(JSVALUE32_64)
ASSERT(info.gpr() == target);
if (node.hasConstant()) {
ASSERT(isBooleanConstant(nodeIndex));
m_jit.move(Imm32(valueOfBooleanConstant(nodeIndex)), target);
} else
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
#endif
return;
}
if (registerFormat == DataFormatCell) {
ASSERT(info.gpr() == target);
if (node.isConstant()) {
JSValue value = valueOfJSConstant(nodeIndex);
ASSERT(value.isCell());
m_jit.move(ImmPtr(value.asCell()), target);
} else
m_jit.loadPtr(JITCompiler::payloadFor(spillMe), target);
return;
}
if (registerFormat == DataFormatStorage) {
ASSERT(info.gpr() == target);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
return;
}
ASSERT(registerFormat & DataFormatJS);
#if USE(JSVALUE64)
ASSERT(info.gpr() == target);
if (node.hasConstant())
m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), target);
else if (info.spillFormat() == DataFormatInteger) {
ASSERT(registerFormat == DataFormatJSInteger);
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, target);
} else if (info.spillFormat() == DataFormatDouble) {
ASSERT(registerFormat == DataFormatJSDouble);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
m_jit.subPtr(GPRInfo::tagTypeNumberRegister, target);
} else
m_jit.loadPtr(JITCompiler::addressFor(spillMe), target);
#else
ASSERT(info.tagGPR() == target || info.payloadGPR() == target);
if (node.hasConstant()) {
JSValue v = valueOfJSConstant(nodeIndex);
m_jit.move(info.tagGPR() == target ? Imm32(v.tag()) : Imm32(v.payload()), target);
} else if (info.spillFormat() == DataFormatInteger) {
ASSERT(registerFormat == DataFormatJSInteger);
if (info.payloadGPR() == target)
m_jit.load32(JITCompiler::payloadFor(spillMe), target);
else
m_jit.move(TrustedImm32(JSValue::Int32Tag), target);
} else
m_jit.load32(info.tagGPR() == target ? JITCompiler::tagFor(spillMe) : JITCompiler::payloadFor(spillMe), target);
#endif
}
void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg target)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.fpr() == target);
NodeIndex nodeIndex = info.nodeIndex();
Node& node = at(nodeIndex);
#if USE(JSVALUE64)
ASSERT(info.registerFormat() == DataFormatDouble);
if (node.hasConstant()) {
ASSERT(isNumberConstant(nodeIndex));
m_jit.move(ImmPtr(bitwise_cast<void*>(valueOfNumberConstant(nodeIndex))), canTrample);
m_jit.movePtrToDouble(canTrample, target);
return;
}
if (info.spillFormat() != DataFormatNone && info.spillFormat() != DataFormatDouble) {
ASSERT(info.spillFormat() & DataFormatJS);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
unboxDouble(canTrample, target);
return;
}
m_jit.loadDouble(JITCompiler::addressFor(spillMe), target);
#elif USE(JSVALUE32_64)
UNUSED_PARAM(canTrample);
ASSERT(info.registerFormat() == DataFormatDouble || info.registerFormat() == DataFormatJSDouble);
if (node.hasConstant()) {
ASSERT(isNumberConstant(nodeIndex));
m_jit.loadDouble(addressOfDoubleConstant(nodeIndex), target);
} else
m_jit.loadDouble(JITCompiler::addressFor(spillMe), target);
#endif
}
void silentSpillAllRegisters(GPRReg exclude, GPRReg exclude2 = InvalidGPRReg)
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
GPRReg gpr = iter.regID();
if (iter.name() != InvalidVirtualRegister && gpr != exclude && gpr != exclude2)
silentSpillGPR(iter.name(), gpr);
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillFPR(iter.name(), iter.regID());
}
}
void silentSpillAllRegisters(FPRReg exclude)
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillGPR(iter.name(), iter.regID());
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
FPRReg fpr = iter.regID();
if (iter.name() != InvalidVirtualRegister && fpr != exclude)
silentSpillFPR(iter.name(), fpr);
}
}
void silentFillAllRegisters(GPRReg exclude, GPRReg exclude2 = InvalidGPRReg)
{
GPRReg canTrample = GPRInfo::regT0;
if (exclude == GPRInfo::regT0)
canTrample = GPRInfo::regT1;
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentFillFPR(iter.name(), canTrample, iter.regID());
}
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
GPRReg gpr = iter.regID();
if (iter.name() != InvalidVirtualRegister && gpr != exclude && gpr != exclude2)
silentFillGPR(iter.name(), gpr);
}
}
void silentFillAllRegisters(FPRReg exclude)
{
GPRReg canTrample = GPRInfo::regT0;
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
FPRReg fpr = iter.regID();
if (iter.name() != InvalidVirtualRegister && fpr != exclude)
silentFillFPR(iter.name(), canTrample, fpr);
}
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentFillGPR(iter.name(), iter.regID());
}
}
#if USE(JSVALUE64)
GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
{
return m_jit.boxDouble(fpr, gpr);
}
FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
{
return m_jit.unboxDouble(gpr, fpr);
}
GPRReg boxDouble(FPRReg fpr)
{
return boxDouble(fpr, allocate());
}
#elif USE(JSVALUE32_64)
void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
{
m_jit.boxDouble(fpr, tagGPR, payloadGPR);
}
void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
{
m_jit.unboxDouble(tagGPR, payloadGPR, fpr, scratchFPR);
}
#endif
void spill(VirtualRegister spillMe)
{
GenerationInfo& info = m_generationInfo[spillMe];
#if USE(JSVALUE32_64)
if (info.registerFormat() == DataFormatNone) return;
#endif
if (!info.needsSpill()) {
info.setSpilled();
return;
}
DataFormat spillFormat = info.registerFormat();
switch (spillFormat) {
case DataFormatStorage: {
m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
info.spill(DataFormatStorage);
return;
}
#if USE(JSVALUE64)
case DataFormatDouble: {
m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe));
info.spill(DataFormatDouble);
return;
}
case DataFormatInteger: {
m_jit.store32(info.gpr(), JITCompiler::payloadFor(spillMe));
info.spill(DataFormatInteger);
return;
}
default:
ASSERT(spillFormat == DataFormatCell || spillFormat & DataFormatJS);
GPRReg reg = info.gpr();
if (spillFormat == DataFormatInteger)
m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
info.spill((DataFormat)(spillFormat | DataFormatJS));
return;
#elif USE(JSVALUE32_64)
case DataFormatDouble:
case DataFormatJSDouble: {
m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe));
info.spill(DataFormatJSDouble);
return;
}
default:
ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat == DataFormatBoolean || (spillFormat & DataFormatJS));
if (spillFormat & DataFormatJS) { m_jit.store32(info.tagGPR(), JITCompiler::tagFor(spillMe));
m_jit.store32(info.payloadGPR(), JITCompiler::payloadFor(spillMe));
} else {
GPRReg reg = info.gpr();
m_jit.store32(reg, JITCompiler::payloadFor(spillMe));
if (spillFormat == DataFormatInteger)
m_jit.store32(TrustedImm32(JSValue::Int32Tag), JITCompiler::tagFor(spillMe));
else if (spillFormat == DataFormatCell)
m_jit.store32(TrustedImm32(JSValue::CellTag), JITCompiler::tagFor(spillMe));
else
m_jit.store32(TrustedImm32(JSValue::BooleanTag), JITCompiler::tagFor(spillMe));
}
info.spill((DataFormat)(spillFormat | DataFormatJS));
return;
#endif
}
}
bool isStrictInt32(NodeIndex);
bool isKnownInteger(NodeIndex);
bool isKnownNumeric(NodeIndex);
bool isKnownCell(NodeIndex);
bool isKnownNotInteger(NodeIndex);
bool isKnownNotNumber(NodeIndex);
bool isKnownBoolean(NodeIndex);
bool isKnownNotCell(NodeIndex);
bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
bool isJSConstant(NodeIndex nodeIndex) { return m_jit.isJSConstant(nodeIndex); }
bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
bool isNumberConstant(NodeIndex nodeIndex) { return m_jit.isNumberConstant(nodeIndex); }
bool isBooleanConstant(NodeIndex nodeIndex) { return m_jit.isBooleanConstant(nodeIndex); }
bool isFunctionConstant(NodeIndex nodeIndex) { return m_jit.isFunctionConstant(nodeIndex); }
int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
double valueOfNumberConstant(NodeIndex nodeIndex) { return m_jit.valueOfNumberConstant(nodeIndex); }
#if USE(JSVALUE32_64)
void* addressOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.addressOfDoubleConstant(nodeIndex); }
#endif
JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
bool valueOfBooleanConstant(NodeIndex nodeIndex) { return m_jit.valueOfBooleanConstant(nodeIndex); }
JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return m_jit.valueOfFunctionConstant(nodeIndex); }
bool isNullConstant(NodeIndex nodeIndex)
{
if (!isConstant(nodeIndex))
return false;
return valueOfJSConstant(nodeIndex).isNull();
}
Identifier* identifier(unsigned index)
{
return &m_jit.codeBlock()->identifier(index);
}
void flushRegisters()
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister) {
spill(iter.name());
iter.release();
}
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister) {
spill(iter.name());
iter.release();
}
}
}
#ifndef NDEBUG
bool isFlushed()
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
return false;
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
return false;
}
return true;
}
#endif
#if USE(JSVALUE64)
MacroAssembler::ImmPtr valueOfJSConstantAsImmPtr(NodeIndex nodeIndex)
{
return MacroAssembler::ImmPtr(JSValue::encode(valueOfJSConstant(nodeIndex)));
}
#endif
void bitOp(NodeType op, int32_t imm, GPRReg op1, GPRReg result)
{
switch (op) {
case BitAnd:
m_jit.and32(Imm32(imm), op1, result);
break;
case BitOr:
m_jit.or32(Imm32(imm), op1, result);
break;
case BitXor:
m_jit.xor32(Imm32(imm), op1, result);
break;
default:
ASSERT_NOT_REACHED();
}
}
void bitOp(NodeType op, GPRReg op1, GPRReg op2, GPRReg result)
{
switch (op) {
case BitAnd:
m_jit.and32(op1, op2, result);
break;
case BitOr:
m_jit.or32(op1, op2, result);
break;
case BitXor:
m_jit.xor32(op1, op2, result);
break;
default:
ASSERT_NOT_REACHED();
}
}
void shiftOp(NodeType op, GPRReg op1, int32_t shiftAmount, GPRReg result)
{
switch (op) {
case BitRShift:
m_jit.rshift32(op1, Imm32(shiftAmount), result);
break;
case BitLShift:
m_jit.lshift32(op1, Imm32(shiftAmount), result);
break;
case BitURShift:
m_jit.urshift32(op1, Imm32(shiftAmount), result);
break;
default:
ASSERT_NOT_REACHED();
}
}
void shiftOp(NodeType op, GPRReg op1, GPRReg shiftAmount, GPRReg result)
{
switch (op) {
case BitRShift:
m_jit.rshift32(op1, shiftAmount, result);
break;
case BitLShift:
m_jit.lshift32(op1, shiftAmount, result);
break;
case BitURShift:
m_jit.urshift32(op1, shiftAmount, result);
break;
default:
ASSERT_NOT_REACHED();
}
}
NodeIndex detectPeepHoleBranch()
{
NodeIndex lastNodeIndex = m_jit.graph().m_blocks[m_block]->end - 1;
for (NodeIndex index = m_compileIndex + 1; index < lastNodeIndex; ++index) {
if (at(index).shouldGenerate())
return NoNode;
}
Node& lastNode = at(lastNodeIndex);
return lastNode.op == Branch && lastNode.child1() == m_compileIndex ? lastNodeIndex : NoNode;
}
void nonSpeculativeValueToNumber(Node&);
void nonSpeculativeValueToInt32(Node&);
void nonSpeculativeUInt32ToNumber(Node&);
void nonSpeculativeKnownConstantArithOp(NodeType op, NodeIndex regChild, NodeIndex immChild, bool commute);
void nonSpeculativeBasicArithOp(NodeType op, Node&);
enum SpillRegistersMode { NeedToSpill, DontSpill };
#if USE(JSVALUE64)
JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
#elif USE(JSVALUE32_64)
JITCompiler::Call cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill);
void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, NodeIndex valueIndex, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
#endif
void nonSpeculativeNonPeepholeCompareNull(NodeIndex operand, bool invert = false);
void nonSpeculativePeepholeBranchNull(NodeIndex operand, NodeIndex branchNodeIndex, bool invert = false);
bool nonSpeculativeCompareNull(Node&, NodeIndex operand, bool invert = false);
void nonSpeculativePeepholeBranch(Node&, NodeIndex branchNodeIndex, MacroAssembler::RelationalCondition, S_DFGOperation_EJJ helperFunction);
void nonSpeculativeNonPeepholeCompare(Node&, MacroAssembler::RelationalCondition, S_DFGOperation_EJJ helperFunction);
bool nonSpeculativeCompare(Node&, MacroAssembler::RelationalCondition, S_DFGOperation_EJJ helperFunction);
void nonSpeculativePeepholeStrictEq(Node&, NodeIndex branchNodeIndex, bool invert = false);
void nonSpeculativeNonPeepholeStrictEq(Node&, bool invert = false);
bool nonSpeculativeStrictEq(Node&, bool invert = false);
void compileInstanceOfForObject(Node&, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchAndResultReg);
void compileInstanceOf(Node&);
MacroAssembler::Address callFrameSlot(int slot)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + slot) * static_cast<int>(sizeof(Register)));
}
MacroAssembler::Address argumentSlot(int argument)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + argumentToOperand(argument)) * static_cast<int>(sizeof(Register)));
}
MacroAssembler::Address callFrameTagSlot(int slot)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + slot) * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
}
MacroAssembler::Address callFramePayloadSlot(int slot)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + slot) * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
}
MacroAssembler::Address argumentTagSlot(int argument)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + argumentToOperand(argument)) * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
}
MacroAssembler::Address argumentPayloadSlot(int argument)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + argumentToOperand(argument)) * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
}
void emitCall(Node&);
void useChildren(Node&);
void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (format == DataFormatInteger) {
m_jit.jitAssertIsInt32(reg);
m_gprs.retain(reg, virtualRegister, SpillOrderInteger);
info.initInteger(nodeIndex, node.refCount(), reg);
} else {
#if USE(JSVALUE64)
ASSERT(format == DataFormatJSInteger);
m_jit.jitAssertIsJSInt32(reg);
m_gprs.retain(reg, virtualRegister, SpillOrderJS);
info.initJSValue(nodeIndex, node.refCount(), reg, format);
#elif USE(JSVALUE32_64)
ASSERT_NOT_REACHED();
#endif
}
}
void integerResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode)
{
integerResult(reg, nodeIndex, DataFormatInteger, mode);
}
void noResult(NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
if (mode == UseChildrenCalledExplicitly)
return;
Node& node = at(nodeIndex);
useChildren(node);
}
void cellResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_gprs.retain(reg, virtualRegister, SpillOrderCell);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initCell(nodeIndex, node.refCount(), reg);
}
void booleanResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_gprs.retain(reg, virtualRegister, SpillOrderBoolean);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initBoolean(nodeIndex, node.refCount(), reg);
}
#if USE(JSVALUE64)
void jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS, UseChildrenMode mode = CallUseChildren)
{
if (format == DataFormatJSInteger)
m_jit.jitAssertIsJSInt32(reg);
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_gprs.retain(reg, virtualRegister, SpillOrderJS);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initJSValue(nodeIndex, node.refCount(), reg, format);
}
void jsValueResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode)
{
jsValueResult(reg, nodeIndex, DataFormatJS, mode);
}
#elif USE(JSVALUE32_64)
void jsValueResult(GPRReg tag, GPRReg payload, NodeIndex nodeIndex, DataFormat format = DataFormatJS, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_gprs.retain(tag, virtualRegister, SpillOrderJS);
m_gprs.retain(payload, virtualRegister, SpillOrderJS);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initJSValue(nodeIndex, node.refCount(), tag, payload, format);
}
void jsValueResult(GPRReg tag, GPRReg payload, NodeIndex nodeIndex, UseChildrenMode mode)
{
jsValueResult(tag, payload, nodeIndex, DataFormatJS, mode);
}
#endif
void storageResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_gprs.retain(reg, virtualRegister, SpillOrderStorage);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initStorage(nodeIndex, node.refCount(), reg);
}
void doubleResult(FPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = at(nodeIndex);
if (mode == CallUseChildren)
useChildren(node);
VirtualRegister virtualRegister = node.virtualRegister();
m_fprs.retain(reg, virtualRegister, SpillOrderDouble);
GenerationInfo& info = m_generationInfo[virtualRegister];
info.initDouble(nodeIndex, node.refCount(), reg);
}
void initConstantInfo(NodeIndex nodeIndex)
{
ASSERT(isInt32Constant(nodeIndex) || isNumberConstant(nodeIndex) || isJSConstant(nodeIndex));
Node& node = at(nodeIndex);
m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount());
}
#if USE(JSVALUE64)
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg result, void* pointer)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(Z_DFGOperation_D operation, GPRReg result, FPRReg arg1)
{
m_jit.setupArguments(arg1);
JITCompiler::Call call = m_jit.appendCall(operation);
m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
return call;
}
JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EI operation, GPRReg result, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EA operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg result, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_ESS operation, GPRReg result, int startConstant, int numConstants)
{
m_jit.setupArgumentsWithExecState(Imm32(startConstant), Imm32(numConstants));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result)
{
m_jit.setupArgumentsExecState();
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(S_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(S_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, MacroAssembler::Imm32 imm)
{
m_jit.setupArgumentsWithExecState(arg1, MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg result, MacroAssembler::Imm32 imm, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(MacroAssembler::ImmPtr(static_cast<const void*>(JSValue::encode(jsNumber(imm.m_value)))), arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(pointer));
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EJCI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(identifier));
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
{
m_jit.setupArguments(arg1, arg2);
return appendCallSetResult(operation, result);
}
#else
JITCompiler::Call callOperation(Z_DFGOperation_D operation, GPRReg result, FPRReg arg1)
{
m_jit.setupArguments(arg1);
JITCompiler::Call call = m_jit.appendCall(operation);
m_jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, result);
return call;
}
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, void* pointer)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EPP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EGI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EI operation, GPRReg resultTag, GPRReg resultPayload, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EPS operation, GPRReg resultTag, GPRReg resultPayload, void* pointer, size_t size)
{
m_jit.setupArgumentsWithExecState(TrustedImmPtr(pointer), TrustedImmPtr(size));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_ESS operation, GPRReg resultTag, GPRReg resultPayload, int startConstant, int numConstants)
{
m_jit.setupArgumentsWithExecState(TrustedImm32(startConstant), TrustedImm32(numConstants));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, ImmPtr(pointer));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJP operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_ECI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJI operation, GPRReg resultTag, GPRReg resultPayload, int32_t arg1Tag, GPRReg arg1Payload, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1Payload, TrustedImm32(arg1Tag), TrustedImmPtr(identifier));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJA operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(C_DFGOperation_E operation, GPRReg result)
{
m_jit.setupArgumentsExecState();
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(C_DFGOperation_EC operation, GPRReg result, GPRReg arg1)
{
m_jit.setupArgumentsWithExecState(arg1);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(C_DFGOperation_ECC operation, GPRReg result, GPRReg arg1, JSCell* cell)
{
m_jit.setupArgumentsWithExecState(arg1, TrustedImmPtr(cell));
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(S_DFGOperation_EJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(S_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1Tag, GPRReg arg1Payload, MacroAssembler::Imm32 imm)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, imm, TrustedImm32(JSValue::Int32Tag));
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_EJJ operation, GPRReg resultTag, GPRReg resultPayload, MacroAssembler::Imm32 imm, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(imm, TrustedImm32(JSValue::Int32Tag), arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(J_DFGOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag);
return appendCallWithExceptionCheckSetResult(operation, resultPayload, resultTag);
}
JITCompiler::Call callOperation(V_DFGOperation_EJPP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, void* pointer)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(pointer));
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EJCI operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2, Identifier* identifier)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag, arg2, TrustedImmPtr(identifier));
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2Payload, arg2Tag, arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EPZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(V_DFGOperation_EAZJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3Tag, GPRReg arg3Payload)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3Payload, arg3Tag);
return appendCallWithExceptionCheck(operation);
}
JITCompiler::Call callOperation(D_DFGOperation_EJ operation, FPRReg result, GPRReg arg1Tag, GPRReg arg1Payload)
{
m_jit.setupArgumentsWithExecState(arg1Payload, arg1Tag);
return appendCallWithExceptionCheckSetResult(operation, result);
}
JITCompiler::Call callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
{
m_jit.setupArguments(arg1, arg2);
return appendCallSetResult(operation, result);
}
#endif
JITCompiler::Call appendCallWithExceptionCheck(const FunctionPtr& function)
{
CodeOrigin codeOrigin = at(m_compileIndex).codeOrigin;
CallBeginToken token = m_jit.beginCall(codeOrigin);
JITCompiler::Call call = m_jit.appendCall(function);
m_jit.addExceptionCheck(call, codeOrigin, token);
return call;
}
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.move(GPRInfo::returnValueGPR, result);
return call;
}
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, GPRReg result1, GPRReg result2)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.setupResults(result1, result2);
return call;
}
#if CPU(X86)
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.assembler().fstpl(0, JITCompiler::stackPointerRegister);
m_jit.loadDouble(JITCompiler::stackPointerRegister, result);
return call;
}
JITCompiler::Call appendCallSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = m_jit.appendCall(function);
m_jit.assembler().fstpl(0, JITCompiler::stackPointerRegister);
m_jit.loadDouble(JITCompiler::stackPointerRegister, result);
return call;
}
#elif CPU(ARM)
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.assembler().vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
return call;
}
JITCompiler::Call appendCallSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = m_jit.appendCall(function);
m_jit.assembler().vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
return call;
}
#else
JITCompiler::Call appendCallWithExceptionCheckSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = appendCallWithExceptionCheck(function);
m_jit.moveDouble(FPRInfo::returnValueFPR, result);
return call;
}
JITCompiler::Call appendCallSetResult(const FunctionPtr& function, FPRReg result)
{
JITCompiler::Call call = m_jit.appendCall(function);
m_jit.moveDouble(FPRInfo::returnValueFPR, result);
return call;
}
#endif
void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
{
m_branches.append(BranchRecord(jump, destination));
}
void linkBranches()
{
for (size_t i = 0; i < m_branches.size(); ++i) {
BranchRecord& branch = m_branches[i];
branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
}
}
BasicBlock* block()
{
return m_jit.graph().m_blocks[m_block].get();
}
#ifndef NDEBUG
void dump(const char* label = 0);
#endif
#if DFG_ENABLE(CONSISTENCY_CHECK)
void checkConsistency();
#else
void checkConsistency() { }
#endif
bool isInteger(NodeIndex nodeIndex)
{
Node& node = at(nodeIndex);
if (node.hasInt32Result())
return true;
if (isInt32Constant(nodeIndex))
return true;
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.isJSInteger();
}
bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
bool compilePeepHoleBranch(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition);
void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr, PredictionChecker);
void compileObjectEquality(Node&, void* vptr, PredictionChecker);
void compileValueAdd(Node&);
void compileObjectOrOtherLogicalNot(NodeIndex value, void* vptr, bool needSpeculationCheck);
void compileLogicalNot(Node&);
void emitObjectOrOtherBranch(NodeIndex value, BlockIndex taken, BlockIndex notTaken, void *vptr, bool needSpeculationCheck);
void emitBranch(Node&);
void compileIntegerCompare(Node&, MacroAssembler::RelationalCondition);
void compileDoubleCompare(Node&, MacroAssembler::DoubleCondition);
bool compileStrictEqForConstant(Node&, NodeIndex value, JSValue constant);
bool compileStrictEq(Node&);
void compileGetCharCodeAt(Node&);
void compileGetByValOnString(Node&);
void compileValueToInt32(Node&);
void compileUInt32ToNumber(Node&);
void compileGetByValOnByteArray(Node&);
void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
void compileArithMul(Node&);
void compileArithMod(Node&);
void compileSoftModulo(Node&);
void compileGetTypedArrayLength(const TypedArrayDescriptor&, Node&, bool needsSpeculationCheck);
enum TypedArraySpeculationRequirements {
NoTypedArraySpecCheck,
NoTypedArrayTypeSpecCheck,
AllTypedArraySpecChecks
};
enum TypedArraySignedness {
SignedTypedArray,
UnsignedTypedArray
};
void compileGetIndexedPropertyStorage(Node&);
void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness);
void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness);
void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements);
void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements);
template<typename T>
void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
{
MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
}
#if USE(JSVALUE64)
JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);
#elif USE(JSVALUE32_64)
JITCompiler::Jump convertToDouble(JSValueOperand&, FPRReg result);
#endif
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail)
{
if (!m_compileOkay)
return;
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.valueProfileFor(nodeIndex), jumpToFail, this));
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail)
{
Vector<MacroAssembler::Jump, 16> JumpVector = jumpsToFail.jumps();
for (unsigned i = 0; i < JumpVector.size(); ++i)
speculationCheck(kind, jsValueSource, nodeIndex, JumpVector[i]);
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
if (!m_compileOkay)
return;
m_jit.codeBlock()->appendSpeculationRecovery(recovery);
m_jit.codeBlock()->appendOSRExit(OSRExit(kind, jsValueSource, m_jit.valueProfileFor(nodeIndex), jumpToFail, this, m_jit.codeBlock()->numberOfSpeculationRecoveries()));
}
void terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, NodeIndex nodeIndex)
{
#if DFG_ENABLE(DEBUG_VERBOSE)
fprintf(stderr, "SpeculativeJIT was terminated.\n");
#endif
if (!m_compileOkay)
return;
speculationCheck(kind, jsValueRegs, nodeIndex, m_jit.jump());
m_compileOkay = false;
}
template<bool strict>
GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
bool m_compileOkay;
ValueSource valueSourceForOperand(int operand)
{
return valueSourceReferenceForOperand(operand);
}
void setNodeIndexForOperand(NodeIndex nodeIndex, int operand)
{
valueSourceReferenceForOperand(operand) = ValueSource(nodeIndex);
}
ValueSource& valueSourceReferenceForOperand(int operand)
{
if (operandIsArgument(operand)) {
int argument = operandToArgument(operand);
return m_arguments[argument];
}
if ((unsigned)operand >= m_variables.size())
m_variables.resize(operand + 1);
return m_variables[operand];
}
JITCompiler& m_jit;
BlockIndex m_block;
NodeIndex m_compileIndex;
Vector<GenerationInfo, 32> m_generationInfo;
RegisterBank<GPRInfo> m_gprs;
RegisterBank<FPRInfo> m_fprs;
Vector<MacroAssembler::Label> m_blockHeads;
struct BranchRecord {
BranchRecord(MacroAssembler::Jump jump, BlockIndex destination)
: jump(jump)
, destination(destination)
{
}
MacroAssembler::Jump jump;
BlockIndex destination;
};
Vector<BranchRecord, 8> m_branches;
Vector<ValueSource, 0> m_arguments;
Vector<ValueSource, 0> m_variables;
int m_lastSetOperand;
CodeOrigin m_codeOriginForOSR;
AbstractState m_state;
ValueRecovery computeValueRecoveryFor(const ValueSource&);
ValueRecovery computeValueRecoveryFor(int operand)
{
return computeValueRecoveryFor(valueSourceForOperand(operand));
}
};
class IntegerOperand {
public:
explicit IntegerOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
#ifndef NDEBUG
, m_format(DataFormatNone)
#endif
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~IntegerOperand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
DataFormat format()
{
gpr(); ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
return m_format;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillInteger(index(), m_format);
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
DataFormat m_format;
};
class DoubleOperand {
public:
explicit DoubleOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_fprOrInvalid(InvalidFPRReg)
{
ASSERT(m_jit);
if (jit->isFilledDouble(index))
fpr();
}
~DoubleOperand()
{
ASSERT(m_fprOrInvalid != InvalidFPRReg);
m_jit->unlock(m_fprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
FPRReg fpr()
{
if (m_fprOrInvalid == InvalidFPRReg)
m_fprOrInvalid = m_jit->fillDouble(index());
return m_fprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
FPRReg m_fprOrInvalid;
};
class JSValueOperand {
public:
explicit JSValueOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
#if USE(JSVALUE64)
, m_gprOrInvalid(InvalidGPRReg)
#elif USE(JSVALUE32_64)
, m_isDouble(false)
#endif
{
ASSERT(m_jit);
#if USE(JSVALUE64)
if (jit->isFilled(index))
gpr();
#elif USE(JSVALUE32_64)
m_register.pair.tagGPR = InvalidGPRReg;
m_register.pair.payloadGPR = InvalidGPRReg;
if (jit->isFilled(index))
fill();
#endif
}
~JSValueOperand()
{
#if USE(JSVALUE64)
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
#elif USE(JSVALUE32_64)
if (m_isDouble) {
ASSERT(m_register.fpr != InvalidFPRReg);
m_jit->unlock(m_register.fpr);
} else {
ASSERT(m_register.pair.tagGPR != InvalidGPRReg && m_register.pair.payloadGPR != InvalidGPRReg);
m_jit->unlock(m_register.pair.tagGPR);
m_jit->unlock(m_register.pair.payloadGPR);
}
#endif
}
NodeIndex index() const
{
return m_index;
}
#if USE(JSVALUE64)
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillJSValue(index());
return m_gprOrInvalid;
}
JSValueRegs jsValueRegs()
{
return JSValueRegs(gpr());
}
#elif USE(JSVALUE32_64)
bool isDouble() { return m_isDouble; }
void fill()
{
if (m_register.pair.tagGPR == InvalidGPRReg && m_register.pair.payloadGPR == InvalidGPRReg)
m_isDouble = !m_jit->fillJSValue(index(), m_register.pair.tagGPR, m_register.pair.payloadGPR, m_register.fpr);
}
GPRReg tagGPR()
{
fill();
ASSERT(!m_isDouble);
return m_register.pair.tagGPR;
}
GPRReg payloadGPR()
{
fill();
ASSERT(!m_isDouble);
return m_register.pair.payloadGPR;
}
JSValueRegs jsValueRegs()
{
return JSValueRegs(tagGPR(), payloadGPR());
}
FPRReg fpr()
{
fill();
ASSERT(m_isDouble);
return m_register.fpr;
}
#endif
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
#if USE(JSVALUE64)
GPRReg m_gprOrInvalid;
#elif USE(JSVALUE32_64)
union {
struct {
GPRReg tagGPR;
GPRReg payloadGPR;
} pair;
FPRReg fpr;
} m_register;
bool m_isDouble;
#endif
};
class StorageOperand {
public:
explicit StorageOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~StorageOperand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillStorage(index());
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
class GPRTemporary {
public:
GPRTemporary();
GPRTemporary(SpeculativeJIT*);
GPRTemporary(SpeculativeJIT*, GPRReg specific);
GPRTemporary(SpeculativeJIT*, SpeculateIntegerOperand&);
GPRTemporary(SpeculativeJIT*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
GPRTemporary(SpeculativeJIT*, SpeculateStrictInt32Operand&);
GPRTemporary(SpeculativeJIT*, IntegerOperand&);
GPRTemporary(SpeculativeJIT*, IntegerOperand&, IntegerOperand&);
GPRTemporary(SpeculativeJIT*, SpeculateCellOperand&);
GPRTemporary(SpeculativeJIT*, SpeculateBooleanOperand&);
#if USE(JSVALUE64)
GPRTemporary(SpeculativeJIT*, JSValueOperand&);
#elif USE(JSVALUE32_64)
GPRTemporary(SpeculativeJIT*, JSValueOperand&, bool tag = true);
#endif
GPRTemporary(SpeculativeJIT*, StorageOperand&);
void adopt(GPRTemporary&);
~GPRTemporary()
{
if (m_jit && m_gpr != InvalidGPRReg)
m_jit->unlock(gpr());
}
GPRReg gpr()
{
if (m_jit && m_gpr == InvalidGPRReg)
m_gpr = m_jit->allocate();
return m_gpr;
}
private:
SpeculativeJIT* m_jit;
GPRReg m_gpr;
};
class FPRTemporary {
public:
FPRTemporary(SpeculativeJIT*);
FPRTemporary(SpeculativeJIT*, DoubleOperand&);
FPRTemporary(SpeculativeJIT*, DoubleOperand&, DoubleOperand&);
FPRTemporary(SpeculativeJIT*, SpeculateDoubleOperand&);
FPRTemporary(SpeculativeJIT*, SpeculateDoubleOperand&, SpeculateDoubleOperand&);
#if USE(JSVALUE32_64)
FPRTemporary(SpeculativeJIT*, JSValueOperand&);
#endif
~FPRTemporary()
{
m_jit->unlock(fpr());
}
FPRReg fpr() const
{
ASSERT(m_fpr != InvalidFPRReg);
return m_fpr;
}
protected:
FPRTemporary(SpeculativeJIT* jit, FPRReg lockedFPR)
: m_jit(jit)
, m_fpr(lockedFPR)
{
}
private:
SpeculativeJIT* m_jit;
FPRReg m_fpr;
};
class GPRResult : public GPRTemporary {
public:
GPRResult(SpeculativeJIT* jit)
: GPRTemporary(jit, GPRInfo::returnValueGPR)
{
}
};
#if USE(JSVALUE32_64)
class GPRResult2 : public GPRTemporary {
public:
GPRResult2(SpeculativeJIT* jit)
: GPRTemporary(jit, GPRInfo::returnValueGPR2)
{
}
};
#endif
class FPRResult : public FPRTemporary {
public:
FPRResult(SpeculativeJIT* jit)
: FPRTemporary(jit, lockedResult(jit))
{
}
private:
static FPRReg lockedResult(SpeculativeJIT* jit)
{
jit->lock(FPRInfo::returnValueFPR);
return FPRInfo::returnValueFPR;
}
};
class SpeculateIntegerOperand {
public:
explicit SpeculateIntegerOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
#ifndef NDEBUG
, m_format(DataFormatNone)
#endif
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~SpeculateIntegerOperand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
DataFormat format()
{
gpr(); ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
return m_format;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
return m_gprOrInvalid;
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
DataFormat m_format;
};
class SpeculateStrictInt32Operand {
public:
explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~SpeculateStrictInt32Operand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillSpeculateIntStrict(index());
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
class SpeculateDoubleOperand {
public:
explicit SpeculateDoubleOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_fprOrInvalid(InvalidFPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
fpr();
}
~SpeculateDoubleOperand()
{
ASSERT(m_fprOrInvalid != InvalidFPRReg);
m_jit->unlock(m_fprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
FPRReg fpr()
{
if (m_fprOrInvalid == InvalidFPRReg)
m_fprOrInvalid = m_jit->fillSpeculateDouble(index());
return m_fprOrInvalid;
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
FPRReg m_fprOrInvalid;
};
class SpeculateCellOperand {
public:
explicit SpeculateCellOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~SpeculateCellOperand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillSpeculateCell(index());
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
class SpeculateBooleanOperand {
public:
explicit SpeculateBooleanOperand(SpeculativeJIT* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~SpeculateBooleanOperand()
{
ASSERT(m_gprOrInvalid != InvalidGPRReg);
m_jit->unlock(m_gprOrInvalid);
}
NodeIndex index() const
{
return m_index;
}
GPRReg gpr()
{
if (m_gprOrInvalid == InvalidGPRReg)
m_gprOrInvalid = m_jit->fillSpeculateBoolean(index());
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
inline SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
: m_compileOkay(true)
, m_jit(jit)
, m_compileIndex(0)
, m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
, m_blockHeads(jit.graph().m_blocks.size())
, m_arguments(jit.codeBlock()->m_numParameters)
, m_variables(jit.graph().m_localVars)
, m_lastSetOperand(std::numeric_limits<int>::max())
, m_state(m_jit.codeBlock(), m_jit.graph())
{
}
} }
#endif
#endif