DFGSpeculativeJIT.h [plain text]
#ifndef DFGSpeculativeJIT_h
#define DFGSpeculativeJIT_h
#if ENABLE(DFG_JIT)
#include <dfg/DFGJITCodeGenerator.h>
namespace JSC { namespace DFG {
class SpeculativeJIT;
enum SpeculationRecoveryType {
SpeculativeAdd
};
class SpeculationRecovery {
public:
SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
: m_type(type)
, m_dest(dest)
, m_src(src)
{
}
SpeculationRecoveryType type() { return m_type; }
GPRReg dest() { return m_dest; }
GPRReg src() { return m_src; }
private:
SpeculationRecoveryType m_type;
GPRReg m_dest;
GPRReg m_src;
};
struct SpeculationCheck {
SpeculationCheck(MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0);
MacroAssembler::Jump m_check;
NodeIndex m_nodeIndex;
unsigned m_recoveryIndex;
struct RegisterInfo {
NodeIndex nodeIndex;
DataFormat format;
bool isSpilled;
};
RegisterInfo m_gprInfo[GPRInfo::numberOfRegisters];
RegisterInfo m_fprInfo[FPRInfo::numberOfRegisters];
};
typedef SegmentedVector<SpeculationCheck, 16> SpeculationCheckVector;
class SpeculativeJIT : public JITCodeGenerator {
friend struct SpeculationCheck;
public:
SpeculativeJIT(JITCompiler& jit)
: JITCodeGenerator(jit, true)
, m_compileOkay(true)
{
}
bool compile();
SpeculationCheckVector& speculationChecks()
{
return m_speculationChecks;
}
SpeculationRecovery* speculationRecovery(size_t index)
{
return index ? &m_speculationRecoveryList[index - 1] : 0;
}
GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat);
GPRReg fillSpeculateIntStrict(NodeIndex);
FPRReg fillSpeculateDouble(NodeIndex);
GPRReg fillSpeculateCell(NodeIndex);
private:
void compile(Node&);
void compile(BasicBlock&);
void checkArgumentTypes();
void initializeVariableTypes();
bool isInteger(NodeIndex nodeIndex)
{
Node& node = m_jit.graph()[nodeIndex];
if (node.hasInt32Result())
return true;
if (isInt32Constant(nodeIndex))
return true;
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
return (info.registerFormat() | DataFormatJS) == DataFormatJSInteger
|| (info.spillFormat() | DataFormatJS) == DataFormatJSInteger;
}
bool shouldSpeculateInteger(NodeIndex nodeIndex)
{
if (isInteger(nodeIndex))
return true;
if (isInt32Prediction(m_jit.graph().getPrediction(m_jit.graph()[nodeIndex])))
return true;
return false;
}
bool shouldSpeculateDouble(NodeIndex nodeIndex)
{
Node& node = m_jit.graph()[nodeIndex];
VirtualRegister virtualRegister = node.virtualRegister();
GenerationInfo& info = m_generationInfo[virtualRegister];
if ((info.registerFormat() | DataFormatJS) == DataFormatJSDouble
|| (info.spillFormat() | DataFormatJS) == DataFormatJSDouble)
return true;
if (isDoublePrediction(m_jit.graph().getPrediction(node)))
return true;
return false;
}
bool shouldSpeculateInteger(NodeIndex op1, NodeIndex op2)
{
return !(shouldSpeculateDouble(op1) || shouldSpeculateDouble(op2)) && (shouldSpeculateInteger(op1) || shouldSpeculateInteger(op2));
}
bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, Z_DFGOperation_EJJ);
void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition, Z_DFGOperation_EJJ);
JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);
void speculationCheck(MacroAssembler::Jump jumpToFail)
{
if (!m_compileOkay)
return;
m_speculationChecks.append(SpeculationCheck(jumpToFail, this));
}
void speculationCheck(MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
if (!m_compileOkay)
return;
m_speculationRecoveryList.append(recovery);
m_speculationChecks.append(SpeculationCheck(jumpToFail, this, m_speculationRecoveryList.size()));
}
void terminateSpeculativeExecution()
{
m_compileOkay = false;
}
template<bool strict>
GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
bool m_compileOkay;
SpeculationCheckVector m_speculationChecks;
Vector<SpeculationRecovery, 16> m_speculationRecoveryList;
};
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 SpeculationCheckIndexIterator {
public:
SpeculationCheckIndexIterator(SpeculationCheckVector& speculationChecks)
: m_speculationChecks(speculationChecks)
, m_iter(m_speculationChecks.begin())
, m_end(m_speculationChecks.end())
{
}
bool hasCheckAtIndex(NodeIndex nodeIndex)
{
while (m_iter != m_end) {
NodeIndex current = m_iter->m_nodeIndex;
if (current >= nodeIndex)
return current == nodeIndex;
++m_iter;
}
return false;
}
private:
SpeculationCheckVector& m_speculationChecks;
SpeculationCheckVector::Iterator m_iter;
SpeculationCheckVector::Iterator m_end;
};
} }
#endif
#endif