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;
};
RegisterInfo m_gprInfo[GPRInfo::numberOfRegisters];
NodeIndex 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);
GPRReg fillSpeculateCell(NodeIndex);
private:
void compile(Node&);
void compile(BasicBlock&);
void checkArgumentTypes();
void initializeVariableTypes();
bool isDoubleConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
{
if (!m_jit.isDoubleConstant(nodeIndex))
return false;
double value = m_jit.valueOfDoubleConstant(nodeIndex);
int32_t asInt32 = static_cast<int32_t>(value);
if (value != asInt32)
return false;
if (!asInt32 && signbit(value))
return false;
out = asInt32;
return true;
}
bool isJSConstantWithInt32Value(NodeIndex nodeIndex, int32_t& out)
{
if (!m_jit.isJSConstant(nodeIndex))
return false;
JSValue value = m_jit.valueOfJSConstant(nodeIndex);
if (!value.isInt32())
return false;
out = value.asInt32();
return true;
}
bool detectPeepHoleBranch()
{
if (m_compileIndex + 2 != m_jit.graph().m_blocks[m_block]->end)
return false;
Node& lastNode = m_jit.graph()[m_compileIndex + 1];
return lastNode.op == Branch && lastNode.child1 == m_compileIndex;
}
void compilePeepHoleBranch(Node&, JITCompiler::RelationalCondition);
void speculationCheck(MacroAssembler::Jump jumpToFail)
{
m_speculationChecks.append(SpeculationCheck(jumpToFail, this));
}
void speculationCheck(MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
{
m_speculationRecoveryList.append(recovery);
m_speculationChecks.append(SpeculationCheck(jumpToFail, this, m_speculationRecoveryList.size()));
}
void terminateSpeculativeExecution()
{
m_compileOkay = false;
speculationCheck(m_jit.jump());
}
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;
}
private:
SpeculativeJIT* m_jit;
NodeIndex m_index;
GPRReg m_gprOrInvalid;
};
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;
}
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