]>
Commit | Line | Data |
---|---|---|
14957cd0 | 1 | /* |
81345200 | 2 | * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. |
14957cd0 A |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
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. | |
12 | * | |
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. | |
24 | */ | |
25 | ||
26 | #ifndef DFGGraph_h | |
27 | #define DFGGraph_h | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
81345200 | 31 | #include "AssemblyHelpers.h" |
6fe7ccc8 A |
32 | #include "CodeBlock.h" |
33 | #include "DFGArgumentPosition.h" | |
6fe7ccc8 | 34 | #include "DFGBasicBlock.h" |
93a37866 A |
35 | #include "DFGDominators.h" |
36 | #include "DFGLongLivedState.h" | |
81345200 | 37 | #include "DFGNaturalLoops.h" |
6fe7ccc8 | 38 | #include "DFGNode.h" |
93a37866 | 39 | #include "DFGNodeAllocator.h" |
81345200 A |
40 | #include "DFGPlan.h" |
41 | #include "DFGScannable.h" | |
93a37866 | 42 | #include "JSStack.h" |
6fe7ccc8 | 43 | #include "MethodOfGettingAValueProfile.h" |
81345200 | 44 | #include <unordered_map> |
6fe7ccc8 A |
45 | #include <wtf/BitVector.h> |
46 | #include <wtf/HashMap.h> | |
14957cd0 A |
47 | #include <wtf/Vector.h> |
48 | #include <wtf/StdLibExtras.h> | |
49 | ||
50 | namespace JSC { | |
51 | ||
52 | class CodeBlock; | |
6fe7ccc8 | 53 | class ExecState; |
14957cd0 A |
54 | |
55 | namespace DFG { | |
56 | ||
6fe7ccc8 | 57 | struct StorageAccessData { |
81345200 | 58 | PropertyOffset offset; |
93a37866 | 59 | unsigned identifierNumber; |
14957cd0 A |
60 | }; |
61 | ||
81345200 A |
62 | struct InlineVariableData { |
63 | InlineCallFrame* inlineCallFrame; | |
64 | unsigned argumentPositionStart; | |
65 | VariableAccessData* calleeVariable; | |
93a37866 A |
66 | }; |
67 | ||
68 | enum AddSpeculationMode { | |
81345200 A |
69 | DontSpeculateInt32, |
70 | SpeculateInt32AndTruncateConstants, | |
71 | SpeculateInt32 | |
93a37866 A |
72 | }; |
73 | ||
93a37866 | 74 | // |
14957cd0 A |
75 | // === Graph === |
76 | // | |
14957cd0 A |
77 | // The order may be significant for nodes with side-effects (property accesses, value conversions). |
78 | // Nodes that are 'dead' remain in the vector with refCount 0. | |
81345200 | 79 | class Graph : public virtual Scannable { |
14957cd0 | 80 | public: |
81345200 | 81 | Graph(VM&, Plan&, LongLivedState&); |
93a37866 A |
82 | ~Graph(); |
83 | ||
84 | void changeChild(Edge& edge, Node* newNode) | |
14957cd0 | 85 | { |
93a37866 | 86 | edge.setNode(newNode); |
14957cd0 | 87 | } |
6fe7ccc8 | 88 | |
93a37866 | 89 | void changeEdge(Edge& edge, Edge newEdge) |
14957cd0 | 90 | { |
93a37866 | 91 | edge = newEdge; |
14957cd0 | 92 | } |
93a37866 A |
93 | |
94 | void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode) | |
6fe7ccc8 | 95 | { |
93a37866 A |
96 | if (edge.node() != oldNode) |
97 | return; | |
98 | changeChild(edge, newNode); | |
6fe7ccc8 A |
99 | } |
100 | ||
93a37866 | 101 | void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge) |
6fe7ccc8 | 102 | { |
93a37866 A |
103 | if (edge != oldEdge) |
104 | return; | |
105 | changeEdge(edge, newEdge); | |
6fe7ccc8 | 106 | } |
93a37866 | 107 | |
93a37866 A |
108 | void performSubstitution(Node* node) |
109 | { | |
110 | if (node->flags() & NodeHasVarArgs) { | |
111 | for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) | |
112 | performSubstitutionForEdge(m_varArgChildren[childIdx]); | |
113 | } else { | |
114 | performSubstitutionForEdge(node->child1()); | |
115 | performSubstitutionForEdge(node->child2()); | |
116 | performSubstitutionForEdge(node->child3()); | |
117 | } | |
118 | } | |
119 | ||
120 | void performSubstitutionForEdge(Edge& child) | |
6fe7ccc8 | 121 | { |
93a37866 A |
122 | // Check if this operand is actually unused. |
123 | if (!child) | |
124 | return; | |
125 | ||
126 | // Check if there is any replacement. | |
81345200 | 127 | Node* replacement = child->misc.replacement; |
93a37866 | 128 | if (!replacement) |
6fe7ccc8 | 129 | return; |
93a37866 A |
130 | |
131 | child.setNode(replacement); | |
132 | ||
133 | // There is definitely a replacement. Assert that the replacement does not | |
134 | // have a replacement. | |
81345200 | 135 | ASSERT(!child->misc.replacement); |
6fe7ccc8 | 136 | } |
93a37866 | 137 | |
81345200 A |
138 | template<typename... Params> |
139 | Node* addNode(SpeculatedType type, Params... params) | |
140 | { | |
141 | Node* node = new (m_allocator) Node(params...); | |
142 | node->predict(type); | |
143 | return node; | |
93a37866 | 144 | } |
14957cd0 | 145 | |
93a37866 A |
146 | void dethread(); |
147 | ||
148 | void convertToConstant(Node* node, unsigned constantNumber) | |
14957cd0 | 149 | { |
93a37866 A |
150 | if (node->op() == GetLocal) |
151 | dethread(); | |
152 | else | |
81345200 | 153 | ASSERT(!node->hasVariableAccessData(*this)); |
93a37866 | 154 | node->convertToConstant(constantNumber); |
14957cd0 | 155 | } |
93a37866 | 156 | |
81345200 A |
157 | unsigned constantRegisterForConstant(JSValue value) |
158 | { | |
159 | unsigned constantRegister; | |
160 | if (!m_codeBlock->findConstant(value, constantRegister)) { | |
161 | constantRegister = m_codeBlock->addConstantLazily(); | |
162 | initializeLazyWriteBarrierForConstant( | |
163 | m_plan.writeBarriers, | |
164 | m_codeBlock->constants()[constantRegister], | |
165 | m_codeBlock, | |
166 | constantRegister, | |
167 | m_codeBlock->ownerExecutable(), | |
168 | value); | |
169 | } | |
170 | return constantRegister; | |
171 | } | |
172 | ||
93a37866 | 173 | void convertToConstant(Node* node, JSValue value) |
14957cd0 | 174 | { |
81345200 A |
175 | if (value.isObject()) |
176 | node->convertToWeakConstant(value.asCell()); | |
177 | else | |
178 | convertToConstant(node, constantRegisterForConstant(value)); | |
14957cd0 A |
179 | } |
180 | ||
6fe7ccc8 | 181 | // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names). |
81345200 | 182 | void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0); |
93a37866 | 183 | enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis }; |
81345200 | 184 | void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*); |
93a37866 | 185 | void dump(PrintStream&, Edge); |
81345200 | 186 | void dump(PrintStream&, const char* prefix, Node*, DumpContext* = 0); |
93a37866 A |
187 | static int amountOfNodeWhiteSpace(Node*); |
188 | static void printNodeWhiteSpace(PrintStream&, Node*); | |
6fe7ccc8 A |
189 | |
190 | // Dump the code origin of the given node as a diff from the code origin of the | |
93a37866 | 191 | // preceding node. Returns true if anything was printed. |
81345200 | 192 | bool dumpCodeOrigin(PrintStream&, const char* prefix, Node* previousNode, Node* currentNode, DumpContext*); |
6fe7ccc8 | 193 | |
93a37866 | 194 | SpeculatedType getJSConstantSpeculation(Node* node) |
6fe7ccc8 | 195 | { |
93a37866 | 196 | return speculationFromValue(node->valueOfJSConstant(m_codeBlock)); |
6fe7ccc8 A |
197 | } |
198 | ||
81345200 | 199 | AddSpeculationMode addSpeculationMode(Node* add, bool leftShouldSpeculateInt32, bool rightShouldSpeculateInt32, PredictionPass pass) |
6fe7ccc8 | 200 | { |
93a37866 | 201 | ASSERT(add->op() == ValueAdd || add->op() == ArithAdd || add->op() == ArithSub); |
6fe7ccc8 | 202 | |
81345200 A |
203 | RareCaseProfilingSource source = add->sourceFor(pass); |
204 | ||
93a37866 A |
205 | Node* left = add->child1().node(); |
206 | Node* right = add->child2().node(); | |
6fe7ccc8 | 207 | |
93a37866 | 208 | if (left->hasConstant()) |
81345200 | 209 | return addImmediateShouldSpeculateInt32(add, rightShouldSpeculateInt32, left, source); |
93a37866 | 210 | if (right->hasConstant()) |
81345200 | 211 | return addImmediateShouldSpeculateInt32(add, leftShouldSpeculateInt32, right, source); |
6fe7ccc8 | 212 | |
81345200 | 213 | return (leftShouldSpeculateInt32 && rightShouldSpeculateInt32 && add->canSpeculateInt32(source)) ? SpeculateInt32 : DontSpeculateInt32; |
93a37866 A |
214 | } |
215 | ||
81345200 | 216 | AddSpeculationMode valueAddSpeculationMode(Node* add, PredictionPass pass) |
93a37866 | 217 | { |
81345200 A |
218 | return addSpeculationMode( |
219 | add, | |
220 | add->child1()->shouldSpeculateInt32OrBooleanExpectingDefined(), | |
221 | add->child2()->shouldSpeculateInt32OrBooleanExpectingDefined(), | |
222 | pass); | |
6fe7ccc8 A |
223 | } |
224 | ||
81345200 | 225 | AddSpeculationMode arithAddSpeculationMode(Node* add, PredictionPass pass) |
6fe7ccc8 | 226 | { |
81345200 A |
227 | return addSpeculationMode( |
228 | add, | |
229 | add->child1()->shouldSpeculateInt32OrBooleanForArithmetic(), | |
230 | add->child2()->shouldSpeculateInt32OrBooleanForArithmetic(), | |
231 | pass); | |
93a37866 A |
232 | } |
233 | ||
81345200 | 234 | AddSpeculationMode addSpeculationMode(Node* add, PredictionPass pass) |
93a37866 A |
235 | { |
236 | if (add->op() == ValueAdd) | |
81345200 | 237 | return valueAddSpeculationMode(add, pass); |
93a37866 | 238 | |
81345200 | 239 | return arithAddSpeculationMode(add, pass); |
6fe7ccc8 A |
240 | } |
241 | ||
81345200 | 242 | bool addShouldSpeculateInt32(Node* add, PredictionPass pass) |
6fe7ccc8 | 243 | { |
81345200 | 244 | return addSpeculationMode(add, pass) != DontSpeculateInt32; |
93a37866 A |
245 | } |
246 | ||
81345200 A |
247 | bool addShouldSpeculateMachineInt(Node* add) |
248 | { | |
249 | if (!enableInt52()) | |
250 | return false; | |
251 | ||
252 | Node* left = add->child1().node(); | |
253 | Node* right = add->child2().node(); | |
254 | ||
255 | bool speculation; | |
256 | if (add->op() == ValueAdd) | |
257 | speculation = Node::shouldSpeculateMachineInt(left, right); | |
258 | else | |
259 | speculation = Node::shouldSpeculateMachineInt(left, right); | |
260 | ||
261 | return speculation && !hasExitSite(add, Int52Overflow); | |
262 | } | |
263 | ||
264 | bool mulShouldSpeculateInt32(Node* mul, PredictionPass pass) | |
93a37866 A |
265 | { |
266 | ASSERT(mul->op() == ArithMul); | |
267 | ||
268 | Node* left = mul->child1().node(); | |
269 | Node* right = mul->child2().node(); | |
270 | ||
81345200 A |
271 | return Node::shouldSpeculateInt32OrBooleanForArithmetic(left, right) |
272 | && mul->canSpeculateInt32(mul->sourceFor(pass)); | |
273 | } | |
274 | ||
275 | bool mulShouldSpeculateMachineInt(Node* mul, PredictionPass pass) | |
276 | { | |
277 | ASSERT(mul->op() == ArithMul); | |
278 | ||
279 | if (!enableInt52()) | |
280 | return false; | |
281 | ||
282 | Node* left = mul->child1().node(); | |
283 | Node* right = mul->child2().node(); | |
284 | ||
285 | return Node::shouldSpeculateMachineInt(left, right) | |
286 | && mul->canSpeculateInt52(pass) | |
287 | && !hasExitSite(mul, Int52Overflow); | |
288 | } | |
289 | ||
290 | bool negateShouldSpeculateInt32(Node* negate, PredictionPass pass) | |
291 | { | |
292 | ASSERT(negate->op() == ArithNegate); | |
293 | return negate->child1()->shouldSpeculateInt32OrBooleanForArithmetic() | |
294 | && negate->canSpeculateInt32(pass); | |
93a37866 A |
295 | } |
296 | ||
81345200 | 297 | bool negateShouldSpeculateMachineInt(Node* negate, PredictionPass pass) |
93a37866 A |
298 | { |
299 | ASSERT(negate->op() == ArithNegate); | |
81345200 A |
300 | if (!enableInt52()) |
301 | return false; | |
302 | return negate->child1()->shouldSpeculateMachineInt() | |
303 | && !hasExitSite(negate, Int52Overflow) | |
304 | && negate->canSpeculateInt52(pass); | |
305 | } | |
306 | ||
307 | VirtualRegister bytecodeRegisterForArgument(CodeOrigin codeOrigin, int argument) | |
308 | { | |
309 | return VirtualRegister( | |
310 | codeOrigin.inlineCallFrame->stackOffset + | |
311 | baselineCodeBlockFor(codeOrigin)->argumentIndexAfterCapture(argument)); | |
6fe7ccc8 A |
312 | } |
313 | ||
314 | // Helper methods to check nodes for constants. | |
93a37866 A |
315 | bool isConstant(Node* node) |
316 | { | |
317 | return node->hasConstant(); | |
318 | } | |
319 | bool isJSConstant(Node* node) | |
6fe7ccc8 | 320 | { |
93a37866 | 321 | return node->hasConstant(); |
6fe7ccc8 | 322 | } |
93a37866 | 323 | bool isInt32Constant(Node* node) |
6fe7ccc8 | 324 | { |
93a37866 | 325 | return node->isInt32Constant(m_codeBlock); |
6fe7ccc8 | 326 | } |
93a37866 | 327 | bool isDoubleConstant(Node* node) |
6fe7ccc8 | 328 | { |
93a37866 | 329 | return node->isDoubleConstant(m_codeBlock); |
6fe7ccc8 | 330 | } |
93a37866 | 331 | bool isNumberConstant(Node* node) |
6fe7ccc8 | 332 | { |
93a37866 | 333 | return node->isNumberConstant(m_codeBlock); |
6fe7ccc8 | 334 | } |
81345200 A |
335 | bool isMachineIntConstant(Node* node) |
336 | { | |
337 | return node->isMachineIntConstant(m_codeBlock); | |
338 | } | |
93a37866 | 339 | bool isBooleanConstant(Node* node) |
14957cd0 | 340 | { |
93a37866 | 341 | return node->isBooleanConstant(m_codeBlock); |
14957cd0 | 342 | } |
93a37866 | 343 | bool isCellConstant(Node* node) |
6fe7ccc8 | 344 | { |
93a37866 A |
345 | if (!isJSConstant(node)) |
346 | return false; | |
347 | JSValue value = valueOfJSConstant(node); | |
348 | return value.isCell() && !!value; | |
349 | } | |
350 | bool isFunctionConstant(Node* node) | |
351 | { | |
352 | if (!isJSConstant(node)) | |
353 | return false; | |
354 | if (!getJSFunction(valueOfJSConstant(node))) | |
355 | return false; | |
356 | return true; | |
6fe7ccc8 | 357 | } |
93a37866 | 358 | bool isInternalFunctionConstant(Node* node) |
6fe7ccc8 | 359 | { |
93a37866 A |
360 | if (!isJSConstant(node)) |
361 | return false; | |
362 | JSValue value = valueOfJSConstant(node); | |
363 | if (!value.isCell() || !value) | |
6fe7ccc8 | 364 | return false; |
93a37866 | 365 | JSCell* cell = value.asCell(); |
81345200 | 366 | if (!cell->inherits(InternalFunction::info())) |
6fe7ccc8 A |
367 | return false; |
368 | return true; | |
369 | } | |
370 | // Helper methods get constant values from nodes. | |
93a37866 | 371 | JSValue valueOfJSConstant(Node* node) |
6fe7ccc8 | 372 | { |
93a37866 | 373 | return node->valueOfJSConstant(m_codeBlock); |
6fe7ccc8 | 374 | } |
93a37866 | 375 | int32_t valueOfInt32Constant(Node* node) |
6fe7ccc8 | 376 | { |
81345200 A |
377 | JSValue value = valueOfJSConstant(node); |
378 | if (!value.isInt32()) { | |
379 | dataLog("Value isn't int32: ", value, "\n"); | |
380 | dump(); | |
381 | RELEASE_ASSERT_NOT_REACHED(); | |
382 | } | |
383 | return value.asInt32(); | |
6fe7ccc8 | 384 | } |
93a37866 | 385 | double valueOfNumberConstant(Node* node) |
6fe7ccc8 | 386 | { |
93a37866 | 387 | return valueOfJSConstant(node).asNumber(); |
6fe7ccc8 | 388 | } |
93a37866 | 389 | bool valueOfBooleanConstant(Node* node) |
6fe7ccc8 | 390 | { |
93a37866 | 391 | return valueOfJSConstant(node).asBoolean(); |
6fe7ccc8 | 392 | } |
93a37866 | 393 | JSFunction* valueOfFunctionConstant(Node* node) |
6fe7ccc8 | 394 | { |
93a37866 | 395 | JSCell* function = getJSFunction(valueOfJSConstant(node)); |
6fe7ccc8 A |
396 | ASSERT(function); |
397 | return jsCast<JSFunction*>(function); | |
398 | } | |
399 | ||
400 | static const char *opName(NodeType); | |
401 | ||
6fe7ccc8 A |
402 | StructureSet* addStructureSet(const StructureSet& structureSet) |
403 | { | |
404 | ASSERT(structureSet.size()); | |
405 | m_structureSet.append(structureSet); | |
406 | return &m_structureSet.last(); | |
407 | } | |
408 | ||
409 | StructureTransitionData* addStructureTransitionData(const StructureTransitionData& structureTransitionData) | |
410 | { | |
411 | m_structureTransitionData.append(structureTransitionData); | |
412 | return &m_structureTransitionData.last(); | |
413 | } | |
414 | ||
93a37866 A |
415 | JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin) |
416 | { | |
417 | return m_codeBlock->globalObjectFor(codeOrigin); | |
418 | } | |
419 | ||
420 | JSObject* globalThisObjectFor(CodeOrigin codeOrigin) | |
421 | { | |
422 | JSGlobalObject* object = globalObjectFor(codeOrigin); | |
81345200 | 423 | return jsCast<JSObject*>(object->methodTable()->toThis(object, object->globalExec(), NotStrictMode)); |
93a37866 A |
424 | } |
425 | ||
81345200 | 426 | ScriptExecutable* executableFor(InlineCallFrame* inlineCallFrame) |
93a37866 A |
427 | { |
428 | if (!inlineCallFrame) | |
429 | return m_codeBlock->ownerExecutable(); | |
430 | ||
431 | return inlineCallFrame->executable.get(); | |
432 | } | |
433 | ||
81345200 | 434 | ScriptExecutable* executableFor(const CodeOrigin& codeOrigin) |
93a37866 A |
435 | { |
436 | return executableFor(codeOrigin.inlineCallFrame); | |
437 | } | |
438 | ||
81345200 A |
439 | CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame) |
440 | { | |
441 | if (!inlineCallFrame) | |
442 | return m_profiledBlock; | |
443 | return baselineCodeBlockForInlineCallFrame(inlineCallFrame); | |
444 | } | |
445 | ||
6fe7ccc8 A |
446 | CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin) |
447 | { | |
448 | return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock); | |
449 | } | |
450 | ||
81345200 A |
451 | bool isStrictModeFor(CodeOrigin codeOrigin) |
452 | { | |
453 | if (!codeOrigin.inlineCallFrame) | |
454 | return m_codeBlock->isStrictMode(); | |
455 | return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode(); | |
456 | } | |
457 | ||
458 | ECMAMode ecmaModeFor(CodeOrigin codeOrigin) | |
459 | { | |
460 | return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode; | |
461 | } | |
462 | ||
463 | bool masqueradesAsUndefinedWatchpointIsStillValid(const CodeOrigin& codeOrigin) | |
464 | { | |
465 | return m_plan.watchpoints.isStillValid( | |
466 | globalObjectFor(codeOrigin)->masqueradesAsUndefinedWatchpoint()); | |
467 | } | |
468 | ||
93a37866 A |
469 | bool hasGlobalExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) |
470 | { | |
471 | return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(exitKind)); | |
472 | } | |
473 | ||
474 | bool hasExitSite(const CodeOrigin& codeOrigin, ExitKind exitKind) | |
475 | { | |
476 | return baselineCodeBlockFor(codeOrigin)->hasExitSite(FrequentExitSite(codeOrigin.bytecodeIndex, exitKind)); | |
477 | } | |
478 | ||
81345200 | 479 | bool hasExitSite(Node* node, ExitKind exitKind) |
93a37866 | 480 | { |
81345200 A |
481 | return hasExitSite(node->origin.semantic, exitKind); |
482 | } | |
483 | ||
484 | VirtualRegister argumentsRegisterFor(InlineCallFrame* inlineCallFrame) | |
485 | { | |
486 | if (!inlineCallFrame) | |
487 | return m_profiledBlock->argumentsRegister(); | |
488 | ||
489 | return VirtualRegister(baselineCodeBlockForInlineCallFrame( | |
490 | inlineCallFrame)->argumentsRegister().offset() + | |
491 | inlineCallFrame->stackOffset); | |
492 | } | |
493 | ||
494 | VirtualRegister argumentsRegisterFor(const CodeOrigin& codeOrigin) | |
495 | { | |
496 | return argumentsRegisterFor(codeOrigin.inlineCallFrame); | |
497 | } | |
498 | ||
499 | VirtualRegister machineArgumentsRegisterFor(InlineCallFrame* inlineCallFrame) | |
500 | { | |
501 | if (!inlineCallFrame) | |
93a37866 A |
502 | return m_codeBlock->argumentsRegister(); |
503 | ||
81345200 | 504 | return inlineCallFrame->argumentsRegister; |
93a37866 A |
505 | } |
506 | ||
81345200 | 507 | VirtualRegister machineArgumentsRegisterFor(const CodeOrigin& codeOrigin) |
93a37866 | 508 | { |
81345200 A |
509 | return machineArgumentsRegisterFor(codeOrigin.inlineCallFrame); |
510 | } | |
511 | ||
512 | VirtualRegister uncheckedArgumentsRegisterFor(InlineCallFrame* inlineCallFrame) | |
513 | { | |
514 | if (!inlineCallFrame) | |
515 | return m_profiledBlock->uncheckedArgumentsRegister(); | |
93a37866 | 516 | |
81345200 | 517 | CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); |
93a37866 | 518 | if (!codeBlock->usesArguments()) |
81345200 | 519 | return VirtualRegister(); |
93a37866 | 520 | |
81345200 A |
521 | return VirtualRegister(codeBlock->argumentsRegister().offset() + |
522 | inlineCallFrame->stackOffset); | |
523 | } | |
524 | ||
525 | VirtualRegister uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin) | |
526 | { | |
527 | return uncheckedArgumentsRegisterFor(codeOrigin.inlineCallFrame); | |
528 | } | |
529 | ||
530 | VirtualRegister activationRegister() | |
531 | { | |
532 | return m_profiledBlock->activationRegister(); | |
533 | } | |
534 | ||
535 | VirtualRegister uncheckedActivationRegister() | |
536 | { | |
537 | return m_profiledBlock->uncheckedActivationRegister(); | |
538 | } | |
539 | ||
540 | VirtualRegister machineActivationRegister() | |
541 | { | |
542 | return m_profiledBlock->activationRegister(); | |
93a37866 A |
543 | } |
544 | ||
81345200 | 545 | VirtualRegister uncheckedMachineActivationRegister() |
93a37866 | 546 | { |
81345200 | 547 | return m_profiledBlock->uncheckedActivationRegister(); |
93a37866 A |
548 | } |
549 | ||
550 | ValueProfile* valueProfileFor(Node* node) | |
6fe7ccc8 | 551 | { |
93a37866 | 552 | if (!node) |
6fe7ccc8 A |
553 | return 0; |
554 | ||
81345200 | 555 | CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); |
6fe7ccc8 | 556 | |
81345200 A |
557 | if (node->op() == GetArgument) |
558 | return profiledBlock->valueProfileForArgument(node->local().toArgument()); | |
559 | ||
560 | if (node->hasLocal(*this)) { | |
561 | if (m_form == SSA) | |
562 | return 0; | |
563 | if (!node->local().isArgument()) | |
6fe7ccc8 | 564 | return 0; |
81345200 | 565 | int argument = node->local().toArgument(); |
93a37866 | 566 | if (node->variableAccessData() != m_arguments[argument]->variableAccessData()) |
6fe7ccc8 A |
567 | return 0; |
568 | return profiledBlock->valueProfileForArgument(argument); | |
569 | } | |
570 | ||
93a37866 | 571 | if (node->hasHeapPrediction()) |
81345200 | 572 | return profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex); |
6fe7ccc8 A |
573 | |
574 | return 0; | |
575 | } | |
576 | ||
93a37866 | 577 | MethodOfGettingAValueProfile methodOfGettingAValueProfileFor(Node* node) |
14957cd0 | 578 | { |
93a37866 | 579 | if (!node) |
6fe7ccc8 A |
580 | return MethodOfGettingAValueProfile(); |
581 | ||
81345200 | 582 | CodeBlock* profiledBlock = baselineCodeBlockFor(node->origin.semantic); |
6fe7ccc8 | 583 | |
93a37866 | 584 | if (node->op() == GetLocal) { |
6fe7ccc8 A |
585 | return MethodOfGettingAValueProfile::fromLazyOperand( |
586 | profiledBlock, | |
587 | LazyOperandValueProfileKey( | |
81345200 | 588 | node->origin.semantic.bytecodeIndex, node->local())); |
14957cd0 | 589 | } |
6fe7ccc8 | 590 | |
93a37866 | 591 | return MethodOfGettingAValueProfile(valueProfileFor(node)); |
6fe7ccc8 A |
592 | } |
593 | ||
93a37866 | 594 | bool usesArguments() const |
6fe7ccc8 | 595 | { |
93a37866 | 596 | return m_codeBlock->usesArguments(); |
6fe7ccc8 | 597 | } |
93a37866 | 598 | |
81345200 A |
599 | BlockIndex numBlocks() const { return m_blocks.size(); } |
600 | BasicBlock* block(BlockIndex blockIndex) const { return m_blocks[blockIndex].get(); } | |
601 | BasicBlock* lastBlock() const { return block(numBlocks() - 1); } | |
602 | ||
603 | void appendBlock(PassRefPtr<BasicBlock> basicBlock) | |
6fe7ccc8 | 604 | { |
81345200 A |
605 | basicBlock->index = m_blocks.size(); |
606 | m_blocks.append(basicBlock); | |
93a37866 | 607 | } |
81345200 A |
608 | |
609 | void killBlock(BlockIndex blockIndex) | |
93a37866 | 610 | { |
81345200 | 611 | m_blocks[blockIndex].clear(); |
93a37866 | 612 | } |
81345200 A |
613 | |
614 | void killBlock(BasicBlock* basicBlock) | |
93a37866 | 615 | { |
81345200 | 616 | killBlock(basicBlock->index); |
93a37866 A |
617 | } |
618 | ||
81345200 A |
619 | void killBlockAndItsContents(BasicBlock*); |
620 | ||
621 | void killUnreachableBlocks(); | |
622 | ||
93a37866 A |
623 | bool isPredictedNumerical(Node* node) |
624 | { | |
625 | return isNumerical(node->child1().useKind()) && isNumerical(node->child2().useKind()); | |
626 | } | |
627 | ||
628 | // Note that a 'true' return does not actually mean that the ByVal access clobbers nothing. | |
629 | // It really means that it will not clobber the entire world. It's still up to you to | |
630 | // carefully consider things like: | |
631 | // - PutByVal definitely changes the array it stores to, and may even change its length. | |
632 | // - PutByOffset definitely changes the object it stores to. | |
633 | // - and so on. | |
634 | bool byValIsPure(Node* node) | |
635 | { | |
636 | switch (node->arrayMode().type()) { | |
637 | case Array::Generic: | |
638 | return false; | |
639 | case Array::Int32: | |
640 | case Array::Double: | |
641 | case Array::Contiguous: | |
642 | case Array::ArrayStorage: | |
643 | return !node->arrayMode().isOutOfBounds(); | |
644 | case Array::SlowPutArrayStorage: | |
645 | return !node->arrayMode().mayStoreToHole(); | |
646 | case Array::String: | |
81345200 | 647 | return node->op() == GetByVal && node->arrayMode().isInBounds(); |
93a37866 A |
648 | #if USE(JSVALUE32_64) |
649 | case Array::Arguments: | |
650 | if (node->op() == GetByVal) | |
651 | return true; | |
652 | return false; | |
653 | #endif // USE(JSVALUE32_64) | |
654 | default: | |
655 | return true; | |
656 | } | |
657 | } | |
658 | ||
659 | bool clobbersWorld(Node* node) | |
660 | { | |
661 | if (node->flags() & NodeClobbersWorld) | |
662 | return true; | |
663 | if (!(node->flags() & NodeMightClobber)) | |
664 | return false; | |
665 | switch (node->op()) { | |
93a37866 | 666 | case GetByVal: |
81345200 | 667 | case PutByValDirect: |
93a37866 A |
668 | case PutByVal: |
669 | case PutByValAlias: | |
670 | return !byValIsPure(node); | |
671 | case ToString: | |
672 | switch (node->child1().useKind()) { | |
673 | case StringObjectUse: | |
674 | case StringOrStringObjectUse: | |
675 | return false; | |
676 | case CellUse: | |
677 | case UntypedUse: | |
678 | return true; | |
679 | default: | |
680 | RELEASE_ASSERT_NOT_REACHED(); | |
681 | return true; | |
682 | } | |
683 | default: | |
684 | RELEASE_ASSERT_NOT_REACHED(); | |
685 | return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst. | |
686 | } | |
687 | } | |
688 | ||
689 | void determineReachability(); | |
690 | void resetReachability(); | |
691 | ||
692 | void resetExitStates(); | |
693 | ||
694 | unsigned varArgNumChildren(Node* node) | |
695 | { | |
696 | ASSERT(node->flags() & NodeHasVarArgs); | |
697 | return node->numChildren(); | |
6fe7ccc8 A |
698 | } |
699 | ||
93a37866 | 700 | unsigned numChildren(Node* node) |
6fe7ccc8 | 701 | { |
93a37866 A |
702 | if (node->flags() & NodeHasVarArgs) |
703 | return varArgNumChildren(node); | |
704 | return AdjacencyList::Size; | |
6fe7ccc8 | 705 | } |
93a37866 A |
706 | |
707 | Edge& varArgChild(Node* node, unsigned index) | |
6fe7ccc8 | 708 | { |
93a37866 A |
709 | ASSERT(node->flags() & NodeHasVarArgs); |
710 | return m_varArgChildren[node->firstChild() + index]; | |
14957cd0 | 711 | } |
6fe7ccc8 | 712 | |
93a37866 A |
713 | Edge& child(Node* node, unsigned index) |
714 | { | |
715 | if (node->flags() & NodeHasVarArgs) | |
716 | return varArgChild(node, index); | |
717 | return node->children.child(index); | |
718 | } | |
719 | ||
81345200 | 720 | void voteNode(Node* node, unsigned ballot, float weight = 1) |
93a37866 A |
721 | { |
722 | switch (node->op()) { | |
723 | case ValueToInt32: | |
724 | case UInt32ToNumber: | |
725 | node = node->child1().node(); | |
726 | break; | |
727 | default: | |
728 | break; | |
729 | } | |
730 | ||
731 | if (node->op() == GetLocal) | |
81345200 | 732 | node->variableAccessData()->vote(ballot, weight); |
93a37866 A |
733 | } |
734 | ||
81345200 | 735 | void voteNode(Edge edge, unsigned ballot, float weight = 1) |
93a37866 | 736 | { |
81345200 | 737 | voteNode(edge.node(), ballot, weight); |
93a37866 A |
738 | } |
739 | ||
81345200 | 740 | void voteChildren(Node* node, unsigned ballot, float weight = 1) |
93a37866 A |
741 | { |
742 | if (node->flags() & NodeHasVarArgs) { | |
743 | for (unsigned childIdx = node->firstChild(); | |
744 | childIdx < node->firstChild() + node->numChildren(); | |
745 | childIdx++) { | |
746 | if (!!m_varArgChildren[childIdx]) | |
81345200 | 747 | voteNode(m_varArgChildren[childIdx], ballot, weight); |
93a37866 A |
748 | } |
749 | return; | |
750 | } | |
751 | ||
752 | if (!node->child1()) | |
753 | return; | |
81345200 | 754 | voteNode(node->child1(), ballot, weight); |
93a37866 A |
755 | if (!node->child2()) |
756 | return; | |
81345200 | 757 | voteNode(node->child2(), ballot, weight); |
93a37866 A |
758 | if (!node->child3()) |
759 | return; | |
81345200 | 760 | voteNode(node->child3(), ballot, weight); |
93a37866 A |
761 | } |
762 | ||
763 | template<typename T> // T = Node* or Edge | |
764 | void substitute(BasicBlock& block, unsigned startIndexInBlock, T oldThing, T newThing) | |
765 | { | |
766 | for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) { | |
767 | Node* node = block[indexInBlock]; | |
768 | if (node->flags() & NodeHasVarArgs) { | |
769 | for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); ++childIdx) { | |
770 | if (!!m_varArgChildren[childIdx]) | |
771 | compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing); | |
772 | } | |
773 | continue; | |
774 | } | |
775 | if (!node->child1()) | |
776 | continue; | |
777 | compareAndSwap(node->children.child1(), oldThing, newThing); | |
778 | if (!node->child2()) | |
779 | continue; | |
780 | compareAndSwap(node->children.child2(), oldThing, newThing); | |
781 | if (!node->child3()) | |
782 | continue; | |
783 | compareAndSwap(node->children.child3(), oldThing, newThing); | |
784 | } | |
785 | } | |
786 | ||
787 | // Use this if you introduce a new GetLocal and you know that you introduced it *before* | |
788 | // any GetLocals in the basic block. | |
789 | // FIXME: it may be appropriate, in the future, to generalize this to handle GetLocals | |
790 | // introduced anywhere in the basic block. | |
81345200 A |
791 | void substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal); |
792 | ||
793 | void invalidateCFG(); | |
794 | ||
795 | void clearFlagsOnAllNodes(NodeFlags); | |
796 | ||
797 | void clearReplacements(); | |
798 | void initializeNodeOwners(); | |
799 | ||
800 | void getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result); | |
801 | ||
802 | Profiler::Compilation* compilation() { return m_plan.compilation.get(); } | |
803 | ||
804 | DesiredIdentifiers& identifiers() { return m_plan.identifiers; } | |
805 | DesiredWatchpoints& watchpoints() { return m_plan.watchpoints; } | |
806 | DesiredStructureChains& chains() { return m_plan.chains; } | |
807 | ||
808 | FullBytecodeLiveness& livenessFor(CodeBlock*); | |
809 | FullBytecodeLiveness& livenessFor(InlineCallFrame*); | |
810 | bool isLiveInBytecode(VirtualRegister, CodeOrigin); | |
811 | ||
812 | unsigned frameRegisterCount(); | |
813 | unsigned stackPointerOffset(); | |
814 | unsigned requiredRegisterCountForExit(); | |
815 | unsigned requiredRegisterCountForExecutionAndExit(); | |
816 | ||
817 | JSActivation* tryGetActivation(Node*); | |
818 | WriteBarrierBase<Unknown>* tryGetRegisters(Node*); | |
819 | ||
820 | JSArrayBufferView* tryGetFoldableView(Node*); | |
821 | JSArrayBufferView* tryGetFoldableView(Node*, ArrayMode); | |
822 | JSArrayBufferView* tryGetFoldableViewForChild1(Node*); | |
823 | ||
824 | virtual void visitChildren(SlotVisitor&) override; | |
93a37866 A |
825 | |
826 | VM& m_vm; | |
81345200 | 827 | Plan& m_plan; |
6fe7ccc8 A |
828 | CodeBlock* m_codeBlock; |
829 | CodeBlock* m_profiledBlock; | |
93a37866 A |
830 | |
831 | NodeAllocator& m_allocator; | |
14957cd0 | 832 | |
81345200 A |
833 | Operands<AbstractValue> m_mustHandleAbstractValues; |
834 | ||
835 | Vector< RefPtr<BasicBlock> , 8> m_blocks; | |
6fe7ccc8 A |
836 | Vector<Edge, 16> m_varArgChildren; |
837 | Vector<StorageAccessData> m_storageAccessData; | |
93a37866 | 838 | Vector<Node*, 8> m_arguments; |
6fe7ccc8 A |
839 | SegmentedVector<VariableAccessData, 16> m_variableAccessData; |
840 | SegmentedVector<ArgumentPosition, 8> m_argumentPositions; | |
841 | SegmentedVector<StructureSet, 16> m_structureSet; | |
842 | SegmentedVector<StructureTransitionData, 8> m_structureTransitionData; | |
93a37866 | 843 | SegmentedVector<NewArrayBufferData, 4> m_newArrayBufferData; |
81345200 A |
844 | Bag<BranchData> m_branchData; |
845 | Bag<SwitchData> m_switchData; | |
846 | Bag<MultiGetByOffsetData> m_multiGetByOffsetData; | |
847 | Bag<MultiPutByOffsetData> m_multiPutByOffsetData; | |
848 | Vector<InlineVariableData, 4> m_inlineVariableData; | |
849 | HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>> m_bytecodeLiveness; | |
93a37866 A |
850 | bool m_hasArguments; |
851 | HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped; | |
81345200 | 852 | BitVector m_lazyVars; |
93a37866 | 853 | Dominators m_dominators; |
81345200 | 854 | NaturalLoops m_naturalLoops; |
6fe7ccc8 | 855 | unsigned m_localVars; |
81345200 | 856 | unsigned m_nextMachineLocal; |
6fe7ccc8 | 857 | unsigned m_parameterSlots; |
81345200 A |
858 | int m_machineCaptureStart; |
859 | std::unique_ptr<SlowArgument[]> m_slowArguments; | |
860 | ||
861 | #if USE(JSVALUE32_64) | |
862 | std::unordered_map<int64_t, double*> m_doubleConstantsMap; | |
863 | std::unique_ptr<Bag<double>> m_doubleConstants; | |
864 | #endif | |
93a37866 A |
865 | |
866 | OptimizationFixpointState m_fixpointState; | |
867 | GraphForm m_form; | |
868 | UnificationState m_unificationState; | |
869 | RefCountState m_refCountState; | |
14957cd0 | 870 | private: |
6fe7ccc8 | 871 | |
81345200 A |
872 | void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor); |
873 | void addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock*); | |
93a37866 | 874 | |
81345200 | 875 | AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate, RareCaseProfilingSource source) |
6fe7ccc8 | 876 | { |
93a37866 | 877 | ASSERT(immediate->hasConstant()); |
6fe7ccc8 | 878 | |
93a37866 | 879 | JSValue immediateValue = immediate->valueOfJSConstant(m_codeBlock); |
81345200 A |
880 | if (!immediateValue.isNumber() && !immediateValue.isBoolean()) |
881 | return DontSpeculateInt32; | |
6fe7ccc8 | 882 | |
81345200 A |
883 | if (!variableShouldSpeculateInt32) |
884 | return DontSpeculateInt32; | |
6fe7ccc8 | 885 | |
81345200 A |
886 | if (immediateValue.isInt32() || immediateValue.isBoolean()) |
887 | return add->canSpeculateInt32(source) ? SpeculateInt32 : DontSpeculateInt32; | |
6fe7ccc8 A |
888 | |
889 | double doubleImmediate = immediateValue.asDouble(); | |
890 | const double twoToThe48 = 281474976710656.0; | |
891 | if (doubleImmediate < -twoToThe48 || doubleImmediate > twoToThe48) | |
81345200 | 892 | return DontSpeculateInt32; |
93a37866 | 893 | |
81345200 | 894 | return bytecodeCanTruncateInteger(add->arithNodeFlags()) ? SpeculateInt32AndTruncateConstants : DontSpeculateInt32; |
93a37866 | 895 | } |
6fe7ccc8 A |
896 | }; |
897 | ||
93a37866 A |
898 | #define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do { \ |
899 | Node* _node = (node); \ | |
900 | if (_node->flags() & NodeHasVarArgs) { \ | |
901 | for (unsigned _childIdx = _node->firstChild(); \ | |
902 | _childIdx < _node->firstChild() + _node->numChildren(); \ | |
903 | _childIdx++) { \ | |
904 | if (!!(graph).m_varArgChildren[_childIdx]) \ | |
905 | thingToDo(_node, (graph).m_varArgChildren[_childIdx]); \ | |
906 | } \ | |
907 | } else { \ | |
908 | if (!_node->child1()) { \ | |
909 | ASSERT( \ | |
910 | !_node->child2() \ | |
911 | && !_node->child3()); \ | |
912 | break; \ | |
913 | } \ | |
914 | thingToDo(_node, _node->child1()); \ | |
915 | \ | |
916 | if (!_node->child2()) { \ | |
917 | ASSERT(!_node->child3()); \ | |
918 | break; \ | |
919 | } \ | |
920 | thingToDo(_node, _node->child2()); \ | |
921 | \ | |
922 | if (!_node->child3()) \ | |
923 | break; \ | |
924 | thingToDo(_node, _node->child3()); \ | |
925 | } \ | |
926 | } while (false) | |
927 | ||
14957cd0 A |
928 | } } // namespace JSC::DFG |
929 | ||
930 | #endif | |
931 | #endif |