2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGFixupPhase.h"
32 #include "DFGInsertionSet.h"
34 #include "DFGPredictionPropagationPhase.h"
35 #include "DFGVariableAccessDataDump.h"
36 #include "Operations.h"
38 namespace JSC
{ namespace DFG
{
40 class FixupPhase
: public Phase
{
42 FixupPhase(Graph
& graph
)
43 : Phase(graph
, "fixup")
44 , m_insertionSet(graph
)
50 ASSERT(m_graph
.m_fixpointState
== BeforeFixpoint
);
51 ASSERT(m_graph
.m_form
== ThreadedCPS
);
53 m_profitabilityChanged
= false;
54 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
)
55 fixupBlock(m_graph
.m_blocks
[blockIndex
].get());
57 while (m_profitabilityChanged
) {
58 m_profitabilityChanged
= false;
60 for (unsigned i
= m_graph
.m_argumentPositions
.size(); i
--;)
61 m_graph
.m_argumentPositions
[i
].mergeArgumentUnboxingAwareness();
63 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.m_blocks
.size(); ++blockIndex
)
64 fixupSetLocalsInBlock(m_graph
.m_blocks
[blockIndex
].get());
71 void fixupBlock(BasicBlock
* block
)
75 ASSERT(block
->isReachable
);
77 for (m_indexInBlock
= 0; m_indexInBlock
< block
->size(); ++m_indexInBlock
) {
78 m_currentNode
= block
->at(m_indexInBlock
);
79 fixupNode(m_currentNode
);
81 m_insertionSet
.execute(block
);
84 void fixupNode(Node
* node
)
86 NodeType op
= node
->op();
88 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
89 dataLogF(" %s @%u: ", Graph::opName(op
), node
->index());
94 // This gets handled by fixupSetLocalsInBlock().
105 fixIntEdge(node
->child1());
106 fixIntEdge(node
->child2());
110 case UInt32ToNumber
: {
111 setUseKindAndUnboxIfProfitable
<KnownInt32Use
>(node
->child1());
115 case DoubleAsInt32
: {
116 RELEASE_ASSERT_NOT_REACHED();
121 if (node
->child1()->shouldSpeculateInteger()) {
122 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
126 if (node
->child1()->shouldSpeculateNumber()) {
127 setUseKindAndUnboxIfProfitable
<NumberUse
>(node
->child1());
131 if (node
->child1()->shouldSpeculateBoolean()) {
132 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
136 setUseKindAndUnboxIfProfitable
<NotCellUse
>(node
->child1());
140 case Int32ToDouble
: {
141 RELEASE_ASSERT_NOT_REACHED();
146 if (attemptToMakeIntegerAdd(node
))
148 if (Node::shouldSpeculateNumberExpectingDefined(node
->child1().node(), node
->child2().node())) {
149 fixDoubleEdge
<NumberUse
>(node
->child1());
150 fixDoubleEdge
<NumberUse
>(node
->child2());
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
159 if (node
->child1()->shouldSpeculateString()
160 && attemptToMakeFastStringAdd
<StringUse
>(node
, node
->child1(), node
->child2()))
162 if (node
->child2()->shouldSpeculateString()
163 && attemptToMakeFastStringAdd
<StringUse
>(node
, node
->child2(), node
->child1()))
165 if (node
->child1()->shouldSpeculateStringObject()
166 && attemptToMakeFastStringAdd
<StringObjectUse
>(node
, node
->child1(), node
->child2()))
168 if (node
->child2()->shouldSpeculateStringObject()
169 && attemptToMakeFastStringAdd
<StringObjectUse
>(node
, node
->child2(), node
->child1()))
171 if (node
->child1()->shouldSpeculateStringOrStringObject()
172 && attemptToMakeFastStringAdd
<StringOrStringObjectUse
>(node
, node
->child1(), node
->child2()))
174 if (node
->child2()->shouldSpeculateStringOrStringObject()
175 && attemptToMakeFastStringAdd
<StringOrStringObjectUse
>(node
, node
->child2(), node
->child1()))
187 if (attemptToMakeIntegerAdd(node
))
189 fixDoubleEdge
<NumberUse
>(node
->child1());
190 fixDoubleEdge
<NumberUse
>(node
->child2());
195 if (m_graph
.negateShouldSpeculateInteger(node
)) {
196 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
199 fixDoubleEdge
<NumberUse
>(node
->child1());
204 if (m_graph
.mulShouldSpeculateInteger(node
)) {
205 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
206 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
209 fixDoubleEdge
<NumberUse
>(node
->child1());
210 fixDoubleEdge
<NumberUse
>(node
->child2());
215 if (Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node())
216 && node
->canSpeculateInteger()) {
217 if (isX86() || isARM64() || isARMv7s()) {
218 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
219 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
222 injectInt32ToDoubleNode(node
->child1());
223 injectInt32ToDoubleNode(node
->child2());
225 // We don't need to do ref'ing on the children because we're stealing them from
226 // the original division.
227 Node
* newDivision
= m_insertionSet
.insertNode(
228 m_indexInBlock
, SpecDouble
, *node
);
230 node
->setOp(DoubleAsInt32
);
231 node
->children
.initialize(Edge(newDivision
, KnownNumberUse
), Edge(), Edge());
234 fixDoubleEdge
<NumberUse
>(node
->child1());
235 fixDoubleEdge
<NumberUse
>(node
->child2());
242 if (Node::shouldSpeculateIntegerForArithmetic(node
->child1().node(), node
->child2().node())
243 && node
->canSpeculateInteger()) {
244 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
245 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
248 fixDoubleEdge
<NumberUse
>(node
->child1());
249 fixDoubleEdge
<NumberUse
>(node
->child2());
254 if (node
->child1()->shouldSpeculateIntegerForArithmetic()
255 && node
->canSpeculateInteger()) {
256 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
259 fixDoubleEdge
<NumberUse
>(node
->child1());
264 fixDoubleEdge
<NumberUse
>(node
->child1());
269 if (node
->child1()->shouldSpeculateBoolean())
270 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
271 else if (node
->child1()->shouldSpeculateObjectOrOther())
272 setUseKindAndUnboxIfProfitable
<ObjectOrOtherUse
>(node
->child1());
273 else if (node
->child1()->shouldSpeculateInteger())
274 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
275 else if (node
->child1()->shouldSpeculateNumber())
276 fixDoubleEdge
<NumberUse
>(node
->child1());
281 if (node
->child1()->shouldSpeculateString())
282 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
283 else if (node
->child1()->shouldSpeculateCell())
284 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
288 case CompareEqConstant
: {
296 case CompareGreaterEq
: {
297 if (Node::shouldSpeculateInteger(node
->child1().node(), node
->child2().node())) {
298 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
299 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
302 if (Node::shouldSpeculateNumber(node
->child1().node(), node
->child2().node())) {
303 fixDoubleEdge
<NumberUse
>(node
->child1());
304 fixDoubleEdge
<NumberUse
>(node
->child2());
307 if (node
->op() != CompareEq
)
309 if (Node::shouldSpeculateBoolean(node
->child1().node(), node
->child2().node())) {
310 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
311 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child2());
314 if (node
->child1()->shouldSpeculateString() && node
->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters
>= 7) {
315 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
316 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child2());
319 if (node
->child1()->shouldSpeculateObject() && node
->child2()->shouldSpeculateObject()) {
320 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child1());
321 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child2());
324 if (node
->child1()->shouldSpeculateObject() && node
->child2()->shouldSpeculateObjectOrOther()) {
325 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child1());
326 setUseKindAndUnboxIfProfitable
<ObjectOrOtherUse
>(node
->child2());
329 if (node
->child1()->shouldSpeculateObjectOrOther() && node
->child2()->shouldSpeculateObject()) {
330 setUseKindAndUnboxIfProfitable
<ObjectOrOtherUse
>(node
->child1());
331 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child2());
337 case CompareStrictEqConstant
: {
341 case CompareStrictEq
: {
342 if (Node::shouldSpeculateBoolean(node
->child1().node(), node
->child2().node())) {
343 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
344 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child2());
347 if (Node::shouldSpeculateInteger(node
->child1().node(), node
->child2().node())) {
348 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
349 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
352 if (Node::shouldSpeculateNumber(node
->child1().node(), node
->child2().node())) {
353 fixDoubleEdge
<NumberUse
>(node
->child1());
354 fixDoubleEdge
<NumberUse
>(node
->child2());
357 if (node
->child1()->shouldSpeculateString() && node
->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters
>= 7) {
358 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
359 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child2());
362 if (node
->child1()->shouldSpeculateObject() && node
->child2()->shouldSpeculateObject()) {
363 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child1());
364 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child2());
370 case StringFromCharCode
:
371 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
375 case StringCharCodeAt
: {
376 // Currently we have no good way of refining these.
377 ASSERT(node
->arrayMode() == ArrayMode(Array::String
));
378 blessArrayOperation(node
->child1(), node
->child2(), node
->child3());
379 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
380 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
386 node
->arrayMode().refine(
387 node
->child1()->prediction(),
388 node
->child2()->prediction(),
389 SpecNone
, node
->flags()));
391 blessArrayOperation(node
->child1(), node
->child2(), node
->child3());
393 ArrayMode arrayMode
= node
->arrayMode();
394 if (arrayMode
.type() == Array::Double
395 && arrayMode
.arrayClass() == Array::OriginalArray
396 && arrayMode
.speculation() == Array::InBounds
397 && arrayMode
.conversion() == Array::AsIs
398 && m_graph
.globalObjectFor(node
->codeOrigin
)->arrayPrototypeChainIsSane()
399 && !(node
->flags() & NodeUsedAsOther
))
400 node
->setArrayMode(arrayMode
.withSpeculation(Array::SaneChain
));
402 switch (node
->arrayMode().type()) {
403 case Array::SelectUsingPredictions
:
404 case Array::Unprofiled
:
405 case Array::Undecided
:
406 RELEASE_ASSERT_NOT_REACHED();
409 #if USE(JSVALUE32_64)
410 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1()); // Speculating cell due to register pressure on 32-bit.
413 case Array::ForceExit
:
416 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
417 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
425 case PutByValAlias
: {
426 Edge
& child1
= m_graph
.varArgChild(node
, 0);
427 Edge
& child2
= m_graph
.varArgChild(node
, 1);
428 Edge
& child3
= m_graph
.varArgChild(node
, 2);
431 node
->arrayMode().refine(
432 child1
->prediction(),
433 child2
->prediction(),
434 child3
->prediction()));
436 blessArrayOperation(child1
, child2
, m_graph
.varArgChild(node
, 3));
438 switch (node
->arrayMode().modeForPut().type()) {
439 case Array::SelectUsingPredictions
:
440 case Array::Unprofiled
:
441 case Array::Undecided
:
442 RELEASE_ASSERT_NOT_REACHED();
444 case Array::ForceExit
:
446 #if USE(JSVALUE32_64)
447 // Due to register pressure on 32-bit, we speculate cell and
448 // ignore the base-is-not-cell case entirely by letting the
449 // baseline JIT handle it.
450 setUseKindAndUnboxIfProfitable
<CellUse
>(child1
);
454 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(child1
);
455 setUseKindAndUnboxIfProfitable
<Int32Use
>(child2
);
456 setUseKindAndUnboxIfProfitable
<Int32Use
>(child3
);
459 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(child1
);
460 setUseKindAndUnboxIfProfitable
<Int32Use
>(child2
);
461 fixDoubleEdge
<RealNumberUse
>(child3
);
463 case Array::Int8Array
:
464 case Array::Int16Array
:
465 case Array::Int32Array
:
466 case Array::Uint8Array
:
467 case Array::Uint8ClampedArray
:
468 case Array::Uint16Array
:
469 case Array::Uint32Array
:
470 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(child1
);
471 setUseKindAndUnboxIfProfitable
<Int32Use
>(child2
);
472 if (child3
->shouldSpeculateInteger())
473 setUseKindAndUnboxIfProfitable
<Int32Use
>(child3
);
475 fixDoubleEdge
<NumberUse
>(child3
);
477 case Array::Float32Array
:
478 case Array::Float64Array
:
479 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(child1
);
480 setUseKindAndUnboxIfProfitable
<Int32Use
>(child2
);
481 fixDoubleEdge
<NumberUse
>(child3
);
484 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(child1
);
485 setUseKindAndUnboxIfProfitable
<Int32Use
>(child2
);
492 // May need to refine the array mode in case the value prediction contravenes
493 // the array prediction. For example, we may have evidence showing that the
494 // array is in Int32 mode, but the value we're storing is likely to be a double.
495 // Then we should turn this into a conversion to Double array followed by the
496 // push. On the other hand, we absolutely don't want to refine based on the
497 // base prediction. If it has non-cell garbage in it, then we want that to be
498 // ignored. That's because ArrayPush can't handle any array modes that aren't
499 // array-related - so if refine() turned this into a "Generic" ArrayPush then
500 // that would break things.
502 node
->arrayMode().refine(
503 node
->child1()->prediction() & SpecCell
,
505 node
->child2()->prediction()));
506 blessArrayOperation(node
->child1(), Edge(), node
->child3());
507 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
509 switch (node
->arrayMode().type()) {
511 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
514 fixDoubleEdge
<RealNumberUse
>(node
->child2());
523 blessArrayOperation(node
->child1(), Edge(), node
->child2());
524 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
530 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
531 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child2());
536 if (node
->child1()->shouldSpeculateBoolean())
537 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
538 else if (node
->child1()->shouldSpeculateObjectOrOther())
539 setUseKindAndUnboxIfProfitable
<ObjectOrOtherUse
>(node
->child1());
540 else if (node
->child1()->shouldSpeculateInteger())
541 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
542 else if (node
->child1()->shouldSpeculateNumber())
543 fixDoubleEdge
<NumberUse
>(node
->child1());
545 Node
* logicalNot
= node
->child1().node();
546 if (logicalNot
->op() == LogicalNot
) {
548 // Make sure that OSR exit can't observe the LogicalNot. If it can,
549 // then we must compute it and cannot peephole around it.
552 for (unsigned i
= m_indexInBlock
; i
--;) {
553 Node
* candidate
= m_block
->at(i
);
554 if (candidate
== logicalNot
) {
558 if (candidate
->canExit()) {
564 ASSERT_UNUSED(found
, found
);
567 Edge newChildEdge
= logicalNot
->child1();
568 if (newChildEdge
->hasBooleanResult()) {
569 node
->children
.setChild1(newChildEdge
);
571 BlockIndex toBeTaken
= node
->notTakenBlockIndex();
572 BlockIndex toBeNotTaken
= node
->takenBlockIndex();
573 node
->setTakenBlockIndex(toBeTaken
);
574 node
->setNotTakenBlockIndex(toBeNotTaken
);
582 fixupToPrimitive(node
);
591 case NewStringObject
: {
592 setUseKindAndUnboxIfProfitable
<KnownStringUse
>(node
->child1());
597 for (unsigned i
= m_graph
.varArgNumChildren(node
); i
--;) {
598 node
->setIndexingType(
599 leastUpperBoundOfIndexingTypeAndType(
600 node
->indexingType(), m_graph
.varArgChild(node
, i
)->prediction()));
602 switch (node
->indexingType()) {
603 case ALL_BLANK_INDEXING_TYPES
:
606 case ALL_UNDECIDED_INDEXING_TYPES
:
607 if (node
->numChildren()) {
608 // This will only happen if the children have no type predictions. We
609 // would have already exited by now, but insert a forced exit just to
611 m_insertionSet
.insertNode(
612 m_indexInBlock
, SpecNone
, ForceOSRExit
, node
->codeOrigin
);
615 case ALL_INT32_INDEXING_TYPES
:
616 for (unsigned operandIndex
= 0; operandIndex
< node
->numChildren(); ++operandIndex
)
617 setUseKindAndUnboxIfProfitable
<Int32Use
>(m_graph
.m_varArgChildren
[node
->firstChild() + operandIndex
]);
619 case ALL_DOUBLE_INDEXING_TYPES
:
620 for (unsigned operandIndex
= 0; operandIndex
< node
->numChildren(); ++operandIndex
)
621 setUseKindAndUnboxIfProfitable
<RealNumberUse
>(m_graph
.m_varArgChildren
[node
->firstChild() + operandIndex
]);
623 case ALL_CONTIGUOUS_INDEXING_TYPES
:
624 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
633 case NewArrayWithSize
: {
634 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
639 if (isOtherSpeculation(node
->child1()->prediction())) {
640 m_insertionSet
.insertNode(
641 m_indexInBlock
, SpecNone
, Phantom
, node
->codeOrigin
,
642 Edge(node
->child1().node(), OtherUse
));
643 observeUseKindOnNode
<OtherUse
>(node
->child1().node());
644 node
->convertToWeakConstant(m_graph
.globalThisObjectFor(node
->codeOrigin
));
648 if (isObjectSpeculation(node
->child1()->prediction())) {
649 setUseKindAndUnboxIfProfitable
<ObjectUse
>(node
->child1());
650 node
->convertToIdentity();
658 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
662 case GetMyArgumentByVal
:
663 case GetMyArgumentByValSafe
: {
664 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
668 case GetScopeRegisters
:
675 case AllocatePropertyStorage
:
676 case ReallocatePropertyStorage
:
679 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
684 if (!node
->child1()->shouldSpeculateCell())
686 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
687 if (!isInt32Speculation(node
->prediction()))
689 if (codeBlock()->identifier(node
->identifierNumber()) != vm().propertyNames
->length
)
691 ArrayProfile
* arrayProfile
=
692 m_graph
.baselineCodeBlockFor(node
->codeOrigin
)->getArrayProfile(
693 node
->codeOrigin
.bytecodeIndex
);
694 ArrayMode arrayMode
= ArrayMode(Array::SelectUsingPredictions
);
696 arrayProfile
->computeUpdatedPrediction(m_graph
.baselineCodeBlockFor(node
->codeOrigin
));
697 arrayMode
= ArrayMode::fromObserved(arrayProfile
, Array::Read
, false);
698 arrayMode
= arrayMode
.refine(
699 node
->child1()->prediction(), node
->prediction());
700 if (arrayMode
.supportsLength() && arrayProfile
->hasDefiniteStructure()) {
701 m_insertionSet
.insertNode(
702 m_indexInBlock
, SpecNone
, CheckStructure
, node
->codeOrigin
,
703 OpInfo(m_graph
.addStructureSet(arrayProfile
->expectedStructure())),
707 arrayMode
= arrayMode
.refine(node
->child1()->prediction(), node
->prediction());
709 if (arrayMode
.type() == Array::Generic
) {
710 // Check if the input is something that we can't get array length for, but for which we
711 // could insert some conversions in order to transform it into something that we can do it
713 if (node
->child1()->shouldSpeculateStringObject())
714 attemptToForceStringArrayModeByToStringConversion
<StringObjectUse
>(arrayMode
, node
);
715 else if (node
->child1()->shouldSpeculateStringOrStringObject())
716 attemptToForceStringArrayModeByToStringConversion
<StringOrStringObjectUse
>(arrayMode
, node
);
719 if (!arrayMode
.supportsLength())
721 node
->setOp(GetArrayLength
);
722 ASSERT(node
->flags() & NodeMustGenerate
);
723 node
->clearFlags(NodeMustGenerate
| NodeClobbersWorld
);
724 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
725 node
->setArrayMode(arrayMode
);
727 Node
* storage
= checkArray(arrayMode
, node
->codeOrigin
, node
->child1().node(), 0, lengthNeedsStorage
);
731 node
->child2() = Edge(storage
);
736 if (node
->child1()->shouldSpeculateCell())
737 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
741 case CheckExecutable
:
743 case ForwardCheckStructure
:
744 case StructureTransitionWatchpoint
:
745 case ForwardStructureTransitionWatchpoint
:
749 case CheckHasInstance
: {
750 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
755 switch (node
->arrayMode().type()) {
757 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
760 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
767 case ArrayifyToStructure
: {
768 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
770 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
775 if (!node
->child1()->hasStorageResult())
776 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
781 if (!node
->child1()->hasStorageResult())
782 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child1());
783 setUseKindAndUnboxIfProfitable
<KnownCellUse
>(node
->child2());
788 // FIXME: This appears broken: CheckHasInstance already does an unconditional cell
789 // check. https://bugs.webkit.org/show_bug.cgi?id=107479
790 if (!(node
->child1()->prediction() & ~SpecCell
))
791 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
792 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child2());
798 switch (node
->child1().useKind()) {
800 if (node
->child1()->shouldSpeculateIntegerForArithmetic())
801 node
->child1().setUseKind(Int32Use
);
806 observeUseKindOnEdge(node
->child1());
813 case ForwardInt32ToDouble
:
814 case PhantomPutStructure
:
815 case GetIndexedPropertyStorage
:
818 case MovHintAndCheck
:
820 RELEASE_ASSERT_NOT_REACHED();
824 // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
832 case GetLocalUnlinked
:
838 case GlobalVarWatchpoint
:
839 case PutGlobalVarCheck
:
840 case AllocationProfileWatchpoint
:
848 case ResolveBaseStrictPut
:
857 case CreateActivation
:
858 case TearOffActivation
:
859 case CreateArguments
:
860 case PhantomArguments
:
861 case TearOffArguments
:
862 case GetMyArgumentsLength
:
863 case GetMyArgumentsLengthSafe
:
864 case CheckArgumentsNotCreated
:
866 case NewFunctionNoCheck
:
867 case NewFunctionExpression
:
871 case ThrowReferenceError
:
875 case CheckWatchdogTimer
:
883 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
884 if (!(node
->flags() & NodeHasVarArgs
)) {
885 dataLogF("new children: ");
886 node
->dumpChildren(WTF::dataFile());
892 template<UseKind useKind
>
893 void createToString(Node
* node
, Edge
& edge
)
895 edge
.setNode(m_insertionSet
.insertNode(
896 m_indexInBlock
, SpecString
, ToString
, node
->codeOrigin
,
897 Edge(edge
.node(), useKind
)));
900 template<UseKind useKind
>
901 void attemptToForceStringArrayModeByToStringConversion(ArrayMode
& arrayMode
, Node
* node
)
903 ASSERT(arrayMode
== ArrayMode(Array::Generic
));
905 if (!canOptimizeStringObjectAccess(node
->codeOrigin
))
908 createToString
<useKind
>(node
, node
->child1());
909 arrayMode
= ArrayMode(Array::String
);
912 template<UseKind useKind
>
913 bool isStringObjectUse()
916 case StringObjectUse
:
917 case StringOrStringObjectUse
:
924 template<UseKind useKind
>
925 void convertStringAddUse(Node
* node
, Edge
& edge
)
927 if (useKind
== StringUse
) {
928 // This preserves the binaryUseKind() invariant ot ValueAdd: ValueAdd's
929 // two edges will always have identical use kinds, which makes the
930 // decision process much easier.
931 observeUseKindOnNode
<StringUse
>(edge
.node());
932 m_insertionSet
.insertNode(
933 m_indexInBlock
, SpecNone
, Phantom
, node
->codeOrigin
,
934 Edge(edge
.node(), StringUse
));
935 edge
.setUseKind(KnownStringUse
);
939 // FIXME: We ought to be able to have a ToPrimitiveToString node.
941 observeUseKindOnNode
<useKind
>(edge
.node());
942 createToString
<useKind
>(node
, edge
);
945 void convertToMakeRope(Node
* node
)
947 node
->setOpAndDefaultFlags(MakeRope
);
951 void fixupMakeRope(Node
* node
)
953 for (unsigned i
= 0; i
< AdjacencyList::Size
; ++i
) {
954 Edge
& edge
= node
->children
.child(i
);
957 edge
.setUseKind(KnownStringUse
);
958 if (!m_graph
.isConstant(edge
.node()))
960 JSString
* string
= jsCast
<JSString
*>(m_graph
.valueOfJSConstant(edge
.node()).asCell());
961 if (string
->length())
964 // Don't allow the MakeRope to have zero children.
965 if (!i
&& !node
->child2())
968 node
->children
.removeEdge(i
--);
971 if (!node
->child2()) {
972 ASSERT(!node
->child3());
973 node
->convertToIdentity();
977 void fixupToPrimitive(Node
* node
)
979 if (node
->child1()->shouldSpeculateInteger()) {
980 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
981 node
->convertToIdentity();
985 if (node
->child1()->shouldSpeculateString()) {
986 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
987 node
->convertToIdentity();
991 if (node
->child1()->shouldSpeculateStringObject()
992 && canOptimizeStringObjectAccess(node
->codeOrigin
)) {
993 setUseKindAndUnboxIfProfitable
<StringObjectUse
>(node
->child1());
994 node
->convertToToString();
998 if (node
->child1()->shouldSpeculateStringOrStringObject()
999 && canOptimizeStringObjectAccess(node
->codeOrigin
)) {
1000 setUseKindAndUnboxIfProfitable
<StringOrStringObjectUse
>(node
->child1());
1001 node
->convertToToString();
1006 void fixupToString(Node
* node
)
1008 if (node
->child1()->shouldSpeculateString()) {
1009 setUseKindAndUnboxIfProfitable
<StringUse
>(node
->child1());
1010 node
->convertToIdentity();
1014 if (node
->child1()->shouldSpeculateStringObject()
1015 && canOptimizeStringObjectAccess(node
->codeOrigin
)) {
1016 setUseKindAndUnboxIfProfitable
<StringObjectUse
>(node
->child1());
1020 if (node
->child1()->shouldSpeculateStringOrStringObject()
1021 && canOptimizeStringObjectAccess(node
->codeOrigin
)) {
1022 setUseKindAndUnboxIfProfitable
<StringOrStringObjectUse
>(node
->child1());
1026 if (node
->child1()->shouldSpeculateCell()) {
1027 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
1032 template<UseKind leftUseKind
>
1033 bool attemptToMakeFastStringAdd(Node
* node
, Edge
& left
, Edge
& right
)
1035 Node
* originalLeft
= left
.node();
1036 Node
* originalRight
= right
.node();
1038 ASSERT(leftUseKind
== StringUse
|| leftUseKind
== StringObjectUse
|| leftUseKind
== StringOrStringObjectUse
);
1040 if (isStringObjectUse
<leftUseKind
>() && !canOptimizeStringObjectAccess(node
->codeOrigin
))
1043 convertStringAddUse
<leftUseKind
>(node
, left
);
1045 if (right
->shouldSpeculateString())
1046 convertStringAddUse
<StringUse
>(node
, right
);
1047 else if (right
->shouldSpeculateStringObject() && canOptimizeStringObjectAccess(node
->codeOrigin
))
1048 convertStringAddUse
<StringObjectUse
>(node
, right
);
1049 else if (right
->shouldSpeculateStringOrStringObject() && canOptimizeStringObjectAccess(node
->codeOrigin
))
1050 convertStringAddUse
<StringOrStringObjectUse
>(node
, right
);
1052 // At this point we know that the other operand is something weird. The semantically correct
1053 // way of dealing with this is:
1055 // MakeRope(@left, ToString(ToPrimitive(@right)))
1057 // So that's what we emit. NB, we need to do all relevant type checks on @left before we do
1058 // anything to @right, since ToPrimitive may be effectful.
1060 Node
* toPrimitive
= m_insertionSet
.insertNode(
1061 m_indexInBlock
, resultOfToPrimitive(right
->prediction()), ToPrimitive
, node
->codeOrigin
,
1062 Edge(right
.node()));
1063 Node
* toString
= m_insertionSet
.insertNode(
1064 m_indexInBlock
, SpecString
, ToString
, node
->codeOrigin
, Edge(toPrimitive
));
1066 fixupToPrimitive(toPrimitive
);
1067 fixupToString(toString
);
1069 right
.setNode(toString
);
1072 // We're doing checks up there, so we need to make sure that the
1073 // *original* inputs to the addition are live up to here.
1074 m_insertionSet
.insertNode(
1075 m_indexInBlock
, SpecNone
, Phantom
, node
->codeOrigin
,
1076 Edge(originalLeft
), Edge(originalRight
));
1078 convertToMakeRope(node
);
1082 bool isStringPrototypeMethodSane(Structure
* stringPrototypeStructure
, const Identifier
& ident
)
1084 unsigned attributesUnused
;
1085 JSCell
* specificValue
;
1086 PropertyOffset offset
= stringPrototypeStructure
->get(
1087 vm(), ident
, attributesUnused
, specificValue
);
1088 if (!isValidOffset(offset
))
1094 if (!specificValue
->inherits(&JSFunction::s_info
))
1097 JSFunction
* function
= jsCast
<JSFunction
*>(specificValue
);
1098 if (function
->executable()->intrinsicFor(CodeForCall
) != StringPrototypeValueOfIntrinsic
)
1104 bool canOptimizeStringObjectAccess(const CodeOrigin
& codeOrigin
)
1106 if (m_graph
.hasExitSite(codeOrigin
, NotStringObject
))
1109 Structure
* stringObjectStructure
= m_graph
.globalObjectFor(codeOrigin
)->stringObjectStructure();
1110 ASSERT(stringObjectStructure
->storedPrototype().isObject());
1111 ASSERT(stringObjectStructure
->storedPrototype().asCell()->classInfo() == &StringPrototype::s_info
);
1113 JSObject
* stringPrototypeObject
= asObject(stringObjectStructure
->storedPrototype());
1114 Structure
* stringPrototypeStructure
= stringPrototypeObject
->structure();
1115 if (stringPrototypeStructure
->transitionWatchpointSetHasBeenInvalidated())
1118 if (stringPrototypeStructure
->isDictionary())
1121 // We're being conservative here. We want DFG's ToString on StringObject to be
1122 // used in both numeric contexts (that would call valueOf()) and string contexts
1123 // (that would call toString()). We don't want the DFG to have to distinguish
1124 // between the two, just because that seems like it would get confusing. So we
1125 // just require both methods to be sane.
1126 if (!isStringPrototypeMethodSane(stringPrototypeStructure
, vm().propertyNames
->valueOf
))
1128 if (!isStringPrototypeMethodSane(stringPrototypeStructure
, vm().propertyNames
->toString
))
1134 void fixupSetLocalsInBlock(BasicBlock
* block
)
1138 ASSERT(block
->isReachable
);
1140 for (m_indexInBlock
= 0; m_indexInBlock
< block
->size(); ++m_indexInBlock
) {
1141 Node
* node
= m_currentNode
= block
->at(m_indexInBlock
);
1142 if (node
->op() != SetLocal
)
1145 VariableAccessData
* variable
= node
->variableAccessData();
1147 if (!variable
->shouldUnboxIfPossible())
1150 if (variable
->shouldUseDoubleFormat()) {
1151 fixDoubleEdge
<NumberUse
>(node
->child1(), ForwardSpeculation
);
1155 SpeculatedType predictedType
= variable
->argumentAwarePrediction();
1156 if (isInt32Speculation(predictedType
))
1157 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
1158 else if (isCellSpeculation(predictedType
))
1159 setUseKindAndUnboxIfProfitable
<CellUse
>(node
->child1());
1160 else if (isBooleanSpeculation(predictedType
))
1161 setUseKindAndUnboxIfProfitable
<BooleanUse
>(node
->child1());
1163 m_insertionSet
.execute(block
);
1166 void findAndRemoveUnnecessaryStructureCheck(Node
* array
, const CodeOrigin
& codeOrigin
)
1168 for (unsigned index
= m_indexInBlock
; index
--;) {
1169 Node
* previousNode
= m_block
->at(index
);
1170 if (previousNode
->codeOrigin
!= codeOrigin
)
1173 if (previousNode
->op() != CheckStructure
)
1176 if (previousNode
->child1() != array
)
1179 previousNode
->child1() = Edge();
1180 previousNode
->convertToPhantom();
1181 return; // Assume we were smart enough to only insert one CheckStructure on the array.
1185 Node
* checkArray(ArrayMode arrayMode
, const CodeOrigin
& codeOrigin
, Node
* array
, Node
* index
, bool (*storageCheck
)(const ArrayMode
&) = canCSEStorage
)
1187 ASSERT(arrayMode
.isSpecific());
1189 Structure
* structure
= arrayMode
.originalArrayStructure(m_graph
, codeOrigin
);
1191 Edge indexEdge
= index
? Edge(index
, Int32Use
) : Edge();
1193 if (arrayMode
.doesConversion()) {
1195 if (m_indexInBlock
> 0) {
1196 // If the previous node was a CheckStructure inserted because of stuff
1197 // that the array profile told us, then remove it, since we're going to be
1198 // doing arrayification instead.
1199 findAndRemoveUnnecessaryStructureCheck(array
, codeOrigin
);
1202 m_insertionSet
.insertNode(
1203 m_indexInBlock
, SpecNone
, ArrayifyToStructure
, codeOrigin
,
1204 OpInfo(structure
), OpInfo(arrayMode
.asWord()), Edge(array
, CellUse
), indexEdge
);
1206 m_insertionSet
.insertNode(
1207 m_indexInBlock
, SpecNone
, Arrayify
, codeOrigin
,
1208 OpInfo(arrayMode
.asWord()), Edge(array
, CellUse
), indexEdge
);
1212 m_insertionSet
.insertNode(
1213 m_indexInBlock
, SpecNone
, CheckStructure
, codeOrigin
,
1214 OpInfo(m_graph
.addStructureSet(structure
)), Edge(array
, CellUse
));
1216 m_insertionSet
.insertNode(
1217 m_indexInBlock
, SpecNone
, CheckArray
, codeOrigin
,
1218 OpInfo(arrayMode
.asWord()), Edge(array
, CellUse
));
1222 if (!storageCheck(arrayMode
))
1225 if (arrayMode
.usesButterfly()) {
1226 return m_insertionSet
.insertNode(
1227 m_indexInBlock
, SpecNone
, GetButterfly
, codeOrigin
, Edge(array
, KnownCellUse
));
1230 return m_insertionSet
.insertNode(
1231 m_indexInBlock
, SpecNone
, GetIndexedPropertyStorage
, codeOrigin
,
1232 OpInfo(arrayMode
.asWord()), Edge(array
, KnownCellUse
));
1235 void blessArrayOperation(Edge base
, Edge index
, Edge
& storageChild
)
1237 Node
* node
= m_currentNode
;
1239 switch (node
->arrayMode().type()) {
1240 case Array::ForceExit
: {
1241 m_insertionSet
.insertNode(
1242 m_indexInBlock
, SpecNone
, ForceOSRExit
, node
->codeOrigin
);
1246 case Array::SelectUsingPredictions
:
1247 case Array::Unprofiled
:
1248 RELEASE_ASSERT_NOT_REACHED();
1251 case Array::Generic
:
1252 findAndRemoveUnnecessaryStructureCheck(base
.node(), node
->codeOrigin
);
1256 Node
* storage
= checkArray(node
->arrayMode(), node
->codeOrigin
, base
.node(), index
.node());
1260 storageChild
= Edge(storage
);
1265 bool alwaysUnboxSimplePrimitives()
1270 // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
1276 template<UseKind useKind
>
1277 void observeUseKindOnNode(Node
* node
)
1279 observeUseKindOnNode(node
, useKind
);
1282 void observeUseKindOnEdge(Edge edge
)
1284 observeUseKindOnNode(edge
.node(), edge
.useKind());
1287 void observeUseKindOnNode(Node
* node
, UseKind useKind
)
1289 if (node
->op() != GetLocal
)
1292 VariableAccessData
* variable
= node
->variableAccessData();
1295 if (alwaysUnboxSimplePrimitives()
1296 || isInt32Speculation(variable
->prediction()))
1297 m_profitabilityChanged
|= variable
->mergeIsProfitableToUnbox(true);
1301 if (variable
->doubleFormatState() == UsingDoubleFormat
)
1302 m_profitabilityChanged
|= variable
->mergeIsProfitableToUnbox(true);
1305 if (alwaysUnboxSimplePrimitives()
1306 || isBooleanSpeculation(variable
->prediction()))
1307 m_profitabilityChanged
|= variable
->mergeIsProfitableToUnbox(true);
1312 case KnownStringUse
:
1313 case StringObjectUse
:
1314 case StringOrStringObjectUse
:
1315 if (alwaysUnboxSimplePrimitives()
1316 || isCellSpeculation(variable
->prediction()))
1317 m_profitabilityChanged
|= variable
->mergeIsProfitableToUnbox(true);
1324 // Set the use kind of the edge. In the future (https://bugs.webkit.org/show_bug.cgi?id=110433),
1325 // this can be used to notify the GetLocal that the variable is profitable to unbox.
1326 template<UseKind useKind
>
1327 void setUseKindAndUnboxIfProfitable(Edge
& edge
)
1329 observeUseKindOnNode
<useKind
>(edge
.node());
1330 edge
.setUseKind(useKind
);
1333 void fixIntEdge(Edge
& edge
)
1335 Node
* node
= edge
.node();
1336 if (node
->op() != ValueToInt32
) {
1337 setUseKindAndUnboxIfProfitable
<KnownInt32Use
>(edge
);
1341 Edge newEdge
= node
->child1();
1343 if (newEdge
.useKind() != Int32Use
) {
1344 edge
.setUseKind(KnownInt32Use
);
1348 ASSERT(newEdge
->shouldSpeculateInteger());
1352 template<UseKind useKind
>
1353 void fixDoubleEdge(Edge
& edge
, SpeculationDirection direction
= BackwardSpeculation
)
1355 ASSERT(useKind
== NumberUse
|| useKind
== KnownNumberUse
|| useKind
== RealNumberUse
);
1357 if (edge
->prediction() & SpecDouble
) {
1358 setUseKindAndUnboxIfProfitable
<useKind
>(edge
);
1362 injectInt32ToDoubleNode(edge
, useKind
, direction
);
1365 void injectInt32ToDoubleNode(Edge
& edge
, UseKind useKind
= NumberUse
, SpeculationDirection direction
= BackwardSpeculation
)
1367 Node
* result
= m_insertionSet
.insertNode(
1368 m_indexInBlock
, SpecDouble
,
1369 direction
== BackwardSpeculation
? Int32ToDouble
: ForwardInt32ToDouble
,
1370 m_currentNode
->codeOrigin
, Edge(edge
.node(), NumberUse
));
1372 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1374 "(replacing @%u->@%u with @%u->@%u) ",
1375 m_currentNode
->index(), edge
->index(), m_currentNode
->index(), result
->index());
1378 edge
= Edge(result
, useKind
);
1381 void truncateConstantToInt32(Edge
& edge
)
1383 Node
* oldNode
= edge
.node();
1385 ASSERT(oldNode
->hasConstant());
1386 JSValue value
= m_graph
.valueOfJSConstant(oldNode
);
1387 if (value
.isInt32())
1390 value
= jsNumber(JSC::toInt32(value
.asNumber()));
1391 ASSERT(value
.isInt32());
1392 edge
.setNode(m_insertionSet
.insertNode(
1393 m_indexInBlock
, SpecInt32
, JSConstant
, m_currentNode
->codeOrigin
,
1394 OpInfo(codeBlock()->addOrFindConstant(value
))));
1397 void truncateConstantsIfNecessary(Node
* node
, AddSpeculationMode mode
)
1399 if (mode
!= SpeculateIntegerAndTruncateConstants
)
1402 ASSERT(node
->child1()->hasConstant() || node
->child2()->hasConstant());
1403 if (node
->child1()->hasConstant())
1404 truncateConstantToInt32(node
->child1());
1406 truncateConstantToInt32(node
->child2());
1409 bool attemptToMakeIntegerAdd(Node
* node
)
1411 AddSpeculationMode mode
= m_graph
.addSpeculationMode(node
);
1412 if (mode
== DontSpeculateInteger
)
1415 truncateConstantsIfNecessary(node
, mode
);
1416 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child1());
1417 setUseKindAndUnboxIfProfitable
<Int32Use
>(node
->child2());
1421 BasicBlock
* m_block
;
1422 unsigned m_indexInBlock
;
1423 Node
* m_currentNode
;
1424 InsertionSet m_insertionSet
;
1425 bool m_profitabilityChanged
;
1428 bool performFixup(Graph
& graph
)
1430 SamplingRegion
samplingRegion("DFG Fixup Phase");
1431 return runPhase
<FixupPhase
>(graph
);
1434 } } // namespace JSC::DFG
1436 #endif // ENABLE(DFG_JIT)