]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGFixupPhase.cpp
JavaScriptCore-1218.0.1.tar.gz
[apple/javascriptcore.git] / dfg / DFGFixupPhase.cpp
CommitLineData
6fe7ccc8 1/*
93a37866 2 * Copyright (C) 2012, 2013 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 "DFGFixupPhase.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGGraph.h"
32#include "DFGInsertionSet.h"
33#include "DFGPhase.h"
93a37866
A
34#include "DFGPredictionPropagationPhase.h"
35#include "DFGVariableAccessDataDump.h"
36#include "Operations.h"
6fe7ccc8
A
37
38namespace JSC { namespace DFG {
39
40class FixupPhase : public Phase {
41public:
42 FixupPhase(Graph& graph)
43 : Phase(graph, "fixup")
93a37866 44 , m_insertionSet(graph)
6fe7ccc8
A
45 {
46 }
47
93a37866 48 bool run()
6fe7ccc8 49 {
93a37866
A
50 ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
51 ASSERT(m_graph.m_form == ThreadedCPS);
52
53 m_profitabilityChanged = false;
6fe7ccc8
A
54 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
55 fixupBlock(m_graph.m_blocks[blockIndex].get());
93a37866
A
56
57 while (m_profitabilityChanged) {
58 m_profitabilityChanged = false;
59
60 for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
61 m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
62
63 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
64 fixupSetLocalsInBlock(m_graph.m_blocks[blockIndex].get());
65 }
66
67 return true;
6fe7ccc8
A
68 }
69
70private:
71 void fixupBlock(BasicBlock* block)
72 {
93a37866
A
73 if (!block)
74 return;
75 ASSERT(block->isReachable);
76 m_block = block;
6fe7ccc8 77 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
93a37866
A
78 m_currentNode = block->at(m_indexInBlock);
79 fixupNode(m_currentNode);
6fe7ccc8 80 }
93a37866 81 m_insertionSet.execute(block);
6fe7ccc8
A
82 }
83
93a37866 84 void fixupNode(Node* node)
6fe7ccc8 85 {
93a37866 86 NodeType op = node->op();
6fe7ccc8
A
87
88#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
93a37866 89 dataLogF(" %s @%u: ", Graph::opName(op), node->index());
6fe7ccc8
A
90#endif
91
92 switch (op) {
93a37866
A
93 case SetLocal: {
94 // This gets handled by fixupSetLocalsInBlock().
95 break;
96 }
97
98 case BitAnd:
99 case BitOr:
100 case BitXor:
101 case BitRShift:
102 case BitLShift:
103 case BitURShift:
104 case ArithIMul: {
105 fixIntEdge(node->child1());
106 fixIntEdge(node->child2());
107 break;
108 }
109
110 case UInt32ToNumber: {
111 setUseKindAndUnboxIfProfitable<KnownInt32Use>(node->child1());
112 break;
113 }
114
115 case DoubleAsInt32: {
116 RELEASE_ASSERT_NOT_REACHED();
117 break;
118 }
119
120 case ValueToInt32: {
121 if (node->child1()->shouldSpeculateInteger()) {
122 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
6fe7ccc8 123 break;
93a37866
A
124 }
125
126 if (node->child1()->shouldSpeculateNumber()) {
127 setUseKindAndUnboxIfProfitable<NumberUse>(node->child1());
6fe7ccc8 128 break;
93a37866
A
129 }
130
131 if (node->child1()->shouldSpeculateBoolean()) {
132 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
6fe7ccc8 133 break;
93a37866 134 }
6fe7ccc8 135
93a37866 136 setUseKindAndUnboxIfProfitable<NotCellUse>(node->child1());
6fe7ccc8
A
137 break;
138 }
139
93a37866
A
140 case Int32ToDouble: {
141 RELEASE_ASSERT_NOT_REACHED();
142 break;
143 }
144
145 case ValueAdd: {
146 if (attemptToMakeIntegerAdd(node))
147 break;
148 if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
149 fixDoubleEdge<NumberUse>(node->child1());
150 fixDoubleEdge<NumberUse>(node->child2());
151 break;
6fe7ccc8 152 }
93a37866
A
153
154 // FIXME: Optimize for the case where one of the operands is the
155 // empty string. Also consider optimizing for the case where we don't
156 // believe either side is the emtpy string. Both of these things should
157 // be easy.
158
159 if (node->child1()->shouldSpeculateString()
160 && attemptToMakeFastStringAdd<StringUse>(node, node->child1(), node->child2()))
161 break;
162 if (node->child2()->shouldSpeculateString()
163 && attemptToMakeFastStringAdd<StringUse>(node, node->child2(), node->child1()))
164 break;
165 if (node->child1()->shouldSpeculateStringObject()
166 && attemptToMakeFastStringAdd<StringObjectUse>(node, node->child1(), node->child2()))
167 break;
168 if (node->child2()->shouldSpeculateStringObject()
169 && attemptToMakeFastStringAdd<StringObjectUse>(node, node->child2(), node->child1()))
170 break;
171 if (node->child1()->shouldSpeculateStringOrStringObject()
172 && attemptToMakeFastStringAdd<StringOrStringObjectUse>(node, node->child1(), node->child2()))
173 break;
174 if (node->child2()->shouldSpeculateStringOrStringObject()
175 && attemptToMakeFastStringAdd<StringOrStringObjectUse>(node, node->child2(), node->child1()))
176 break;
6fe7ccc8
A
177 break;
178 }
179
93a37866
A
180 case MakeRope: {
181 fixupMakeRope(node);
182 break;
183 }
184
185 case ArithAdd:
186 case ArithSub: {
187 if (attemptToMakeIntegerAdd(node))
188 break;
189 fixDoubleEdge<NumberUse>(node->child1());
190 fixDoubleEdge<NumberUse>(node->child2());
191 break;
192 }
193
194 case ArithNegate: {
195 if (m_graph.negateShouldSpeculateInteger(node)) {
196 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
197 break;
198 }
199 fixDoubleEdge<NumberUse>(node->child1());
200 break;
201 }
202
203 case ArithMul: {
204 if (m_graph.mulShouldSpeculateInteger(node)) {
205 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
206 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
207 break;
208 }
209 fixDoubleEdge<NumberUse>(node->child1());
210 fixDoubleEdge<NumberUse>(node->child2());
211 break;
212 }
213
214 case ArithDiv: {
215 if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
216 && node->canSpeculateInteger()) {
217 if (isX86() || isARM64() || isARMv7s()) {
218 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
219 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
220 break;
221 }
222 injectInt32ToDoubleNode(node->child1());
223 injectInt32ToDoubleNode(node->child2());
224
225 // We don't need to do ref'ing on the children because we're stealing them from
226 // the original division.
227 Node* newDivision = m_insertionSet.insertNode(
228 m_indexInBlock, SpecDouble, *node);
229
230 node->setOp(DoubleAsInt32);
231 node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
232 break;
233 }
234 fixDoubleEdge<NumberUse>(node->child1());
235 fixDoubleEdge<NumberUse>(node->child2());
6fe7ccc8
A
236 break;
237 }
238
93a37866
A
239 case ArithMin:
240 case ArithMax:
241 case ArithMod: {
242 if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
243 && node->canSpeculateInteger()) {
244 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
245 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
246 break;
247 }
248 fixDoubleEdge<NumberUse>(node->child1());
249 fixDoubleEdge<NumberUse>(node->child2());
250 break;
251 }
252
253 case ArithAbs: {
254 if (node->child1()->shouldSpeculateIntegerForArithmetic()
255 && node->canSpeculateInteger()) {
256 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
257 break;
258 }
259 fixDoubleEdge<NumberUse>(node->child1());
260 break;
261 }
262
263 case ArithSqrt: {
264 fixDoubleEdge<NumberUse>(node->child1());
265 break;
266 }
267
268 case LogicalNot: {
269 if (node->child1()->shouldSpeculateBoolean())
270 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
271 else if (node->child1()->shouldSpeculateObjectOrOther())
272 setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
273 else if (node->child1()->shouldSpeculateInteger())
274 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
275 else if (node->child1()->shouldSpeculateNumber())
276 fixDoubleEdge<NumberUse>(node->child1());
277 break;
278 }
279
280 case TypeOf: {
281 if (node->child1()->shouldSpeculateString())
282 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
283 else if (node->child1()->shouldSpeculateCell())
284 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
285 break;
286 }
287
288 case CompareEqConstant: {
289 break;
290 }
291
6fe7ccc8
A
292 case CompareEq:
293 case CompareLess:
294 case CompareLessEq:
295 case CompareGreater:
93a37866
A
296 case CompareGreaterEq: {
297 if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
298 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
299 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
300 break;
301 }
302 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
303 fixDoubleEdge<NumberUse>(node->child1());
304 fixDoubleEdge<NumberUse>(node->child2());
305 break;
306 }
307 if (node->op() != CompareEq)
308 break;
309 if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
310 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
311 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
312 break;
313 }
314 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
315 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
316 setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
317 break;
318 }
319 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
320 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
321 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
6fe7ccc8 322 break;
93a37866
A
323 }
324 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
325 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
326 setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child2());
6fe7ccc8 327 break;
93a37866
A
328 }
329 if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
330 setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
331 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
332 break;
333 }
6fe7ccc8
A
334 break;
335 }
336
93a37866
A
337 case CompareStrictEqConstant: {
338 break;
339 }
340
341 case CompareStrictEq: {
342 if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
343 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
344 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child2());
345 break;
346 }
347 if (Node::shouldSpeculateInteger(node->child1().node(), node->child2().node())) {
348 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
349 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
6fe7ccc8 350 break;
93a37866
A
351 }
352 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
353 fixDoubleEdge<NumberUse>(node->child1());
354 fixDoubleEdge<NumberUse>(node->child2());
355 break;
356 }
357 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
358 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
359 setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
6fe7ccc8 360 break;
93a37866
A
361 }
362 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
363 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
364 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child2());
365 break;
366 }
6fe7ccc8
A
367 break;
368 }
6fe7ccc8 369
93a37866
A
370 case StringFromCharCode:
371 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
372 break;
373
374 case StringCharAt:
375 case StringCharCodeAt: {
376 // Currently we have no good way of refining these.
377 ASSERT(node->arrayMode() == ArrayMode(Array::String));
378 blessArrayOperation(node->child1(), node->child2(), node->child3());
379 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
380 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
6fe7ccc8
A
381 break;
382 }
93a37866
A
383
384 case GetByVal: {
385 node->setArrayMode(
386 node->arrayMode().refine(
387 node->child1()->prediction(),
388 node->child2()->prediction(),
389 SpecNone, node->flags()));
6fe7ccc8 390
93a37866
A
391 blessArrayOperation(node->child1(), node->child2(), node->child3());
392
393 ArrayMode arrayMode = node->arrayMode();
394 if (arrayMode.type() == Array::Double
395 && arrayMode.arrayClass() == Array::OriginalArray
396 && arrayMode.speculation() == Array::InBounds
397 && arrayMode.conversion() == Array::AsIs
398 && m_graph.globalObjectFor(node->codeOrigin)->arrayPrototypeChainIsSane()
399 && !(node->flags() & NodeUsedAsOther))
400 node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
401
402 switch (node->arrayMode().type()) {
403 case Array::SelectUsingPredictions:
404 case Array::Unprofiled:
405 case Array::Undecided:
406 RELEASE_ASSERT_NOT_REACHED();
407 break;
408 case Array::Generic:
409#if USE(JSVALUE32_64)
410 setUseKindAndUnboxIfProfitable<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
411#endif
412 break;
413 case Array::ForceExit:
6fe7ccc8 414 break;
93a37866
A
415 default:
416 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
417 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
6fe7ccc8 418 break;
93a37866
A
419 }
420
6fe7ccc8
A
421 break;
422 }
423
93a37866
A
424 case PutByVal:
425 case PutByValAlias: {
426 Edge& child1 = m_graph.varArgChild(node, 0);
427 Edge& child2 = m_graph.varArgChild(node, 1);
428 Edge& child3 = m_graph.varArgChild(node, 2);
429
430 node->setArrayMode(
431 node->arrayMode().refine(
432 child1->prediction(),
433 child2->prediction(),
434 child3->prediction()));
435
436 blessArrayOperation(child1, child2, m_graph.varArgChild(node, 3));
437
438 switch (node->arrayMode().modeForPut().type()) {
439 case Array::SelectUsingPredictions:
440 case Array::Unprofiled:
441 case Array::Undecided:
442 RELEASE_ASSERT_NOT_REACHED();
6fe7ccc8 443 break;
93a37866
A
444 case Array::ForceExit:
445 case Array::Generic:
446#if USE(JSVALUE32_64)
447 // Due to register pressure on 32-bit, we speculate cell and
448 // ignore the base-is-not-cell case entirely by letting the
449 // baseline JIT handle it.
450 setUseKindAndUnboxIfProfitable<CellUse>(child1);
451#endif
452 break;
453 case Array::Int32:
454 setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
455 setUseKindAndUnboxIfProfitable<Int32Use>(child2);
456 setUseKindAndUnboxIfProfitable<Int32Use>(child3);
457 break;
458 case Array::Double:
459 setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
460 setUseKindAndUnboxIfProfitable<Int32Use>(child2);
461 fixDoubleEdge<RealNumberUse>(child3);
462 break;
463 case Array::Int8Array:
464 case Array::Int16Array:
465 case Array::Int32Array:
466 case Array::Uint8Array:
467 case Array::Uint8ClampedArray:
468 case Array::Uint16Array:
469 case Array::Uint32Array:
470 setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
471 setUseKindAndUnboxIfProfitable<Int32Use>(child2);
472 if (child3->shouldSpeculateInteger())
473 setUseKindAndUnboxIfProfitable<Int32Use>(child3);
474 else
475 fixDoubleEdge<NumberUse>(child3);
6fe7ccc8 476 break;
93a37866
A
477 case Array::Float32Array:
478 case Array::Float64Array:
479 setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
480 setUseKindAndUnboxIfProfitable<Int32Use>(child2);
481 fixDoubleEdge<NumberUse>(child3);
482 break;
483 default:
484 setUseKindAndUnboxIfProfitable<KnownCellUse>(child1);
485 setUseKindAndUnboxIfProfitable<Int32Use>(child2);
486 break;
487 }
6fe7ccc8
A
488 break;
489 }
490
93a37866
A
491 case ArrayPush: {
492 // May need to refine the array mode in case the value prediction contravenes
493 // the array prediction. For example, we may have evidence showing that the
494 // array is in Int32 mode, but the value we're storing is likely to be a double.
495 // Then we should turn this into a conversion to Double array followed by the
496 // push. On the other hand, we absolutely don't want to refine based on the
497 // base prediction. If it has non-cell garbage in it, then we want that to be
498 // ignored. That's because ArrayPush can't handle any array modes that aren't
499 // array-related - so if refine() turned this into a "Generic" ArrayPush then
500 // that would break things.
501 node->setArrayMode(
502 node->arrayMode().refine(
503 node->child1()->prediction() & SpecCell,
504 SpecInt32,
505 node->child2()->prediction()));
506 blessArrayOperation(node->child1(), Edge(), node->child3());
507 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
508
509 switch (node->arrayMode().type()) {
510 case Array::Int32:
511 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
512 break;
513 case Array::Double:
514 fixDoubleEdge<RealNumberUse>(node->child2());
515 break;
516 default:
6fe7ccc8 517 break;
93a37866 518 }
6fe7ccc8
A
519 break;
520 }
521
93a37866
A
522 case ArrayPop: {
523 blessArrayOperation(node->child1(), Edge(), node->child2());
524 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
6fe7ccc8
A
525 break;
526 }
527
93a37866
A
528 case RegExpExec:
529 case RegExpTest: {
530 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
531 setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
6fe7ccc8
A
532 break;
533 }
534
93a37866
A
535 case Branch: {
536 if (node->child1()->shouldSpeculateBoolean())
537 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
538 else if (node->child1()->shouldSpeculateObjectOrOther())
539 setUseKindAndUnboxIfProfitable<ObjectOrOtherUse>(node->child1());
540 else if (node->child1()->shouldSpeculateInteger())
541 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
542 else if (node->child1()->shouldSpeculateNumber())
543 fixDoubleEdge<NumberUse>(node->child1());
544
545 Node* logicalNot = node->child1().node();
546 if (logicalNot->op() == LogicalNot) {
6fe7ccc8 547
93a37866
A
548 // Make sure that OSR exit can't observe the LogicalNot. If it can,
549 // then we must compute it and cannot peephole around it.
550 bool found = false;
551 bool ok = true;
552 for (unsigned i = m_indexInBlock; i--;) {
553 Node* candidate = m_block->at(i);
554 if (candidate == logicalNot) {
555 found = true;
556 break;
557 }
558 if (candidate->canExit()) {
559 ok = false;
560 found = true;
561 break;
562 }
563 }
564 ASSERT_UNUSED(found, found);
6fe7ccc8 565
93a37866
A
566 if (ok) {
567 Edge newChildEdge = logicalNot->child1();
568 if (newChildEdge->hasBooleanResult()) {
569 node->children.setChild1(newChildEdge);
570
571 BlockIndex toBeTaken = node->notTakenBlockIndex();
572 BlockIndex toBeNotTaken = node->takenBlockIndex();
573 node->setTakenBlockIndex(toBeTaken);
574 node->setNotTakenBlockIndex(toBeNotTaken);
575 }
576 }
577 }
578 break;
579 }
580
581 case ToPrimitive: {
582 fixupToPrimitive(node);
583 break;
584 }
585
586 case ToString: {
587 fixupToString(node);
588 break;
589 }
590
591 case NewStringObject: {
592 setUseKindAndUnboxIfProfitable<KnownStringUse>(node->child1());
593 break;
594 }
595
596 case NewArray: {
597 for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
598 node->setIndexingType(
599 leastUpperBoundOfIndexingTypeAndType(
600 node->indexingType(), m_graph.varArgChild(node, i)->prediction()));
601 }
602 switch (node->indexingType()) {
603 case ALL_BLANK_INDEXING_TYPES:
604 CRASH();
605 break;
606 case ALL_UNDECIDED_INDEXING_TYPES:
607 if (node->numChildren()) {
608 // This will only happen if the children have no type predictions. We
609 // would have already exited by now, but insert a forced exit just to
610 // be safe.
611 m_insertionSet.insertNode(
612 m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
613 }
614 break;
615 case ALL_INT32_INDEXING_TYPES:
616 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
617 setUseKindAndUnboxIfProfitable<Int32Use>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
618 break;
619 case ALL_DOUBLE_INDEXING_TYPES:
620 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
621 setUseKindAndUnboxIfProfitable<RealNumberUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
622 break;
623 case ALL_CONTIGUOUS_INDEXING_TYPES:
624 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
625 break;
626 default:
627 CRASH();
6fe7ccc8
A
628 break;
629 }
6fe7ccc8
A
630 break;
631 }
632
93a37866
A
633 case NewArrayWithSize: {
634 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
635 break;
636 }
637
638 case ConvertThis: {
639 if (isOtherSpeculation(node->child1()->prediction())) {
640 m_insertionSet.insertNode(
641 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
642 Edge(node->child1().node(), OtherUse));
643 observeUseKindOnNode<OtherUse>(node->child1().node());
644 node->convertToWeakConstant(m_graph.globalThisObjectFor(node->codeOrigin));
6fe7ccc8 645 break;
93a37866
A
646 }
647
648 if (isObjectSpeculation(node->child1()->prediction())) {
649 setUseKindAndUnboxIfProfitable<ObjectUse>(node->child1());
650 node->convertToIdentity();
651 break;
652 }
653
6fe7ccc8
A
654 break;
655 }
656
93a37866
A
657 case CreateThis: {
658 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
659 break;
660 }
661
662 case GetMyArgumentByVal:
663 case GetMyArgumentByValSafe: {
664 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
665 break;
666 }
667
668 case GetScopeRegisters:
669 case PutScopedVar:
670 case SkipTopScope:
671 case SkipScope:
672 case SetCallee:
673 case SetMyScope:
674 case PutStructure:
675 case AllocatePropertyStorage:
676 case ReallocatePropertyStorage:
677 case GetScope:
678 case GetButterfly: {
679 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
6fe7ccc8
A
680 break;
681 }
682
93a37866
A
683 case GetById: {
684 if (!node->child1()->shouldSpeculateCell())
6fe7ccc8 685 break;
93a37866
A
686 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
687 if (!isInt32Speculation(node->prediction()))
6fe7ccc8 688 break;
93a37866 689 if (codeBlock()->identifier(node->identifierNumber()) != vm().propertyNames->length)
6fe7ccc8 690 break;
93a37866
A
691 ArrayProfile* arrayProfile =
692 m_graph.baselineCodeBlockFor(node->codeOrigin)->getArrayProfile(
693 node->codeOrigin.bytecodeIndex);
694 ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
695 if (arrayProfile) {
696 arrayProfile->computeUpdatedPrediction(m_graph.baselineCodeBlockFor(node->codeOrigin));
697 arrayMode = ArrayMode::fromObserved(arrayProfile, Array::Read, false);
698 arrayMode = arrayMode.refine(
699 node->child1()->prediction(), node->prediction());
700 if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
701 m_insertionSet.insertNode(
702 m_indexInBlock, SpecNone, CheckStructure, node->codeOrigin,
703 OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
704 node->child1());
705 }
706 } else
707 arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
708
709 if (arrayMode.type() == Array::Generic) {
710 // Check if the input is something that we can't get array length for, but for which we
711 // could insert some conversions in order to transform it into something that we can do it
712 // for.
713 if (node->child1()->shouldSpeculateStringObject())
714 attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
715 else if (node->child1()->shouldSpeculateStringOrStringObject())
716 attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
6fe7ccc8 717 }
93a37866
A
718
719 if (!arrayMode.supportsLength())
720 break;
721 node->setOp(GetArrayLength);
722 ASSERT(node->flags() & NodeMustGenerate);
723 node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
724 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
725 node->setArrayMode(arrayMode);
726
727 Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage);
728 if (!storage)
729 break;
730
731 node->child2() = Edge(storage);
732 break;
733 }
734
735 case GetByIdFlush: {
736 if (node->child1()->shouldSpeculateCell())
737 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
738 break;
739 }
740
741 case CheckExecutable:
742 case CheckStructure:
743 case ForwardCheckStructure:
744 case StructureTransitionWatchpoint:
745 case ForwardStructureTransitionWatchpoint:
746 case CheckFunction:
747 case PutById:
748 case PutByIdDirect:
749 case CheckHasInstance: {
750 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
751 break;
752 }
753
754 case CheckArray: {
755 switch (node->arrayMode().type()) {
756 case Array::String:
757 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
758 break;
759 default:
760 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
6fe7ccc8
A
761 break;
762 }
763 break;
764 }
765
93a37866
A
766 case Arrayify:
767 case ArrayifyToStructure: {
768 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
769 if (node->child2())
770 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
771 break;
772 }
773
774 case GetByOffset: {
775 if (!node->child1()->hasStorageResult())
776 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
777 break;
778 }
779
780 case PutByOffset: {
781 if (!node->child1()->hasStorageResult())
782 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
783 setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child2());
784 break;
785 }
786
787 case InstanceOf: {
788 // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
789 // check. https://bugs.webkit.org/show_bug.cgi?id=107479
790 if (!(node->child1()->prediction() & ~SpecCell))
791 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
792 setUseKindAndUnboxIfProfitable<CellUse>(node->child2());
793 break;
794 }
795
796 case Phantom:
797 case Identity: {
798 switch (node->child1().useKind()) {
799 case NumberUse:
800 if (node->child1()->shouldSpeculateIntegerForArithmetic())
801 node->child1().setUseKind(Int32Use);
802 break;
803 default:
804 break;
805 }
806 observeUseKindOnEdge(node->child1());
807 break;
808 }
809
810 case GetArrayLength:
811 case Nop:
812 case Phi:
813 case ForwardInt32ToDouble:
814 case PhantomPutStructure:
815 case GetIndexedPropertyStorage:
816 case LastNodeType:
817 case MovHint:
818 case MovHintAndCheck:
819 case ZombieHint:
820 RELEASE_ASSERT_NOT_REACHED();
821 break;
822
823#if !ASSERT_DISABLED
824 // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
825 case SetArgument:
826 case JSConstant:
827 case WeakJSConstant:
828 case GetLocal:
829 case GetCallee:
830 case Flush:
831 case PhantomLocal:
832 case GetLocalUnlinked:
833 case InlineStart:
834 case GetMyScope:
835 case GetScopedVar:
836 case GetGlobalVar:
837 case PutGlobalVar:
838 case GlobalVarWatchpoint:
839 case PutGlobalVarCheck:
840 case AllocationProfileWatchpoint:
841 case Call:
842 case Construct:
843 case NewObject:
844 case NewArrayBuffer:
845 case NewRegexp:
846 case Resolve:
847 case ResolveBase:
848 case ResolveBaseStrictPut:
849 case ResolveGlobal:
850 case Breakpoint:
851 case IsUndefined:
852 case IsBoolean:
853 case IsNumber:
854 case IsString:
855 case IsObject:
856 case IsFunction:
857 case CreateActivation:
858 case TearOffActivation:
859 case CreateArguments:
860 case PhantomArguments:
861 case TearOffArguments:
862 case GetMyArgumentsLength:
863 case GetMyArgumentsLengthSafe:
864 case CheckArgumentsNotCreated:
865 case NewFunction:
866 case NewFunctionNoCheck:
867 case NewFunctionExpression:
868 case Jump:
869 case Return:
870 case Throw:
871 case ThrowReferenceError:
872 case GarbageValue:
873 case CountExecution:
874 case ForceOSRExit:
875 case CheckWatchdogTimer:
876 break;
877#else
6fe7ccc8
A
878 default:
879 break;
93a37866 880#endif
6fe7ccc8
A
881 }
882
883#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
93a37866
A
884 if (!(node->flags() & NodeHasVarArgs)) {
885 dataLogF("new children: ");
886 node->dumpChildren(WTF::dataFile());
6fe7ccc8 887 }
93a37866 888 dataLogF("\n");
6fe7ccc8
A
889#endif
890 }
891
93a37866
A
892 template<UseKind useKind>
893 void createToString(Node* node, Edge& edge)
894 {
895 edge.setNode(m_insertionSet.insertNode(
896 m_indexInBlock, SpecString, ToString, node->codeOrigin,
897 Edge(edge.node(), useKind)));
898 }
899
900 template<UseKind useKind>
901 void attemptToForceStringArrayModeByToStringConversion(ArrayMode& arrayMode, Node* node)
902 {
903 ASSERT(arrayMode == ArrayMode(Array::Generic));
904
905 if (!canOptimizeStringObjectAccess(node->codeOrigin))
906 return;
907
908 createToString<useKind>(node, node->child1());
909 arrayMode = ArrayMode(Array::String);
910 }
911
912 template<UseKind useKind>
913 bool isStringObjectUse()
914 {
915 switch (useKind) {
916 case StringObjectUse:
917 case StringOrStringObjectUse:
918 return true;
919 default:
920 return false;
921 }
922 }
923
924 template<UseKind useKind>
925 void convertStringAddUse(Node* node, Edge& edge)
926 {
927 if (useKind == StringUse) {
928 // This preserves the binaryUseKind() invariant ot ValueAdd: ValueAdd's
929 // two edges will always have identical use kinds, which makes the
930 // decision process much easier.
931 observeUseKindOnNode<StringUse>(edge.node());
932 m_insertionSet.insertNode(
933 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
934 Edge(edge.node(), StringUse));
935 edge.setUseKind(KnownStringUse);
936 return;
937 }
938
939 // FIXME: We ought to be able to have a ToPrimitiveToString node.
940
941 observeUseKindOnNode<useKind>(edge.node());
942 createToString<useKind>(node, edge);
943 }
944
945 void convertToMakeRope(Node* node)
946 {
947 node->setOpAndDefaultFlags(MakeRope);
948 fixupMakeRope(node);
949 }
950
951 void fixupMakeRope(Node* node)
952 {
953 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
954 Edge& edge = node->children.child(i);
955 if (!edge)
956 break;
957 edge.setUseKind(KnownStringUse);
958 if (!m_graph.isConstant(edge.node()))
959 continue;
960 JSString* string = jsCast<JSString*>(m_graph.valueOfJSConstant(edge.node()).asCell());
961 if (string->length())
962 continue;
963
964 // Don't allow the MakeRope to have zero children.
965 if (!i && !node->child2())
966 break;
967
968 node->children.removeEdge(i--);
969 }
970
971 if (!node->child2()) {
972 ASSERT(!node->child3());
973 node->convertToIdentity();
974 }
975 }
976
977 void fixupToPrimitive(Node* node)
978 {
979 if (node->child1()->shouldSpeculateInteger()) {
980 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
981 node->convertToIdentity();
982 return;
983 }
984
985 if (node->child1()->shouldSpeculateString()) {
986 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
987 node->convertToIdentity();
988 return;
989 }
990
991 if (node->child1()->shouldSpeculateStringObject()
992 && canOptimizeStringObjectAccess(node->codeOrigin)) {
993 setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
994 node->convertToToString();
995 return;
996 }
997
998 if (node->child1()->shouldSpeculateStringOrStringObject()
999 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1000 setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
1001 node->convertToToString();
1002 return;
1003 }
1004 }
1005
1006 void fixupToString(Node* node)
1007 {
1008 if (node->child1()->shouldSpeculateString()) {
1009 setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
1010 node->convertToIdentity();
1011 return;
1012 }
1013
1014 if (node->child1()->shouldSpeculateStringObject()
1015 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1016 setUseKindAndUnboxIfProfitable<StringObjectUse>(node->child1());
1017 return;
1018 }
1019
1020 if (node->child1()->shouldSpeculateStringOrStringObject()
1021 && canOptimizeStringObjectAccess(node->codeOrigin)) {
1022 setUseKindAndUnboxIfProfitable<StringOrStringObjectUse>(node->child1());
1023 return;
1024 }
1025
1026 if (node->child1()->shouldSpeculateCell()) {
1027 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
1028 return;
1029 }
1030 }
1031
1032 template<UseKind leftUseKind>
1033 bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
1034 {
1035 Node* originalLeft = left.node();
1036 Node* originalRight = right.node();
1037
1038 ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse);
1039
1040 if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->codeOrigin))
1041 return false;
1042
1043 convertStringAddUse<leftUseKind>(node, left);
1044
1045 if (right->shouldSpeculateString())
1046 convertStringAddUse<StringUse>(node, right);
1047 else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
1048 convertStringAddUse<StringObjectUse>(node, right);
1049 else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->codeOrigin))
1050 convertStringAddUse<StringOrStringObjectUse>(node, right);
1051 else {
1052 // At this point we know that the other operand is something weird. The semantically correct
1053 // way of dealing with this is:
1054 //
1055 // MakeRope(@left, ToString(ToPrimitive(@right)))
1056 //
1057 // So that's what we emit. NB, we need to do all relevant type checks on @left before we do
1058 // anything to @right, since ToPrimitive may be effectful.
1059
1060 Node* toPrimitive = m_insertionSet.insertNode(
1061 m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive, node->codeOrigin,
1062 Edge(right.node()));
1063 Node* toString = m_insertionSet.insertNode(
1064 m_indexInBlock, SpecString, ToString, node->codeOrigin, Edge(toPrimitive));
1065
1066 fixupToPrimitive(toPrimitive);
1067 fixupToString(toString);
1068
1069 right.setNode(toString);
1070 }
1071
1072 // We're doing checks up there, so we need to make sure that the
1073 // *original* inputs to the addition are live up to here.
1074 m_insertionSet.insertNode(
1075 m_indexInBlock, SpecNone, Phantom, node->codeOrigin,
1076 Edge(originalLeft), Edge(originalRight));
1077
1078 convertToMakeRope(node);
1079 return true;
1080 }
1081
1082 bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, const Identifier& ident)
1083 {
1084 unsigned attributesUnused;
1085 JSCell* specificValue;
1086 PropertyOffset offset = stringPrototypeStructure->get(
1087 vm(), ident, attributesUnused, specificValue);
1088 if (!isValidOffset(offset))
1089 return false;
1090
1091 if (!specificValue)
1092 return false;
1093
1094 if (!specificValue->inherits(&JSFunction::s_info))
1095 return false;
1096
1097 JSFunction* function = jsCast<JSFunction*>(specificValue);
1098 if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
1099 return false;
1100
1101 return true;
1102 }
1103
1104 bool canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
1105 {
1106 if (m_graph.hasExitSite(codeOrigin, NotStringObject))
1107 return false;
1108
1109 Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
1110 ASSERT(stringObjectStructure->storedPrototype().isObject());
1111 ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == &StringPrototype::s_info);
1112
1113 JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
1114 Structure* stringPrototypeStructure = stringPrototypeObject->structure();
1115 if (stringPrototypeStructure->transitionWatchpointSetHasBeenInvalidated())
1116 return false;
1117
1118 if (stringPrototypeStructure->isDictionary())
1119 return false;
1120
1121 // We're being conservative here. We want DFG's ToString on StringObject to be
1122 // used in both numeric contexts (that would call valueOf()) and string contexts
1123 // (that would call toString()). We don't want the DFG to have to distinguish
1124 // between the two, just because that seems like it would get confusing. So we
1125 // just require both methods to be sane.
1126 if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf))
1127 return false;
1128 if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString))
1129 return false;
1130
1131 return true;
1132 }
1133
1134 void fixupSetLocalsInBlock(BasicBlock* block)
1135 {
1136 if (!block)
1137 return;
1138 ASSERT(block->isReachable);
1139 m_block = block;
1140 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
1141 Node* node = m_currentNode = block->at(m_indexInBlock);
1142 if (node->op() != SetLocal)
1143 continue;
1144
1145 VariableAccessData* variable = node->variableAccessData();
1146
1147 if (!variable->shouldUnboxIfPossible())
1148 continue;
1149
1150 if (variable->shouldUseDoubleFormat()) {
1151 fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
1152 continue;
1153 }
1154
1155 SpeculatedType predictedType = variable->argumentAwarePrediction();
1156 if (isInt32Speculation(predictedType))
1157 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
1158 else if (isCellSpeculation(predictedType))
1159 setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
1160 else if (isBooleanSpeculation(predictedType))
1161 setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
1162 }
1163 m_insertionSet.execute(block);
1164 }
1165
1166 void findAndRemoveUnnecessaryStructureCheck(Node* array, const CodeOrigin& codeOrigin)
1167 {
1168 for (unsigned index = m_indexInBlock; index--;) {
1169 Node* previousNode = m_block->at(index);
1170 if (previousNode->codeOrigin != codeOrigin)
1171 return;
1172
1173 if (previousNode->op() != CheckStructure)
1174 continue;
1175
1176 if (previousNode->child1() != array)
1177 continue;
1178
1179 previousNode->child1() = Edge();
1180 previousNode->convertToPhantom();
1181 return; // Assume we were smart enough to only insert one CheckStructure on the array.
1182 }
1183 }
1184
1185 Node* checkArray(ArrayMode arrayMode, const CodeOrigin& codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
1186 {
1187 ASSERT(arrayMode.isSpecific());
1188
1189 Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
1190
1191 Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
1192
1193 if (arrayMode.doesConversion()) {
1194 if (structure) {
1195 if (m_indexInBlock > 0) {
1196 // If the previous node was a CheckStructure inserted because of stuff
1197 // that the array profile told us, then remove it, since we're going to be
1198 // doing arrayification instead.
1199 findAndRemoveUnnecessaryStructureCheck(array, codeOrigin);
1200 }
1201
1202 m_insertionSet.insertNode(
1203 m_indexInBlock, SpecNone, ArrayifyToStructure, codeOrigin,
1204 OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1205 } else {
1206 m_insertionSet.insertNode(
1207 m_indexInBlock, SpecNone, Arrayify, codeOrigin,
1208 OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1209 }
1210 } else {
1211 if (structure) {
1212 m_insertionSet.insertNode(
1213 m_indexInBlock, SpecNone, CheckStructure, codeOrigin,
1214 OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
1215 } else {
1216 m_insertionSet.insertNode(
1217 m_indexInBlock, SpecNone, CheckArray, codeOrigin,
1218 OpInfo(arrayMode.asWord()), Edge(array, CellUse));
1219 }
1220 }
1221
1222 if (!storageCheck(arrayMode))
1223 return 0;
1224
1225 if (arrayMode.usesButterfly()) {
1226 return m_insertionSet.insertNode(
1227 m_indexInBlock, SpecNone, GetButterfly, codeOrigin, Edge(array, KnownCellUse));
1228 }
1229
1230 return m_insertionSet.insertNode(
1231 m_indexInBlock, SpecNone, GetIndexedPropertyStorage, codeOrigin,
1232 OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
1233 }
1234
1235 void blessArrayOperation(Edge base, Edge index, Edge& storageChild)
1236 {
1237 Node* node = m_currentNode;
1238
1239 switch (node->arrayMode().type()) {
1240 case Array::ForceExit: {
1241 m_insertionSet.insertNode(
1242 m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
1243 return;
1244 }
1245
1246 case Array::SelectUsingPredictions:
1247 case Array::Unprofiled:
1248 RELEASE_ASSERT_NOT_REACHED();
1249 return;
1250
1251 case Array::Generic:
1252 findAndRemoveUnnecessaryStructureCheck(base.node(), node->codeOrigin);
1253 return;
1254
1255 default: {
1256 Node* storage = checkArray(node->arrayMode(), node->codeOrigin, base.node(), index.node());
1257 if (!storage)
1258 return;
1259
1260 storageChild = Edge(storage);
1261 return;
1262 } }
1263 }
1264
1265 bool alwaysUnboxSimplePrimitives()
1266 {
1267#if USE(JSVALUE64)
1268 return false;
1269#else
1270 // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
1271 // reduces traffic.
1272 return true;
1273#endif
1274 }
1275
1276 template<UseKind useKind>
1277 void observeUseKindOnNode(Node* node)
1278 {
1279 observeUseKindOnNode(node, useKind);
1280 }
1281
1282 void observeUseKindOnEdge(Edge edge)
1283 {
1284 observeUseKindOnNode(edge.node(), edge.useKind());
1285 }
1286
1287 void observeUseKindOnNode(Node* node, UseKind useKind)
6fe7ccc8 1288 {
93a37866 1289 if (node->op() != GetLocal)
6fe7ccc8
A
1290 return;
1291
93a37866
A
1292 VariableAccessData* variable = node->variableAccessData();
1293 switch (useKind) {
1294 case Int32Use:
1295 if (alwaysUnboxSimplePrimitives()
1296 || isInt32Speculation(variable->prediction()))
1297 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1298 break;
1299 case NumberUse:
1300 case RealNumberUse:
1301 if (variable->doubleFormatState() == UsingDoubleFormat)
1302 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1303 break;
1304 case BooleanUse:
1305 if (alwaysUnboxSimplePrimitives()
1306 || isBooleanSpeculation(variable->prediction()))
1307 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1308 break;
1309 case CellUse:
1310 case ObjectUse:
1311 case StringUse:
1312 case KnownStringUse:
1313 case StringObjectUse:
1314 case StringOrStringObjectUse:
1315 if (alwaysUnboxSimplePrimitives()
1316 || isCellSpeculation(variable->prediction()))
1317 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1318 break;
1319 default:
1320 break;
1321 }
1322 }
1323
1324 // Set the use kind of the edge. In the future (https://bugs.webkit.org/show_bug.cgi?id=110433),
1325 // this can be used to notify the GetLocal that the variable is profitable to unbox.
1326 template<UseKind useKind>
1327 void setUseKindAndUnboxIfProfitable(Edge& edge)
1328 {
1329 observeUseKindOnNode<useKind>(edge.node());
1330 edge.setUseKind(useKind);
1331 }
1332
1333 void fixIntEdge(Edge& edge)
1334 {
1335 Node* node = edge.node();
1336 if (node->op() != ValueToInt32) {
1337 setUseKindAndUnboxIfProfitable<KnownInt32Use>(edge);
6fe7ccc8 1338 return;
93a37866 1339 }
6fe7ccc8 1340
93a37866 1341 Edge newEdge = node->child1();
6fe7ccc8 1342
93a37866
A
1343 if (newEdge.useKind() != Int32Use) {
1344 edge.setUseKind(KnownInt32Use);
1345 return;
1346 }
6fe7ccc8 1347
93a37866 1348 ASSERT(newEdge->shouldSpeculateInteger());
6fe7ccc8
A
1349 edge = newEdge;
1350 }
1351
93a37866
A
1352 template<UseKind useKind>
1353 void fixDoubleEdge(Edge& edge, SpeculationDirection direction = BackwardSpeculation)
6fe7ccc8 1354 {
93a37866 1355 ASSERT(useKind == NumberUse || useKind == KnownNumberUse || useKind == RealNumberUse);
6fe7ccc8 1356
93a37866
A
1357 if (edge->prediction() & SpecDouble) {
1358 setUseKindAndUnboxIfProfitable<useKind>(edge);
6fe7ccc8
A
1359 return;
1360 }
1361
93a37866
A
1362 injectInt32ToDoubleNode(edge, useKind, direction);
1363 }
1364
1365 void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
1366 {
1367 Node* result = m_insertionSet.insertNode(
1368 m_indexInBlock, SpecDouble,
1369 direction == BackwardSpeculation ? Int32ToDouble : ForwardInt32ToDouble,
1370 m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
6fe7ccc8
A
1371
1372#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
93a37866
A
1373 dataLogF(
1374 "(replacing @%u->@%u with @%u->@%u) ",
1375 m_currentNode->index(), edge->index(), m_currentNode->index(), result->index());
6fe7ccc8 1376#endif
6fe7ccc8 1377
93a37866
A
1378 edge = Edge(result, useKind);
1379 }
1380
1381 void truncateConstantToInt32(Edge& edge)
1382 {
1383 Node* oldNode = edge.node();
1384
1385 ASSERT(oldNode->hasConstant());
1386 JSValue value = m_graph.valueOfJSConstant(oldNode);
1387 if (value.isInt32())
1388 return;
1389
1390 value = jsNumber(JSC::toInt32(value.asNumber()));
1391 ASSERT(value.isInt32());
1392 edge.setNode(m_insertionSet.insertNode(
1393 m_indexInBlock, SpecInt32, JSConstant, m_currentNode->codeOrigin,
1394 OpInfo(codeBlock()->addOrFindConstant(value))));
1395 }
1396
1397 void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
1398 {
1399 if (mode != SpeculateIntegerAndTruncateConstants)
1400 return;
6fe7ccc8 1401
93a37866
A
1402 ASSERT(node->child1()->hasConstant() || node->child2()->hasConstant());
1403 if (node->child1()->hasConstant())
1404 truncateConstantToInt32(node->child1());
1405 else
1406 truncateConstantToInt32(node->child2());
6fe7ccc8
A
1407 }
1408
93a37866
A
1409 bool attemptToMakeIntegerAdd(Node* node)
1410 {
1411 AddSpeculationMode mode = m_graph.addSpeculationMode(node);
1412 if (mode == DontSpeculateInteger)
1413 return false;
1414
1415 truncateConstantsIfNecessary(node, mode);
1416 setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
1417 setUseKindAndUnboxIfProfitable<Int32Use>(node->child2());
1418 return true;
1419 }
1420
1421 BasicBlock* m_block;
6fe7ccc8 1422 unsigned m_indexInBlock;
93a37866
A
1423 Node* m_currentNode;
1424 InsertionSet m_insertionSet;
1425 bool m_profitabilityChanged;
6fe7ccc8
A
1426};
1427
93a37866 1428bool performFixup(Graph& graph)
6fe7ccc8 1429{
93a37866
A
1430 SamplingRegion samplingRegion("DFG Fixup Phase");
1431 return runPhase<FixupPhase>(graph);
6fe7ccc8
A
1432}
1433
1434} } // namespace JSC::DFG
1435
1436#endif // ENABLE(DFG_JIT)
1437