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