]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2011-2015 Apple Inc. All rights reserved. |
6fe7ccc8 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 | #include "config.h" | |
27 | #include "DFGPredictionPropagationPhase.h" | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "DFGGraph.h" | |
32 | #include "DFGPhase.h" | |
81345200 | 33 | #include "JSCInlines.h" |
6fe7ccc8 A |
34 | |
35 | namespace JSC { namespace DFG { | |
36 | ||
93a37866 A |
37 | SpeculatedType resultOfToPrimitive(SpeculatedType type) |
38 | { | |
39 | if (type & SpecObject) { | |
40 | // Objects get turned into strings. So if the input has hints of objectness, | |
41 | // the output will have hinsts of stringiness. | |
42 | return mergeSpeculations(type & ~SpecObject, SpecString); | |
43 | } | |
44 | ||
45 | return type; | |
46 | } | |
47 | ||
6fe7ccc8 A |
48 | class PredictionPropagationPhase : public Phase { |
49 | public: | |
50 | PredictionPropagationPhase(Graph& graph) | |
51 | : Phase(graph, "prediction propagation") | |
52 | { | |
53 | } | |
54 | ||
93a37866 | 55 | bool run() |
6fe7ccc8 | 56 | { |
93a37866 A |
57 | ASSERT(m_graph.m_form == ThreadedCPS); |
58 | ASSERT(m_graph.m_unificationState == GloballyUnified); | |
6fe7ccc8 | 59 | |
ed1e77d3 A |
60 | propagateThroughArgumentPositions(); |
61 | ||
81345200 A |
62 | m_pass = PrimaryPass; |
63 | propagateToFixpoint(); | |
64 | ||
65 | m_pass = RareCasePass; | |
66 | propagateToFixpoint(); | |
67 | ||
68 | m_pass = DoubleVotingPass; | |
69 | do { | |
70 | m_changed = false; | |
71 | doRoundOfDoubleVoting(); | |
72 | if (!m_changed) | |
73 | break; | |
74 | m_changed = false; | |
75 | propagateForward(); | |
76 | } while (m_changed); | |
77 | ||
78 | return true; | |
79 | } | |
80 | ||
81 | private: | |
82 | void propagateToFixpoint() | |
83 | { | |
6fe7ccc8 A |
84 | do { |
85 | m_changed = false; | |
86 | ||
87 | // Forward propagation is near-optimal for both topologically-sorted and | |
88 | // DFS-sorted code. | |
89 | propagateForward(); | |
90 | if (!m_changed) | |
91 | break; | |
92 | ||
93 | // Backward propagation reduces the likelihood that pathological code will | |
94 | // cause slowness. Loops (especially nested ones) resemble backward flow. | |
95 | // This pass captures two cases: (1) it detects if the forward fixpoint | |
96 | // found a sound solution and (2) short-circuits backward flow. | |
97 | m_changed = false; | |
98 | propagateBackward(); | |
99 | } while (m_changed); | |
6fe7ccc8 A |
100 | } |
101 | ||
93a37866 | 102 | bool setPrediction(SpeculatedType prediction) |
6fe7ccc8 | 103 | { |
93a37866 | 104 | ASSERT(m_currentNode->hasResult()); |
6fe7ccc8 A |
105 | |
106 | // setPrediction() is used when we know that there is no way that we can change | |
107 | // our minds about what the prediction is going to be. There is no semantic | |
93a37866 | 108 | // difference between setPrediction() and mergeSpeculation() other than the |
6fe7ccc8 | 109 | // increased checking to validate this property. |
93a37866 | 110 | ASSERT(m_currentNode->prediction() == SpecNone || m_currentNode->prediction() == prediction); |
6fe7ccc8 | 111 | |
93a37866 | 112 | return m_currentNode->predict(prediction); |
6fe7ccc8 A |
113 | } |
114 | ||
93a37866 | 115 | bool mergePrediction(SpeculatedType prediction) |
6fe7ccc8 | 116 | { |
93a37866 | 117 | ASSERT(m_currentNode->hasResult()); |
6fe7ccc8 | 118 | |
93a37866 | 119 | return m_currentNode->predict(prediction); |
6fe7ccc8 A |
120 | } |
121 | ||
93a37866 | 122 | SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value) |
6fe7ccc8 | 123 | { |
81345200 A |
124 | SpeculatedType result = SpecDoubleReal; |
125 | if (value & SpecDoubleImpureNaN) | |
126 | result |= SpecDoubleImpureNaN; | |
127 | if (value & SpecDoublePureNaN) | |
128 | result |= SpecDoublePureNaN; | |
129 | if (!isFullNumberOrBooleanSpeculation(value)) | |
130 | result |= SpecDoublePureNaN; | |
131 | return result; | |
6fe7ccc8 | 132 | } |
93a37866 A |
133 | |
134 | SpeculatedType speculatedDoubleTypeForPredictions(SpeculatedType left, SpeculatedType right) | |
6fe7ccc8 | 135 | { |
93a37866 | 136 | return speculatedDoubleTypeForPrediction(mergeSpeculations(left, right)); |
6fe7ccc8 | 137 | } |
93a37866 A |
138 | |
139 | void propagate(Node* node) | |
6fe7ccc8 | 140 | { |
93a37866 | 141 | NodeType op = node->op(); |
6fe7ccc8 | 142 | |
6fe7ccc8 A |
143 | bool changed = false; |
144 | ||
145 | switch (op) { | |
ed1e77d3 A |
146 | case JSConstant: { |
147 | SpeculatedType type = speculationFromValue(node->asJSValue()); | |
81345200 A |
148 | if (type == SpecInt52AsDouble && enableInt52()) |
149 | type = SpecInt52; | |
150 | changed |= setPrediction(type); | |
6fe7ccc8 A |
151 | break; |
152 | } | |
ed1e77d3 A |
153 | case DoubleConstant: { |
154 | SpeculatedType type = speculationFromValue(node->asJSValue()); | |
155 | changed |= setPrediction(type); | |
156 | break; | |
157 | } | |
6fe7ccc8 A |
158 | |
159 | case GetLocal: { | |
81345200 A |
160 | VariableAccessData* variable = node->variableAccessData(); |
161 | SpeculatedType prediction = variable->prediction(); | |
162 | if (!variable->couldRepresentInt52() && (prediction & SpecInt52)) | |
163 | prediction = (prediction | SpecInt52AsDouble) & ~SpecInt52; | |
6fe7ccc8 A |
164 | if (prediction) |
165 | changed |= mergePrediction(prediction); | |
6fe7ccc8 A |
166 | break; |
167 | } | |
168 | ||
169 | case SetLocal: { | |
93a37866 A |
170 | VariableAccessData* variableAccessData = node->variableAccessData(); |
171 | changed |= variableAccessData->predict(node->child1()->prediction()); | |
6fe7ccc8 A |
172 | break; |
173 | } | |
174 | ||
175 | case BitAnd: | |
176 | case BitOr: | |
177 | case BitXor: | |
178 | case BitRShift: | |
179 | case BitLShift: | |
93a37866 | 180 | case BitURShift: |
ed1e77d3 A |
181 | case ArithIMul: |
182 | case ArithClz32: { | |
93a37866 | 183 | changed |= setPrediction(SpecInt32); |
6fe7ccc8 A |
184 | break; |
185 | } | |
186 | ||
93a37866 A |
187 | case ArrayPop: |
188 | case ArrayPush: | |
6fe7ccc8 | 189 | case RegExpExec: |
93a37866 A |
190 | case RegExpTest: |
191 | case GetById: | |
192 | case GetByIdFlush: | |
93a37866 | 193 | case GetByOffset: |
81345200 | 194 | case MultiGetByOffset: |
ed1e77d3 | 195 | case GetDirectPname: |
93a37866 A |
196 | case Call: |
197 | case Construct: | |
ed1e77d3 A |
198 | case CallVarargs: |
199 | case ConstructVarargs: | |
200 | case CallForwardVarargs: | |
201 | case ConstructForwardVarargs: | |
202 | case NativeCall: | |
203 | case NativeConstruct: | |
93a37866 | 204 | case GetGlobalVar: |
ed1e77d3 A |
205 | case GetClosureVar: |
206 | case GetFromArguments: { | |
93a37866 | 207 | changed |= setPrediction(node->getHeapPrediction()); |
6fe7ccc8 A |
208 | break; |
209 | } | |
ed1e77d3 A |
210 | |
211 | case GetGetterSetterByOffset: | |
212 | case GetExecutable: { | |
213 | changed |= setPrediction(SpecCellOther); | |
214 | break; | |
215 | } | |
216 | ||
217 | case GetGetter: | |
218 | case GetSetter: | |
219 | case GetCallee: | |
220 | case NewFunction: { | |
221 | changed |= setPrediction(SpecFunction); | |
222 | break; | |
223 | } | |
224 | ||
225 | case GetArgumentCount: { | |
226 | changed |= setPrediction(SpecInt32); | |
227 | break; | |
228 | } | |
6fe7ccc8 A |
229 | |
230 | case StringCharCodeAt: { | |
93a37866 | 231 | changed |= setPrediction(SpecInt32); |
6fe7ccc8 A |
232 | break; |
233 | } | |
234 | ||
6fe7ccc8 | 235 | case UInt32ToNumber: { |
81345200 A |
236 | // FIXME: Support Int52. |
237 | // https://bugs.webkit.org/show_bug.cgi?id=125704 | |
238 | if (node->canSpeculateInt32(m_pass)) | |
93a37866 | 239 | changed |= mergePrediction(SpecInt32); |
6fe7ccc8 | 240 | else |
81345200 | 241 | changed |= mergePrediction(SpecBytecodeNumber); |
6fe7ccc8 A |
242 | break; |
243 | } | |
244 | ||
245 | case ValueAdd: { | |
93a37866 A |
246 | SpeculatedType left = node->child1()->prediction(); |
247 | SpeculatedType right = node->child2()->prediction(); | |
6fe7ccc8 A |
248 | |
249 | if (left && right) { | |
81345200 A |
250 | if (isFullNumberOrBooleanSpeculationExpectingDefined(left) |
251 | && isFullNumberOrBooleanSpeculationExpectingDefined(right)) { | |
252 | if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32) | |
93a37866 | 253 | changed |= mergePrediction(SpecInt32); |
81345200 A |
254 | else if (m_graph.addShouldSpeculateMachineInt(node)) |
255 | changed |= mergePrediction(SpecInt52); | |
6fe7ccc8 | 256 | else |
93a37866 | 257 | changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); |
81345200 A |
258 | } else if ( |
259 | !(left & (SpecFullNumber | SpecBoolean)) | |
260 | || !(right & (SpecFullNumber | SpecBoolean))) { | |
6fe7ccc8 | 261 | // left or right is definitely something other than a number. |
93a37866 | 262 | changed |= mergePrediction(SpecString); |
6fe7ccc8 | 263 | } else |
81345200 | 264 | changed |= mergePrediction(SpecString | SpecInt32 | SpecBytecodeDouble); |
6fe7ccc8 | 265 | } |
6fe7ccc8 A |
266 | break; |
267 | } | |
ed1e77d3 A |
268 | |
269 | case ArithAdd: | |
6fe7ccc8 | 270 | case ArithSub: { |
93a37866 A |
271 | SpeculatedType left = node->child1()->prediction(); |
272 | SpeculatedType right = node->child2()->prediction(); | |
6fe7ccc8 A |
273 | |
274 | if (left && right) { | |
81345200 | 275 | if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32) |
93a37866 | 276 | changed |= mergePrediction(SpecInt32); |
81345200 A |
277 | else if (m_graph.addShouldSpeculateMachineInt(node)) |
278 | changed |= mergePrediction(SpecInt52); | |
6fe7ccc8 | 279 | else |
93a37866 | 280 | changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); |
6fe7ccc8 | 281 | } |
6fe7ccc8 A |
282 | break; |
283 | } | |
284 | ||
285 | case ArithNegate: | |
93a37866 | 286 | if (node->child1()->prediction()) { |
81345200 | 287 | if (m_graph.negateShouldSpeculateInt32(node, m_pass)) |
93a37866 | 288 | changed |= mergePrediction(SpecInt32); |
81345200 A |
289 | else if (m_graph.negateShouldSpeculateMachineInt(node, m_pass)) |
290 | changed |= mergePrediction(SpecInt52); | |
6fe7ccc8 | 291 | else |
93a37866 | 292 | changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction())); |
6fe7ccc8 | 293 | } |
6fe7ccc8 A |
294 | break; |
295 | ||
296 | case ArithMin: | |
297 | case ArithMax: { | |
93a37866 A |
298 | SpeculatedType left = node->child1()->prediction(); |
299 | SpeculatedType right = node->child2()->prediction(); | |
6fe7ccc8 A |
300 | |
301 | if (left && right) { | |
81345200 A |
302 | if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) |
303 | && node->canSpeculateInt32(m_pass)) | |
93a37866 | 304 | changed |= mergePrediction(SpecInt32); |
6fe7ccc8 | 305 | else |
93a37866 | 306 | changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); |
6fe7ccc8 | 307 | } |
93a37866 A |
308 | break; |
309 | } | |
6fe7ccc8 | 310 | |
93a37866 A |
311 | case ArithMul: { |
312 | SpeculatedType left = node->child1()->prediction(); | |
313 | SpeculatedType right = node->child2()->prediction(); | |
314 | ||
315 | if (left && right) { | |
81345200 | 316 | if (m_graph.mulShouldSpeculateInt32(node, m_pass)) |
93a37866 | 317 | changed |= mergePrediction(SpecInt32); |
81345200 A |
318 | else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass)) |
319 | changed |= mergePrediction(SpecInt52); | |
93a37866 A |
320 | else |
321 | changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right)); | |
322 | } | |
6fe7ccc8 A |
323 | break; |
324 | } | |
ed1e77d3 A |
325 | |
326 | case ArithDiv: | |
93a37866 A |
327 | case ArithMod: { |
328 | SpeculatedType left = node->child1()->prediction(); | |
329 | SpeculatedType right = node->child2()->prediction(); | |
330 | ||
331 | if (left && right) { | |
81345200 A |
332 | if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) |
333 | && node->canSpeculateInt32(m_pass)) | |
93a37866 A |
334 | changed |= mergePrediction(SpecInt32); |
335 | else | |
81345200 | 336 | changed |= mergePrediction(SpecBytecodeDouble); |
93a37866 | 337 | } |
6fe7ccc8 A |
338 | break; |
339 | } | |
ed1e77d3 A |
340 | |
341 | case ArithPow: | |
81345200 A |
342 | case ArithSqrt: |
343 | case ArithFRound: | |
344 | case ArithSin: | |
ed1e77d3 A |
345 | case ArithCos: |
346 | case ArithLog: { | |
81345200 | 347 | changed |= setPrediction(SpecBytecodeDouble); |
6fe7ccc8 A |
348 | break; |
349 | } | |
ed1e77d3 A |
350 | |
351 | case ArithRound: { | |
352 | if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass)) | |
353 | changed |= setPrediction(SpecInt32); | |
354 | else | |
355 | changed |= setPrediction(SpecBytecodeDouble); | |
356 | break; | |
357 | } | |
358 | ||
6fe7ccc8 | 359 | case ArithAbs: { |
93a37866 | 360 | SpeculatedType child = node->child1()->prediction(); |
81345200 A |
361 | if (isInt32OrBooleanSpeculationForArithmetic(child) |
362 | && node->canSpeculateInt32(m_pass)) | |
93a37866 | 363 | changed |= mergePrediction(SpecInt32); |
6fe7ccc8 | 364 | else |
93a37866 | 365 | changed |= mergePrediction(speculatedDoubleTypeForPrediction(child)); |
6fe7ccc8 A |
366 | break; |
367 | } | |
368 | ||
369 | case LogicalNot: | |
370 | case CompareLess: | |
371 | case CompareLessEq: | |
372 | case CompareGreater: | |
373 | case CompareGreaterEq: | |
374 | case CompareEq: | |
93a37866 | 375 | case CompareEqConstant: |
6fe7ccc8 A |
376 | case CompareStrictEq: |
377 | case InstanceOf: | |
378 | case IsUndefined: | |
379 | case IsBoolean: | |
380 | case IsNumber: | |
381 | case IsString: | |
382 | case IsObject: | |
ed1e77d3 | 383 | case IsObjectOrNull: |
6fe7ccc8 | 384 | case IsFunction: { |
93a37866 | 385 | changed |= setPrediction(SpecBoolean); |
6fe7ccc8 A |
386 | break; |
387 | } | |
93a37866 A |
388 | |
389 | case TypeOf: { | |
ed1e77d3 | 390 | changed |= setPrediction(SpecStringIdent); |
6fe7ccc8 A |
391 | break; |
392 | } | |
93a37866 | 393 | |
6fe7ccc8 | 394 | case GetByVal: { |
81345200 A |
395 | if (!node->child1()->prediction()) |
396 | break; | |
397 | ||
398 | ArrayMode arrayMode = node->arrayMode().refine( | |
399 | m_graph, node, | |
400 | node->child1()->prediction(), | |
401 | node->child2()->prediction(), | |
ed1e77d3 | 402 | SpecNone); |
81345200 A |
403 | |
404 | switch (arrayMode.type()) { | |
ed1e77d3 A |
405 | case Array::Int32: |
406 | if (arrayMode.isOutOfBounds()) | |
407 | changed |= mergePrediction(node->getHeapPrediction() | SpecInt32); | |
408 | else | |
409 | changed |= mergePrediction(SpecInt32); | |
410 | break; | |
81345200 A |
411 | case Array::Double: |
412 | if (arrayMode.isOutOfBounds()) | |
413 | changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal); | |
414 | else | |
415 | changed |= mergePrediction(SpecDoubleReal); | |
416 | break; | |
417 | case Array::Float32Array: | |
418 | case Array::Float64Array: | |
419 | changed |= mergePrediction(SpecFullDouble); | |
420 | break; | |
421 | case Array::Uint32Array: | |
ed1e77d3 | 422 | if (isInt32SpeculationForArithmetic(node->getHeapPrediction())) |
81345200 A |
423 | changed |= mergePrediction(SpecInt32); |
424 | else if (enableInt52()) | |
425 | changed |= mergePrediction(SpecMachineInt); | |
426 | else | |
427 | changed |= mergePrediction(SpecInt32 | SpecInt52AsDouble); | |
428 | break; | |
ed1e77d3 A |
429 | case Array::Int8Array: |
430 | case Array::Uint8Array: | |
431 | case Array::Int16Array: | |
432 | case Array::Uint16Array: | |
433 | case Array::Int32Array: | |
434 | changed |= mergePrediction(SpecInt32); | |
435 | break; | |
81345200 | 436 | default: |
93a37866 | 437 | changed |= mergePrediction(node->getHeapPrediction()); |
81345200 A |
438 | break; |
439 | } | |
6fe7ccc8 A |
440 | break; |
441 | } | |
442 | ||
93a37866 A |
443 | case GetButterfly: |
444 | case GetIndexedPropertyStorage: | |
445 | case AllocatePropertyStorage: | |
446 | case ReallocatePropertyStorage: { | |
447 | changed |= setPrediction(SpecOther); | |
6fe7ccc8 A |
448 | break; |
449 | } | |
93a37866 | 450 | |
81345200 | 451 | case ToThis: { |
93a37866 | 452 | SpeculatedType prediction = node->child1()->prediction(); |
6fe7ccc8 | 453 | if (prediction) { |
93a37866 A |
454 | if (prediction & ~SpecObject) { |
455 | prediction &= SpecObject; | |
456 | prediction = mergeSpeculations(prediction, SpecObjectOther); | |
6fe7ccc8 A |
457 | } |
458 | changed |= mergePrediction(prediction); | |
459 | } | |
6fe7ccc8 A |
460 | break; |
461 | } | |
462 | ||
93a37866 A |
463 | case SkipScope: { |
464 | changed |= setPrediction(SpecObjectOther); | |
6fe7ccc8 A |
465 | break; |
466 | } | |
467 | ||
6fe7ccc8 A |
468 | case CreateThis: |
469 | case NewObject: { | |
93a37866 | 470 | changed |= setPrediction(SpecFinalObject); |
6fe7ccc8 A |
471 | break; |
472 | } | |
473 | ||
93a37866 A |
474 | case NewArray: |
475 | case NewArrayWithSize: | |
6fe7ccc8 | 476 | case NewArrayBuffer: { |
93a37866 | 477 | changed |= setPrediction(SpecArray); |
6fe7ccc8 A |
478 | break; |
479 | } | |
480 | ||
81345200 A |
481 | case NewTypedArray: { |
482 | changed |= setPrediction(speculationFromTypedArrayType(node->typedArrayType())); | |
483 | break; | |
484 | } | |
485 | ||
93a37866 A |
486 | case NewRegexp: |
487 | case CreateActivation: { | |
488 | changed |= setPrediction(SpecObjectOther); | |
6fe7ccc8 A |
489 | break; |
490 | } | |
491 | ||
93a37866 A |
492 | case StringFromCharCode: { |
493 | changed |= setPrediction(SpecString); | |
81345200 | 494 | changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt); |
6fe7ccc8 A |
495 | break; |
496 | } | |
93a37866 | 497 | case StringCharAt: |
ed1e77d3 | 498 | case CallStringConstructor: |
93a37866 A |
499 | case ToString: |
500 | case MakeRope: { | |
501 | changed |= setPrediction(SpecString); | |
6fe7ccc8 A |
502 | break; |
503 | } | |
504 | ||
505 | case ToPrimitive: { | |
93a37866 A |
506 | SpeculatedType child = node->child1()->prediction(); |
507 | if (child) | |
508 | changed |= mergePrediction(resultOfToPrimitive(child)); | |
6fe7ccc8 A |
509 | break; |
510 | } | |
511 | ||
93a37866 A |
512 | case NewStringObject: { |
513 | changed |= setPrediction(SpecStringObject); | |
514 | break; | |
515 | } | |
516 | ||
ed1e77d3 A |
517 | case CreateDirectArguments: { |
518 | changed |= setPrediction(SpecDirectArguments); | |
93a37866 A |
519 | break; |
520 | } | |
521 | ||
ed1e77d3 A |
522 | case CreateScopedArguments: { |
523 | changed |= setPrediction(SpecScopedArguments); | |
6fe7ccc8 A |
524 | break; |
525 | } | |
526 | ||
ed1e77d3 A |
527 | case CreateClonedArguments: { |
528 | changed |= setPrediction(SpecObjectOther); | |
6fe7ccc8 A |
529 | break; |
530 | } | |
531 | ||
81345200 A |
532 | case FiatInt52: { |
533 | RELEASE_ASSERT(enableInt52()); | |
534 | changed |= setPrediction(SpecMachineInt); | |
535 | break; | |
536 | } | |
537 | ||
6fe7ccc8 A |
538 | case PutByValAlias: |
539 | case GetArrayLength: | |
81345200 | 540 | case GetTypedArrayByteOffset: |
93a37866 A |
541 | case DoubleAsInt32: |
542 | case GetLocalUnlinked: | |
93a37866 A |
543 | case CheckArray: |
544 | case Arrayify: | |
545 | case ArrayifyToStructure: | |
81345200 A |
546 | case CheckTierUpInLoop: |
547 | case CheckTierUpAtReturn: | |
548 | case CheckTierUpAndOSREnter: | |
ed1e77d3 | 549 | case CheckTierUpWithNestedTriggerAndOSREnter: |
81345200 A |
550 | case InvalidationPoint: |
551 | case CheckInBounds: | |
552 | case ValueToInt32: | |
81345200 A |
553 | case DoubleRep: |
554 | case ValueRep: | |
555 | case Int52Rep: | |
81345200 A |
556 | case Int52Constant: |
557 | case Identity: | |
ed1e77d3 A |
558 | case BooleanToNumber: |
559 | case PhantomNewObject: | |
560 | case PhantomNewFunction: | |
561 | case PhantomCreateActivation: | |
562 | case PhantomDirectArguments: | |
563 | case PhantomClonedArguments: | |
564 | case GetMyArgumentByVal: | |
565 | case ForwardVarargs: | |
566 | case PutHint: | |
567 | case CheckStructureImmediate: | |
568 | case MaterializeNewObject: | |
569 | case MaterializeCreateActivation: | |
570 | case PutStack: | |
571 | case KillStack: | |
572 | case StoreBarrier: | |
573 | case GetStack: { | |
6fe7ccc8 A |
574 | // This node should never be visible at this stage of compilation. It is |
575 | // inserted by fixup(), which follows this phase. | |
ed1e77d3 | 576 | DFG_CRASH(m_graph, node, "Unexpected node during prediction propagation"); |
6fe7ccc8 A |
577 | break; |
578 | } | |
579 | ||
93a37866 A |
580 | case Phi: |
581 | // Phis should not be visible here since we're iterating the all-but-Phi's | |
582 | // part of basic blocks. | |
81345200 A |
583 | RELEASE_ASSERT_NOT_REACHED(); |
584 | break; | |
585 | ||
586 | case Upsilon: | |
81345200 A |
587 | // These don't get inserted until we go into SSA. |
588 | RELEASE_ASSERT_NOT_REACHED(); | |
6fe7ccc8 A |
589 | break; |
590 | ||
93a37866 A |
591 | case GetScope: |
592 | changed |= setPrediction(SpecObjectOther); | |
6fe7ccc8 | 593 | break; |
81345200 A |
594 | |
595 | case In: | |
596 | changed |= setPrediction(SpecBoolean); | |
6fe7ccc8 A |
597 | break; |
598 | ||
ed1e77d3 A |
599 | case GetEnumerableLength: { |
600 | changed |= setPrediction(SpecInt32); | |
601 | break; | |
602 | } | |
603 | case HasGenericProperty: | |
604 | case HasStructureProperty: | |
605 | case HasIndexedProperty: { | |
606 | changed |= setPrediction(SpecBoolean); | |
607 | break; | |
608 | } | |
609 | case GetPropertyEnumerator: { | |
610 | changed |= setPrediction(SpecCell); | |
611 | break; | |
612 | } | |
613 | case GetEnumeratorStructurePname: { | |
614 | changed |= setPrediction(SpecCell | SpecOther); | |
615 | break; | |
616 | } | |
617 | case GetEnumeratorGenericPname: { | |
618 | changed |= setPrediction(SpecCell | SpecOther); | |
619 | break; | |
620 | } | |
621 | case ToIndexString: { | |
622 | changed |= setPrediction(SpecString); | |
623 | break; | |
624 | } | |
625 | ||
6fe7ccc8 A |
626 | #ifndef NDEBUG |
627 | // These get ignored because they don't return anything. | |
81345200 | 628 | case PutByValDirect: |
93a37866 | 629 | case PutByVal: |
81345200 | 630 | case PutClosureVar: |
ed1e77d3 | 631 | case PutToArguments: |
93a37866 A |
632 | case Return: |
633 | case Throw: | |
634 | case PutById: | |
81345200 | 635 | case PutByIdFlush: |
93a37866 A |
636 | case PutByIdDirect: |
637 | case PutByOffset: | |
81345200 | 638 | case MultiPutByOffset: |
6fe7ccc8 A |
639 | case DFG::Jump: |
640 | case Branch: | |
81345200 | 641 | case Switch: |
6fe7ccc8 | 642 | case Breakpoint: |
81345200 A |
643 | case ProfileWillCall: |
644 | case ProfileDidCall: | |
ed1e77d3 A |
645 | case ProfileType: |
646 | case ProfileControlFlow: | |
6fe7ccc8 A |
647 | case CheckHasInstance: |
648 | case ThrowReferenceError: | |
649 | case ForceOSRExit: | |
650 | case SetArgument: | |
651 | case CheckStructure: | |
ed1e77d3 A |
652 | case CheckCell: |
653 | case CheckNotEmpty: | |
654 | case CheckBadCell: | |
6fe7ccc8 | 655 | case PutStructure: |
81345200 | 656 | case VarInjectionWatchpoint: |
93a37866 | 657 | case Phantom: |
81345200 | 658 | case Check: |
93a37866 | 659 | case PutGlobalVar: |
93a37866 | 660 | case CheckWatchdogTimer: |
12899fa2 | 661 | case Unreachable: |
81345200 A |
662 | case LoopHint: |
663 | case NotifyWrite: | |
81345200 A |
664 | case ConstantStoragePointer: |
665 | case MovHint: | |
666 | case ZombieHint: | |
ed1e77d3 A |
667 | case LoadVarargs: |
668 | break; | |
669 | ||
670 | // This gets ignored because it only pretends to produce a value. | |
671 | case BottomValue: | |
81345200 A |
672 | break; |
673 | ||
674 | // This gets ignored because it already has a prediction. | |
675 | case ExtractOSREntryLocal: | |
6fe7ccc8 A |
676 | break; |
677 | ||
678 | // These gets ignored because it doesn't do anything. | |
93a37866 A |
679 | case CountExecution: |
680 | case PhantomLocal: | |
681 | case Flush: | |
6fe7ccc8 A |
682 | break; |
683 | ||
684 | case LastNodeType: | |
81345200 | 685 | RELEASE_ASSERT_NOT_REACHED(); |
6fe7ccc8 A |
686 | break; |
687 | #else | |
688 | default: | |
6fe7ccc8 A |
689 | break; |
690 | #endif | |
691 | } | |
692 | ||
6fe7ccc8 A |
693 | m_changed |= changed; |
694 | } | |
695 | ||
6fe7ccc8 A |
696 | void propagateForward() |
697 | { | |
81345200 A |
698 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { |
699 | BasicBlock* block = m_graph.block(blockIndex); | |
93a37866 A |
700 | if (!block) |
701 | continue; | |
702 | ASSERT(block->isReachable); | |
703 | for (unsigned i = 0; i < block->size(); ++i) { | |
704 | m_currentNode = block->at(i); | |
705 | propagate(m_currentNode); | |
706 | } | |
707 | } | |
6fe7ccc8 A |
708 | } |
709 | ||
710 | void propagateBackward() | |
711 | { | |
81345200 A |
712 | for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { |
713 | BasicBlock* block = m_graph.block(blockIndex); | |
93a37866 A |
714 | if (!block) |
715 | continue; | |
716 | ASSERT(block->isReachable); | |
717 | for (unsigned i = block->size(); i--;) { | |
718 | m_currentNode = block->at(i); | |
719 | propagate(m_currentNode); | |
720 | } | |
6fe7ccc8 | 721 | } |
6fe7ccc8 A |
722 | } |
723 | ||
81345200 | 724 | void doDoubleVoting(Node* node, float weight) |
6fe7ccc8 | 725 | { |
81345200 A |
726 | // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate |
727 | // that we actually don't know they weight. Assume that they execute once. This turns | |
728 | // out to be an OK assumption since the pre-header doesn't have any meaningful code. | |
729 | if (weight != weight) | |
730 | weight = 1; | |
731 | ||
93a37866 A |
732 | switch (node->op()) { |
733 | case ValueAdd: | |
734 | case ArithAdd: | |
735 | case ArithSub: { | |
736 | SpeculatedType left = node->child1()->prediction(); | |
737 | SpeculatedType right = node->child2()->prediction(); | |
738 | ||
739 | DoubleBallot ballot; | |
740 | ||
81345200 A |
741 | if (isFullNumberSpeculation(left) |
742 | && isFullNumberSpeculation(right) | |
743 | && !m_graph.addShouldSpeculateInt32(node, m_pass) | |
744 | && !m_graph.addShouldSpeculateMachineInt(node)) | |
93a37866 A |
745 | ballot = VoteDouble; |
746 | else | |
747 | ballot = VoteValue; | |
748 | ||
81345200 A |
749 | m_graph.voteNode(node->child1(), ballot, weight); |
750 | m_graph.voteNode(node->child2(), ballot, weight); | |
93a37866 | 751 | break; |
6fe7ccc8 | 752 | } |
6fe7ccc8 | 753 | |
93a37866 A |
754 | case ArithMul: { |
755 | SpeculatedType left = node->child1()->prediction(); | |
756 | SpeculatedType right = node->child2()->prediction(); | |
6fe7ccc8 | 757 | |
93a37866 | 758 | DoubleBallot ballot; |
6fe7ccc8 | 759 | |
81345200 A |
760 | if (isFullNumberSpeculation(left) |
761 | && isFullNumberSpeculation(right) | |
762 | && !m_graph.mulShouldSpeculateInt32(node, m_pass) | |
763 | && !m_graph.mulShouldSpeculateMachineInt(node, m_pass)) | |
93a37866 A |
764 | ballot = VoteDouble; |
765 | else | |
766 | ballot = VoteValue; | |
6fe7ccc8 | 767 | |
81345200 A |
768 | m_graph.voteNode(node->child1(), ballot, weight); |
769 | m_graph.voteNode(node->child2(), ballot, weight); | |
93a37866 A |
770 | break; |
771 | } | |
772 | ||
773 | case ArithMin: | |
774 | case ArithMax: | |
775 | case ArithMod: | |
776 | case ArithDiv: { | |
777 | SpeculatedType left = node->child1()->prediction(); | |
778 | SpeculatedType right = node->child2()->prediction(); | |
6fe7ccc8 | 779 | |
93a37866 | 780 | DoubleBallot ballot; |
6fe7ccc8 | 781 | |
81345200 A |
782 | if (isFullNumberSpeculation(left) |
783 | && isFullNumberSpeculation(right) | |
784 | && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32(m_pass))) | |
93a37866 A |
785 | ballot = VoteDouble; |
786 | else | |
787 | ballot = VoteValue; | |
6fe7ccc8 | 788 | |
81345200 A |
789 | m_graph.voteNode(node->child1(), ballot, weight); |
790 | m_graph.voteNode(node->child2(), ballot, weight); | |
93a37866 A |
791 | break; |
792 | } | |
6fe7ccc8 | 793 | |
93a37866 A |
794 | case ArithAbs: |
795 | DoubleBallot ballot; | |
81345200 A |
796 | if (node->child1()->shouldSpeculateNumber() |
797 | && !(node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(m_pass))) | |
93a37866 A |
798 | ballot = VoteDouble; |
799 | else | |
800 | ballot = VoteValue; | |
6fe7ccc8 | 801 | |
81345200 | 802 | m_graph.voteNode(node->child1(), ballot, weight); |
93a37866 | 803 | break; |
6fe7ccc8 | 804 | |
93a37866 | 805 | case ArithSqrt: |
81345200 A |
806 | case ArithCos: |
807 | case ArithSin: | |
ed1e77d3 | 808 | case ArithLog: |
81345200 A |
809 | if (node->child1()->shouldSpeculateNumber()) |
810 | m_graph.voteNode(node->child1(), VoteDouble, weight); | |
811 | else | |
812 | m_graph.voteNode(node->child1(), VoteValue, weight); | |
93a37866 | 813 | break; |
6fe7ccc8 | 814 | |
93a37866 A |
815 | case SetLocal: { |
816 | SpeculatedType prediction = node->child1()->prediction(); | |
817 | if (isDoubleSpeculation(prediction)) | |
81345200 A |
818 | node->variableAccessData()->vote(VoteDouble, weight); |
819 | else if ( | |
820 | !isFullNumberSpeculation(prediction) | |
821 | || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction)) | |
822 | node->variableAccessData()->vote(VoteValue, weight); | |
93a37866 A |
823 | break; |
824 | } | |
81345200 A |
825 | |
826 | case PutByValDirect: | |
93a37866 A |
827 | case PutByVal: |
828 | case PutByValAlias: { | |
829 | Edge child1 = m_graph.varArgChild(node, 0); | |
830 | Edge child2 = m_graph.varArgChild(node, 1); | |
831 | Edge child3 = m_graph.varArgChild(node, 2); | |
81345200 A |
832 | m_graph.voteNode(child1, VoteValue, weight); |
833 | m_graph.voteNode(child2, VoteValue, weight); | |
93a37866 A |
834 | switch (node->arrayMode().type()) { |
835 | case Array::Double: | |
81345200 | 836 | m_graph.voteNode(child3, VoteDouble, weight); |
93a37866 | 837 | break; |
6fe7ccc8 | 838 | default: |
81345200 | 839 | m_graph.voteNode(child3, VoteValue, weight); |
6fe7ccc8 A |
840 | break; |
841 | } | |
93a37866 A |
842 | break; |
843 | } | |
844 | ||
81345200 A |
845 | case MovHint: |
846 | // Ignore these since they have no effect on in-DFG execution. | |
847 | break; | |
848 | ||
93a37866 | 849 | default: |
81345200 | 850 | m_graph.voteChildren(node, VoteValue, weight); |
93a37866 A |
851 | break; |
852 | } | |
853 | } | |
854 | ||
855 | void doRoundOfDoubleVoting() | |
856 | { | |
93a37866 A |
857 | for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) |
858 | m_graph.m_variableAccessData[i].find()->clearVotes(); | |
81345200 A |
859 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { |
860 | BasicBlock* block = m_graph.block(blockIndex); | |
93a37866 A |
861 | if (!block) |
862 | continue; | |
863 | ASSERT(block->isReachable); | |
864 | for (unsigned i = 0; i < block->size(); ++i) { | |
865 | m_currentNode = block->at(i); | |
81345200 | 866 | doDoubleVoting(m_currentNode, block->executionCount); |
93a37866 | 867 | } |
6fe7ccc8 A |
868 | } |
869 | for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { | |
870 | VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; | |
871 | if (!variableAccessData->isRoot()) | |
872 | continue; | |
6fe7ccc8 A |
873 | m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat(); |
874 | } | |
ed1e77d3 | 875 | propagateThroughArgumentPositions(); |
6fe7ccc8 A |
876 | for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) { |
877 | VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i]; | |
878 | if (!variableAccessData->isRoot()) | |
879 | continue; | |
6fe7ccc8 A |
880 | m_changed |= variableAccessData->makePredictionForDoubleFormat(); |
881 | } | |
882 | } | |
883 | ||
ed1e77d3 A |
884 | void propagateThroughArgumentPositions() |
885 | { | |
886 | for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i) | |
887 | m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness(); | |
888 | } | |
889 | ||
93a37866 | 890 | Node* m_currentNode; |
6fe7ccc8 | 891 | bool m_changed; |
81345200 | 892 | PredictionPass m_pass; // We use different logic for considering predictions depending on how far along we are in propagation. |
6fe7ccc8 A |
893 | }; |
894 | ||
93a37866 | 895 | bool performPredictionPropagation(Graph& graph) |
6fe7ccc8 | 896 | { |
93a37866 A |
897 | SamplingRegion samplingRegion("DFG Prediction Propagation Phase"); |
898 | return runPhase<PredictionPropagationPhase>(graph); | |
6fe7ccc8 A |
899 | } |
900 | ||
901 | } } // namespace JSC::DFG | |
902 | ||
903 | #endif // ENABLE(DFG_JIT) | |
904 |