]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGFixupPhase.cpp
1affa1ab8fe9c1302381e82a1e2ee47a2ffe62c0
[apple/javascriptcore.git] / dfg / DFGFixupPhase.cpp
1 /*
2 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "DFGFixupPhase.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "ArrayPrototype.h"
32 #include "DFGGraph.h"
33 #include "DFGInsertionSet.h"
34 #include "DFGPhase.h"
35 #include "DFGPredictionPropagationPhase.h"
36 #include "DFGVariableAccessDataDump.h"
37 #include "JSCInlines.h"
38 #include "TypeLocation.h"
39
40 namespace JSC { namespace DFG {
41
42 class FixupPhase : public Phase {
43 public:
44 FixupPhase(Graph& graph)
45 : Phase(graph, "fixup")
46 , m_insertionSet(graph)
47 {
48 }
49
50 bool run()
51 {
52 ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
53 ASSERT(m_graph.m_form == ThreadedCPS);
54
55 m_profitabilityChanged = false;
56 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
57 fixupBlock(m_graph.block(blockIndex));
58
59 while (m_profitabilityChanged) {
60 m_profitabilityChanged = false;
61
62 for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
63 m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
64
65 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
66 fixupGetAndSetLocalsInBlock(m_graph.block(blockIndex));
67 }
68
69 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex)
70 injectTypeConversionsInBlock(m_graph.block(blockIndex));
71
72 m_graph.m_planStage = PlanStage::AfterFixup;
73
74 return true;
75 }
76
77 private:
78 void fixupBlock(BasicBlock* block)
79 {
80 if (!block)
81 return;
82 ASSERT(block->isReachable);
83 m_block = block;
84 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
85 m_currentNode = block->at(m_indexInBlock);
86 fixupNode(m_currentNode);
87 }
88 m_insertionSet.execute(block);
89 }
90
91 void fixupNode(Node* node)
92 {
93 NodeType op = node->op();
94
95 switch (op) {
96 case SetLocal: {
97 // This gets handled by fixupGetAndSetLocalsInBlock().
98 return;
99 }
100
101 case BitAnd:
102 case BitOr:
103 case BitXor:
104 case BitRShift:
105 case BitLShift:
106 case BitURShift: {
107 fixIntConvertingEdge(node->child1());
108 fixIntConvertingEdge(node->child2());
109 break;
110 }
111
112 case ArithIMul: {
113 fixIntConvertingEdge(node->child1());
114 fixIntConvertingEdge(node->child2());
115 node->setOp(ArithMul);
116 node->setArithMode(Arith::Unchecked);
117 node->child1().setUseKind(Int32Use);
118 node->child2().setUseKind(Int32Use);
119 break;
120 }
121
122 case ArithClz32: {
123 fixIntConvertingEdge(node->child1());
124 node->setArithMode(Arith::Unchecked);
125 break;
126 }
127
128 case UInt32ToNumber: {
129 fixIntConvertingEdge(node->child1());
130 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
131 node->convertToIdentity();
132 else if (node->canSpeculateInt32(FixupPass))
133 node->setArithMode(Arith::CheckOverflow);
134 else {
135 node->setArithMode(Arith::DoOverflow);
136 node->setResult(NodeResultDouble);
137 }
138 break;
139 }
140
141 case ValueAdd: {
142 if (attemptToMakeIntegerAdd(node)) {
143 node->setOp(ArithAdd);
144 break;
145 }
146 if (Node::shouldSpeculateNumberOrBooleanExpectingDefined(node->child1().node(), node->child2().node())) {
147 fixDoubleOrBooleanEdge(node->child1());
148 fixDoubleOrBooleanEdge(node->child2());
149 node->setOp(ArithAdd);
150 node->setResult(NodeResultDouble);
151 break;
152 }
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;
177 break;
178 }
179
180 case MakeRope: {
181 fixupMakeRope(node);
182 break;
183 }
184
185 case ArithAdd:
186 case ArithSub: {
187 if (attemptToMakeIntegerAdd(node))
188 break;
189 fixDoubleOrBooleanEdge(node->child1());
190 fixDoubleOrBooleanEdge(node->child2());
191 node->setResult(NodeResultDouble);
192 break;
193 }
194
195 case ArithNegate: {
196 if (m_graph.negateShouldSpeculateInt32(node, FixupPass)) {
197 fixIntOrBooleanEdge(node->child1());
198 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
199 node->setArithMode(Arith::Unchecked);
200 else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
201 node->setArithMode(Arith::CheckOverflow);
202 else
203 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
204 break;
205 }
206 if (m_graph.negateShouldSpeculateMachineInt(node, FixupPass)) {
207 fixEdge<Int52RepUse>(node->child1());
208 if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
209 node->setArithMode(Arith::CheckOverflow);
210 else
211 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
212 node->setResult(NodeResultInt52);
213 break;
214 }
215 fixDoubleOrBooleanEdge(node->child1());
216 node->setResult(NodeResultDouble);
217 break;
218 }
219
220 case ArithMul: {
221 if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
222 fixIntOrBooleanEdge(node->child1());
223 fixIntOrBooleanEdge(node->child2());
224 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
225 node->setArithMode(Arith::Unchecked);
226 else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
227 node->setArithMode(Arith::CheckOverflow);
228 else
229 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
230 break;
231 }
232 if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
233 fixEdge<Int52RepUse>(node->child1());
234 fixEdge<Int52RepUse>(node->child2());
235 if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
236 node->setArithMode(Arith::CheckOverflow);
237 else
238 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
239 node->setResult(NodeResultInt52);
240 break;
241 }
242 fixDoubleOrBooleanEdge(node->child1());
243 fixDoubleOrBooleanEdge(node->child2());
244 node->setResult(NodeResultDouble);
245 break;
246 }
247
248 case ArithDiv:
249 case ArithMod: {
250 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
251 && node->canSpeculateInt32(FixupPass)) {
252 if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
253 fixIntOrBooleanEdge(node->child1());
254 fixIntOrBooleanEdge(node->child2());
255 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
256 node->setArithMode(Arith::Unchecked);
257 else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
258 node->setArithMode(Arith::CheckOverflow);
259 else
260 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
261 break;
262 }
263
264 // This will cause conversion nodes to be inserted later.
265 fixDoubleOrBooleanEdge(node->child1());
266 fixDoubleOrBooleanEdge(node->child2());
267
268 // We don't need to do ref'ing on the children because we're stealing them from
269 // the original division.
270 Node* newDivision = m_insertionSet.insertNode(
271 m_indexInBlock, SpecBytecodeDouble, *node);
272 newDivision->setResult(NodeResultDouble);
273
274 node->setOp(DoubleAsInt32);
275 node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge());
276 if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
277 node->setArithMode(Arith::CheckOverflow);
278 else
279 node->setArithMode(Arith::CheckOverflowAndNegativeZero);
280 break;
281 }
282 fixDoubleOrBooleanEdge(node->child1());
283 fixDoubleOrBooleanEdge(node->child2());
284 node->setResult(NodeResultDouble);
285 break;
286 }
287
288 case ArithMin:
289 case ArithMax: {
290 if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
291 && node->canSpeculateInt32(FixupPass)) {
292 fixIntOrBooleanEdge(node->child1());
293 fixIntOrBooleanEdge(node->child2());
294 break;
295 }
296 fixDoubleOrBooleanEdge(node->child1());
297 fixDoubleOrBooleanEdge(node->child2());
298 node->setResult(NodeResultDouble);
299 break;
300 }
301
302 case ArithAbs: {
303 if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
304 && node->canSpeculateInt32(FixupPass)) {
305 fixIntOrBooleanEdge(node->child1());
306 break;
307 }
308 fixDoubleOrBooleanEdge(node->child1());
309 node->setResult(NodeResultDouble);
310 break;
311 }
312
313 case ArithPow: {
314 node->setResult(NodeResultDouble);
315 if (node->child2()->shouldSpeculateInt32OrBooleanForArithmetic()) {
316 fixDoubleOrBooleanEdge(node->child1());
317 fixIntOrBooleanEdge(node->child2());
318 break;
319 }
320
321 fixDoubleOrBooleanEdge(node->child1());
322 fixDoubleOrBooleanEdge(node->child2());
323 break;
324 }
325
326 case ArithRound: {
327 if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(FixupPass)) {
328 fixIntOrBooleanEdge(node->child1());
329 insertCheck<Int32Use>(m_indexInBlock, node->child1().node());
330 node->convertToIdentity();
331 break;
332 }
333 fixDoubleOrBooleanEdge(node->child1());
334
335 if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
336 node->setResult(NodeResultInt32);
337 if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
338 node->setArithRoundingMode(Arith::RoundingMode::Int32);
339 else
340 node->setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
341 } else {
342 node->setResult(NodeResultDouble);
343 node->setArithRoundingMode(Arith::RoundingMode::Double);
344 }
345 break;
346 }
347
348 case ArithSqrt:
349 case ArithFRound:
350 case ArithSin:
351 case ArithCos:
352 case ArithLog: {
353 fixDoubleOrBooleanEdge(node->child1());
354 node->setResult(NodeResultDouble);
355 break;
356 }
357
358 case LogicalNot: {
359 if (node->child1()->shouldSpeculateBoolean())
360 fixEdge<BooleanUse>(node->child1());
361 else if (node->child1()->shouldSpeculateObjectOrOther())
362 fixEdge<ObjectOrOtherUse>(node->child1());
363 else if (node->child1()->shouldSpeculateInt32OrBoolean())
364 fixIntOrBooleanEdge(node->child1());
365 else if (node->child1()->shouldSpeculateNumber())
366 fixEdge<DoubleRepUse>(node->child1());
367 else if (node->child1()->shouldSpeculateString())
368 fixEdge<StringUse>(node->child1());
369 break;
370 }
371
372 case CompareEqConstant: {
373 break;
374 }
375
376 case CompareEq:
377 case CompareLess:
378 case CompareLessEq:
379 case CompareGreater:
380 case CompareGreaterEq: {
381 if (node->op() == CompareEq
382 && Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
383 fixEdge<BooleanUse>(node->child1());
384 fixEdge<BooleanUse>(node->child2());
385 node->clearFlags(NodeMustGenerate);
386 break;
387 }
388 if (Node::shouldSpeculateInt32OrBoolean(node->child1().node(), node->child2().node())) {
389 fixIntOrBooleanEdge(node->child1());
390 fixIntOrBooleanEdge(node->child2());
391 node->clearFlags(NodeMustGenerate);
392 break;
393 }
394 if (enableInt52()
395 && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
396 fixEdge<Int52RepUse>(node->child1());
397 fixEdge<Int52RepUse>(node->child2());
398 node->clearFlags(NodeMustGenerate);
399 break;
400 }
401 if (Node::shouldSpeculateNumberOrBoolean(node->child1().node(), node->child2().node())) {
402 fixDoubleOrBooleanEdge(node->child1());
403 fixDoubleOrBooleanEdge(node->child2());
404 node->clearFlags(NodeMustGenerate);
405 break;
406 }
407 if (node->op() != CompareEq)
408 break;
409 if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
410 fixEdge<StringIdentUse>(node->child1());
411 fixEdge<StringIdentUse>(node->child2());
412 node->clearFlags(NodeMustGenerate);
413 break;
414 }
415 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
416 fixEdge<StringUse>(node->child1());
417 fixEdge<StringUse>(node->child2());
418 node->clearFlags(NodeMustGenerate);
419 break;
420 }
421 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
422 fixEdge<ObjectUse>(node->child1());
423 fixEdge<ObjectUse>(node->child2());
424 node->clearFlags(NodeMustGenerate);
425 break;
426 }
427 if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObjectOrOther()) {
428 fixEdge<ObjectUse>(node->child1());
429 fixEdge<ObjectOrOtherUse>(node->child2());
430 node->clearFlags(NodeMustGenerate);
431 break;
432 }
433 if (node->child1()->shouldSpeculateObjectOrOther() && node->child2()->shouldSpeculateObject()) {
434 fixEdge<ObjectOrOtherUse>(node->child1());
435 fixEdge<ObjectUse>(node->child2());
436 node->clearFlags(NodeMustGenerate);
437 break;
438 }
439 break;
440 }
441
442 case CompareStrictEq: {
443 if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
444 fixEdge<BooleanUse>(node->child1());
445 fixEdge<BooleanUse>(node->child2());
446 break;
447 }
448 if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
449 fixEdge<Int32Use>(node->child1());
450 fixEdge<Int32Use>(node->child2());
451 break;
452 }
453 if (enableInt52()
454 && Node::shouldSpeculateMachineInt(node->child1().node(), node->child2().node())) {
455 fixEdge<Int52RepUse>(node->child1());
456 fixEdge<Int52RepUse>(node->child2());
457 break;
458 }
459 if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
460 fixEdge<DoubleRepUse>(node->child1());
461 fixEdge<DoubleRepUse>(node->child2());
462 break;
463 }
464 if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
465 fixEdge<StringIdentUse>(node->child1());
466 fixEdge<StringIdentUse>(node->child2());
467 break;
468 }
469 if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) {
470 fixEdge<StringUse>(node->child1());
471 fixEdge<StringUse>(node->child2());
472 break;
473 }
474 WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint();
475 if (masqueradesAsUndefinedWatchpoint->isStillValid()) {
476
477 if (node->child1()->shouldSpeculateObject()) {
478 m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
479 fixEdge<ObjectUse>(node->child1());
480 break;
481 }
482 if (node->child2()->shouldSpeculateObject()) {
483 m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
484 fixEdge<ObjectUse>(node->child2());
485 break;
486 }
487
488 } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
489 fixEdge<ObjectUse>(node->child1());
490 fixEdge<ObjectUse>(node->child2());
491 break;
492 }
493 if (node->child1()->shouldSpeculateMisc()) {
494 fixEdge<MiscUse>(node->child1());
495 break;
496 }
497 if (node->child2()->shouldSpeculateMisc()) {
498 fixEdge<MiscUse>(node->child2());
499 break;
500 }
501 if (node->child1()->shouldSpeculateStringIdent()
502 && node->child2()->shouldSpeculateNotStringVar()) {
503 fixEdge<StringIdentUse>(node->child1());
504 fixEdge<NotStringVarUse>(node->child2());
505 break;
506 }
507 if (node->child2()->shouldSpeculateStringIdent()
508 && node->child1()->shouldSpeculateNotStringVar()) {
509 fixEdge<StringIdentUse>(node->child2());
510 fixEdge<NotStringVarUse>(node->child1());
511 break;
512 }
513 if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
514 fixEdge<StringUse>(node->child1());
515 break;
516 }
517 if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
518 fixEdge<StringUse>(node->child2());
519 break;
520 }
521 break;
522 }
523
524 case StringFromCharCode:
525 fixEdge<Int32Use>(node->child1());
526 break;
527
528 case StringCharAt:
529 case StringCharCodeAt: {
530 // Currently we have no good way of refining these.
531 ASSERT(node->arrayMode() == ArrayMode(Array::String));
532 blessArrayOperation(node->child1(), node->child2(), node->child3());
533 fixEdge<KnownCellUse>(node->child1());
534 fixEdge<Int32Use>(node->child2());
535 break;
536 }
537
538 case GetByVal: {
539 if (!node->prediction()) {
540 m_insertionSet.insertNode(
541 m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
542 }
543
544 node->setArrayMode(
545 node->arrayMode().refine(
546 m_graph, node,
547 node->child1()->prediction(),
548 node->child2()->prediction(),
549 SpecNone));
550
551 blessArrayOperation(node->child1(), node->child2(), node->child3());
552
553 ArrayMode arrayMode = node->arrayMode();
554 switch (arrayMode.type()) {
555 case Array::Contiguous:
556 case Array::Double:
557 if (arrayMode.arrayClass() == Array::OriginalArray
558 && arrayMode.speculation() == Array::InBounds) {
559 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
560 if (globalObject->arrayPrototypeChainIsSane()) {
561 // Check if SaneChain will work on a per-type basis. Note that:
562 //
563 // 1) We don't want double arrays to sometimes return undefined, since
564 // that would require a change to the return type and it would pessimise
565 // things a lot. So, we'd only want to do that if we actually had
566 // evidence that we could read from a hole. That's pretty annoying.
567 // Likely the best way to handle that case is with an equivalent of
568 // SaneChain for OutOfBounds. For now we just detect when Undefined and
569 // NaN are indistinguishable according to backwards propagation, and just
570 // use SaneChain in that case. This happens to catch a lot of cases.
571 //
572 // 2) We don't want int32 array loads to have to do a hole check just to
573 // coerce to Undefined, since that would mean twice the checks.
574 //
575 // This has two implications. First, we have to do more checks than we'd
576 // like. It's unfortunate that we have to do the hole check. Second,
577 // some accesses that hit a hole will now need to take the full-blown
578 // out-of-bounds slow path. We can fix that with:
579 // https://bugs.webkit.org/show_bug.cgi?id=144668
580
581 bool canDoSaneChain = false;
582 switch (arrayMode.type()) {
583 case Array::Contiguous:
584 // This is happens to be entirely natural. We already would have
585 // returned any JSValue, and now we'll return Undefined. We still do
586 // the check but it doesn't require taking any kind of slow path.
587 canDoSaneChain = true;
588 break;
589
590 case Array::Double:
591 if (!(node->flags() & NodeBytecodeUsesAsOther)) {
592 // Holes look like NaN already, so if the user doesn't care
593 // about the difference between Undefined and NaN then we can
594 // do this.
595 canDoSaneChain = true;
596 }
597 break;
598
599 default:
600 break;
601 }
602
603 if (canDoSaneChain) {
604 m_graph.watchpoints().addLazily(
605 globalObject->arrayPrototype()->structure()->transitionWatchpointSet());
606 m_graph.watchpoints().addLazily(
607 globalObject->objectPrototype()->structure()->transitionWatchpointSet());
608 node->setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
609 }
610 }
611 }
612 break;
613
614 case Array::String:
615 if ((node->prediction() & ~SpecString)
616 || m_graph.hasExitSite(node->origin.semantic, OutOfBounds))
617 node->setArrayMode(arrayMode.withSpeculation(Array::OutOfBounds));
618 break;
619
620 default:
621 break;
622 }
623
624 arrayMode = node->arrayMode();
625 switch (arrayMode.type()) {
626 case Array::SelectUsingPredictions:
627 case Array::Unprofiled:
628 case Array::Undecided:
629 RELEASE_ASSERT_NOT_REACHED();
630 break;
631 case Array::Generic:
632 #if USE(JSVALUE32_64)
633 fixEdge<CellUse>(node->child1()); // Speculating cell due to register pressure on 32-bit.
634 #endif
635 break;
636 case Array::ForceExit:
637 break;
638 default:
639 fixEdge<KnownCellUse>(node->child1());
640 fixEdge<Int32Use>(node->child2());
641 break;
642 }
643
644 switch (arrayMode.type()) {
645 case Array::Double:
646 if (!arrayMode.isOutOfBounds())
647 node->setResult(NodeResultDouble);
648 break;
649
650 case Array::Float32Array:
651 case Array::Float64Array:
652 node->setResult(NodeResultDouble);
653 break;
654
655 case Array::Uint32Array:
656 if (node->shouldSpeculateInt32())
657 break;
658 if (node->shouldSpeculateMachineInt() && enableInt52())
659 node->setResult(NodeResultInt52);
660 else
661 node->setResult(NodeResultDouble);
662 break;
663
664 default:
665 break;
666 }
667
668 break;
669 }
670
671 case PutByValDirect:
672 case PutByVal:
673 case PutByValAlias: {
674 Edge& child1 = m_graph.varArgChild(node, 0);
675 Edge& child2 = m_graph.varArgChild(node, 1);
676 Edge& child3 = m_graph.varArgChild(node, 2);
677
678 node->setArrayMode(
679 node->arrayMode().refine(
680 m_graph, node,
681 child1->prediction(),
682 child2->prediction(),
683 child3->prediction()));
684
685 blessArrayOperation(child1, child2, m_graph.varArgChild(node, 3));
686
687 switch (node->arrayMode().modeForPut().type()) {
688 case Array::SelectUsingPredictions:
689 case Array::Unprofiled:
690 case Array::Undecided:
691 RELEASE_ASSERT_NOT_REACHED();
692 break;
693 case Array::ForceExit:
694 case Array::Generic:
695 #if USE(JSVALUE32_64)
696 // Due to register pressure on 32-bit, we speculate cell and
697 // ignore the base-is-not-cell case entirely by letting the
698 // baseline JIT handle it.
699 fixEdge<CellUse>(child1);
700 #endif
701 break;
702 case Array::Int32:
703 fixEdge<KnownCellUse>(child1);
704 fixEdge<Int32Use>(child2);
705 fixEdge<Int32Use>(child3);
706 break;
707 case Array::Double:
708 fixEdge<KnownCellUse>(child1);
709 fixEdge<Int32Use>(child2);
710 fixEdge<DoubleRepRealUse>(child3);
711 break;
712 case Array::Int8Array:
713 case Array::Int16Array:
714 case Array::Int32Array:
715 case Array::Uint8Array:
716 case Array::Uint8ClampedArray:
717 case Array::Uint16Array:
718 case Array::Uint32Array:
719 fixEdge<KnownCellUse>(child1);
720 fixEdge<Int32Use>(child2);
721 if (child3->shouldSpeculateInt32())
722 fixIntOrBooleanEdge(child3);
723 else if (child3->shouldSpeculateMachineInt())
724 fixEdge<Int52RepUse>(child3);
725 else
726 fixDoubleOrBooleanEdge(child3);
727 break;
728 case Array::Float32Array:
729 case Array::Float64Array:
730 fixEdge<KnownCellUse>(child1);
731 fixEdge<Int32Use>(child2);
732 fixDoubleOrBooleanEdge(child3);
733 break;
734 case Array::Contiguous:
735 case Array::ArrayStorage:
736 case Array::SlowPutArrayStorage:
737 fixEdge<KnownCellUse>(child1);
738 fixEdge<Int32Use>(child2);
739 speculateForBarrier(child3);
740 break;
741 default:
742 fixEdge<KnownCellUse>(child1);
743 fixEdge<Int32Use>(child2);
744 break;
745 }
746 break;
747 }
748
749 case ArrayPush: {
750 // May need to refine the array mode in case the value prediction contravenes
751 // the array prediction. For example, we may have evidence showing that the
752 // array is in Int32 mode, but the value we're storing is likely to be a double.
753 // Then we should turn this into a conversion to Double array followed by the
754 // push. On the other hand, we absolutely don't want to refine based on the
755 // base prediction. If it has non-cell garbage in it, then we want that to be
756 // ignored. That's because ArrayPush can't handle any array modes that aren't
757 // array-related - so if refine() turned this into a "Generic" ArrayPush then
758 // that would break things.
759 node->setArrayMode(
760 node->arrayMode().refine(
761 m_graph, node,
762 node->child1()->prediction() & SpecCell,
763 SpecInt32,
764 node->child2()->prediction()));
765 blessArrayOperation(node->child1(), Edge(), node->child3());
766 fixEdge<KnownCellUse>(node->child1());
767
768 switch (node->arrayMode().type()) {
769 case Array::Int32:
770 fixEdge<Int32Use>(node->child2());
771 break;
772 case Array::Double:
773 fixEdge<DoubleRepRealUse>(node->child2());
774 break;
775 case Array::Contiguous:
776 case Array::ArrayStorage:
777 speculateForBarrier(node->child2());
778 break;
779 default:
780 break;
781 }
782 break;
783 }
784
785 case ArrayPop: {
786 blessArrayOperation(node->child1(), Edge(), node->child2());
787 fixEdge<KnownCellUse>(node->child1());
788 break;
789 }
790
791 case RegExpExec:
792 case RegExpTest: {
793 fixEdge<CellUse>(node->child1());
794 fixEdge<CellUse>(node->child2());
795 break;
796 }
797
798 case Branch: {
799 if (node->child1()->shouldSpeculateBoolean())
800 fixEdge<BooleanUse>(node->child1());
801 else if (node->child1()->shouldSpeculateObjectOrOther())
802 fixEdge<ObjectOrOtherUse>(node->child1());
803 else if (node->child1()->shouldSpeculateInt32OrBoolean())
804 fixIntOrBooleanEdge(node->child1());
805 else if (node->child1()->shouldSpeculateNumber())
806 fixEdge<DoubleRepUse>(node->child1());
807 else if (node->child1()->shouldSpeculateString())
808 fixEdge<StringUse>(node->child1());
809 break;
810 }
811
812 case Switch: {
813 SwitchData* data = node->switchData();
814 switch (data->kind) {
815 case SwitchImm:
816 if (node->child1()->shouldSpeculateInt32())
817 fixEdge<Int32Use>(node->child1());
818 break;
819 case SwitchChar:
820 if (node->child1()->shouldSpeculateString())
821 fixEdge<StringUse>(node->child1());
822 break;
823 case SwitchString:
824 if (node->child1()->shouldSpeculateStringIdent())
825 fixEdge<StringIdentUse>(node->child1());
826 else if (node->child1()->shouldSpeculateString())
827 fixEdge<StringUse>(node->child1());
828 break;
829 case SwitchCell:
830 if (node->child1()->shouldSpeculateCell())
831 fixEdge<CellUse>(node->child1());
832 // else it's fine for this to have UntypedUse; we will handle this by just making
833 // non-cells take the default case.
834 break;
835 }
836 break;
837 }
838
839 case ToPrimitive: {
840 fixupToPrimitive(node);
841 break;
842 }
843
844 case ToString:
845 case CallStringConstructor: {
846 fixupToStringOrCallStringConstructor(node);
847 break;
848 }
849
850 case NewStringObject: {
851 fixEdge<KnownStringUse>(node->child1());
852 break;
853 }
854
855 case NewArray: {
856 for (unsigned i = m_graph.varArgNumChildren(node); i--;) {
857 node->setIndexingType(
858 leastUpperBoundOfIndexingTypeAndType(
859 node->indexingType(), m_graph.varArgChild(node, i)->prediction()));
860 }
861 switch (node->indexingType()) {
862 case ALL_BLANK_INDEXING_TYPES:
863 CRASH();
864 break;
865 case ALL_UNDECIDED_INDEXING_TYPES:
866 if (node->numChildren()) {
867 // This will only happen if the children have no type predictions. We
868 // would have already exited by now, but insert a forced exit just to
869 // be safe.
870 m_insertionSet.insertNode(
871 m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
872 }
873 break;
874 case ALL_INT32_INDEXING_TYPES:
875 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
876 fixEdge<Int32Use>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
877 break;
878 case ALL_DOUBLE_INDEXING_TYPES:
879 for (unsigned operandIndex = 0; operandIndex < node->numChildren(); ++operandIndex)
880 fixEdge<DoubleRepRealUse>(m_graph.m_varArgChildren[node->firstChild() + operandIndex]);
881 break;
882 case ALL_CONTIGUOUS_INDEXING_TYPES:
883 case ALL_ARRAY_STORAGE_INDEXING_TYPES:
884 break;
885 default:
886 CRASH();
887 break;
888 }
889 break;
890 }
891
892 case NewTypedArray: {
893 if (node->child1()->shouldSpeculateInt32()) {
894 fixEdge<Int32Use>(node->child1());
895 node->clearFlags(NodeMustGenerate);
896 break;
897 }
898 break;
899 }
900
901 case NewArrayWithSize: {
902 fixEdge<Int32Use>(node->child1());
903 break;
904 }
905
906 case ToThis: {
907 ECMAMode ecmaMode = m_graph.executableFor(node->origin.semantic)->isStrictMode() ? StrictMode : NotStrictMode;
908
909 if (node->child1()->shouldSpeculateOther()) {
910 if (ecmaMode == StrictMode) {
911 fixEdge<OtherUse>(node->child1());
912 node->convertToIdentity();
913 break;
914 }
915
916 m_insertionSet.insertNode(
917 m_indexInBlock, SpecNone, Check, node->origin,
918 Edge(node->child1().node(), OtherUse));
919 observeUseKindOnNode<OtherUse>(node->child1().node());
920 m_graph.convertToConstant(
921 node, m_graph.globalThisObjectFor(node->origin.semantic));
922 break;
923 }
924
925 if (isFinalObjectSpeculation(node->child1()->prediction())) {
926 fixEdge<FinalObjectUse>(node->child1());
927 node->convertToIdentity();
928 break;
929 }
930
931 break;
932 }
933
934 case PutStructure: {
935 fixEdge<KnownCellUse>(node->child1());
936 break;
937 }
938
939 case GetClosureVar:
940 case GetFromArguments: {
941 fixEdge<KnownCellUse>(node->child1());
942 break;
943 }
944
945 case PutClosureVar:
946 case PutToArguments: {
947 fixEdge<KnownCellUse>(node->child1());
948 speculateForBarrier(node->child2());
949 break;
950 }
951
952 case SkipScope:
953 case GetScope:
954 case GetGetter:
955 case GetSetter: {
956 fixEdge<KnownCellUse>(node->child1());
957 break;
958 }
959
960 case AllocatePropertyStorage:
961 case ReallocatePropertyStorage: {
962 fixEdge<KnownCellUse>(node->child1());
963 break;
964 }
965
966 case GetById:
967 case GetByIdFlush: {
968 if (!node->child1()->shouldSpeculateCell())
969 break;
970
971 // If we hadn't exited because of BadCache, BadIndexingType, or ExoticObjectMode, then
972 // leave this as a GetById.
973 if (!m_graph.hasExitSite(node->origin.semantic, BadCache)
974 && !m_graph.hasExitSite(node->origin.semantic, BadIndexingType)
975 && !m_graph.hasExitSite(node->origin.semantic, ExoticObjectMode)) {
976 auto uid = m_graph.identifiers()[node->identifierNumber()];
977 if (uid == vm().propertyNames->length.impl()) {
978 attemptToMakeGetArrayLength(node);
979 break;
980 }
981 if (uid == vm().propertyNames->byteLength.impl()) {
982 attemptToMakeGetTypedArrayByteLength(node);
983 break;
984 }
985 if (uid == vm().propertyNames->byteOffset.impl()) {
986 attemptToMakeGetTypedArrayByteOffset(node);
987 break;
988 }
989 }
990 fixEdge<CellUse>(node->child1());
991 break;
992 }
993
994 case PutById:
995 case PutByIdFlush:
996 case PutByIdDirect: {
997 fixEdge<CellUse>(node->child1());
998 speculateForBarrier(node->child2());
999 break;
1000 }
1001
1002 case GetExecutable: {
1003 fixEdge<FunctionUse>(node->child1());
1004 break;
1005 }
1006
1007 case CheckStructure:
1008 case CheckCell:
1009 case CheckHasInstance:
1010 case CreateThis:
1011 case GetButterfly: {
1012 fixEdge<CellUse>(node->child1());
1013 break;
1014 }
1015
1016 case Arrayify:
1017 case ArrayifyToStructure: {
1018 fixEdge<CellUse>(node->child1());
1019 if (node->child2())
1020 fixEdge<Int32Use>(node->child2());
1021 break;
1022 }
1023
1024 case GetByOffset:
1025 case GetGetterSetterByOffset: {
1026 if (!node->child1()->hasStorageResult())
1027 fixEdge<KnownCellUse>(node->child1());
1028 fixEdge<KnownCellUse>(node->child2());
1029 break;
1030 }
1031
1032 case MultiGetByOffset: {
1033 fixEdge<CellUse>(node->child1());
1034 break;
1035 }
1036
1037 case PutByOffset: {
1038 if (!node->child1()->hasStorageResult())
1039 fixEdge<KnownCellUse>(node->child1());
1040 fixEdge<KnownCellUse>(node->child2());
1041 speculateForBarrier(node->child3());
1042 break;
1043 }
1044
1045 case MultiPutByOffset: {
1046 fixEdge<CellUse>(node->child1());
1047 speculateForBarrier(node->child2());
1048 break;
1049 }
1050
1051 case InstanceOf: {
1052 if (!(node->child1()->prediction() & ~SpecCell))
1053 fixEdge<CellUse>(node->child1());
1054 fixEdge<CellUse>(node->child2());
1055 break;
1056 }
1057
1058 case In: {
1059 // FIXME: We should at some point have array profiling on op_in, in which
1060 // case we would be able to turn this into a kind of GetByVal.
1061
1062 fixEdge<CellUse>(node->child2());
1063 break;
1064 }
1065
1066 case Check: {
1067 m_graph.doToChildren(
1068 node,
1069 [&] (Edge& edge) {
1070 switch (edge.useKind()) {
1071 case NumberUse:
1072 if (edge->shouldSpeculateInt32ForArithmetic())
1073 edge.setUseKind(Int32Use);
1074 break;
1075 default:
1076 break;
1077 }
1078 observeUseKindOnEdge(edge);
1079 });
1080 break;
1081 }
1082
1083 case Phantom:
1084 // Phantoms are meaningless past Fixup. We recreate them on-demand in the backend.
1085 node->remove();
1086 break;
1087
1088 case FiatInt52: {
1089 RELEASE_ASSERT(enableInt52());
1090 node->convertToIdentity();
1091 fixEdge<Int52RepUse>(node->child1());
1092 node->setResult(NodeResultInt52);
1093 break;
1094 }
1095
1096 case GetArrayLength:
1097 case Phi:
1098 case Upsilon:
1099 case GetIndexedPropertyStorage:
1100 case GetTypedArrayByteOffset:
1101 case LastNodeType:
1102 case CheckTierUpInLoop:
1103 case CheckTierUpAtReturn:
1104 case CheckTierUpAndOSREnter:
1105 case CheckTierUpWithNestedTriggerAndOSREnter:
1106 case InvalidationPoint:
1107 case CheckArray:
1108 case CheckInBounds:
1109 case ConstantStoragePointer:
1110 case DoubleAsInt32:
1111 case ValueToInt32:
1112 case DoubleRep:
1113 case ValueRep:
1114 case Int52Rep:
1115 case Int52Constant:
1116 case Identity: // This should have been cleaned up.
1117 case BooleanToNumber:
1118 case PhantomNewObject:
1119 case PhantomNewFunction:
1120 case PhantomCreateActivation:
1121 case PhantomDirectArguments:
1122 case PhantomClonedArguments:
1123 case ForwardVarargs:
1124 case GetMyArgumentByVal:
1125 case PutHint:
1126 case CheckStructureImmediate:
1127 case MaterializeNewObject:
1128 case MaterializeCreateActivation:
1129 case PutStack:
1130 case KillStack:
1131 case GetStack:
1132 case StoreBarrier:
1133 // These are just nodes that we don't currently expect to see during fixup.
1134 // If we ever wanted to insert them prior to fixup, then we just have to create
1135 // fixup rules for them.
1136 DFG_CRASH(m_graph, node, "Unexpected node during fixup");
1137 break;
1138
1139 case PutGlobalVar: {
1140 fixEdge<CellUse>(node->child1());
1141 speculateForBarrier(node->child2());
1142 break;
1143 }
1144
1145 case IsString:
1146 if (node->child1()->shouldSpeculateString()) {
1147 m_insertionSet.insertNode(
1148 m_indexInBlock, SpecNone, Check, node->origin,
1149 Edge(node->child1().node(), StringUse));
1150 m_graph.convertToConstant(node, jsBoolean(true));
1151 observeUseKindOnNode<StringUse>(node);
1152 }
1153 break;
1154
1155 case IsObject:
1156 if (node->child1()->shouldSpeculateObject()) {
1157 m_insertionSet.insertNode(
1158 m_indexInBlock, SpecNone, Check, node->origin,
1159 Edge(node->child1().node(), ObjectUse));
1160 m_graph.convertToConstant(node, jsBoolean(true));
1161 observeUseKindOnNode<ObjectUse>(node);
1162 }
1163 break;
1164
1165 case GetEnumerableLength: {
1166 fixEdge<CellUse>(node->child1());
1167 break;
1168 }
1169 case HasGenericProperty: {
1170 fixEdge<CellUse>(node->child2());
1171 break;
1172 }
1173 case HasStructureProperty: {
1174 fixEdge<StringUse>(node->child2());
1175 fixEdge<KnownCellUse>(node->child3());
1176 break;
1177 }
1178 case HasIndexedProperty: {
1179 node->setArrayMode(
1180 node->arrayMode().refine(
1181 m_graph, node,
1182 node->child1()->prediction(),
1183 node->child2()->prediction(),
1184 SpecNone));
1185
1186 blessArrayOperation(node->child1(), node->child2(), node->child3());
1187 fixEdge<CellUse>(node->child1());
1188 fixEdge<KnownInt32Use>(node->child2());
1189 break;
1190 }
1191 case GetDirectPname: {
1192 Edge& base = m_graph.varArgChild(node, 0);
1193 Edge& property = m_graph.varArgChild(node, 1);
1194 Edge& index = m_graph.varArgChild(node, 2);
1195 Edge& enumerator = m_graph.varArgChild(node, 3);
1196 fixEdge<CellUse>(base);
1197 fixEdge<KnownCellUse>(property);
1198 fixEdge<KnownInt32Use>(index);
1199 fixEdge<KnownCellUse>(enumerator);
1200 break;
1201 }
1202 case GetPropertyEnumerator: {
1203 fixEdge<CellUse>(node->child1());
1204 break;
1205 }
1206 case GetEnumeratorStructurePname: {
1207 fixEdge<KnownCellUse>(node->child1());
1208 fixEdge<KnownInt32Use>(node->child2());
1209 break;
1210 }
1211 case GetEnumeratorGenericPname: {
1212 fixEdge<KnownCellUse>(node->child1());
1213 fixEdge<KnownInt32Use>(node->child2());
1214 break;
1215 }
1216 case ToIndexString: {
1217 fixEdge<KnownInt32Use>(node->child1());
1218 break;
1219 }
1220 case ProfileType: {
1221 // We want to insert type checks based on the instructionTypeSet of the TypeLocation, not the globalTypeSet.
1222 // Because the instructionTypeSet is contained in globalTypeSet, if we produce a type check for
1223 // type T for the instructionTypeSet, the global type set must also have information for type T.
1224 // So if it the type check succeeds for type T in the instructionTypeSet, a type check for type T
1225 // in the globalTypeSet would've also succeeded.
1226 // (The other direction does not hold in general).
1227
1228 RefPtr<TypeSet> typeSet = node->typeLocation()->m_instructionTypeSet;
1229 RuntimeTypeMask seenTypes = typeSet->seenTypes();
1230 if (typeSet->doesTypeConformTo(TypeMachineInt)) {
1231 if (node->child1()->shouldSpeculateInt32())
1232 fixEdge<Int32Use>(node->child1());
1233 else
1234 fixEdge<MachineIntUse>(node->child1());
1235 node->remove();
1236 } else if (typeSet->doesTypeConformTo(TypeNumber | TypeMachineInt)) {
1237 fixEdge<NumberUse>(node->child1());
1238 node->remove();
1239 } else if (typeSet->doesTypeConformTo(TypeString)) {
1240 fixEdge<StringUse>(node->child1());
1241 node->remove();
1242 } else if (typeSet->doesTypeConformTo(TypeBoolean)) {
1243 fixEdge<BooleanUse>(node->child1());
1244 node->remove();
1245 } else if (typeSet->doesTypeConformTo(TypeUndefined | TypeNull) && (seenTypes & TypeUndefined) && (seenTypes & TypeNull)) {
1246 fixEdge<OtherUse>(node->child1());
1247 node->remove();
1248 } else if (typeSet->doesTypeConformTo(TypeObject)) {
1249 StructureSet set = typeSet->structureSet();
1250 if (!set.isEmpty()) {
1251 fixEdge<CellUse>(node->child1());
1252 node->convertToCheckStructure(m_graph.addStructureSet(set));
1253 }
1254 }
1255
1256 break;
1257 }
1258
1259 case CreateScopedArguments:
1260 case CreateActivation:
1261 case NewFunction: {
1262 fixEdge<CellUse>(node->child1());
1263 break;
1264 }
1265
1266 #if !ASSERT_DISABLED
1267 // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
1268 case SetArgument:
1269 case JSConstant:
1270 case DoubleConstant:
1271 case GetLocal:
1272 case GetCallee:
1273 case GetArgumentCount:
1274 case Flush:
1275 case PhantomLocal:
1276 case GetLocalUnlinked:
1277 case GetGlobalVar:
1278 case NotifyWrite:
1279 case VarInjectionWatchpoint:
1280 case Call:
1281 case Construct:
1282 case CallVarargs:
1283 case ConstructVarargs:
1284 case CallForwardVarargs:
1285 case ConstructForwardVarargs:
1286 case LoadVarargs:
1287 case ProfileControlFlow:
1288 case NativeCall:
1289 case NativeConstruct:
1290 case NewObject:
1291 case NewArrayBuffer:
1292 case NewRegexp:
1293 case Breakpoint:
1294 case ProfileWillCall:
1295 case ProfileDidCall:
1296 case IsUndefined:
1297 case IsBoolean:
1298 case IsNumber:
1299 case IsObjectOrNull:
1300 case IsFunction:
1301 case CreateDirectArguments:
1302 case CreateClonedArguments:
1303 case Jump:
1304 case Return:
1305 case Throw:
1306 case ThrowReferenceError:
1307 case CountExecution:
1308 case ForceOSRExit:
1309 case CheckBadCell:
1310 case CheckNotEmpty:
1311 case CheckWatchdogTimer:
1312 case Unreachable:
1313 case ExtractOSREntryLocal:
1314 case LoopHint:
1315 case MovHint:
1316 case ZombieHint:
1317 case BottomValue:
1318 case TypeOf:
1319 break;
1320 #else
1321 default:
1322 break;
1323 #endif
1324 }
1325 }
1326
1327 template<UseKind useKind>
1328 void createToString(Node* node, Edge& edge)
1329 {
1330 edge.setNode(m_insertionSet.insertNode(
1331 m_indexInBlock, SpecString, ToString, node->origin,
1332 Edge(edge.node(), useKind)));
1333 }
1334
1335 template<UseKind useKind>
1336 void attemptToForceStringArrayModeByToStringConversion(ArrayMode& arrayMode, Node* node)
1337 {
1338 ASSERT(arrayMode == ArrayMode(Array::Generic));
1339
1340 if (!canOptimizeStringObjectAccess(node->origin.semantic))
1341 return;
1342
1343 createToString<useKind>(node, node->child1());
1344 arrayMode = ArrayMode(Array::String);
1345 }
1346
1347 template<UseKind useKind>
1348 bool isStringObjectUse()
1349 {
1350 switch (useKind) {
1351 case StringObjectUse:
1352 case StringOrStringObjectUse:
1353 return true;
1354 default:
1355 return false;
1356 }
1357 }
1358
1359 template<UseKind useKind>
1360 void convertStringAddUse(Node* node, Edge& edge)
1361 {
1362 if (useKind == StringUse) {
1363 // This preserves the binaryUseKind() invariant ot ValueAdd: ValueAdd's
1364 // two edges will always have identical use kinds, which makes the
1365 // decision process much easier.
1366 observeUseKindOnNode<StringUse>(edge.node());
1367 m_insertionSet.insertNode(
1368 m_indexInBlock, SpecNone, Check, node->origin,
1369 Edge(edge.node(), StringUse));
1370 edge.setUseKind(KnownStringUse);
1371 return;
1372 }
1373
1374 // FIXME: We ought to be able to have a ToPrimitiveToString node.
1375
1376 observeUseKindOnNode<useKind>(edge.node());
1377 createToString<useKind>(node, edge);
1378 }
1379
1380 void convertToMakeRope(Node* node)
1381 {
1382 node->setOpAndDefaultFlags(MakeRope);
1383 fixupMakeRope(node);
1384 }
1385
1386 void fixupMakeRope(Node* node)
1387 {
1388 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
1389 Edge& edge = node->children.child(i);
1390 if (!edge)
1391 break;
1392 edge.setUseKind(KnownStringUse);
1393 JSString* string = edge->dynamicCastConstant<JSString*>();
1394 if (!string)
1395 continue;
1396 if (string->length())
1397 continue;
1398
1399 // Don't allow the MakeRope to have zero children.
1400 if (!i && !node->child2())
1401 break;
1402
1403 node->children.removeEdge(i--);
1404 }
1405
1406 if (!node->child2()) {
1407 ASSERT(!node->child3());
1408 node->convertToIdentity();
1409 }
1410 }
1411
1412 void fixupToPrimitive(Node* node)
1413 {
1414 if (node->child1()->shouldSpeculateInt32()) {
1415 fixEdge<Int32Use>(node->child1());
1416 node->convertToIdentity();
1417 return;
1418 }
1419
1420 if (node->child1()->shouldSpeculateString()) {
1421 fixEdge<StringUse>(node->child1());
1422 node->convertToIdentity();
1423 return;
1424 }
1425
1426 if (node->child1()->shouldSpeculateStringObject()
1427 && canOptimizeStringObjectAccess(node->origin.semantic)) {
1428 fixEdge<StringObjectUse>(node->child1());
1429 node->convertToToString();
1430 return;
1431 }
1432
1433 if (node->child1()->shouldSpeculateStringOrStringObject()
1434 && canOptimizeStringObjectAccess(node->origin.semantic)) {
1435 fixEdge<StringOrStringObjectUse>(node->child1());
1436 node->convertToToString();
1437 return;
1438 }
1439 }
1440
1441 void fixupToStringOrCallStringConstructor(Node* node)
1442 {
1443 if (node->child1()->shouldSpeculateString()) {
1444 fixEdge<StringUse>(node->child1());
1445 node->convertToIdentity();
1446 return;
1447 }
1448
1449 if (node->child1()->shouldSpeculateStringObject()
1450 && canOptimizeStringObjectAccess(node->origin.semantic)) {
1451 fixEdge<StringObjectUse>(node->child1());
1452 return;
1453 }
1454
1455 if (node->child1()->shouldSpeculateStringOrStringObject()
1456 && canOptimizeStringObjectAccess(node->origin.semantic)) {
1457 fixEdge<StringOrStringObjectUse>(node->child1());
1458 return;
1459 }
1460
1461 if (node->child1()->shouldSpeculateCell()) {
1462 fixEdge<CellUse>(node->child1());
1463 return;
1464 }
1465 }
1466
1467 template<UseKind leftUseKind>
1468 bool attemptToMakeFastStringAdd(Node* node, Edge& left, Edge& right)
1469 {
1470 ASSERT(leftUseKind == StringUse || leftUseKind == StringObjectUse || leftUseKind == StringOrStringObjectUse);
1471
1472 if (isStringObjectUse<leftUseKind>() && !canOptimizeStringObjectAccess(node->origin.semantic))
1473 return false;
1474
1475 convertStringAddUse<leftUseKind>(node, left);
1476
1477 if (right->shouldSpeculateString())
1478 convertStringAddUse<StringUse>(node, right);
1479 else if (right->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
1480 convertStringAddUse<StringObjectUse>(node, right);
1481 else if (right->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node->origin.semantic))
1482 convertStringAddUse<StringOrStringObjectUse>(node, right);
1483 else {
1484 // At this point we know that the other operand is something weird. The semantically correct
1485 // way of dealing with this is:
1486 //
1487 // MakeRope(@left, ToString(ToPrimitive(@right)))
1488 //
1489 // So that's what we emit. NB, we need to do all relevant type checks on @left before we do
1490 // anything to @right, since ToPrimitive may be effectful.
1491
1492 Node* toPrimitive = m_insertionSet.insertNode(
1493 m_indexInBlock, resultOfToPrimitive(right->prediction()), ToPrimitive,
1494 node->origin, Edge(right.node()));
1495 Node* toString = m_insertionSet.insertNode(
1496 m_indexInBlock, SpecString, ToString, node->origin, Edge(toPrimitive));
1497
1498 fixupToPrimitive(toPrimitive);
1499
1500 // Don't fix up ToString. ToString and ToPrimitive are originated from the same bytecode and
1501 // ToPrimitive may have an observable side effect. ToString should not be converted into Check
1502 // with speculative type check because OSR exit reproduce an observable side effect done in
1503 // ToPrimitive.
1504
1505 right.setNode(toString);
1506 }
1507
1508 convertToMakeRope(node);
1509 return true;
1510 }
1511
1512 bool isStringPrototypeMethodSane(
1513 JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid)
1514 {
1515 unsigned attributesUnused;
1516 PropertyOffset offset =
1517 stringPrototypeStructure->getConcurrently(uid, attributesUnused);
1518 if (!isValidOffset(offset))
1519 return false;
1520
1521 JSValue value = m_graph.tryGetConstantProperty(
1522 stringPrototype, stringPrototypeStructure, offset);
1523 if (!value)
1524 return false;
1525
1526 JSFunction* function = jsDynamicCast<JSFunction*>(value);
1527 if (!function)
1528 return false;
1529
1530 if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
1531 return false;
1532
1533 return true;
1534 }
1535
1536 bool canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
1537 {
1538 if (m_graph.hasExitSite(codeOrigin, NotStringObject))
1539 return false;
1540
1541 Structure* stringObjectStructure = m_graph.globalObjectFor(codeOrigin)->stringObjectStructure();
1542 ASSERT(stringObjectStructure->storedPrototype().isObject());
1543 ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == StringPrototype::info());
1544
1545 JSObject* stringPrototypeObject = asObject(stringObjectStructure->storedPrototype());
1546 Structure* stringPrototypeStructure = stringPrototypeObject->structure();
1547 if (m_graph.registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched)
1548 return false;
1549
1550 if (stringPrototypeStructure->isDictionary())
1551 return false;
1552
1553 // We're being conservative here. We want DFG's ToString on StringObject to be
1554 // used in both numeric contexts (that would call valueOf()) and string contexts
1555 // (that would call toString()). We don't want the DFG to have to distinguish
1556 // between the two, just because that seems like it would get confusing. So we
1557 // just require both methods to be sane.
1558 if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->valueOf.impl()))
1559 return false;
1560 if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, vm().propertyNames->toString.impl()))
1561 return false;
1562
1563 return true;
1564 }
1565
1566 void fixupGetAndSetLocalsInBlock(BasicBlock* block)
1567 {
1568 if (!block)
1569 return;
1570 ASSERT(block->isReachable);
1571 m_block = block;
1572 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
1573 Node* node = m_currentNode = block->at(m_indexInBlock);
1574 if (node->op() != SetLocal && node->op() != GetLocal)
1575 continue;
1576
1577 VariableAccessData* variable = node->variableAccessData();
1578 switch (node->op()) {
1579 case GetLocal:
1580 switch (variable->flushFormat()) {
1581 case FlushedDouble:
1582 node->setResult(NodeResultDouble);
1583 break;
1584 case FlushedInt52:
1585 node->setResult(NodeResultInt52);
1586 break;
1587 default:
1588 break;
1589 }
1590 break;
1591
1592 case SetLocal:
1593 switch (variable->flushFormat()) {
1594 case FlushedJSValue:
1595 break;
1596 case FlushedDouble:
1597 fixEdge<DoubleRepUse>(node->child1());
1598 break;
1599 case FlushedInt32:
1600 fixEdge<Int32Use>(node->child1());
1601 break;
1602 case FlushedInt52:
1603 fixEdge<Int52RepUse>(node->child1());
1604 break;
1605 case FlushedCell:
1606 fixEdge<CellUse>(node->child1());
1607 break;
1608 case FlushedBoolean:
1609 fixEdge<BooleanUse>(node->child1());
1610 break;
1611 default:
1612 RELEASE_ASSERT_NOT_REACHED();
1613 break;
1614 }
1615 break;
1616
1617 default:
1618 RELEASE_ASSERT_NOT_REACHED();
1619 break;
1620 }
1621 }
1622 m_insertionSet.execute(block);
1623 }
1624
1625 Node* checkArray(ArrayMode arrayMode, const NodeOrigin& origin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
1626 {
1627 ASSERT(arrayMode.isSpecific());
1628
1629 if (arrayMode.type() == Array::String) {
1630 m_insertionSet.insertNode(
1631 m_indexInBlock, SpecNone, Check, origin, Edge(array, StringUse));
1632 } else {
1633 // Note that we only need to be using a structure check if we opt for SaneChain, since
1634 // that needs to protect against JSArray's __proto__ being changed.
1635 Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic);
1636
1637 Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
1638
1639 if (arrayMode.doesConversion()) {
1640 if (structure) {
1641 m_insertionSet.insertNode(
1642 m_indexInBlock, SpecNone, ArrayifyToStructure, origin,
1643 OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1644 } else {
1645 m_insertionSet.insertNode(
1646 m_indexInBlock, SpecNone, Arrayify, origin,
1647 OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
1648 }
1649 } else {
1650 if (structure) {
1651 m_insertionSet.insertNode(
1652 m_indexInBlock, SpecNone, CheckStructure, origin,
1653 OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
1654 } else {
1655 m_insertionSet.insertNode(
1656 m_indexInBlock, SpecNone, CheckArray, origin,
1657 OpInfo(arrayMode.asWord()), Edge(array, CellUse));
1658 }
1659 }
1660 }
1661
1662 if (!storageCheck(arrayMode))
1663 return 0;
1664
1665 if (arrayMode.usesButterfly()) {
1666 return m_insertionSet.insertNode(
1667 m_indexInBlock, SpecNone, GetButterfly, origin, Edge(array, CellUse));
1668 }
1669
1670 return m_insertionSet.insertNode(
1671 m_indexInBlock, SpecNone, GetIndexedPropertyStorage, origin,
1672 OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
1673 }
1674
1675 void blessArrayOperation(Edge base, Edge index, Edge& storageChild)
1676 {
1677 Node* node = m_currentNode;
1678
1679 switch (node->arrayMode().type()) {
1680 case Array::ForceExit: {
1681 m_insertionSet.insertNode(
1682 m_indexInBlock, SpecNone, ForceOSRExit, node->origin);
1683 return;
1684 }
1685
1686 case Array::SelectUsingPredictions:
1687 case Array::Unprofiled:
1688 RELEASE_ASSERT_NOT_REACHED();
1689 return;
1690
1691 case Array::Generic:
1692 return;
1693
1694 default: {
1695 Node* storage = checkArray(node->arrayMode(), node->origin, base.node(), index.node());
1696 if (!storage)
1697 return;
1698
1699 storageChild = Edge(storage);
1700 return;
1701 } }
1702 }
1703
1704 bool alwaysUnboxSimplePrimitives()
1705 {
1706 #if USE(JSVALUE64)
1707 return false;
1708 #else
1709 // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
1710 // reduces traffic.
1711 return true;
1712 #endif
1713 }
1714
1715 template<UseKind useKind>
1716 void observeUseKindOnNode(Node* node)
1717 {
1718 if (useKind == UntypedUse)
1719 return;
1720 observeUseKindOnNode(node, useKind);
1721 }
1722
1723 void observeUseKindOnEdge(Edge edge)
1724 {
1725 observeUseKindOnNode(edge.node(), edge.useKind());
1726 }
1727
1728 void observeUseKindOnNode(Node* node, UseKind useKind)
1729 {
1730 if (node->op() != GetLocal)
1731 return;
1732
1733 // FIXME: The way this uses alwaysUnboxSimplePrimitives() is suspicious.
1734 // https://bugs.webkit.org/show_bug.cgi?id=121518
1735
1736 VariableAccessData* variable = node->variableAccessData();
1737 switch (useKind) {
1738 case Int32Use:
1739 if (alwaysUnboxSimplePrimitives()
1740 || isInt32Speculation(variable->prediction()))
1741 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1742 break;
1743 case NumberUse:
1744 case RealNumberUse:
1745 case DoubleRepUse:
1746 case DoubleRepRealUse:
1747 if (variable->doubleFormatState() == UsingDoubleFormat)
1748 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1749 break;
1750 case BooleanUse:
1751 if (alwaysUnboxSimplePrimitives()
1752 || isBooleanSpeculation(variable->prediction()))
1753 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1754 break;
1755 case Int52RepUse:
1756 if (isMachineIntSpeculation(variable->prediction()))
1757 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1758 break;
1759 case CellUse:
1760 case KnownCellUse:
1761 case ObjectUse:
1762 case FunctionUse:
1763 case StringUse:
1764 case KnownStringUse:
1765 case StringObjectUse:
1766 case StringOrStringObjectUse:
1767 if (alwaysUnboxSimplePrimitives()
1768 || isCellSpeculation(variable->prediction()))
1769 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
1770 break;
1771 default:
1772 break;
1773 }
1774 }
1775
1776 template<UseKind useKind>
1777 void fixEdge(Edge& edge)
1778 {
1779 observeUseKindOnNode<useKind>(edge.node());
1780 edge.setUseKind(useKind);
1781 }
1782
1783 void speculateForBarrier(Edge value)
1784 {
1785 // Currently, the DFG won't take advantage of this speculation. But, we want to do it in
1786 // the DFG anyway because if such a speculation would be wrong, we want to know before
1787 // we do an expensive compile.
1788
1789 if (value->shouldSpeculateInt32()) {
1790 insertCheck<Int32Use>(m_indexInBlock, value.node());
1791 return;
1792 }
1793
1794 if (value->shouldSpeculateBoolean()) {
1795 insertCheck<BooleanUse>(m_indexInBlock, value.node());
1796 return;
1797 }
1798
1799 if (value->shouldSpeculateOther()) {
1800 insertCheck<OtherUse>(m_indexInBlock, value.node());
1801 return;
1802 }
1803
1804 if (value->shouldSpeculateNumber()) {
1805 insertCheck<NumberUse>(m_indexInBlock, value.node());
1806 return;
1807 }
1808
1809 if (value->shouldSpeculateNotCell()) {
1810 insertCheck<NotCellUse>(m_indexInBlock, value.node());
1811 return;
1812 }
1813 }
1814
1815 template<UseKind useKind>
1816 void insertCheck(unsigned indexInBlock, Node* node)
1817 {
1818 observeUseKindOnNode<useKind>(node);
1819 m_insertionSet.insertNode(
1820 indexInBlock, SpecNone, Check, m_currentNode->origin, Edge(node, useKind));
1821 }
1822
1823 void fixIntConvertingEdge(Edge& edge)
1824 {
1825 Node* node = edge.node();
1826 if (node->shouldSpeculateInt32OrBoolean()) {
1827 fixIntOrBooleanEdge(edge);
1828 return;
1829 }
1830
1831 UseKind useKind;
1832 if (node->shouldSpeculateMachineInt())
1833 useKind = Int52RepUse;
1834 else if (node->shouldSpeculateNumber())
1835 useKind = DoubleRepUse;
1836 else
1837 useKind = NotCellUse;
1838 Node* newNode = m_insertionSet.insertNode(
1839 m_indexInBlock, SpecInt32, ValueToInt32, m_currentNode->origin,
1840 Edge(node, useKind));
1841 observeUseKindOnNode(node, useKind);
1842
1843 edge = Edge(newNode, KnownInt32Use);
1844 }
1845
1846 void fixIntOrBooleanEdge(Edge& edge)
1847 {
1848 Node* node = edge.node();
1849 if (!node->sawBooleans()) {
1850 fixEdge<Int32Use>(edge);
1851 return;
1852 }
1853
1854 UseKind useKind;
1855 if (node->shouldSpeculateBoolean())
1856 useKind = BooleanUse;
1857 else
1858 useKind = UntypedUse;
1859 Node* newNode = m_insertionSet.insertNode(
1860 m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
1861 Edge(node, useKind));
1862 observeUseKindOnNode(node, useKind);
1863
1864 edge = Edge(newNode, Int32Use);
1865 }
1866
1867 void fixDoubleOrBooleanEdge(Edge& edge)
1868 {
1869 Node* node = edge.node();
1870 if (!node->sawBooleans()) {
1871 fixEdge<DoubleRepUse>(edge);
1872 return;
1873 }
1874
1875 UseKind useKind;
1876 if (node->shouldSpeculateBoolean())
1877 useKind = BooleanUse;
1878 else
1879 useKind = UntypedUse;
1880 Node* newNode = m_insertionSet.insertNode(
1881 m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
1882 Edge(node, useKind));
1883 observeUseKindOnNode(node, useKind);
1884
1885 edge = Edge(newNode, DoubleRepUse);
1886 }
1887
1888 void truncateConstantToInt32(Edge& edge)
1889 {
1890 Node* oldNode = edge.node();
1891
1892 JSValue value = oldNode->asJSValue();
1893 if (value.isInt32())
1894 return;
1895
1896 value = jsNumber(JSC::toInt32(value.asNumber()));
1897 ASSERT(value.isInt32());
1898 edge.setNode(m_insertionSet.insertNode(
1899 m_indexInBlock, SpecInt32, JSConstant, m_currentNode->origin,
1900 OpInfo(m_graph.freeze(value))));
1901 }
1902
1903 void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
1904 {
1905 if (mode != SpeculateInt32AndTruncateConstants)
1906 return;
1907
1908 ASSERT(node->child1()->hasConstant() || node->child2()->hasConstant());
1909 if (node->child1()->hasConstant())
1910 truncateConstantToInt32(node->child1());
1911 else
1912 truncateConstantToInt32(node->child2());
1913 }
1914
1915 bool attemptToMakeIntegerAdd(Node* node)
1916 {
1917 AddSpeculationMode mode = m_graph.addSpeculationMode(node, FixupPass);
1918 if (mode != DontSpeculateInt32) {
1919 truncateConstantsIfNecessary(node, mode);
1920 fixIntOrBooleanEdge(node->child1());
1921 fixIntOrBooleanEdge(node->child2());
1922 if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
1923 node->setArithMode(Arith::Unchecked);
1924 else
1925 node->setArithMode(Arith::CheckOverflow);
1926 return true;
1927 }
1928
1929 if (m_graph.addShouldSpeculateMachineInt(node)) {
1930 fixEdge<Int52RepUse>(node->child1());
1931 fixEdge<Int52RepUse>(node->child2());
1932 node->setArithMode(Arith::CheckOverflow);
1933 node->setResult(NodeResultInt52);
1934 return true;
1935 }
1936
1937 return false;
1938 }
1939
1940 bool attemptToMakeGetArrayLength(Node* node)
1941 {
1942 if (!isInt32Speculation(node->prediction()))
1943 return false;
1944 CodeBlock* profiledBlock = m_graph.baselineCodeBlockFor(node->origin.semantic);
1945 ArrayProfile* arrayProfile =
1946 profiledBlock->getArrayProfile(node->origin.semantic.bytecodeIndex);
1947 ArrayMode arrayMode = ArrayMode(Array::SelectUsingPredictions);
1948 if (arrayProfile) {
1949 ConcurrentJITLocker locker(profiledBlock->m_lock);
1950 arrayProfile->computeUpdatedPrediction(locker, profiledBlock);
1951 arrayMode = ArrayMode::fromObserved(locker, arrayProfile, Array::Read, false);
1952 if (arrayMode.type() == Array::Unprofiled) {
1953 // For normal array operations, it makes sense to treat Unprofiled
1954 // accesses as ForceExit and get more data rather than using
1955 // predictions and then possibly ending up with a Generic. But here,
1956 // we treat anything that is Unprofiled as Generic and keep the
1957 // GetById. I.e. ForceExit = Generic. So, there is no harm - and only
1958 // profit - from treating the Unprofiled case as
1959 // SelectUsingPredictions.
1960 arrayMode = ArrayMode(Array::SelectUsingPredictions);
1961 }
1962 }
1963
1964 arrayMode = arrayMode.refine(
1965 m_graph, node, node->child1()->prediction(), node->prediction());
1966
1967 if (arrayMode.type() == Array::Generic) {
1968 // Check if the input is something that we can't get array length for, but for which we
1969 // could insert some conversions in order to transform it into something that we can do it
1970 // for.
1971 if (node->child1()->shouldSpeculateStringObject())
1972 attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
1973 else if (node->child1()->shouldSpeculateStringOrStringObject())
1974 attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
1975 }
1976
1977 if (!arrayMode.supportsLength())
1978 return false;
1979
1980 convertToGetArrayLength(node, arrayMode);
1981 return true;
1982 }
1983
1984 bool attemptToMakeGetTypedArrayByteLength(Node* node)
1985 {
1986 if (!isInt32Speculation(node->prediction()))
1987 return false;
1988
1989 TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
1990 if (!isTypedView(type))
1991 return false;
1992
1993 if (elementSize(type) == 1) {
1994 convertToGetArrayLength(node, ArrayMode(toArrayType(type)));
1995 return true;
1996 }
1997
1998 Node* length = prependGetArrayLength(
1999 node->origin, node->child1().node(), ArrayMode(toArrayType(type)));
2000
2001 Node* shiftAmount = m_insertionSet.insertNode(
2002 m_indexInBlock, SpecInt32, JSConstant, node->origin,
2003 OpInfo(m_graph.freeze(jsNumber(logElementSize(type)))));
2004
2005 // We can use a BitLShift here because typed arrays will never have a byteLength
2006 // that overflows int32.
2007 node->setOp(BitLShift);
2008 node->clearFlags(NodeMustGenerate);
2009 observeUseKindOnNode(length, Int32Use);
2010 observeUseKindOnNode(shiftAmount, Int32Use);
2011 node->child1() = Edge(length, Int32Use);
2012 node->child2() = Edge(shiftAmount, Int32Use);
2013 return true;
2014 }
2015
2016 void convertToGetArrayLength(Node* node, ArrayMode arrayMode)
2017 {
2018 node->setOp(GetArrayLength);
2019 node->clearFlags(NodeMustGenerate);
2020 fixEdge<KnownCellUse>(node->child1());
2021 node->setArrayMode(arrayMode);
2022
2023 Node* storage = checkArray(arrayMode, node->origin, node->child1().node(), 0, lengthNeedsStorage);
2024 if (!storage)
2025 return;
2026
2027 node->child2() = Edge(storage);
2028 }
2029
2030 Node* prependGetArrayLength(NodeOrigin origin, Node* child, ArrayMode arrayMode)
2031 {
2032 Node* storage = checkArray(arrayMode, origin, child, 0, lengthNeedsStorage);
2033 return m_insertionSet.insertNode(
2034 m_indexInBlock, SpecInt32, GetArrayLength, origin,
2035 OpInfo(arrayMode.asWord()), Edge(child, KnownCellUse), Edge(storage));
2036 }
2037
2038 bool attemptToMakeGetTypedArrayByteOffset(Node* node)
2039 {
2040 if (!isInt32Speculation(node->prediction()))
2041 return false;
2042
2043 TypedArrayType type = typedArrayTypeFromSpeculation(node->child1()->prediction());
2044 if (!isTypedView(type))
2045 return false;
2046
2047 checkArray(
2048 ArrayMode(toArrayType(type)), node->origin, node->child1().node(),
2049 0, neverNeedsStorage);
2050
2051 node->setOp(GetTypedArrayByteOffset);
2052 node->clearFlags(NodeMustGenerate);
2053 fixEdge<KnownCellUse>(node->child1());
2054 return true;
2055 }
2056
2057 void injectTypeConversionsInBlock(BasicBlock* block)
2058 {
2059 if (!block)
2060 return;
2061 ASSERT(block->isReachable);
2062 m_block = block;
2063 for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
2064 m_currentNode = block->at(m_indexInBlock);
2065 tryToRelaxRepresentation(m_currentNode);
2066 DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
2067 }
2068 m_insertionSet.execute(block);
2069 }
2070
2071 void tryToRelaxRepresentation(Node* node)
2072 {
2073 // Some operations may be able to operate more efficiently over looser representations.
2074 // Identify those here. This avoids inserting a redundant representation conversion.
2075 // Also, for some operations, like MovHint, this is a necessary optimization: inserting
2076 // an otherwise-dead conversion just for a MovHint would break OSR's understanding of
2077 // the IR.
2078
2079 switch (node->op()) {
2080 case MovHint:
2081 case Check:
2082 DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, fixEdgeRepresentation);
2083 break;
2084
2085 case ValueToInt32:
2086 if (node->child1().useKind() == DoubleRepUse
2087 && !node->child1()->hasDoubleResult()) {
2088 node->child1().setUseKind(NumberUse);
2089 break;
2090 }
2091 break;
2092
2093 default:
2094 break;
2095 }
2096 }
2097
2098 void fixEdgeRepresentation(Node*, Edge& edge)
2099 {
2100 switch (edge.useKind()) {
2101 case DoubleRepUse:
2102 case DoubleRepRealUse:
2103 if (edge->hasDoubleResult())
2104 break;
2105
2106 if (edge->hasInt52Result())
2107 edge.setUseKind(Int52RepUse);
2108 else if (edge.useKind() == DoubleRepUse)
2109 edge.setUseKind(NumberUse);
2110 break;
2111
2112 case Int52RepUse:
2113 // Nothing we can really do.
2114 break;
2115
2116 case UntypedUse:
2117 case NumberUse:
2118 if (edge->hasDoubleResult())
2119 edge.setUseKind(DoubleRepUse);
2120 else if (edge->hasInt52Result())
2121 edge.setUseKind(Int52RepUse);
2122 break;
2123
2124 case RealNumberUse:
2125 if (edge->hasDoubleResult())
2126 edge.setUseKind(DoubleRepRealUse);
2127 else if (edge->hasInt52Result())
2128 edge.setUseKind(Int52RepUse);
2129 break;
2130
2131 default:
2132 break;
2133 }
2134 }
2135
2136 void injectTypeConversionsForEdge(Node* node, Edge& edge)
2137 {
2138 ASSERT(node == m_currentNode);
2139 Node* result = nullptr;
2140
2141 switch (edge.useKind()) {
2142 case DoubleRepUse:
2143 case DoubleRepRealUse:
2144 case DoubleRepMachineIntUse: {
2145 if (edge->hasDoubleResult())
2146 break;
2147
2148 if (edge->isNumberConstant()) {
2149 result = m_insertionSet.insertNode(
2150 m_indexInBlock, SpecBytecodeDouble, DoubleConstant, node->origin,
2151 OpInfo(m_graph.freeze(jsDoubleNumber(edge->asNumber()))));
2152 } else if (edge->hasInt52Result()) {
2153 result = m_insertionSet.insertNode(
2154 m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
2155 Edge(edge.node(), Int52RepUse));
2156 } else {
2157 UseKind useKind;
2158 if (edge->shouldSpeculateDoubleReal())
2159 useKind = RealNumberUse;
2160 else if (edge->shouldSpeculateNumber())
2161 useKind = NumberUse;
2162 else
2163 useKind = NotCellUse;
2164
2165 result = m_insertionSet.insertNode(
2166 m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin,
2167 Edge(edge.node(), useKind));
2168 }
2169
2170 edge.setNode(result);
2171 break;
2172 }
2173
2174 case Int52RepUse: {
2175 if (edge->hasInt52Result())
2176 break;
2177
2178 if (edge->isMachineIntConstant()) {
2179 result = m_insertionSet.insertNode(
2180 m_indexInBlock, SpecMachineInt, Int52Constant, node->origin,
2181 OpInfo(edge->constant()));
2182 } else if (edge->hasDoubleResult()) {
2183 result = m_insertionSet.insertNode(
2184 m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
2185 Edge(edge.node(), DoubleRepMachineIntUse));
2186 } else if (edge->shouldSpeculateInt32ForArithmetic()) {
2187 result = m_insertionSet.insertNode(
2188 m_indexInBlock, SpecInt32, Int52Rep, node->origin,
2189 Edge(edge.node(), Int32Use));
2190 } else {
2191 result = m_insertionSet.insertNode(
2192 m_indexInBlock, SpecMachineInt, Int52Rep, node->origin,
2193 Edge(edge.node(), MachineIntUse));
2194 }
2195
2196 edge.setNode(result);
2197 break;
2198 }
2199
2200 default: {
2201 if (!edge->hasDoubleResult() && !edge->hasInt52Result())
2202 break;
2203
2204 if (edge->hasDoubleResult()) {
2205 result = m_insertionSet.insertNode(
2206 m_indexInBlock, SpecBytecodeDouble, ValueRep, node->origin,
2207 Edge(edge.node(), DoubleRepUse));
2208 } else {
2209 result = m_insertionSet.insertNode(
2210 m_indexInBlock, SpecInt32 | SpecInt52AsDouble, ValueRep, node->origin,
2211 Edge(edge.node(), Int52RepUse));
2212 }
2213
2214 edge.setNode(result);
2215 break;
2216 } }
2217 }
2218
2219 BasicBlock* m_block;
2220 unsigned m_indexInBlock;
2221 Node* m_currentNode;
2222 InsertionSet m_insertionSet;
2223 bool m_profitabilityChanged;
2224 };
2225
2226 bool performFixup(Graph& graph)
2227 {
2228 SamplingRegion samplingRegion("DFG Fixup Phase");
2229 return runPhase<FixupPhase>(graph);
2230 }
2231
2232 } } // namespace JSC::DFG
2233
2234 #endif // ENABLE(DFG_JIT)
2235