summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGGraph.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGraph.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h297
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