diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGraph.h')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGGraph.h | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h new file mode 100644 index 000000000..fb729063d --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -0,0 +1,297 @@ +/* + * 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 |