blob: fb729063d977f6e6988ce43cd41d89811dba1fe0 [file] [log] [blame]
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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;
// NOTE: the offset and identifierNumber do not by themselves
// uniquely identify a property. The identifierNumber and a
// Structure* do. If those two match, then the offset should
// be the same, as well. For any Node that has a StorageAccessData,
// it is possible to retrieve the Structure* by looking at the
// first child. It should be a CheckStructure, which has the
// Structure*.
};
struct ResolveGlobalData {
unsigned identifierNumber;
unsigned resolveInfoIndex;
};
//
// === Graph ===
//
// The dataflow graph is an ordered vector of nodes.
// The order may be significant for nodes with side-effects (property accesses, value conversions).
// Nodes that are 'dead' remain in the vector with refCount 0.
class Graph : public Vector<Node, 64> {
public:
// Mark a node as being referenced.
void ref(NodeIndex nodeIndex)
{
Node& node = at(nodeIndex);
// If the value (before incrementing) was at refCount zero then we need to ref its children.
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
// CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
void dump(CodeBlock* = 0);
void dump(NodeIndex, CodeBlock* = 0);
// Dump the code origin of the given node as a diff from the code origin of the
// preceding node.
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));
}
// Helper methods to check nodes for constants.
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;
}
// Helper methods get constant values from nodes.
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);
// This is O(n), and should only be used for verbose dumps.
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);
}
// Nodes derives from calls need special handling because the value profile is
// associated with the op_call_put_result instruction.
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:
// When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
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));
}
} } // namespace JSC::DFG
#endif
#endif