#ifndef DFGNode_h
#define DFGNode_h
#define DFG_DEBUG_VERBOSE 0
#define DFG_JIT_ASSERT 0
#define DFG_CONSISTENCY_CHECK 0
#define DFG_JIT_BREAK_ON_EVERY_FUNCTION 0
#define DFG_JIT_BREAK_ON_EVERY_BLOCK 0
#define DFG_JIT_BREAK_ON_EVERY_NODE 0
#define DFG_JIT_BREAK_ON_SPECULATION_FAILURE 0
#define DFG_DEBUG_LOCAL_DISBALE 0
#define DFG_DEBUG_LOCAL_DISBALE_SPECULATIVE 0
#define DFG_SUCCESS_STATS 0
#if ENABLE(DFG_JIT)
#include <wtf/Vector.h>
namespace JSC { namespace DFG {
enum VirtualRegister { InvalidVirtualRegister = -1 };
COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit);
typedef uint32_t NodeIndex;
static const NodeIndex NoNode = UINT_MAX;
typedef uint32_t ExceptionInfo;
#define NodeIdMask 0xFFF
#define NodeResultMask 0xF000
#define NodeMustGenerate 0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE.
#define NodeIsConstant 0x20000
#define NodeIsJump 0x40000
#define NodeIsBranch 0x80000
#define NodeIsTerminal 0x100000
#define NodeHasVarArgs 0x200000
#define NodeResultJS 0x1000
#define NodeResultDouble 0x2000
#define NodeResultInt32 0x3000
#define FOR_EACH_DFG_OP(macro) \
\
macro(JSConstant, NodeResultJS) \
macro(ConvertThis, NodeResultJS) \
\
\
macro(GetLocal, NodeResultJS) \
macro(SetLocal, 0) \
macro(Phi, 0) \
\
\
macro(BitAnd, NodeResultInt32) \
macro(BitOr, NodeResultInt32) \
macro(BitXor, NodeResultInt32) \
macro(BitLShift, NodeResultInt32) \
macro(BitRShift, NodeResultInt32) \
macro(BitURShift, NodeResultInt32) \
\
macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
\
macro(UInt32ToNumber, NodeResultDouble) \
\
\
macro(ArithAdd, NodeResultDouble) \
macro(ArithSub, NodeResultDouble) \
macro(ArithMul, NodeResultDouble) \
macro(ArithDiv, NodeResultDouble) \
macro(ArithMod, NodeResultDouble) \
\
macro(ValueToNumber, NodeResultDouble | NodeMustGenerate) \
\
\
macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
\
\
\
\
\
macro(GetByVal, NodeResultJS | NodeMustGenerate) \
macro(PutByVal, NodeMustGenerate) \
macro(PutByValAlias, NodeMustGenerate) \
macro(GetById, NodeResultJS | NodeMustGenerate) \
macro(PutById, NodeMustGenerate) \
macro(PutByIdDirect, NodeMustGenerate) \
macro(GetMethod, NodeResultJS | NodeMustGenerate) \
macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \
macro(PutGlobalVar, NodeMustGenerate) \
\
\
macro(CompareLess, NodeResultJS | NodeMustGenerate) \
macro(CompareLessEq, NodeResultJS | NodeMustGenerate) \
macro(CompareGreater, NodeResultJS | NodeMustGenerate) \
macro(CompareGreaterEq, NodeResultJS | NodeMustGenerate) \
macro(CompareEq, NodeResultJS | NodeMustGenerate) \
macro(CompareStrictEq, NodeResultJS) \
\
\
macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
macro(Construct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
\
\
macro(Resolve, NodeResultJS | NodeMustGenerate) \
macro(ResolveBase, NodeResultJS | NodeMustGenerate) \
macro(ResolveBaseStrictPut, NodeResultJS | NodeMustGenerate) \
\
\
macro(Breakpoint, NodeMustGenerate) \
macro(CheckHasInstance, NodeMustGenerate) \
macro(InstanceOf, NodeResultJS) \
macro(LogicalNot, NodeResultJS) \
\
\
macro(Jump, NodeMustGenerate | NodeIsTerminal | NodeIsJump) \
macro(Branch, NodeMustGenerate | NodeIsTerminal | NodeIsBranch) \
macro(Return, NodeMustGenerate | NodeIsTerminal)
enum NodeId {
#define DFG_OP_ENUM(opcode, flags) opcode##_id,
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
};
enum NodeType {
#define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags),
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
};
struct OpInfo {
explicit OpInfo(unsigned value) : m_value(value) {}
unsigned m_value;
};
typedef uint8_t PredictedType;
static const PredictedType PredictNone = 0;
static const PredictedType PredictCell = 0x01;
static const PredictedType PredictArray = 0x03;
static const PredictedType PredictInt32 = 0x04;
static const PredictedType PredictDouble = 0x08;
static const PredictedType PredictNumber = 0x0c;
inline bool isCellPrediction(PredictedType value)
{
return (value & PredictCell) == PredictCell && !(value & ~PredictArray);
}
inline bool isArrayPrediction(PredictedType value)
{
return value == PredictArray;
}
inline bool isInt32Prediction(PredictedType value)
{
return value == PredictInt32;
}
inline bool isDoublePrediction(PredictedType value)
{
return value == PredictDouble;
}
inline bool isNumberPrediction(PredictedType value)
{
return !!(value & PredictNumber) && !(value & ~PredictNumber);
}
#ifndef NDEBUG
inline const char* predictionToString(PredictedType value)
{
switch (value) {
case PredictNone:
return "p-bottom";
case PredictCell:
return "p-cell";
case PredictArray:
return "p-array";
case PredictInt32:
return "p-int32";
case PredictNumber:
return "p-number";
default:
return "p-top";
}
}
#endif
struct Node {
enum VarArgTag { VarArg };
Node(NodeType op, ExceptionInfo exceptionInfo, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
: op(op)
, exceptionInfo(exceptionInfo)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
{
ASSERT(!(op & NodeHasVarArgs));
children.fixed.child1 = child1;
children.fixed.child2 = child2;
children.fixed.child3 = child3;
}
Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
: op(op)
, exceptionInfo(exceptionInfo)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
, m_opInfo(imm.m_value)
{
ASSERT(!(op & NodeHasVarArgs));
children.fixed.child1 = child1;
children.fixed.child2 = child2;
children.fixed.child3 = child3;
}
Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode)
: op(op)
, exceptionInfo(exceptionInfo)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
, m_opInfo(imm1.m_value)
, m_opInfo2(imm2.m_value)
{
ASSERT(!(op & NodeHasVarArgs));
children.fixed.child1 = child1;
children.fixed.child2 = child2;
children.fixed.child3 = child3;
}
Node(VarArgTag, NodeType op, ExceptionInfo exceptionInfo, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren)
: op(op)
, exceptionInfo(exceptionInfo)
, m_virtualRegister(InvalidVirtualRegister)
, m_refCount(0)
, m_opInfo(imm1.m_value)
, m_opInfo2(imm2.m_value)
{
ASSERT(op & NodeHasVarArgs);
children.variable.firstChild = firstChild;
children.variable.numChildren = numChildren;
}
bool mustGenerate()
{
return op & NodeMustGenerate;
}
bool isConstant()
{
return op == JSConstant;
}
unsigned constantNumber()
{
ASSERT(isConstant());
return m_opInfo;
}
bool hasLocal()
{
return op == GetLocal || op == SetLocal;
}
VirtualRegister local()
{
ASSERT(hasLocal());
return (VirtualRegister)m_opInfo;
}
#if !ASSERT_DISABLED
bool hasIdentifier()
{
return op == GetById || op == PutById || op == PutByIdDirect || op == GetMethod
|| op == Resolve || op == ResolveBase || op == ResolveBaseStrictPut;
}
#endif
unsigned identifierNumber()
{
ASSERT(hasIdentifier());
return m_opInfo;
}
bool hasVarNumber()
{
return op == GetGlobalVar || op == PutGlobalVar;
}
unsigned varNumber()
{
ASSERT(hasVarNumber());
return m_opInfo;
}
bool hasResult()
{
return op & NodeResultMask;
}
bool hasInt32Result()
{
return (op & NodeResultMask) == NodeResultInt32;
}
bool hasDoubleResult()
{
return (op & NodeResultMask) == NodeResultDouble;
}
bool hasJSResult()
{
return (op & NodeResultMask) == NodeResultJS;
}
bool hasNumericResult()
{
ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult());
return !hasJSResult();
}
bool isJump()
{
return op & NodeIsJump;
}
bool isBranch()
{
return op & NodeIsBranch;
}
bool isTerminal()
{
return op & NodeIsTerminal;
}
unsigned takenBytecodeOffset()
{
ASSERT(isBranch() || isJump());
return m_opInfo;
}
unsigned notTakenBytecodeOffset()
{
ASSERT(isBranch());
return m_opInfo2;
}
bool hasPrediction()
{
switch (op) {
case GetById:
case GetMethod:
case GetByVal:
case Call:
case Construct:
return true;
default:
return false;
}
}
PredictedType getPrediction()
{
ASSERT(hasPrediction());
return static_cast<PredictedType>(m_opInfo2);
}
void predict(PredictedType prediction)
{
ASSERT(hasPrediction());
m_opInfo2 |= prediction;
}
VirtualRegister virtualRegister()
{
ASSERT(hasResult());
ASSERT(m_virtualRegister != InvalidVirtualRegister);
return m_virtualRegister;
}
void setVirtualRegister(VirtualRegister virtualRegister)
{
ASSERT(hasResult());
ASSERT(m_virtualRegister == InvalidVirtualRegister);
m_virtualRegister = virtualRegister;
}
bool shouldGenerate()
{
return m_refCount && op != Phi;
}
unsigned refCount()
{
return m_refCount;
}
bool ref()
{
return !m_refCount++;
}
unsigned adjustedRefCount()
{
return mustGenerate() ? m_refCount - 1 : m_refCount;
}
NodeIndex child1()
{
ASSERT(!(op & NodeHasVarArgs));
return children.fixed.child1;
}
NodeIndex child2()
{
ASSERT(!(op & NodeHasVarArgs));
return children.fixed.child2;
}
NodeIndex child3()
{
ASSERT(!(op & NodeHasVarArgs));
return children.fixed.child3;
}
unsigned firstChild()
{
ASSERT(op & NodeHasVarArgs);
return children.variable.firstChild;
}
unsigned numChildren()
{
ASSERT(op & NodeHasVarArgs);
return children.variable.numChildren;
}
NodeType op;
ExceptionInfo exceptionInfo;
union {
struct {
NodeIndex child1, child2, child3;
} fixed;
struct {
unsigned firstChild;
unsigned numChildren;
} variable;
} children;
private:
VirtualRegister m_virtualRegister;
unsigned m_refCount;
unsigned m_opInfo, m_opInfo2;
};
} }
#endif
#endif