#ifndef DFGGraph_h
#define DFGGraph_h
#if ENABLE(DFG_JIT)
#include "CodeBlock.h"
#include "DFGBasicBlock.h"
#include "DFGNode.h"
#include "PredictionTracker.h"
#include "RegisterFile.h"
#include <wtf/BitVector.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
#include <wtf/StdLibExtras.h>
namespace JSC {
class CodeBlock;
class ExecState;
namespace DFG {
struct StorageAccessData {
size_t offset;
unsigned identifierNumber;
};
struct ResolveGlobalData {
unsigned identifierNumber;
unsigned resolveInfoIndex;
};
class Graph : public Vector<Node, 64> {
public:
void ref(NodeIndex nodeIndex)
{
Node& node = at(nodeIndex);
if (node.ref())
refChildren(nodeIndex);
}
void deref(NodeIndex nodeIndex)
{
if (at(nodeIndex).deref())
derefChildren(nodeIndex);
}
void clearAndDerefChild1(Node& node)
{
if (node.children.fixed.child1 == NoNode)
return;
deref(node.children.fixed.child1);
node.children.fixed.child1 = NoNode;
}
void clearAndDerefChild2(Node& node)
{
if (node.children.fixed.child2 == NoNode)
return;
deref(node.children.fixed.child2);
node.children.fixed.child2 = NoNode;
}
void clearAndDerefChild3(Node& node)
{
if (node.children.fixed.child3 == NoNode)
return;
deref(node.children.fixed.child3);
node.children.fixed.child3 = NoNode;
}
#ifndef NDEBUG
void dump(CodeBlock* = 0);
void dump(NodeIndex, CodeBlock* = 0);
void dumpCodeOrigin(NodeIndex);
#endif
BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin);
bool predictGlobalVar(unsigned varNumber, PredictedType prediction)
{
return m_predictions.predictGlobalVar(varNumber, prediction);
}
PredictedType getGlobalVarPrediction(unsigned varNumber)
{
return m_predictions.getGlobalVarPrediction(varNumber);
}
PredictedType getJSConstantPrediction(Node& node, CodeBlock* codeBlock)
{
return predictionFromValue(node.valueOfJSConstant(codeBlock));
}
bool isConstant(NodeIndex nodeIndex)
{
return at(nodeIndex).hasConstant();
}
bool isJSConstant(NodeIndex nodeIndex)
{
return at(nodeIndex).hasConstant();
}
bool isInt32Constant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return at(nodeIndex).isInt32Constant(codeBlock);
}
bool isDoubleConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return at(nodeIndex).isDoubleConstant(codeBlock);
}
bool isNumberConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return at(nodeIndex).isNumberConstant(codeBlock);
}
bool isBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return at(nodeIndex).isBooleanConstant(codeBlock);
}
bool isFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
if (!isJSConstant(nodeIndex))
return false;
if (!getJSFunction(valueOfJSConstant(codeBlock, nodeIndex)))
return false;
return true;
}
JSValue valueOfJSConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return at(nodeIndex).valueOfJSConstant(codeBlock);
}
int32_t valueOfInt32Constant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return valueOfJSConstant(codeBlock, nodeIndex).asInt32();
}
double valueOfNumberConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return valueOfJSConstant(codeBlock, nodeIndex).asNumber();
}
bool valueOfBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
return valueOfJSConstant(codeBlock, nodeIndex).asBoolean();
}
JSFunction* valueOfFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
{
JSCell* function = getJSFunction(valueOfJSConstant(codeBlock, nodeIndex));
ASSERT(function);
return asFunction(function);
}
#ifndef NDEBUG
static const char *opName(NodeType);
const char* nameOfVariableAccessData(VariableAccessData*);
#endif
void predictArgumentTypes(CodeBlock*);
StructureSet* addStructureSet(const StructureSet& structureSet)
{
ASSERT(structureSet.size());
m_structureSet.append(structureSet);
return &m_structureSet.last();
}
StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
{
m_structureTransitionData.append(structureTransitionData);
return &m_structureTransitionData.last();
}
ValueProfile* valueProfileFor(NodeIndex nodeIndex, CodeBlock* profiledBlock)
{
if (nodeIndex == NoNode)
return 0;
Node& node = at(nodeIndex);
switch (node.op) {
case GetLocal: {
if (!operandIsArgument(node.local()))
return 0;
int argument = operandToArgument(node.local());
if (node.variableAccessData() != at(m_arguments[argument]).variableAccessData())
return 0;
return profiledBlock->valueProfileForArgument(argument);
}
case Call:
case Construct:
case ArrayPop:
case ArrayPush: {
ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex + OPCODE_LENGTH(op_call));
}
default:
if (node.hasHeapPrediction())
return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex);
return 0;
}
}
Vector< OwnPtr<BasicBlock> , 8> m_blocks;
Vector<NodeIndex, 16> m_varArgChildren;
Vector<StorageAccessData> m_storageAccessData;
Vector<ResolveGlobalData> m_resolveGlobalData;
Vector<NodeIndex, 8> m_arguments;
SegmentedVector<VariableAccessData, 16> m_variableAccessData;
SegmentedVector<StructureSet, 16> m_structureSet;
SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
BitVector m_preservedVars;
unsigned m_localVars;
unsigned m_parameterSlots;
private:
void refChildren(NodeIndex);
void derefChildren(NodeIndex);
PredictionTracker m_predictions;
};
class GetBytecodeBeginForBlock {
public:
GetBytecodeBeginForBlock(Graph& graph)
: m_graph(graph)
{
}
unsigned operator()(BlockIndex* blockIndex) const
{
return m_graph.m_blocks[*blockIndex]->bytecodeBegin;
}
private:
Graph& m_graph;
};
inline BlockIndex Graph::blockIndexForBytecodeOffset(Vector<BlockIndex>& linkingTargets, unsigned bytecodeBegin)
{
return *WTF::binarySearchWithFunctor<BlockIndex, unsigned>(linkingTargets.begin(), linkingTargets.size(), bytecodeBegin, WTF::KeyMustBePresentInArray, GetBytecodeBeginForBlock(*this));
}
} }
#endif
#endif