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 "DFGArgumentPosition.h"
33 #include "DFGAssemblyHelpers.h"
34 #include "DFGBasicBlock.h"
36 #include "MethodOfGettingAValueProfile.h"
37 #include "RegisterFile.h"
38 #include <wtf/BitVector.h>
39 #include <wtf/HashMap.h>
40 #include <wtf/Vector.h>
41 #include <wtf/StdLibExtras.h>
50 struct StorageAccessData
{
52 unsigned identifierNumber
;
54 // NOTE: the offset and identifierNumber do not by themselves
55 // uniquely identify a property. The identifierNumber and a
56 // Structure* do. If those two match, then the offset should
57 // be the same, as well. For any Node that has a StorageAccessData,
58 // it is possible to retrieve the Structure* by looking at the
59 // first child. It should be a CheckStructure, which has the
63 struct ResolveGlobalData
{
64 unsigned identifierNumber
;
65 unsigned resolveInfoIndex
;
71 // The dataflow graph is an ordered vector of nodes.
72 // The order may be significant for nodes with side-effects (property accesses, value conversions).
73 // Nodes that are 'dead' remain in the vector with refCount 0.
74 class Graph
: public Vector
<Node
, 64> {
76 Graph(JSGlobalData
& globalData
, CodeBlock
* codeBlock
)
77 : m_globalData(globalData
)
78 , m_codeBlock(codeBlock
)
79 , m_profiledBlock(codeBlock
->alternative())
81 ASSERT(m_profiledBlock
);
84 using Vector
<Node
, 64>::operator[];
85 using Vector
<Node
, 64>::at
;
87 Node
& operator[](Edge nodeUse
) { return at(nodeUse
.index()); }
88 const Node
& operator[](Edge nodeUse
) const { return at(nodeUse
.index()); }
90 Node
& at(Edge nodeUse
) { return at(nodeUse
.index()); }
91 const Node
& at(Edge nodeUse
) const { return at(nodeUse
.index()); }
93 // Mark a node as being referenced.
94 void ref(NodeIndex nodeIndex
)
96 Node
& node
= at(nodeIndex
);
97 // If the value (before incrementing) was at refCount zero then we need to ref its children.
99 refChildren(nodeIndex
);
101 void ref(Edge nodeUse
)
103 ref(nodeUse
.index());
106 void deref(NodeIndex nodeIndex
)
108 if (at(nodeIndex
).deref())
109 derefChildren(nodeIndex
);
111 void deref(Edge nodeUse
)
113 deref(nodeUse
.index());
116 void clearAndDerefChild1(Node
& node
)
120 deref(node
.child1());
121 node
.children
.child1() = Edge();
124 void clearAndDerefChild2(Node
& node
)
128 deref(node
.child2());
129 node
.children
.child2() = Edge();
132 void clearAndDerefChild3(Node
& node
)
136 deref(node
.child3());
137 node
.children
.child3() = Edge();
140 // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
142 void dump(NodeIndex
);
144 // Dump the code origin of the given node as a diff from the code origin of the
146 void dumpCodeOrigin(NodeIndex
, NodeIndex
);
148 BlockIndex
blockIndexForBytecodeOffset(Vector
<BlockIndex
>& blocks
, unsigned bytecodeBegin
);
150 PredictedType
getJSConstantPrediction(Node
& node
)
152 return predictionFromValue(node
.valueOfJSConstant(m_codeBlock
));
155 bool addShouldSpeculateInteger(Node
& add
)
157 ASSERT(add
.op() == ValueAdd
|| add
.op() == ArithAdd
|| add
.op() == ArithSub
);
159 Node
& left
= at(add
.child1());
160 Node
& right
= at(add
.child2());
162 if (left
.hasConstant())
163 return addImmediateShouldSpeculateInteger(add
, right
, left
);
164 if (right
.hasConstant())
165 return addImmediateShouldSpeculateInteger(add
, left
, right
);
167 return Node::shouldSpeculateInteger(left
, right
) && add
.canSpeculateInteger();
170 bool negateShouldSpeculateInteger(Node
& negate
)
172 ASSERT(negate
.op() == ArithNegate
);
173 return at(negate
.child1()).shouldSpeculateInteger() && negate
.canSpeculateInteger();
176 bool addShouldSpeculateInteger(NodeIndex nodeIndex
)
178 return addShouldSpeculateInteger(at(nodeIndex
));
181 // Helper methods to check nodes for constants.
182 bool isConstant(NodeIndex nodeIndex
)
184 return at(nodeIndex
).hasConstant();
186 bool isJSConstant(NodeIndex nodeIndex
)
188 return at(nodeIndex
).hasConstant();
190 bool isInt32Constant(NodeIndex nodeIndex
)
192 return at(nodeIndex
).isInt32Constant(m_codeBlock
);
194 bool isDoubleConstant(NodeIndex nodeIndex
)
196 return at(nodeIndex
).isDoubleConstant(m_codeBlock
);
198 bool isNumberConstant(NodeIndex nodeIndex
)
200 return at(nodeIndex
).isNumberConstant(m_codeBlock
);
202 bool isBooleanConstant(NodeIndex nodeIndex
)
204 return at(nodeIndex
).isBooleanConstant(m_codeBlock
);
206 bool isFunctionConstant(NodeIndex nodeIndex
)
208 if (!isJSConstant(nodeIndex
))
210 if (!getJSFunction(valueOfJSConstant(nodeIndex
)))
214 // Helper methods get constant values from nodes.
215 JSValue
valueOfJSConstant(NodeIndex nodeIndex
)
217 return at(nodeIndex
).valueOfJSConstant(m_codeBlock
);
219 int32_t valueOfInt32Constant(NodeIndex nodeIndex
)
221 return valueOfJSConstant(nodeIndex
).asInt32();
223 double valueOfNumberConstant(NodeIndex nodeIndex
)
225 return valueOfJSConstant(nodeIndex
).asNumber();
227 bool valueOfBooleanConstant(NodeIndex nodeIndex
)
229 return valueOfJSConstant(nodeIndex
).asBoolean();
231 JSFunction
* valueOfFunctionConstant(NodeIndex nodeIndex
)
233 JSCell
* function
= getJSFunction(valueOfJSConstant(nodeIndex
));
235 return jsCast
<JSFunction
*>(function
);
238 static const char *opName(NodeType
);
240 // This is O(n), and should only be used for verbose dumps.
241 const char* nameOfVariableAccessData(VariableAccessData
*);
243 void predictArgumentTypes();
245 StructureSet
* addStructureSet(const StructureSet
& structureSet
)
247 ASSERT(structureSet
.size());
248 m_structureSet
.append(structureSet
);
249 return &m_structureSet
.last();
252 StructureTransitionData
* addStructureTransitionData(const StructureTransitionData
& structureTransitionData
)
254 m_structureTransitionData
.append(structureTransitionData
);
255 return &m_structureTransitionData
.last();
258 CodeBlock
* baselineCodeBlockFor(const CodeOrigin
& codeOrigin
)
260 return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin
, m_profiledBlock
);
263 ValueProfile
* valueProfileFor(NodeIndex nodeIndex
)
265 if (nodeIndex
== NoNode
)
268 Node
& node
= at(nodeIndex
);
269 CodeBlock
* profiledBlock
= baselineCodeBlockFor(node
.codeOrigin
);
271 if (node
.hasLocal()) {
272 if (!operandIsArgument(node
.local()))
274 int argument
= operandToArgument(node
.local());
275 if (node
.variableAccessData() != at(m_arguments
[argument
]).variableAccessData())
277 return profiledBlock
->valueProfileForArgument(argument
);
280 if (node
.hasHeapPrediction())
281 return profiledBlock
->valueProfileForBytecodeOffset(node
.codeOrigin
.bytecodeIndexForValueProfile());
286 MethodOfGettingAValueProfile
methodOfGettingAValueProfileFor(NodeIndex nodeIndex
)
288 if (nodeIndex
== NoNode
)
289 return MethodOfGettingAValueProfile();
291 Node
& node
= at(nodeIndex
);
292 CodeBlock
* profiledBlock
= baselineCodeBlockFor(node
.codeOrigin
);
294 if (node
.op() == GetLocal
) {
295 return MethodOfGettingAValueProfile::fromLazyOperand(
297 LazyOperandValueProfileKey(
298 node
.codeOrigin
.bytecodeIndex
, node
.local()));
301 return MethodOfGettingAValueProfile(valueProfileFor(nodeIndex
));
304 bool needsActivation() const
306 #if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
309 return m_codeBlock
->needsFullScopeChain() && m_codeBlock
->codeType() != GlobalCode
;
313 // Pass an argument index. Currently it's ignored, but that's somewhat
315 bool argumentIsCaptured(int) const
317 return needsActivation();
319 bool localIsCaptured(int operand
) const
321 #if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
322 return operand
< m_codeBlock
->m_numVars
;
324 return operand
< m_codeBlock
->m_numCapturedVars
;
328 bool isCaptured(int operand
) const
330 if (operandIsArgument(operand
))
331 return argumentIsCaptured(operandToArgument(operand
));
332 return localIsCaptured(operand
);
334 bool isCaptured(VirtualRegister virtualRegister
) const
336 return isCaptured(static_cast<int>(virtualRegister
));
339 JSGlobalData
& m_globalData
;
340 CodeBlock
* m_codeBlock
;
341 CodeBlock
* m_profiledBlock
;
343 Vector
< OwnPtr
<BasicBlock
> , 8> m_blocks
;
344 Vector
<Edge
, 16> m_varArgChildren
;
345 Vector
<StorageAccessData
> m_storageAccessData
;
346 Vector
<ResolveGlobalData
> m_resolveGlobalData
;
347 Vector
<NodeIndex
, 8> m_arguments
;
348 SegmentedVector
<VariableAccessData
, 16> m_variableAccessData
;
349 SegmentedVector
<ArgumentPosition
, 8> m_argumentPositions
;
350 SegmentedVector
<StructureSet
, 16> m_structureSet
;
351 SegmentedVector
<StructureTransitionData
, 8> m_structureTransitionData
;
352 BitVector m_preservedVars
;
353 unsigned m_localVars
;
354 unsigned m_parameterSlots
;
357 bool addImmediateShouldSpeculateInteger(Node
& add
, Node
& variable
, Node
& immediate
)
359 ASSERT(immediate
.hasConstant());
361 JSValue immediateValue
= immediate
.valueOfJSConstant(m_codeBlock
);
362 if (!immediateValue
.isNumber())
365 if (!variable
.shouldSpeculateInteger())
368 if (immediateValue
.isInt32())
369 return add
.canSpeculateInteger();
371 double doubleImmediate
= immediateValue
.asDouble();
372 const double twoToThe48
= 281474976710656.0;
373 if (doubleImmediate
< -twoToThe48
|| doubleImmediate
> twoToThe48
)
376 return nodeCanTruncateInteger(add
.arithNodeFlags());
379 // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
380 void refChildren(NodeIndex
);
381 void derefChildren(NodeIndex
);
384 class GetBytecodeBeginForBlock
{
386 GetBytecodeBeginForBlock(Graph
& graph
)
391 unsigned operator()(BlockIndex
* blockIndex
) const
393 return m_graph
.m_blocks
[*blockIndex
]->bytecodeBegin
;
400 inline BlockIndex
Graph::blockIndexForBytecodeOffset(Vector
<BlockIndex
>& linkingTargets
, unsigned bytecodeBegin
)
402 return *WTF::binarySearchWithFunctor
<BlockIndex
, unsigned>(linkingTargets
.begin(), linkingTargets
.size(), bytecodeBegin
, WTF::KeyMustBePresentInArray
, GetBytecodeBeginForBlock(*this));
405 } } // namespace JSC::DFG