DFGJITCodeGenerator.h [plain text]
#ifndef DFGJITCodeGenerator_h
#define DFGJITCodeGenerator_h
#if ENABLE(DFG_JIT)
#include "CodeBlock.h"
#include <dfg/DFGGenerationInfo.h>
#include <dfg/DFGGraph.h>
#include <dfg/DFGJITCompiler.h>
#include <dfg/DFGOperations.h>
#include <dfg/DFGRegisterBank.h>
namespace JSC { namespace DFG {
class SpeculateIntegerOperand;
class SpeculateStrictInt32Operand;
class SpeculateDoubleOperand;
class SpeculateCellOperand;
class JITCodeGenerator {
protected:
typedef MacroAssembler::TrustedImm32 TrustedImm32;
typedef MacroAssembler::Imm32 Imm32;
enum SpillOrder {
SpillOrderConstant = 1, SpillOrderSpilled = 2, SpillOrderJS = 4, SpillOrderCell = 4, SpillOrderInteger = 5, SpillOrderDouble = 6, };
enum UseChildrenMode { CallUseChildren, UseChildrenCalledExplicitly };
public:
GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
FPRReg fillDouble(NodeIndex);
GPRReg fillJSValue(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 = m_jit.graph()[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)
spill(spillMe);
return gpr;
}
GPRReg allocate(GPRReg specific)
{
VirtualRegister spillMe = m_gprs.allocateSpecific(specific);
if (spillMe != InvalidVirtualRegister)
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 = m_jit.graph()[nodeIndex].virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.registerFormat() != DataFormatNone;
}
bool isFilledDouble(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return info.registerFormat() == DataFormatDouble;
}
void use(NodeIndex nodeIndex)
{
VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if (!info.use())
return;
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatDouble)
m_fprs.release(info.fpr());
else if (registerFormat != DataFormatNone)
m_gprs.release(info.gpr());
}
static void writeBarrier(MacroAssembler&, GPRReg ownerGPR, GPRReg scratchGPR);
static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg)
{
if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0)
return GPRInfo::regT0;
if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1)
return GPRInfo::regT1;
if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2)
return GPRInfo::regT2;
return GPRInfo::regT3;
}
protected:
JITCodeGenerator(JITCompiler& jit, bool isSpeculative)
: m_jit(jit)
, m_isSpeculative(isSpeculative)
, m_compileIndex(0)
, m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
, m_blockHeads(jit.graph().m_blocks.size())
{
}
void silentSpillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() != DataFormatNone);
ASSERT(info.registerFormat() != DataFormatDouble);
if (!info.needsSpill() || (info.gpr() == exclude))
return;
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatInteger) {
m_jit.store32(info.gpr(), JITCompiler::addressFor(spillMe));
} else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
}
}
void silentSpillFPR(VirtualRegister spillMe, FPRReg exclude = InvalidFPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
ASSERT(info.registerFormat() == DataFormatDouble);
if (info.fpr() == exclude)
return;
if (!info.needsSpill()) {
ASSERT(m_jit.graph()[info.nodeIndex()].isConstant() || info.spillFormat() != DataFormatNone);
return;
}
ASSERT(!m_jit.graph()[info.nodeIndex()].isConstant());
ASSERT(info.spillFormat() == DataFormatNone);
m_jit.storeDouble(info.fpr(), JITCompiler::addressFor(spillMe));
}
void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
if (info.gpr() == exclude)
return;
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
ASSERT(info.registerFormat() != DataFormatNone);
ASSERT(info.registerFormat() != DataFormatDouble);
DataFormat registerFormat = info.registerFormat();
if (registerFormat == DataFormatInteger) {
if (node.isConstant()) {
ASSERT(isInt32Constant(nodeIndex));
m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), info.gpr());
} else
m_jit.load32(JITCompiler::addressFor(spillMe), info.gpr());
return;
}
if (node.isConstant())
m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), info.gpr());
else {
ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr());
}
}
void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
{
GenerationInfo& info = m_generationInfo[spillMe];
if (info.fpr() == exclude)
return;
NodeIndex nodeIndex = info.nodeIndex();
Node& node = m_jit.graph()[nodeIndex];
ASSERT(info.registerFormat() == DataFormatDouble);
if (node.isConstant()) {
ASSERT(isDoubleConstant(nodeIndex));
m_jit.move(JITCompiler::ImmPtr(bitwise_cast<void*>(valueOfDoubleConstant(nodeIndex))), canTrample);
m_jit.movePtrToDouble(canTrample, info.fpr());
return;
}
if (info.spillFormat() != DataFormatNone) {
ASSERT(info.spillFormat() & DataFormatJS);
m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
unboxDouble(canTrample, info.fpr());
return;
}
m_jit.loadDouble(JITCompiler::addressFor(spillMe), info.fpr());
}
void silentSpillAllRegisters(GPRReg exclude)
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillGPR(iter.name(), exclude);
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillFPR(iter.name());
}
}
void silentSpillAllRegisters(FPRReg exclude)
{
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillGPR(iter.name());
}
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentSpillFPR(iter.name(), exclude);
}
}
void silentFillAllRegisters(GPRReg exclude)
{
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);
}
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentFillGPR(iter.name(), exclude);
}
}
void silentFillAllRegisters(FPRReg exclude)
{
GPRReg canTrample = GPRInfo::regT0;
for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister) {
ASSERT_UNUSED(exclude, iter.regID() != exclude);
silentFillFPR(iter.name(), canTrample, exclude);
}
}
for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
if (iter.name() != InvalidVirtualRegister)
silentFillGPR(iter.name());
}
}
GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
{
m_jit.moveDoubleToPtr(fpr, gpr);
m_jit.subPtr(GPRInfo::tagTypeNumberRegister, gpr);
return gpr;
}
FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
{
m_jit.addPtr(GPRInfo::tagTypeNumberRegister, gpr);
m_jit.movePtrToDouble(gpr, fpr);
return fpr;
}
GPRReg boxDouble(FPRReg fpr)
{
return boxDouble(fpr, allocate());
}
void spill(VirtualRegister spillMe)
{
GenerationInfo& info = m_generationInfo[spillMe];
if (!info.needsSpill()) {
info.setSpilled();
return;
}
DataFormat spillFormat = info.registerFormat();
if (spillFormat == DataFormatDouble) {
GPRReg gpr = boxDouble(info.fpr());
m_jit.storePtr(gpr, JITCompiler::addressFor(spillMe));
unlock(gpr);
info.spill(DataFormatJSDouble);
return;
}
ASSERT(spillFormat == DataFormatInteger || 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));
}
bool isKnownInteger(NodeIndex);
bool isKnownNumeric(NodeIndex);
bool isKnownCell(NodeIndex);
bool isKnownNotInteger(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); }
int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(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
MacroAssembler::ImmPtr valueOfJSConstantAsImmPtr(NodeIndex nodeIndex)
{
return MacroAssembler::ImmPtr(JSValue::encode(valueOfJSConstant(nodeIndex)));
}
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 (m_jit.graph()[index].shouldGenerate())
return NoNode;
}
Node& lastNode = m_jit.graph()[lastNodeIndex];
return lastNode.op == Branch && lastNode.child1() == m_compileIndex ? lastNodeIndex : NoNode;
}
JITCompiler::Call cachedGetById(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), NodeType = GetById);
void cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
void cachedGetMethod(GPRReg baseGPR, GPRReg resultGPR, GPRReg scratchGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump());
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, Z_DFGOperation_EJJ helperFunction);
void nonSpeculativeNonPeepholeCompare(Node&, MacroAssembler::RelationalCondition, Z_DFGOperation_EJJ helperFunction);
bool nonSpeculativeCompare(Node&, MacroAssembler::RelationalCondition, Z_DFGOperation_EJJ helperFunction);
void nonSpeculativePeepholeStrictEq(Node&, NodeIndex branchNodeIndex, bool invert = false);
void nonSpeculativeNonPeepholeStrictEq(Node&, bool invert = false);
bool nonSpeculativeStrictEq(Node&, bool invert = false);
void emitBranch(Node&);
MacroAssembler::Address addressOfCallData(int idx)
{
return MacroAssembler::Address(GPRInfo::callFrameRegister, (m_jit.codeBlock()->m_numCalleeRegisters + idx) * static_cast<int>(sizeof(Register)));
}
void emitCall(Node&);
void useChildren(Node&);
void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger, UseChildrenMode mode = CallUseChildren)
{
Node& node = m_jit.graph()[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 {
ASSERT(format == DataFormatJSInteger);
m_jit.jitAssertIsJSInt32(reg);
m_gprs.retain(reg, virtualRegister, SpillOrderJS);
info.initJSValue(nodeIndex, node.refCount(), reg, format);
}
}
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 = m_jit.graph()[nodeIndex];
useChildren(node);
}
void cellResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = m_jit.graph()[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 jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS, UseChildrenMode mode = CallUseChildren)
{
if (format == DataFormatJSInteger)
m_jit.jitAssertIsJSInt32(reg);
Node& node = m_jit.graph()[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);
}
void doubleResult(FPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
{
Node& node = m_jit.graph()[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) || isDoubleConstant(nodeIndex) || isJSConstant(nodeIndex));
Node& node = m_jit.graph()[nodeIndex];
m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount());
}
template<GPRReg destA, GPRReg destB>
void setupTwoStubArgs(GPRReg srcA, GPRReg srcB)
{
if (srcB != destA) {
m_jit.move(srcA, destA);
m_jit.move(srcB, destB);
} else if (srcA != destB) {
m_jit.move(srcB, destB);
m_jit.move(srcA, destA);
} else
m_jit.swap(destA, destB);
}
template<FPRReg destA, FPRReg destB>
void setupTwoStubArgs(FPRReg srcA, FPRReg srcB)
{
if (srcB != destA) {
m_jit.moveDouble(srcA, destA);
m_jit.moveDouble(srcB, destB);
return;
}
if (srcA != destB) {
m_jit.moveDouble(srcB, destB);
m_jit.moveDouble(srcA, destA);
return;
}
ASSERT(srcB == destA && srcA == destB);
FPRReg temp;
if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3)
temp = FPRInfo::argumentFPR3;
else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2)
temp = FPRInfo::argumentFPR2;
else {
ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1);
temp = FPRInfo::argumentFPR1;
}
m_jit.moveDouble(destA, temp);
m_jit.moveDouble(destB, destA);
m_jit.moveDouble(temp, destB);
}
void setupStubArguments(GPRReg arg1, GPRReg arg2)
{
setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
}
void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) {
m_jit.move(arg1, GPRInfo::argumentGPR1);
setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3);
return;
}
if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) {
m_jit.move(arg2, GPRInfo::argumentGPR2);
setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
return;
}
if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) {
m_jit.move(arg3, GPRInfo::argumentGPR3);
setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
return;
}
if (arg1 != GPRInfo::argumentGPR1) {
m_jit.swap(arg1, GPRInfo::argumentGPR1);
ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1);
if (arg2 == GPRInfo::argumentGPR1)
arg2 = arg1;
else
arg3 = arg1;
}
ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3)
|| (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2));
if (arg2 != GPRInfo::argumentGPR2)
m_jit.swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
}
void callOperation(J_DFGOperation_EP operation, GPRReg result, void* pointer)
{
ASSERT(isFlushed());
m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR1);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(J_DFGOperation_EI operation, GPRReg result, Identifier* identifier)
{
callOperation((J_DFGOperation_EP)operation, result, identifier);
}
void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
{
ASSERT(isFlushed());
m_jit.move(arg1, GPRInfo::argumentGPR1);
m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR2);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
{
callOperation((J_DFGOperation_EJP)operation, result, arg1, identifier);
}
void callOperation(J_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
{
ASSERT(isFlushed());
m_jit.move(arg1, GPRInfo::argumentGPR1);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
{
ASSERT(isFlushed());
m_jit.move(arg1, GPRInfo::argumentGPR1);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
ASSERT(isFlushed());
setupStubArguments(arg1, arg2);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
ASSERT(isFlushed());
setupStubArguments(arg1, arg2);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
m_jit.move(GPRInfo::returnValueGPR, result);
}
void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
{
ASSERT(isFlushed());
setupStubArguments(arg1, arg2);
m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR3);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
}
void callOperation(V_DFGOperation_EJJI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
{
callOperation((V_DFGOperation_EJJP)operation, arg1, arg2, identifier);
}
void callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
ASSERT(isFlushed());
setupStubArguments(arg1, arg2, arg3);
m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
appendCallWithExceptionCheck(operation);
}
void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
{
ASSERT(isFlushed());
setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
m_jit.appendCall(operation);
m_jit.moveDouble(FPRInfo::returnValueFPR, result);
}
JITCompiler::Call appendCallWithExceptionCheck(const FunctionPtr& function)
{
return m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
}
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);
}
}
#ifndef NDEBUG
void dump(const char* label = 0);
#endif
#if DFG_CONSISTENCY_CHECK
void checkConsistency();
#else
void checkConsistency() {}
#endif
JITCompiler& m_jit;
bool m_isSpeculative;
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;
};
class IntegerOperand {
public:
explicit IntegerOperand(JITCodeGenerator* 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:
JITCodeGenerator* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
DataFormat m_format;
};
class DoubleOperand {
public:
explicit DoubleOperand(JITCodeGenerator* 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:
JITCodeGenerator* m_jit;
NodeIndex m_index;
FPRReg m_fprOrInvalid;
};
class JSValueOperand {
public:
explicit JSValueOperand(JITCodeGenerator* jit, NodeIndex index)
: m_jit(jit)
, m_index(index)
, m_gprOrInvalid(InvalidGPRReg)
{
ASSERT(m_jit);
if (jit->isFilled(index))
gpr();
}
~JSValueOperand()
{
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->fillJSValue(index());
return m_gprOrInvalid;
}
void use()
{
m_jit->use(m_index);
}
private:
JITCodeGenerator* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
class GPRTemporary {
public:
GPRTemporary(JITCodeGenerator*);
GPRTemporary(JITCodeGenerator*, GPRReg specific);
GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&);
GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
GPRTemporary(JITCodeGenerator*, IntegerOperand&);
GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
GPRTemporary(JITCodeGenerator*, JSValueOperand&);
~GPRTemporary()
{
m_jit->unlock(gpr());
}
GPRReg gpr()
{
ASSERT(m_gpr != InvalidGPRReg);
return m_gpr;
}
private:
JITCodeGenerator* m_jit;
GPRReg m_gpr;
};
class FPRTemporary {
public:
FPRTemporary(JITCodeGenerator*);
FPRTemporary(JITCodeGenerator*, DoubleOperand&);
FPRTemporary(JITCodeGenerator*, DoubleOperand&, DoubleOperand&);
FPRTemporary(JITCodeGenerator*, SpeculateDoubleOperand&);
FPRTemporary(JITCodeGenerator*, SpeculateDoubleOperand&, SpeculateDoubleOperand&);
~FPRTemporary()
{
m_jit->unlock(fpr());
}
FPRReg fpr() const
{
ASSERT(m_fpr != InvalidFPRReg);
return m_fpr;
}
protected:
FPRTemporary(JITCodeGenerator* jit, FPRReg lockedFPR)
: m_jit(jit)
, m_fpr(lockedFPR)
{
}
private:
JITCodeGenerator* m_jit;
FPRReg m_fpr;
};
class GPRResult : public GPRTemporary {
public:
GPRResult(JITCodeGenerator* jit)
: GPRTemporary(jit, GPRInfo::returnValueGPR)
{
}
};
class FPRResult : public FPRTemporary {
public:
FPRResult(JITCodeGenerator* jit)
: FPRTemporary(jit, lockedResult(jit))
{
}
private:
static FPRReg lockedResult(JITCodeGenerator* jit)
{
jit->lock(FPRInfo::returnValueFPR);
return FPRInfo::returnValueFPR;
}
};
} }
#endif
#endif