]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGPredictionPropagationPhase.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / dfg / DFGPredictionPropagationPhase.cpp
1 /*
2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
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 #include "config.h"
27 #include "DFGPredictionPropagationPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGGraph.h"
32 #include "DFGPhase.h"
33
34 namespace JSC { namespace DFG {
35
36 class PredictionPropagationPhase : public Phase {
37 public:
38 PredictionPropagationPhase(Graph& graph)
39 : Phase(graph, "prediction propagation")
40 {
41 }
42
43 void run()
44 {
45 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
46 m_count = 0;
47 #endif
48 // 1) propagate predictions
49
50 do {
51 m_changed = false;
52
53 // Forward propagation is near-optimal for both topologically-sorted and
54 // DFS-sorted code.
55 propagateForward();
56 if (!m_changed)
57 break;
58
59 // Backward propagation reduces the likelihood that pathological code will
60 // cause slowness. Loops (especially nested ones) resemble backward flow.
61 // This pass captures two cases: (1) it detects if the forward fixpoint
62 // found a sound solution and (2) short-circuits backward flow.
63 m_changed = false;
64 propagateBackward();
65 } while (m_changed);
66
67 // 2) repropagate predictions while doing double voting.
68
69 do {
70 m_changed = false;
71 doRoundOfDoubleVoting();
72 propagateForward();
73 if (!m_changed)
74 break;
75
76 m_changed = false;
77 doRoundOfDoubleVoting();
78 propagateBackward();
79 } while (m_changed);
80 }
81
82 private:
83 bool setPrediction(PredictedType prediction)
84 {
85 ASSERT(m_graph[m_compileIndex].hasResult());
86
87 // setPrediction() is used when we know that there is no way that we can change
88 // our minds about what the prediction is going to be. There is no semantic
89 // difference between setPrediction() and mergePrediction() other than the
90 // increased checking to validate this property.
91 ASSERT(m_graph[m_compileIndex].prediction() == PredictNone || m_graph[m_compileIndex].prediction() == prediction);
92
93 return m_graph[m_compileIndex].predict(prediction);
94 }
95
96 bool mergePrediction(PredictedType prediction)
97 {
98 ASSERT(m_graph[m_compileIndex].hasResult());
99
100 return m_graph[m_compileIndex].predict(prediction);
101 }
102
103 bool isNotNegZero(NodeIndex nodeIndex)
104 {
105 if (!m_graph.isNumberConstant(nodeIndex))
106 return false;
107 double value = m_graph.valueOfNumberConstant(nodeIndex);
108 return !value && 1.0 / value < 0.0;
109 }
110
111 bool isNotZero(NodeIndex nodeIndex)
112 {
113 if (!m_graph.isNumberConstant(nodeIndex))
114 return false;
115 return !!m_graph.valueOfNumberConstant(nodeIndex);
116 }
117
118 void propagate(Node& node)
119 {
120 if (!node.shouldGenerate())
121 return;
122
123 NodeType op = node.op();
124 NodeFlags flags = node.flags() & NodeBackPropMask;
125
126 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
127 dataLog(" %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
128 #endif
129
130 bool changed = false;
131
132 switch (op) {
133 case JSConstant:
134 case WeakJSConstant: {
135 changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
136 break;
137 }
138
139 case GetLocal: {
140 VariableAccessData* variableAccessData = node.variableAccessData();
141 PredictedType prediction = variableAccessData->prediction();
142 if (prediction)
143 changed |= mergePrediction(prediction);
144
145 changed |= variableAccessData->mergeFlags(flags);
146 break;
147 }
148
149 case SetLocal: {
150 VariableAccessData* variableAccessData = node.variableAccessData();
151 changed |= variableAccessData->predict(m_graph[node.child1()].prediction());
152 changed |= m_graph[node.child1()].mergeFlags(variableAccessData->flags());
153 break;
154 }
155
156 case Flush: {
157 // Make sure that the analysis knows that flushed locals escape.
158 VariableAccessData* variableAccessData = node.variableAccessData();
159 changed |= variableAccessData->mergeFlags(NodeUsedAsValue);
160 break;
161 }
162
163 case BitAnd:
164 case BitOr:
165 case BitXor:
166 case BitRShift:
167 case BitLShift:
168 case BitURShift: {
169 changed |= setPrediction(PredictInt32);
170 flags |= NodeUsedAsInt;
171 flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
172 changed |= m_graph[node.child1()].mergeFlags(flags);
173 changed |= m_graph[node.child2()].mergeFlags(flags);
174 break;
175 }
176
177 case ValueToInt32: {
178 changed |= setPrediction(PredictInt32);
179 flags |= NodeUsedAsInt;
180 flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
181 changed |= m_graph[node.child1()].mergeFlags(flags);
182 break;
183 }
184
185 case ArrayPop: {
186 changed |= mergePrediction(node.getHeapPrediction());
187 changed |= mergeDefaultFlags(node);
188 break;
189 }
190
191 case ArrayPush: {
192 changed |= mergePrediction(node.getHeapPrediction());
193 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
194 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
195 break;
196 }
197
198 case RegExpExec:
199 case RegExpTest: {
200 changed |= mergePrediction(node.getHeapPrediction());
201 changed |= mergeDefaultFlags(node);
202 break;
203 }
204
205 case StringCharCodeAt: {
206 changed |= mergePrediction(PredictInt32);
207 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
208 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
209 break;
210 }
211
212 case ArithMod: {
213 PredictedType left = m_graph[node.child1()].prediction();
214 PredictedType right = m_graph[node.child2()].prediction();
215
216 if (left && right) {
217 if (isInt32Prediction(mergePredictions(left, right))
218 && nodeCanSpeculateInteger(node.arithNodeFlags()))
219 changed |= mergePrediction(PredictInt32);
220 else
221 changed |= mergePrediction(PredictDouble);
222 }
223
224 flags |= NodeUsedAsValue;
225 changed |= m_graph[node.child1()].mergeFlags(flags);
226 changed |= m_graph[node.child2()].mergeFlags(flags);
227 break;
228 }
229
230 case UInt32ToNumber: {
231 if (nodeCanSpeculateInteger(node.arithNodeFlags()))
232 changed |= mergePrediction(PredictInt32);
233 else
234 changed |= mergePrediction(PredictNumber);
235
236 changed |= m_graph[node.child1()].mergeFlags(flags);
237 break;
238 }
239
240 case ValueAdd: {
241 PredictedType left = m_graph[node.child1()].prediction();
242 PredictedType right = m_graph[node.child2()].prediction();
243
244 if (left && right) {
245 if (isNumberPrediction(left) && isNumberPrediction(right)) {
246 if (m_graph.addShouldSpeculateInteger(node))
247 changed |= mergePrediction(PredictInt32);
248 else
249 changed |= mergePrediction(PredictDouble);
250 } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
251 // left or right is definitely something other than a number.
252 changed |= mergePrediction(PredictString);
253 } else
254 changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble);
255 }
256
257 if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
258 flags &= ~NodeNeedsNegZero;
259
260 changed |= m_graph[node.child1()].mergeFlags(flags);
261 changed |= m_graph[node.child2()].mergeFlags(flags);
262 break;
263 }
264
265 case ArithAdd: {
266 PredictedType left = m_graph[node.child1()].prediction();
267 PredictedType right = m_graph[node.child2()].prediction();
268
269 if (left && right) {
270 if (m_graph.addShouldSpeculateInteger(node))
271 changed |= mergePrediction(PredictInt32);
272 else
273 changed |= mergePrediction(PredictDouble);
274 }
275
276 if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
277 flags &= ~NodeNeedsNegZero;
278
279 changed |= m_graph[node.child1()].mergeFlags(flags);
280 changed |= m_graph[node.child2()].mergeFlags(flags);
281 break;
282 }
283
284 case ArithSub: {
285 PredictedType left = m_graph[node.child1()].prediction();
286 PredictedType right = m_graph[node.child2()].prediction();
287
288 if (left && right) {
289 if (m_graph.addShouldSpeculateInteger(node))
290 changed |= mergePrediction(PredictInt32);
291 else
292 changed |= mergePrediction(PredictDouble);
293 }
294
295 if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
296 flags &= ~NodeNeedsNegZero;
297
298 changed |= m_graph[node.child1()].mergeFlags(flags);
299 changed |= m_graph[node.child2()].mergeFlags(flags);
300 break;
301 }
302
303 case ArithNegate:
304 if (m_graph[node.child1()].prediction()) {
305 if (m_graph.negateShouldSpeculateInteger(node))
306 changed |= mergePrediction(PredictInt32);
307 else
308 changed |= mergePrediction(PredictDouble);
309 }
310
311 changed |= m_graph[node.child1()].mergeFlags(flags);
312 break;
313
314 case ArithMin:
315 case ArithMax: {
316 PredictedType left = m_graph[node.child1()].prediction();
317 PredictedType right = m_graph[node.child2()].prediction();
318
319 if (left && right) {
320 if (isInt32Prediction(mergePredictions(left, right))
321 && nodeCanSpeculateInteger(node.arithNodeFlags()))
322 changed |= mergePrediction(PredictInt32);
323 else
324 changed |= mergePrediction(PredictDouble);
325 }
326
327 flags |= NodeUsedAsNumber;
328 changed |= m_graph[node.child1()].mergeFlags(flags);
329 changed |= m_graph[node.child2()].mergeFlags(flags);
330 break;
331 }
332
333 case ArithMul:
334 case ArithDiv: {
335 PredictedType left = m_graph[node.child1()].prediction();
336 PredictedType right = m_graph[node.child2()].prediction();
337
338 if (left && right) {
339 if (isInt32Prediction(mergePredictions(left, right))
340 && nodeCanSpeculateInteger(node.arithNodeFlags()))
341 changed |= mergePrediction(PredictInt32);
342 else
343 changed |= mergePrediction(PredictDouble);
344 }
345
346 // As soon as a multiply happens, we can easily end up in the part
347 // of the double domain where the point at which you do truncation
348 // can change the outcome. So, ArithMul always checks for overflow
349 // no matter what, and always forces its inputs to check as well.
350
351 flags |= NodeUsedAsNumber | NodeNeedsNegZero;
352 changed |= m_graph[node.child1()].mergeFlags(flags);
353 changed |= m_graph[node.child2()].mergeFlags(flags);
354 break;
355 }
356
357 case ArithSqrt: {
358 changed |= setPrediction(PredictDouble);
359 changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
360 break;
361 }
362
363 case ArithAbs: {
364 PredictedType child = m_graph[node.child1()].prediction();
365 if (nodeCanSpeculateInteger(node.arithNodeFlags()))
366 changed |= mergePrediction(child);
367 else
368 changed |= setPrediction(PredictDouble);
369
370 flags &= ~NodeNeedsNegZero;
371 changed |= m_graph[node.child1()].mergeFlags(flags);
372 break;
373 }
374
375 case LogicalNot:
376 case CompareLess:
377 case CompareLessEq:
378 case CompareGreater:
379 case CompareGreaterEq:
380 case CompareEq:
381 case CompareStrictEq:
382 case InstanceOf:
383 case IsUndefined:
384 case IsBoolean:
385 case IsNumber:
386 case IsString:
387 case IsObject:
388 case IsFunction: {
389 changed |= setPrediction(PredictBoolean);
390 changed |= mergeDefaultFlags(node);
391 break;
392 }
393
394 case GetById: {
395 changed |= mergePrediction(node.getHeapPrediction());
396 changed |= mergeDefaultFlags(node);
397 break;
398 }
399
400 case GetByIdFlush:
401 changed |= mergePrediction(node.getHeapPrediction());
402 changed |= mergeDefaultFlags(node);
403 break;
404
405 case GetByVal: {
406 if (m_graph[node.child1()].shouldSpeculateFloat32Array()
407 || m_graph[node.child1()].shouldSpeculateFloat64Array())
408 changed |= mergePrediction(PredictDouble);
409 else
410 changed |= mergePrediction(node.getHeapPrediction());
411
412 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
413 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
414 break;
415 }
416
417 case GetPropertyStorage:
418 case GetIndexedPropertyStorage: {
419 changed |= setPrediction(PredictOther);
420 changed |= mergeDefaultFlags(node);
421 break;
422 }
423
424 case GetByOffset: {
425 changed |= mergePrediction(node.getHeapPrediction());
426 changed |= mergeDefaultFlags(node);
427 break;
428 }
429
430 case Call:
431 case Construct: {
432 changed |= mergePrediction(node.getHeapPrediction());
433 for (unsigned childIdx = node.firstChild();
434 childIdx < node.firstChild() + node.numChildren();
435 ++childIdx) {
436 Edge edge = m_graph.m_varArgChildren[childIdx];
437 changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
438 }
439 break;
440 }
441
442 case ConvertThis: {
443 PredictedType prediction = m_graph[node.child1()].prediction();
444 if (prediction) {
445 if (prediction & ~PredictObjectMask) {
446 prediction &= PredictObjectMask;
447 prediction = mergePredictions(prediction, PredictObjectOther);
448 }
449 changed |= mergePrediction(prediction);
450 }
451 changed |= mergeDefaultFlags(node);
452 break;
453 }
454
455 case GetGlobalVar: {
456 changed |= mergePrediction(node.getHeapPrediction());
457 break;
458 }
459
460 case PutGlobalVar: {
461 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
462 break;
463 }
464
465 case GetScopedVar:
466 case Resolve:
467 case ResolveBase:
468 case ResolveBaseStrictPut:
469 case ResolveGlobal: {
470 PredictedType prediction = node.getHeapPrediction();
471 changed |= mergePrediction(prediction);
472 break;
473 }
474
475 case GetScopeChain: {
476 changed |= setPrediction(PredictCellOther);
477 break;
478 }
479
480 case GetCallee: {
481 changed |= setPrediction(PredictFunction);
482 break;
483 }
484
485 case CreateThis:
486 case NewObject: {
487 changed |= setPrediction(PredictFinalObject);
488 changed |= mergeDefaultFlags(node);
489 break;
490 }
491
492 case NewArray: {
493 changed |= setPrediction(PredictArray);
494 for (unsigned childIdx = node.firstChild();
495 childIdx < node.firstChild() + node.numChildren();
496 ++childIdx) {
497 Edge edge = m_graph.m_varArgChildren[childIdx];
498 changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
499 }
500 break;
501 }
502
503 case NewArrayBuffer: {
504 changed |= setPrediction(PredictArray);
505 break;
506 }
507
508 case NewRegexp: {
509 changed |= setPrediction(PredictObjectOther);
510 break;
511 }
512
513 case StringCharAt: {
514 changed |= setPrediction(PredictString);
515 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
516 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
517 break;
518 }
519
520 case StrCat: {
521 changed |= setPrediction(PredictString);
522 for (unsigned childIdx = node.firstChild();
523 childIdx < node.firstChild() + node.numChildren();
524 ++childIdx)
525 changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
526 break;
527 }
528
529 case ToPrimitive: {
530 PredictedType child = m_graph[node.child1()].prediction();
531 if (child) {
532 if (isObjectPrediction(child)) {
533 // I'd love to fold this case into the case below, but I can't, because
534 // removing PredictObjectMask from something that only has an object
535 // prediction and nothing else means we have an ill-formed PredictedType
536 // (strong predict-none). This should be killed once we remove all traces
537 // of static (aka weak) predictions.
538 changed |= mergePrediction(PredictString);
539 } else if (child & PredictObjectMask) {
540 // Objects get turned into strings. So if the input has hints of objectness,
541 // the output will have hinsts of stringiness.
542 changed |= mergePrediction(
543 mergePredictions(child & ~PredictObjectMask, PredictString));
544 } else
545 changed |= mergePrediction(child);
546 }
547 changed |= m_graph[node.child1()].mergeFlags(flags);
548 break;
549 }
550
551 case CreateActivation: {
552 changed |= setPrediction(PredictObjectOther);
553 break;
554 }
555
556 case NewFunction:
557 case NewFunctionNoCheck:
558 case NewFunctionExpression: {
559 changed |= setPrediction(PredictFunction);
560 break;
561 }
562
563 case PutByValAlias:
564 case GetArrayLength:
565 case GetInt8ArrayLength:
566 case GetInt16ArrayLength:
567 case GetInt32ArrayLength:
568 case GetUint8ArrayLength:
569 case GetUint8ClampedArrayLength:
570 case GetUint16ArrayLength:
571 case GetUint32ArrayLength:
572 case GetFloat32ArrayLength:
573 case GetFloat64ArrayLength:
574 case GetStringLength:
575 case Int32ToDouble:
576 case DoubleAsInt32: {
577 // This node should never be visible at this stage of compilation. It is
578 // inserted by fixup(), which follows this phase.
579 ASSERT_NOT_REACHED();
580 break;
581 }
582
583 case PutByVal:
584 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
585 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
586 changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
587 break;
588
589 case PutScopedVar:
590 case Return:
591 case Throw:
592 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
593 break;
594
595 case PutById:
596 case PutByIdDirect:
597 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
598 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
599 break;
600
601 case PutByOffset:
602 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
603 changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
604 break;
605
606 case Phi:
607 break;
608
609 #ifndef NDEBUG
610 // These get ignored because they don't return anything.
611 case DFG::Jump:
612 case Branch:
613 case Breakpoint:
614 case CheckHasInstance:
615 case ThrowReferenceError:
616 case ForceOSRExit:
617 case SetArgument:
618 case CheckStructure:
619 case CheckFunction:
620 case PutStructure:
621 case TearOffActivation:
622 case CheckNumber:
623 changed |= mergeDefaultFlags(node);
624 break;
625
626 // These gets ignored because it doesn't do anything.
627 case Phantom:
628 case InlineStart:
629 case Nop:
630 break;
631
632 case LastNodeType:
633 ASSERT_NOT_REACHED();
634 break;
635 #else
636 default:
637 changed |= mergeDefaultFlags(node);
638 break;
639 #endif
640 }
641
642 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
643 dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
644 #endif
645
646 m_changed |= changed;
647 }
648
649 bool mergeDefaultFlags(Node& node)
650 {
651 bool changed = false;
652 if (node.flags() & NodeHasVarArgs) {
653 for (unsigned childIdx = node.firstChild();
654 childIdx < node.firstChild() + node.numChildren();
655 childIdx++)
656 changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
657 } else {
658 if (!node.child1())
659 return changed;
660 changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
661 if (!node.child2())
662 return changed;
663 changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
664 if (!node.child3())
665 return changed;
666 changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
667 }
668 return changed;
669 }
670
671 void propagateForward()
672 {
673 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
674 dataLog("Propagating predictions forward [%u]\n", ++m_count);
675 #endif
676 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
677 propagate(m_graph[m_compileIndex]);
678 }
679
680 void propagateBackward()
681 {
682 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
683 dataLog("Propagating predictions backward [%u]\n", ++m_count);
684 #endif
685 for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
686 propagate(m_graph[m_compileIndex]);
687 }
688
689 void vote(Edge nodeUse, VariableAccessData::Ballot ballot)
690 {
691 switch (m_graph[nodeUse].op()) {
692 case ValueToInt32:
693 case UInt32ToNumber:
694 nodeUse = m_graph[nodeUse].child1();
695 break;
696 default:
697 break;
698 }
699
700 if (m_graph[nodeUse].op() == GetLocal)
701 m_graph[nodeUse].variableAccessData()->vote(ballot);
702 }
703
704 void vote(Node& node, VariableAccessData::Ballot ballot)
705 {
706 if (node.flags() & NodeHasVarArgs) {
707 for (unsigned childIdx = node.firstChild();
708 childIdx < node.firstChild() + node.numChildren();
709 childIdx++)
710 vote(m_graph.m_varArgChildren[childIdx], ballot);
711 return;
712 }
713
714 if (!node.child1())
715 return;
716 vote(node.child1(), ballot);
717 if (!node.child2())
718 return;
719 vote(node.child2(), ballot);
720 if (!node.child3())
721 return;
722 vote(node.child3(), ballot);
723 }
724
725 void doRoundOfDoubleVoting()
726 {
727 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
728 dataLog("Voting on double uses of locals [%u]\n", m_count);
729 #endif
730 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
731 m_graph.m_variableAccessData[i].find()->clearVotes();
732 for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex) {
733 Node& node = m_graph[m_compileIndex];
734 switch (node.op()) {
735 case ValueAdd:
736 case ArithAdd:
737 case ArithSub: {
738 PredictedType left = m_graph[node.child1()].prediction();
739 PredictedType right = m_graph[node.child2()].prediction();
740
741 VariableAccessData::Ballot ballot;
742
743 if (isNumberPrediction(left) && isNumberPrediction(right)
744 && !m_graph.addShouldSpeculateInteger(node))
745 ballot = VariableAccessData::VoteDouble;
746 else
747 ballot = VariableAccessData::VoteValue;
748
749 vote(node.child1(), ballot);
750 vote(node.child2(), ballot);
751 break;
752 }
753
754 case ArithMul:
755 case ArithMin:
756 case ArithMax:
757 case ArithMod:
758 case ArithDiv: {
759 PredictedType left = m_graph[node.child1()].prediction();
760 PredictedType right = m_graph[node.child2()].prediction();
761
762 VariableAccessData::Ballot ballot;
763
764 if (isNumberPrediction(left) && isNumberPrediction(right)
765 && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()])
766 && node.canSpeculateInteger()))
767 ballot = VariableAccessData::VoteDouble;
768 else
769 ballot = VariableAccessData::VoteValue;
770
771 vote(node.child1(), ballot);
772 vote(node.child2(), ballot);
773 break;
774 }
775
776 case ArithAbs:
777 VariableAccessData::Ballot ballot;
778 if (!(m_graph[node.child1()].shouldSpeculateInteger()
779 && node.canSpeculateInteger()))
780 ballot = VariableAccessData::VoteDouble;
781 else
782 ballot = VariableAccessData::VoteValue;
783
784 vote(node.child1(), ballot);
785 break;
786
787 case ArithSqrt:
788 vote(node.child1(), VariableAccessData::VoteDouble);
789 break;
790
791 case SetLocal: {
792 PredictedType prediction = m_graph[node.child1()].prediction();
793 if (isDoublePrediction(prediction))
794 node.variableAccessData()->vote(VariableAccessData::VoteDouble);
795 else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction))
796 node.variableAccessData()->vote(VariableAccessData::VoteValue);
797 break;
798 }
799
800 default:
801 vote(node, VariableAccessData::VoteValue);
802 break;
803 }
804 }
805 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
806 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
807 if (!variableAccessData->isRoot())
808 continue;
809 if (operandIsArgument(variableAccessData->local())
810 || m_graph.isCaptured(variableAccessData->local()))
811 continue;
812 m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
813 }
814 for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
815 m_changed |= m_graph.m_argumentPositions[i].mergeArgumentAwareness();
816 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
817 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
818 if (!variableAccessData->isRoot())
819 continue;
820 if (operandIsArgument(variableAccessData->local())
821 || m_graph.isCaptured(variableAccessData->local()))
822 continue;
823 m_changed |= variableAccessData->makePredictionForDoubleFormat();
824 }
825 }
826
827 NodeIndex m_compileIndex;
828 bool m_changed;
829
830 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
831 unsigned m_count;
832 #endif
833 };
834
835 void performPredictionPropagation(Graph& graph)
836 {
837 runPhase<PredictionPropagationPhase>(graph);
838 }
839
840 } } // namespace JSC::DFG
841
842 #endif // ENABLE(DFG_JIT)
843