2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "CodeBlock.h"
32 #include "DFGBasicBlock.h"
34 #include "PredictionTracker.h"
35 #include "RegisterFile.h"
36 #include <wtf/BitVector.h>
37 #include <wtf/HashMap.h>
38 #include <wtf/Vector.h>
39 #include <wtf/StdLibExtras.h>
48 struct StorageAccessData {
50 unsigned identifierNumber;
52 // NOTE: the offset and identifierNumber do not by themselves
53 // uniquely identify a property. The identifierNumber and a
54 // Structure* do. If those two match, then the offset should
55 // be the same, as well. For any Node that has a StorageAccessData,
56 // it is possible to retrieve the Structure* by looking at the
57 // first child. It should be a CheckStructure, which has the
61 struct ResolveGlobalData {
62 unsigned identifierNumber;
63 unsigned resolveInfoIndex;
69 // The dataflow graph is an ordered vector of nodes.
70 // The order may be significant for nodes with side-effects (property accesses, value conversions).
71 // Nodes that are 'dead' remain in the vector with refCount 0.
72 class Graph : public Vector<Node, 64> {
74 // Mark a node as being referenced.
75 void ref(NodeIndex nodeIndex)
77 Node& node = at(nodeIndex);
78 // If the value (before incrementing) was at refCount zero then we need to ref its children.
80 refChildren(nodeIndex);
84 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
85 void dump(CodeBlock* = 0);
86 void dump(NodeIndex, CodeBlock* = 0);
88 // Dump the code origin of the given node as a diff from the code origin of the
90 void dumpCodeOrigin(NodeIndex);
93 BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin);
95 bool predictGlobalVar(unsigned varNumber, PredictedType prediction)
97 return m_predictions.predictGlobalVar(varNumber, prediction);
100 PredictedType getGlobalVarPrediction(unsigned varNumber)
102 return m_predictions.getGlobalVarPrediction(varNumber);
105 PredictedType getJSConstantPrediction(Node& node, CodeBlock* codeBlock)
107 return predictionFromValue(node.valueOfJSConstant(codeBlock));
110 // Helper methods to check nodes for constants.
111 bool isConstant(NodeIndex nodeIndex)
113 return at(nodeIndex).hasConstant();
115 bool isJSConstant(NodeIndex nodeIndex)
117 return at(nodeIndex).hasConstant();
119 bool isInt32Constant(CodeBlock* codeBlock, NodeIndex nodeIndex)
121 return at(nodeIndex).isInt32Constant(codeBlock);
123 bool isDoubleConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
125 return at(nodeIndex).isDoubleConstant(codeBlock);
127 bool isNumberConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
129 return at(nodeIndex).isNumberConstant(codeBlock);
131 bool isBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
133 return at(nodeIndex).isBooleanConstant(codeBlock);
135 bool isFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
137 if (!isJSConstant(nodeIndex))
139 if (!getJSFunction(valueOfJSConstant(codeBlock, nodeIndex)))
143 // Helper methods get constant values from nodes.
144 JSValue valueOfJSConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
146 return at(nodeIndex).valueOfJSConstant(codeBlock);
148 int32_t valueOfInt32Constant(CodeBlock* codeBlock, NodeIndex nodeIndex)
150 return valueOfJSConstant(codeBlock, nodeIndex).asInt32();
152 double valueOfNumberConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
154 return valueOfJSConstant(codeBlock, nodeIndex).asNumber();
156 bool valueOfBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
158 return valueOfJSConstant(codeBlock, nodeIndex).asBoolean();
160 JSFunction* valueOfFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
162 JSCell* function = getJSFunction(valueOfJSConstant(codeBlock, nodeIndex));
164 return asFunction(function);
168 static const char *opName(NodeType);
170 // This is O(n), and should only be used for verbose dumps.
171 const char* nameOfVariableAccessData(VariableAccessData*);
174 void predictArgumentTypes(CodeBlock*);
176 StructureSet* addStructureSet(const StructureSet& structureSet)
178 ASSERT(structureSet.size());
179 m_structureSet.append(structureSet);
180 return &m_structureSet.last();
183 StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData)
185 m_structureTransitionData.append(structureTransitionData);
186 return &m_structureTransitionData.last();
189 ValueProfile* valueProfileFor(NodeIndex nodeIndex, CodeBlock* profiledBlock)
191 if (nodeIndex == NoNode)
194 Node& node = at(nodeIndex);
198 if (!operandIsArgument(node.local()))
200 int argument = node.local() + m_arguments.size() + RegisterFile::CallFrameHeaderSize;
201 if (node.variableAccessData() != at(m_arguments[argument]).variableAccessData())
203 return profiledBlock->valueProfileForArgument(argument);
206 // Nodes derives from calls need special handling because the value profile is
207 // associated with the op_call_put_result instruction.
212 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
213 return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex + OPCODE_LENGTH(op_call));
217 if (node.hasHeapPrediction())
218 return profiledBlock->valueProfileForBytecodeOffset(node.codeOrigin.bytecodeIndex);
223 Vector< OwnPtr<BasicBlock> , 8> m_blocks;
224 Vector<NodeIndex, 16> m_varArgChildren;
225 Vector<StorageAccessData> m_storageAccessData;
226 Vector<ResolveGlobalData> m_resolveGlobalData;
227 Vector<NodeIndex, 8> m_arguments;
228 SegmentedVector<VariableAccessData, 16> m_variableAccessData;
229 SegmentedVector<StructureSet, 16> m_structureSet;
230 SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
231 BitVector m_preservedVars;
232 unsigned m_localVars;
233 unsigned m_parameterSlots;
236 // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
237 void refChildren(NodeIndex);
239 PredictionTracker m_predictions;
242 class GetBytecodeBeginForBlock {
244 GetBytecodeBeginForBlock(Graph& graph)
249 unsigned operator()(BlockIndex* blockIndex) const
251 return m_graph.m_blocks[*blockIndex]->bytecodeBegin;
258 inline BlockIndex Graph::blockIndexForBytecodeOffset(Vector<BlockIndex>& linkingTargets, unsigned bytecodeBegin)
260 return *WTF::binarySearchWithFunctor<BlockIndex, unsigned>(linkingTargets.begin(), linkingTargets.size(), bytecodeBegin, WTF::KeyMustBePresentInArray, GetBytecodeBeginForBlock(*this));
263 } } // namespace JSC::DFG