2 * Copyright (C) 2011, 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 "DFGAbstractState.h"
31 #include "CodeBlock.h"
32 #include "DFGBasicBlock.h"
33 #include "GetByIdStatus.h"
34 #include "Operations.h"
35 #include "PutByIdStatus.h"
36 #include "StringObject.h"
38 namespace JSC
{ namespace DFG
{
40 AbstractState::AbstractState(Graph
& graph
)
41 : m_codeBlock(graph
.m_codeBlock
)
43 , m_variables(m_codeBlock
->numParameters(), graph
.m_localVars
)
48 AbstractState::~AbstractState() { }
50 void AbstractState::beginBasicBlock(BasicBlock
* basicBlock
)
54 ASSERT(basicBlock
->variablesAtHead
.numberOfLocals() == basicBlock
->valuesAtHead
.numberOfLocals());
55 ASSERT(basicBlock
->variablesAtTail
.numberOfLocals() == basicBlock
->valuesAtTail
.numberOfLocals());
56 ASSERT(basicBlock
->variablesAtHead
.numberOfLocals() == basicBlock
->variablesAtTail
.numberOfLocals());
58 for (size_t i
= 0; i
< basicBlock
->size(); i
++)
59 forNode(basicBlock
->at(i
)).clear();
61 m_variables
= basicBlock
->valuesAtHead
;
62 m_haveStructures
= false;
63 for (size_t i
= 0; i
< m_variables
.numberOfArguments(); ++i
) {
64 if (m_variables
.argument(i
).m_currentKnownStructure
.isNeitherClearNorTop()) {
65 m_haveStructures
= true;
69 for (size_t i
= 0; i
< m_variables
.numberOfLocals(); ++i
) {
70 if (m_variables
.local(i
).m_currentKnownStructure
.isNeitherClearNorTop()) {
71 m_haveStructures
= true;
76 basicBlock
->cfaShouldRevisit
= false;
77 basicBlock
->cfaHasVisited
= true;
80 m_foundConstants
= false;
81 m_branchDirection
= InvalidBranchDirection
;
84 void AbstractState::initialize(Graph
& graph
)
86 BasicBlock
* root
= graph
.m_blocks
[0].get();
87 root
->cfaShouldRevisit
= true;
88 root
->cfaHasVisited
= false;
89 root
->cfaFoundConstants
= false;
90 for (size_t i
= 0; i
< root
->valuesAtHead
.numberOfArguments(); ++i
) {
91 Node
* node
= root
->variablesAtHead
.argument(i
);
92 ASSERT(node
->op() == SetArgument
);
93 if (!node
->variableAccessData()->shouldUnboxIfPossible()) {
94 root
->valuesAtHead
.argument(i
).makeTop();
98 SpeculatedType prediction
= node
->variableAccessData()->prediction();
99 if (isInt32Speculation(prediction
))
100 root
->valuesAtHead
.argument(i
).set(SpecInt32
);
101 else if (isBooleanSpeculation(prediction
))
102 root
->valuesAtHead
.argument(i
).set(SpecBoolean
);
103 else if (isCellSpeculation(prediction
))
104 root
->valuesAtHead
.argument(i
).set(SpecCell
);
106 root
->valuesAtHead
.argument(i
).makeTop();
108 root
->valuesAtTail
.argument(i
).clear();
110 for (size_t i
= 0; i
< root
->valuesAtHead
.numberOfLocals(); ++i
) {
111 Node
* node
= root
->variablesAtHead
.local(i
);
112 if (node
&& node
->variableAccessData()->isCaptured())
113 root
->valuesAtHead
.local(i
).makeTop();
115 root
->valuesAtHead
.local(i
).clear();
116 root
->valuesAtTail
.local(i
).clear();
118 for (BlockIndex blockIndex
= 1 ; blockIndex
< graph
.m_blocks
.size(); ++blockIndex
) {
119 BasicBlock
* block
= graph
.m_blocks
[blockIndex
].get();
122 if (!block
->isReachable
)
124 block
->cfaShouldRevisit
= false;
125 block
->cfaHasVisited
= false;
126 block
->cfaFoundConstants
= false;
127 for (size_t i
= 0; i
< block
->valuesAtHead
.numberOfArguments(); ++i
) {
128 block
->valuesAtHead
.argument(i
).clear();
129 block
->valuesAtTail
.argument(i
).clear();
131 for (size_t i
= 0; i
< block
->valuesAtHead
.numberOfLocals(); ++i
) {
132 block
->valuesAtHead
.local(i
).clear();
133 block
->valuesAtTail
.local(i
).clear();
135 if (!block
->isOSRTarget
)
137 if (block
->bytecodeBegin
!= graph
.m_osrEntryBytecodeIndex
)
139 for (size_t i
= 0; i
< graph
.m_mustHandleValues
.size(); ++i
) {
141 value
.setMostSpecific(graph
.m_mustHandleValues
[i
]);
142 int operand
= graph
.m_mustHandleValues
.operandForIndex(i
);
143 block
->valuesAtHead
.operand(operand
).merge(value
);
144 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
145 dataLogF(" Initializing Block #%u, operand r%d, to ", blockIndex
, operand
);
146 block
->valuesAtHead
.operand(operand
).dump(WTF::dataFile());
150 block
->cfaShouldRevisit
= true;
154 bool AbstractState::endBasicBlock(MergeMode mergeMode
)
158 BasicBlock
* block
= m_block
; // Save the block for successor merging.
160 block
->cfaFoundConstants
= m_foundConstants
;
161 block
->cfaDidFinish
= m_isValid
;
162 block
->cfaBranchDirection
= m_branchDirection
;
169 bool changed
= false;
171 if (mergeMode
!= DontMerge
|| !ASSERT_DISABLED
) {
172 for (size_t argument
= 0; argument
< block
->variablesAtTail
.numberOfArguments(); ++argument
) {
173 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
174 dataLogF(" Merging state for argument %zu.\n", argument
);
176 AbstractValue
& destination
= block
->valuesAtTail
.argument(argument
);
177 changed
|= mergeStateAtTail(destination
, m_variables
.argument(argument
), block
->variablesAtTail
.argument(argument
));
180 for (size_t local
= 0; local
< block
->variablesAtTail
.numberOfLocals(); ++local
) {
181 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
182 dataLogF(" Merging state for local %zu.\n", local
);
184 AbstractValue
& destination
= block
->valuesAtTail
.local(local
);
185 changed
|= mergeStateAtTail(destination
, m_variables
.local(local
), block
->variablesAtTail
.local(local
));
189 ASSERT(mergeMode
!= DontMerge
|| !changed
);
191 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
192 dataLogF(" Branch direction = %s\n", branchDirectionToString(m_branchDirection
));
197 if (mergeMode
!= MergeToSuccessors
)
200 return mergeToSuccessors(m_graph
, block
);
203 void AbstractState::reset()
207 m_branchDirection
= InvalidBranchDirection
;
210 AbstractState::BooleanResult
AbstractState::booleanResult(Node
* node
, AbstractValue
& value
)
212 JSValue childConst
= value
.value();
214 if (childConst
.toBoolean(m_codeBlock
->globalObjectFor(node
->codeOrigin
)->globalExec()))
215 return DefinitelyTrue
;
216 return DefinitelyFalse
;
219 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
220 if (isCellSpeculation(value
.m_type
)
221 && value
.m_currentKnownStructure
.hasSingleton()) {
222 Structure
* structure
= value
.m_currentKnownStructure
.singleton();
223 if (!structure
->masqueradesAsUndefined(m_codeBlock
->globalObjectFor(node
->codeOrigin
))
224 && structure
->typeInfo().type() != StringType
)
225 return DefinitelyTrue
;
228 return UnknownBooleanResult
;
231 bool AbstractState::startExecuting(Node
* node
)
236 m_didClobber
= false;
238 node
->setCanExit(false);
240 if (!node
->shouldGenerate())
246 bool AbstractState::startExecuting(unsigned indexInBlock
)
248 return startExecuting(m_block
->at(indexInBlock
));
251 void AbstractState::executeEdges(Node
* node
)
253 DFG_NODE_DO_TO_CHILDREN(m_graph
, node
, filterEdgeByUse
);
256 void AbstractState::executeEdges(unsigned indexInBlock
)
258 executeEdges(m_block
->at(indexInBlock
));
261 void AbstractState::verifyEdge(Node
*, Edge edge
)
263 RELEASE_ASSERT(!(forNode(edge
).m_type
& ~typeFilterFor(edge
.useKind())));
266 void AbstractState::verifyEdges(Node
* node
)
268 DFG_NODE_DO_TO_CHILDREN(m_graph
, node
, verifyEdge
);
271 bool AbstractState::executeEffects(unsigned indexInBlock
, Node
* node
)
273 if (!ASSERT_DISABLED
)
276 switch (node
->op()) {
279 case PhantomArguments
: {
280 forNode(node
).set(m_graph
.valueOfJSConstant(node
));
285 forNode(node
) = forNode(node
->child1());
290 VariableAccessData
* variableAccessData
= node
->variableAccessData();
291 if (variableAccessData
->prediction() == SpecNone
) {
295 AbstractValue value
= m_variables
.operand(variableAccessData
->local());
296 if (!variableAccessData
->isCaptured()) {
298 node
->setCanExit(true);
301 m_foundConstants
= true;
302 forNode(node
) = value
;
306 case GetLocalUnlinked
: {
307 AbstractValue value
= m_variables
.operand(node
->unlinkedLocal());
309 m_foundConstants
= true;
310 forNode(node
) = value
;
315 m_variables
.operand(node
->local()) = forNode(node
->child1());
319 case MovHintAndCheck
: {
320 // Don't need to do anything. A MovHint is effectively a promise that the SetLocal
327 RELEASE_ASSERT_NOT_REACHED();
332 // Assert that the state of arguments has been set.
333 ASSERT(!m_block
->valuesAtHead
.operand(node
->local()).isClear());
342 JSValue left
= forNode(node
->child1()).value();
343 JSValue right
= forNode(node
->child2()).value();
344 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
345 int32_t a
= left
.asInt32();
346 int32_t b
= right
.asInt32();
348 switch (node
->op()) {
350 constantWasSet
= trySetConstant(node
, JSValue(a
& b
));
353 constantWasSet
= trySetConstant(node
, JSValue(a
| b
));
356 constantWasSet
= trySetConstant(node
, JSValue(a
^ b
));
359 constantWasSet
= trySetConstant(node
, JSValue(a
>> static_cast<uint32_t>(b
)));
362 constantWasSet
= trySetConstant(node
, JSValue(a
<< static_cast<uint32_t>(b
)));
365 constantWasSet
= trySetConstant(node
, JSValue(static_cast<uint32_t>(a
) >> static_cast<uint32_t>(b
)));
368 RELEASE_ASSERT_NOT_REACHED();
369 constantWasSet
= false;
371 if (constantWasSet
) {
372 m_foundConstants
= true;
376 forNode(node
).set(SpecInt32
);
380 case UInt32ToNumber
: {
381 JSValue child
= forNode(node
->child1()).value();
382 if (child
&& child
.isNumber()) {
383 ASSERT(child
.isInt32());
384 if (trySetConstant(node
, JSValue(child
.asUInt32()))) {
385 m_foundConstants
= true;
389 if (!node
->canSpeculateInteger())
390 forNode(node
).set(SpecDouble
);
392 forNode(node
).set(SpecInt32
);
393 node
->setCanExit(true);
398 case DoubleAsInt32
: {
399 JSValue child
= forNode(node
->child1()).value();
400 if (child
&& child
.isNumber()) {
401 double asDouble
= child
.asNumber();
402 int32_t asInt
= JSC::toInt32(asDouble
);
403 if (bitwise_cast
<int64_t>(static_cast<double>(asInt
)) == bitwise_cast
<int64_t>(asDouble
)
404 && trySetConstant(node
, JSValue(asInt
))) {
405 m_foundConstants
= true;
409 node
->setCanExit(true);
410 forNode(node
).set(SpecInt32
);
415 JSValue child
= forNode(node
->child1()).value();
416 if (child
&& child
.isNumber()) {
419 constantWasSet
= trySetConstant(node
, child
);
421 constantWasSet
= trySetConstant(node
, JSValue(JSC::toInt32(child
.asDouble())));
422 if (constantWasSet
) {
423 m_foundConstants
= true;
428 forNode(node
).set(SpecInt32
);
433 case ForwardInt32ToDouble
: {
434 JSValue child
= forNode(node
->child1()).value();
435 if (child
&& child
.isNumber()
436 && trySetConstant(node
, JSValue(JSValue::EncodeAsDouble
, child
.asNumber()))) {
437 m_foundConstants
= true;
440 if (isInt32Speculation(forNode(node
->child1()).m_type
))
441 forNode(node
).set(SpecDoubleReal
);
443 forNode(node
).set(SpecDouble
);
449 JSValue left
= forNode(node
->child1()).value();
450 JSValue right
= forNode(node
->child2()).value();
451 if (left
&& right
&& left
.isNumber() && right
.isNumber()
452 && trySetConstant(node
, JSValue(left
.asNumber() + right
.asNumber()))) {
453 m_foundConstants
= true;
456 switch (node
->binaryUseKind()) {
458 forNode(node
).set(SpecInt32
);
459 if (!nodeCanTruncateInteger(node
->arithNodeFlags()))
460 node
->setCanExit(true);
463 if (isRealNumberSpeculation(forNode(node
->child1()).m_type
)
464 && isRealNumberSpeculation(forNode(node
->child2()).m_type
))
465 forNode(node
).set(SpecDoubleReal
);
467 forNode(node
).set(SpecDouble
);
470 RELEASE_ASSERT(node
->op() == ValueAdd
);
471 clobberWorld(node
->codeOrigin
, indexInBlock
);
472 forNode(node
).set(SpecString
| SpecInt32
| SpecNumber
);
479 forNode(node
).set(m_graph
.m_vm
.stringStructure
.get());
484 JSValue left
= forNode(node
->child1()).value();
485 JSValue right
= forNode(node
->child2()).value();
486 if (left
&& right
&& left
.isNumber() && right
.isNumber()
487 && trySetConstant(node
, JSValue(left
.asNumber() - right
.asNumber()))) {
488 m_foundConstants
= true;
491 switch (node
->binaryUseKind()) {
493 forNode(node
).set(SpecInt32
);
494 if (!nodeCanTruncateInteger(node
->arithNodeFlags()))
495 node
->setCanExit(true);
498 forNode(node
).set(SpecDouble
);
501 RELEASE_ASSERT_NOT_REACHED();
508 JSValue child
= forNode(node
->child1()).value();
509 if (child
&& child
.isNumber()
510 && trySetConstant(node
, JSValue(-child
.asNumber()))) {
511 m_foundConstants
= true;
514 switch (node
->child1().useKind()) {
516 forNode(node
).set(SpecInt32
);
517 if (!nodeCanTruncateInteger(node
->arithNodeFlags()))
518 node
->setCanExit(true);
521 forNode(node
).set(SpecDouble
);
524 RELEASE_ASSERT_NOT_REACHED();
531 JSValue left
= forNode(node
->child1()).value();
532 JSValue right
= forNode(node
->child2()).value();
533 if (left
&& right
&& left
.isNumber() && right
.isNumber()
534 && trySetConstant(node
, JSValue(left
.asNumber() * right
.asNumber()))) {
535 m_foundConstants
= true;
538 switch (node
->binaryUseKind()) {
540 forNode(node
).set(SpecInt32
);
541 if (!nodeCanTruncateInteger(node
->arithNodeFlags())
542 || !nodeCanIgnoreNegativeZero(node
->arithNodeFlags()))
543 node
->setCanExit(true);
546 if (isRealNumberSpeculation(forNode(node
->child1()).m_type
)
547 || isRealNumberSpeculation(forNode(node
->child2()).m_type
))
548 forNode(node
).set(SpecDoubleReal
);
550 forNode(node
).set(SpecDouble
);
553 RELEASE_ASSERT_NOT_REACHED();
560 forNode(node
).set(SpecInt32
);
568 JSValue left
= forNode(node
->child1()).value();
569 JSValue right
= forNode(node
->child2()).value();
570 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
571 double a
= left
.asNumber();
572 double b
= right
.asNumber();
574 switch (node
->op()) {
576 constantWasSet
= trySetConstant(node
, JSValue(a
/ b
));
579 constantWasSet
= trySetConstant(node
, JSValue(a
< b
? a
: (b
<= a
? b
: a
+ b
)));
582 constantWasSet
= trySetConstant(node
, JSValue(a
> b
? a
: (b
>= a
? b
: a
+ b
)));
585 constantWasSet
= trySetConstant(node
, JSValue(fmod(a
, b
)));
588 RELEASE_ASSERT_NOT_REACHED();
589 constantWasSet
= false;
592 if (constantWasSet
) {
593 m_foundConstants
= true;
597 switch (node
->binaryUseKind()) {
599 forNode(node
).set(SpecInt32
);
600 node
->setCanExit(true);
603 forNode(node
).set(SpecDouble
);
606 RELEASE_ASSERT_NOT_REACHED();
613 JSValue child
= forNode(node
->child1()).value();
614 if (child
&& child
.isNumber()
615 && trySetConstant(node
, JSValue(fabs(child
.asNumber())))) {
616 m_foundConstants
= true;
619 switch (node
->child1().useKind()) {
621 forNode(node
).set(SpecInt32
);
622 node
->setCanExit(true);
625 forNode(node
).set(SpecDouble
);
628 RELEASE_ASSERT_NOT_REACHED();
635 JSValue child
= forNode(node
->child1()).value();
636 if (child
&& child
.isNumber()
637 && trySetConstant(node
, JSValue(sqrt(child
.asNumber())))) {
638 m_foundConstants
= true;
641 forNode(node
).set(SpecDouble
);
646 bool didSetConstant
= false;
647 switch (booleanResult(node
, forNode(node
->child1()))) {
649 didSetConstant
= trySetConstant(node
, jsBoolean(false));
651 case DefinitelyFalse
:
652 didSetConstant
= trySetConstant(node
, jsBoolean(true));
657 if (didSetConstant
) {
658 m_foundConstants
= true;
661 switch (node
->child1().useKind()) {
667 case ObjectOrOtherUse
:
668 node
->setCanExit(true);
671 RELEASE_ASSERT_NOT_REACHED();
674 forNode(node
).set(SpecBoolean
);
684 node
->setCanExit(node
->op() == IsUndefined
&& m_codeBlock
->globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid());
685 JSValue child
= forNode(node
->child1()).value();
688 switch (node
->op()) {
690 if (m_codeBlock
->globalObjectFor(node
->codeOrigin
)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
691 constantWasSet
= trySetConstant(node
, jsBoolean(
694 : child
.isUndefined()));
696 constantWasSet
= trySetConstant(node
, jsBoolean(
698 ? child
.asCell()->structure()->masqueradesAsUndefined(m_codeBlock
->globalObjectFor(node
->codeOrigin
))
699 : child
.isUndefined()));
703 constantWasSet
= trySetConstant(node
, jsBoolean(child
.isBoolean()));
706 constantWasSet
= trySetConstant(node
, jsBoolean(child
.isNumber()));
709 constantWasSet
= trySetConstant(node
, jsBoolean(isJSString(child
)));
712 if (child
.isNull() || !child
.isObject()) {
713 constantWasSet
= trySetConstant(node
, jsBoolean(child
.isNull()));
717 constantWasSet
= false;
720 if (constantWasSet
) {
721 m_foundConstants
= true;
726 forNode(node
).set(SpecBoolean
);
731 VM
* vm
= m_codeBlock
->vm();
732 JSValue child
= forNode(node
->child1()).value();
733 AbstractValue
& abstractChild
= forNode(node
->child1());
735 JSValue typeString
= jsTypeStringForValue(*vm
, m_codeBlock
->globalObjectFor(node
->codeOrigin
), child
);
736 if (trySetConstant(node
, typeString
)) {
737 m_foundConstants
= true;
740 } else if (isNumberSpeculation(abstractChild
.m_type
)) {
741 if (trySetConstant(node
, vm
->smallStrings
.numberString())) {
742 forNode(node
->child1()).filter(SpecNumber
);
743 m_foundConstants
= true;
746 } else if (isStringSpeculation(abstractChild
.m_type
)) {
747 if (trySetConstant(node
, vm
->smallStrings
.stringString())) {
748 forNode(node
->child1()).filter(SpecString
);
749 m_foundConstants
= true;
752 } else if (isFinalObjectSpeculation(abstractChild
.m_type
) || isArraySpeculation(abstractChild
.m_type
) || isArgumentsSpeculation(abstractChild
.m_type
)) {
753 if (trySetConstant(node
, vm
->smallStrings
.objectString())) {
754 forNode(node
->child1()).filter(SpecFinalObject
| SpecArray
| SpecArguments
);
755 m_foundConstants
= true;
758 } else if (isFunctionSpeculation(abstractChild
.m_type
)) {
759 if (trySetConstant(node
, vm
->smallStrings
.functionString())) {
760 forNode(node
->child1()).filter(SpecFunction
);
761 m_foundConstants
= true;
764 } else if (isBooleanSpeculation(abstractChild
.m_type
)) {
765 if (trySetConstant(node
, vm
->smallStrings
.booleanString())) {
766 forNode(node
->child1()).filter(SpecBoolean
);
767 m_foundConstants
= true;
772 switch (node
->child1().useKind()) {
775 node
->setCanExit(true);
780 RELEASE_ASSERT_NOT_REACHED();
783 forNode(node
).set(m_graph
.m_vm
.stringStructure
.get());
790 case CompareGreaterEq
:
792 case CompareEqConstant
: {
793 bool constantWasSet
= false;
795 JSValue leftConst
= forNode(node
->child1()).value();
796 JSValue rightConst
= forNode(node
->child2()).value();
797 if (leftConst
&& rightConst
&& leftConst
.isNumber() && rightConst
.isNumber()) {
798 double a
= leftConst
.asNumber();
799 double b
= rightConst
.asNumber();
800 switch (node
->op()) {
802 constantWasSet
= trySetConstant(node
, jsBoolean(a
< b
));
805 constantWasSet
= trySetConstant(node
, jsBoolean(a
<= b
));
808 constantWasSet
= trySetConstant(node
, jsBoolean(a
> b
));
810 case CompareGreaterEq
:
811 constantWasSet
= trySetConstant(node
, jsBoolean(a
>= b
));
814 constantWasSet
= trySetConstant(node
, jsBoolean(a
== b
));
817 RELEASE_ASSERT_NOT_REACHED();
818 constantWasSet
= false;
823 if (!constantWasSet
&& (node
->op() == CompareEqConstant
|| node
->op() == CompareEq
)) {
824 SpeculatedType leftType
= forNode(node
->child1()).m_type
;
825 SpeculatedType rightType
= forNode(node
->child2()).m_type
;
826 if ((isInt32Speculation(leftType
) && isOtherSpeculation(rightType
))
827 || (isOtherSpeculation(leftType
) && isInt32Speculation(rightType
)))
828 constantWasSet
= trySetConstant(node
, jsBoolean(false));
831 if (constantWasSet
) {
832 m_foundConstants
= true;
836 forNode(node
).set(SpecBoolean
);
838 // This is overly conservative. But the only thing this prevents is store elimination,
839 // and how likely is it, really, that you'll have redundant stores across a comparison
840 // operation? Comparison operations are typically at the end of basic blocks, so
841 // unless we have global store elimination (super unlikely given how unprofitable that
842 // optimization is to begin with), you aren't going to be wanting to store eliminate
843 // across an equality op.
844 node
->setCanExit(true);
848 case CompareStrictEq
:
849 case CompareStrictEqConstant
: {
850 Node
* leftNode
= node
->child1().node();
851 Node
* rightNode
= node
->child2().node();
852 JSValue left
= forNode(leftNode
).value();
853 JSValue right
= forNode(rightNode
).value();
854 if (left
&& right
&& left
.isNumber() && right
.isNumber()
855 && trySetConstant(node
, jsBoolean(left
.asNumber() == right
.asNumber()))) {
856 m_foundConstants
= true;
859 forNode(node
).set(SpecBoolean
);
860 node
->setCanExit(true); // This is overly conservative.
864 case StringCharCodeAt
:
865 node
->setCanExit(true);
866 forNode(node
).set(SpecInt32
);
869 case StringFromCharCode
:
870 forNode(node
).set(SpecString
);
874 node
->setCanExit(true);
875 forNode(node
).set(m_graph
.m_vm
.stringStructure
.get());
879 node
->setCanExit(true);
880 switch (node
->arrayMode().type()) {
881 case Array::SelectUsingPredictions
:
882 case Array::Unprofiled
:
883 case Array::Undecided
:
884 RELEASE_ASSERT_NOT_REACHED();
886 case Array::ForceExit
:
890 clobberWorld(node
->codeOrigin
, indexInBlock
);
891 forNode(node
).makeTop();
894 forNode(node
).set(m_graph
.m_vm
.stringStructure
.get());
896 case Array::Arguments
:
897 forNode(node
).makeTop();
900 if (node
->arrayMode().isOutOfBounds()) {
901 clobberWorld(node
->codeOrigin
, indexInBlock
);
902 forNode(node
).makeTop();
904 forNode(node
).set(SpecInt32
);
907 if (node
->arrayMode().isOutOfBounds()) {
908 clobberWorld(node
->codeOrigin
, indexInBlock
);
909 forNode(node
).makeTop();
910 } else if (node
->arrayMode().isSaneChain())
911 forNode(node
).set(SpecDouble
);
913 forNode(node
).set(SpecDoubleReal
);
915 case Array::Contiguous
:
916 case Array::ArrayStorage
:
917 case Array::SlowPutArrayStorage
:
918 if (node
->arrayMode().isOutOfBounds())
919 clobberWorld(node
->codeOrigin
, indexInBlock
);
920 forNode(node
).makeTop();
922 case Array::Int8Array
:
923 forNode(node
).set(SpecInt32
);
925 case Array::Int16Array
:
926 forNode(node
).set(SpecInt32
);
928 case Array::Int32Array
:
929 forNode(node
).set(SpecInt32
);
931 case Array::Uint8Array
:
932 forNode(node
).set(SpecInt32
);
934 case Array::Uint8ClampedArray
:
935 forNode(node
).set(SpecInt32
);
937 case Array::Uint16Array
:
938 forNode(node
).set(SpecInt32
);
940 case Array::Uint32Array
:
941 if (node
->shouldSpeculateInteger())
942 forNode(node
).set(SpecInt32
);
944 forNode(node
).set(SpecDouble
);
946 case Array::Float32Array
:
947 forNode(node
).set(SpecDouble
);
949 case Array::Float64Array
:
950 forNode(node
).set(SpecDouble
);
953 RELEASE_ASSERT_NOT_REACHED();
960 case PutByValAlias
: {
961 node
->setCanExit(true);
962 switch (node
->arrayMode().modeForPut().type()) {
963 case Array::ForceExit
:
967 clobberWorld(node
->codeOrigin
, indexInBlock
);
970 if (node
->arrayMode().isOutOfBounds())
971 clobberWorld(node
->codeOrigin
, indexInBlock
);
974 if (node
->arrayMode().isOutOfBounds())
975 clobberWorld(node
->codeOrigin
, indexInBlock
);
977 case Array::Contiguous
:
978 case Array::ArrayStorage
:
979 if (node
->arrayMode().isOutOfBounds())
980 clobberWorld(node
->codeOrigin
, indexInBlock
);
982 case Array::SlowPutArrayStorage
:
983 if (node
->arrayMode().mayStoreToHole())
984 clobberWorld(node
->codeOrigin
, indexInBlock
);
993 node
->setCanExit(true);
994 clobberWorld(node
->codeOrigin
, indexInBlock
);
995 forNode(node
).set(SpecNumber
);
999 node
->setCanExit(true);
1000 clobberWorld(node
->codeOrigin
, indexInBlock
);
1001 forNode(node
).makeTop();
1005 forNode(node
).makeTop();
1009 forNode(node
).set(SpecBoolean
);
1016 Node
* child
= node
->child1().node();
1017 BooleanResult result
= booleanResult(node
, forNode(child
));
1018 if (result
== DefinitelyTrue
) {
1019 m_branchDirection
= TakeTrue
;
1022 if (result
== DefinitelyFalse
) {
1023 m_branchDirection
= TakeFalse
;
1026 // FIXME: The above handles the trivial cases of sparse conditional
1027 // constant propagation, but we can do better:
1028 // We can specialize the source variable's value on each direction of
1030 node
->setCanExit(true); // This is overly conservative.
1031 m_branchDirection
= TakeBoth
;
1040 case ThrowReferenceError
:
1042 node
->setCanExit(true);
1046 JSValue childConst
= forNode(node
->child1()).value();
1047 if (childConst
&& childConst
.isNumber() && trySetConstant(node
, childConst
)) {
1048 m_foundConstants
= true;
1052 ASSERT(node
->child1().useKind() == UntypedUse
);
1054 AbstractValue
& source
= forNode(node
->child1());
1055 AbstractValue
& destination
= forNode(node
);
1057 // NB. The more canonical way of writing this would have been:
1059 // destination = source;
1060 // if (destination.m_type & !(SpecNumber | SpecString | SpecBoolean)) {
1061 // destination.filter(SpecNumber | SpecString | SpecBoolean);
1062 // AbstractValue string;
1063 // string.set(vm->stringStructure);
1064 // destination.merge(string);
1067 // The reason why this would, in most other cases, have been better is that
1068 // then destination would preserve any non-SpeculatedType knowledge of source.
1069 // As it stands, the code below forgets any non-SpeculatedType knowledge that
1070 // source would have had. Fortunately, though, for things like strings and
1071 // numbers and booleans, we don't care about the non-SpeculatedType knowedge:
1072 // the structure won't tell us anything we don't already know, and neither
1073 // will ArrayModes. And if the source was a meaningful constant then we
1074 // would have handled that above. Unfortunately, this does mean that
1075 // ToPrimitive will currently forget string constants. But that's not a big
1076 // deal since we don't do any optimization on those currently.
1078 clobberWorld(node
->codeOrigin
, indexInBlock
);
1080 SpeculatedType type
= source
.m_type
;
1081 if (type
& ~(SpecNumber
| SpecString
| SpecBoolean
))
1082 type
= (SpecTop
& ~SpecCell
) | SpecString
;
1084 destination
.set(type
);
1089 switch (node
->child1().useKind()) {
1090 case StringObjectUse
:
1091 // This also filters that the StringObject has the primordial StringObject
1093 forNode(node
->child1()).filter(m_graph
.globalObjectFor(node
->codeOrigin
)->stringObjectStructure());
1094 node
->setCanExit(true); // We could be more precise but it's likely not worth it.
1096 case StringOrStringObjectUse
:
1097 node
->setCanExit(true); // We could be more precise but it's likely not worth it.
1101 clobberWorld(node
->codeOrigin
, indexInBlock
);
1104 RELEASE_ASSERT_NOT_REACHED();
1107 forNode(node
).set(m_graph
.m_vm
.stringStructure
.get());
1111 case NewStringObject
: {
1112 ASSERT(node
->structure()->classInfo() == &StringObject::s_info
);
1113 forNode(node
).set(node
->structure());
1118 node
->setCanExit(true);
1119 forNode(node
).set(m_graph
.globalObjectFor(node
->codeOrigin
)->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()));
1120 m_haveStructures
= true;
1123 case NewArrayBuffer
:
1124 node
->setCanExit(true);
1125 forNode(node
).set(m_graph
.globalObjectFor(node
->codeOrigin
)->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()));
1126 m_haveStructures
= true;
1129 case NewArrayWithSize
:
1130 node
->setCanExit(true);
1131 forNode(node
).set(SpecArray
);
1132 m_haveStructures
= true;
1136 forNode(node
).set(m_graph
.globalObjectFor(node
->codeOrigin
)->regExpStructure());
1137 m_haveStructures
= true;
1141 AbstractValue
& source
= forNode(node
->child1());
1142 AbstractValue
& destination
= forNode(node
);
1144 destination
= source
;
1145 destination
.merge(SpecObjectOther
);
1150 forNode(node
).set(SpecFinalObject
);
1154 case AllocationProfileWatchpoint
:
1155 node
->setCanExit(true);
1159 forNode(node
).set(node
->structure());
1160 m_haveStructures
= true;
1163 case CreateActivation
:
1164 forNode(node
).set(m_codeBlock
->globalObjectFor(node
->codeOrigin
)->activationStructure());
1165 m_haveStructures
= true;
1168 case CreateArguments
:
1169 forNode(node
).set(m_codeBlock
->globalObjectFor(node
->codeOrigin
)->argumentsStructure());
1170 m_haveStructures
= true;
1173 case TearOffActivation
:
1174 case TearOffArguments
:
1175 // Does nothing that is user-visible.
1178 case CheckArgumentsNotCreated
:
1179 if (isEmptySpeculation(
1180 m_variables
.operand(
1181 m_graph
.argumentsRegisterFor(node
->codeOrigin
)).m_type
))
1182 m_foundConstants
= true;
1184 node
->setCanExit(true);
1187 case GetMyArgumentsLength
:
1188 // We know that this executable does not escape its arguments, so we can optimize
1189 // the arguments a bit. Note that this is not sufficient to force constant folding
1190 // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
1191 // We perform further optimizations on this later on.
1192 if (node
->codeOrigin
.inlineCallFrame
)
1193 forNode(node
).set(jsNumber(node
->codeOrigin
.inlineCallFrame
->arguments
.size() - 1));
1195 forNode(node
).set(SpecInt32
);
1197 !isEmptySpeculation(
1198 m_variables
.operand(
1199 m_graph
.argumentsRegisterFor(node
->codeOrigin
)).m_type
));
1202 case GetMyArgumentsLengthSafe
:
1203 // This potentially clobbers all structures if the arguments object had a getter
1204 // installed on the length property.
1205 clobberWorld(node
->codeOrigin
, indexInBlock
);
1206 // We currently make no guarantee about what this returns because it does not
1207 // speculate that the length property is actually a length.
1208 forNode(node
).makeTop();
1211 case GetMyArgumentByVal
:
1212 node
->setCanExit(true);
1213 // We know that this executable does not escape its arguments, so we can optimize
1214 // the arguments a bit. Note that this ends up being further optimized by the
1215 // ArgumentsSimplificationPhase.
1216 forNode(node
).makeTop();
1219 case GetMyArgumentByValSafe
:
1220 node
->setCanExit(true);
1221 // This potentially clobbers all structures if the property we're accessing has
1222 // a getter. We don't speculate against this.
1223 clobberWorld(node
->codeOrigin
, indexInBlock
);
1224 // And the result is unknown.
1225 forNode(node
).makeTop();
1229 AbstractValue
& value
= forNode(node
);
1230 value
= forNode(node
->child1());
1232 if (!(value
.m_type
& SpecEmpty
)) {
1233 m_foundConstants
= true;
1237 value
.set((value
.m_type
& ~SpecEmpty
) | SpecFunction
);
1241 case NewFunctionExpression
:
1242 case NewFunctionNoCheck
:
1243 forNode(node
).set(m_codeBlock
->globalObjectFor(node
->codeOrigin
)->functionStructure());
1247 forNode(node
).set(SpecFunction
);
1254 case GetScope
: // FIXME: We could get rid of these if we know that the JSFunction is a constant. https://bugs.webkit.org/show_bug.cgi?id=106202
1257 forNode(node
).set(SpecObjectOther
);
1261 JSValue child
= forNode(node
->child1()).value();
1262 if (child
&& trySetConstant(node
, JSValue(jsCast
<JSScope
*>(child
.asCell())->next()))) {
1263 m_foundConstants
= true;
1266 forNode(node
).set(SpecObjectOther
);
1270 case GetScopeRegisters
:
1271 forNode(node
).clear(); // The result is not a JS value.
1275 forNode(node
).makeTop();
1279 clobberCapturedVars(node
->codeOrigin
);
1284 node
->setCanExit(true);
1285 if (!node
->prediction()) {
1289 if (isCellSpeculation(node
->child1()->prediction())) {
1290 if (Structure
* structure
= forNode(node
->child1()).bestProvenStructure()) {
1291 GetByIdStatus status
= GetByIdStatus::computeFor(
1292 m_graph
.m_vm
, structure
,
1293 m_graph
.m_codeBlock
->identifier(node
->identifierNumber()));
1294 if (status
.isSimple()) {
1295 // Assert things that we can't handle and that the computeFor() method
1296 // above won't be able to return.
1297 ASSERT(status
.structureSet().size() == 1);
1298 ASSERT(status
.chain().isEmpty());
1300 if (status
.specificValue())
1301 forNode(node
).set(status
.specificValue());
1303 forNode(node
).makeTop();
1304 forNode(node
->child1()).filter(status
.structureSet());
1306 m_foundConstants
= true;
1311 clobberWorld(node
->codeOrigin
, indexInBlock
);
1312 forNode(node
).makeTop();
1315 case GetArrayLength
:
1316 node
->setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
1317 forNode(node
).set(SpecInt32
);
1320 case CheckExecutable
: {
1321 // FIXME: We could track executables in AbstractValue, which would allow us to get rid of these checks
1322 // more thoroughly. https://bugs.webkit.org/show_bug.cgi?id=106200
1323 // FIXME: We could eliminate these entirely if we know the exact value that flows into this.
1324 // https://bugs.webkit.org/show_bug.cgi?id=106201
1325 node
->setCanExit(true);
1329 case CheckStructure
:
1330 case ForwardCheckStructure
: {
1331 // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
1332 AbstractValue
& value
= forNode(node
->child1());
1333 ASSERT(!(value
.m_type
& ~SpecCell
)); // Edge filtering should have already ensured this.
1334 // If this structure check is attempting to prove knowledge already held in
1335 // the futurePossibleStructure set then the constant folding phase should
1336 // turn this into a watchpoint instead.
1337 StructureSet
& set
= node
->structureSet();
1338 if (value
.m_futurePossibleStructure
.isSubsetOf(set
)
1339 || value
.m_currentKnownStructure
.isSubsetOf(set
))
1340 m_foundConstants
= true;
1341 if (!value
.m_currentKnownStructure
.isSubsetOf(set
))
1342 node
->setCanExit(true);
1344 m_haveStructures
= true;
1348 case StructureTransitionWatchpoint
:
1349 case ForwardStructureTransitionWatchpoint
: {
1350 AbstractValue
& value
= forNode(node
->child1());
1352 // It's only valid to issue a structure transition watchpoint if we already
1353 // know that the watchpoint covers a superset of the structures known to
1354 // belong to the set of future structures that this value may have.
1355 // Currently, we only issue singleton watchpoints (that check one structure)
1356 // and our futurePossibleStructure set can only contain zero, one, or an
1357 // infinity of structures.
1358 ASSERT(value
.m_futurePossibleStructure
.isSubsetOf(StructureSet(node
->structure())));
1360 value
.filter(node
->structure());
1361 m_haveStructures
= true;
1362 node
->setCanExit(true);
1367 case PhantomPutStructure
:
1368 if (!forNode(node
->child1()).m_currentKnownStructure
.isClear()) {
1369 clobberStructures(indexInBlock
);
1370 forNode(node
->child1()).set(node
->structureTransitionData().newStructure
);
1371 m_haveStructures
= true;
1375 case AllocatePropertyStorage
:
1376 case ReallocatePropertyStorage
:
1377 forNode(node
).clear(); // The result is not a JS value.
1380 if (node
->arrayMode().alreadyChecked(m_graph
, node
, forNode(node
->child1()))) {
1381 m_foundConstants
= true;
1384 node
->setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
1385 switch (node
->arrayMode().type()) {
1387 forNode(node
->child1()).filter(SpecString
);
1391 case Array::Contiguous
:
1392 case Array::ArrayStorage
:
1393 case Array::SlowPutArrayStorage
:
1395 case Array::Arguments
:
1396 forNode(node
->child1()).filter(SpecArguments
);
1398 case Array::Int8Array
:
1399 forNode(node
->child1()).filter(SpecInt8Array
);
1401 case Array::Int16Array
:
1402 forNode(node
->child1()).filter(SpecInt16Array
);
1404 case Array::Int32Array
:
1405 forNode(node
->child1()).filter(SpecInt32Array
);
1407 case Array::Uint8Array
:
1408 forNode(node
->child1()).filter(SpecUint8Array
);
1410 case Array::Uint8ClampedArray
:
1411 forNode(node
->child1()).filter(SpecUint8ClampedArray
);
1413 case Array::Uint16Array
:
1414 forNode(node
->child1()).filter(SpecUint16Array
);
1416 case Array::Uint32Array
:
1417 forNode(node
->child1()).filter(SpecUint32Array
);
1419 case Array::Float32Array
:
1420 forNode(node
->child1()).filter(SpecFloat32Array
);
1422 case Array::Float64Array
:
1423 forNode(node
->child1()).filter(SpecFloat64Array
);
1426 RELEASE_ASSERT_NOT_REACHED();
1429 forNode(node
->child1()).filterArrayModes(node
->arrayMode().arrayModesThatPassFiltering());
1430 m_haveStructures
= true;
1434 if (node
->arrayMode().alreadyChecked(m_graph
, node
, forNode(node
->child1()))) {
1435 m_foundConstants
= true;
1438 ASSERT(node
->arrayMode().conversion() == Array::Convert
1439 || node
->arrayMode().conversion() == Array::RageConvert
);
1440 node
->setCanExit(true);
1441 clobberStructures(indexInBlock
);
1442 forNode(node
->child1()).filterArrayModes(node
->arrayMode().arrayModesThatPassFiltering());
1443 m_haveStructures
= true;
1446 case ArrayifyToStructure
: {
1447 AbstractValue
& value
= forNode(node
->child1());
1448 StructureSet set
= node
->structure();
1449 if (value
.m_futurePossibleStructure
.isSubsetOf(set
)
1450 || value
.m_currentKnownStructure
.isSubsetOf(set
))
1451 m_foundConstants
= true;
1452 node
->setCanExit(true);
1453 clobberStructures(indexInBlock
);
1455 m_haveStructures
= true;
1458 case GetIndexedPropertyStorage
: {
1459 forNode(node
).clear();
1463 forNode(node
).makeTop();
1471 case CheckFunction
: {
1472 JSValue value
= forNode(node
->child1()).value();
1473 if (value
== node
->function()) {
1474 m_foundConstants
= true;
1479 node
->setCanExit(true); // Lies! We can do better.
1480 forNode(node
->child1()).filterByValue(node
->function());
1486 node
->setCanExit(true);
1487 if (Structure
* structure
= forNode(node
->child1()).bestProvenStructure()) {
1488 PutByIdStatus status
= PutByIdStatus::computeFor(
1490 m_graph
.globalObjectFor(node
->codeOrigin
),
1492 m_graph
.m_codeBlock
->identifier(node
->identifierNumber()),
1493 node
->op() == PutByIdDirect
);
1494 if (status
.isSimpleReplace()) {
1495 forNode(node
->child1()).filter(structure
);
1496 m_foundConstants
= true;
1499 if (status
.isSimpleTransition()) {
1500 clobberStructures(indexInBlock
);
1501 forNode(node
->child1()).set(status
.newStructure());
1502 m_haveStructures
= true;
1503 m_foundConstants
= true;
1507 clobberWorld(node
->codeOrigin
, indexInBlock
);
1511 forNode(node
).makeTop();
1514 case GlobalVarWatchpoint
:
1515 node
->setCanExit(true);
1519 case PutGlobalVarCheck
:
1522 case CheckHasInstance
:
1523 node
->setCanExit(true);
1524 // Sadly, we don't propagate the fact that we've done CheckHasInstance
1528 node
->setCanExit(true);
1529 // Again, sadly, we don't propagate the fact that we've done InstanceOf
1530 forNode(node
).set(SpecBoolean
);
1543 case ResolveBaseStrictPut
:
1545 node
->setCanExit(true);
1546 clobberWorld(node
->codeOrigin
, indexInBlock
);
1547 forNode(node
).makeTop();
1551 clobberWorld(node
->codeOrigin
, indexInBlock
);
1552 forNode(node
).makeTop();
1556 RELEASE_ASSERT_NOT_REACHED();
1560 node
->setCanExit(true);
1564 case CheckWatchdogTimer
:
1565 node
->setCanExit(true);
1571 case CountExecution
:
1575 RELEASE_ASSERT_NOT_REACHED();
1582 bool AbstractState::executeEffects(unsigned indexInBlock
)
1584 return executeEffects(indexInBlock
, m_block
->at(indexInBlock
));
1587 bool AbstractState::execute(unsigned indexInBlock
)
1589 Node
* node
= m_block
->at(indexInBlock
);
1590 if (!startExecuting(node
))
1594 return executeEffects(indexInBlock
, node
);
1597 inline void AbstractState::clobberWorld(const CodeOrigin
& codeOrigin
, unsigned indexInBlock
)
1599 clobberCapturedVars(codeOrigin
);
1600 clobberStructures(indexInBlock
);
1603 inline void AbstractState::clobberCapturedVars(const CodeOrigin
& codeOrigin
)
1605 if (codeOrigin
.inlineCallFrame
) {
1606 const BitVector
& capturedVars
= codeOrigin
.inlineCallFrame
->capturedVars
;
1607 for (size_t i
= capturedVars
.size(); i
--;) {
1608 if (!capturedVars
.quickGet(i
))
1610 m_variables
.local(i
).makeTop();
1613 for (size_t i
= m_codeBlock
->m_numVars
; i
--;) {
1614 if (m_codeBlock
->isCaptured(i
))
1615 m_variables
.local(i
).makeTop();
1619 for (size_t i
= m_variables
.numberOfArguments(); i
--;) {
1620 if (m_codeBlock
->isCaptured(argumentToOperand(i
)))
1621 m_variables
.argument(i
).makeTop();
1625 inline void AbstractState::clobberStructures(unsigned indexInBlock
)
1627 if (!m_haveStructures
)
1629 for (size_t i
= indexInBlock
+ 1; i
--;)
1630 forNode(m_block
->at(i
)).clobberStructures();
1631 for (size_t i
= m_variables
.numberOfArguments(); i
--;)
1632 m_variables
.argument(i
).clobberStructures();
1633 for (size_t i
= m_variables
.numberOfLocals(); i
--;)
1634 m_variables
.local(i
).clobberStructures();
1635 m_haveStructures
= false;
1636 m_didClobber
= true;
1639 inline bool AbstractState::mergeStateAtTail(AbstractValue
& destination
, AbstractValue
& inVariable
, Node
* node
)
1644 AbstractValue source
;
1646 if (node
->variableAccessData()->isCaptured()) {
1647 // If it's captured then we know that whatever value was stored into the variable last is the
1648 // one we care about. This is true even if the variable at tail is dead, which might happen if
1649 // the last thing we did to the variable was a GetLocal and then ended up now using the
1650 // GetLocal's result.
1652 source
= inVariable
;
1653 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1654 dataLogF(" Transfering ");
1655 source
.dump(WTF::dataFile());
1656 dataLogF(" from last access due to captured variable.\n");
1659 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1660 dataLogF(" It's live, node @%u.\n", node
->index());
1663 switch (node
->op()) {
1668 // The block transfers the value from head to tail.
1669 source
= inVariable
;
1670 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1671 dataLogF(" Transfering ");
1672 source
.dump(WTF::dataFile());
1673 dataLogF(" from head to tail.\n");
1678 // The block refines the value with additional speculations.
1679 source
= forNode(node
);
1680 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1681 dataLogF(" Refining to ");
1682 source
.dump(WTF::dataFile());
1688 // The block sets the variable, and potentially refines it, both
1689 // before and after setting it.
1690 if (node
->variableAccessData()->shouldUseDoubleFormat()) {
1691 // FIXME: This unnecessarily loses precision.
1692 source
.set(SpecDouble
);
1694 source
= forNode(node
->child1());
1695 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1696 dataLogF(" Setting to ");
1697 source
.dump(WTF::dataFile());
1703 RELEASE_ASSERT_NOT_REACHED();
1708 if (destination
== source
) {
1709 // Abstract execution did not change the output value of the variable, for this
1710 // basic block, on this iteration.
1711 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1712 dataLogF(" Not changed!\n");
1717 // Abstract execution reached a new conclusion about the speculations reached about
1718 // this variable after execution of this basic block. Update the state, and return
1719 // true to indicate that the fixpoint must go on!
1720 destination
= source
;
1721 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1722 dataLogF(" Changed!\n");
1727 inline bool AbstractState::merge(BasicBlock
* from
, BasicBlock
* to
)
1729 ASSERT(from
->variablesAtTail
.numberOfArguments() == to
->variablesAtHead
.numberOfArguments());
1730 ASSERT(from
->variablesAtTail
.numberOfLocals() == to
->variablesAtHead
.numberOfLocals());
1732 bool changed
= false;
1734 for (size_t argument
= 0; argument
< from
->variablesAtTail
.numberOfArguments(); ++argument
) {
1735 AbstractValue
& destination
= to
->valuesAtHead
.argument(argument
);
1736 changed
|= mergeVariableBetweenBlocks(destination
, from
->valuesAtTail
.argument(argument
), to
->variablesAtHead
.argument(argument
), from
->variablesAtTail
.argument(argument
));
1739 for (size_t local
= 0; local
< from
->variablesAtTail
.numberOfLocals(); ++local
) {
1740 AbstractValue
& destination
= to
->valuesAtHead
.local(local
);
1741 changed
|= mergeVariableBetweenBlocks(destination
, from
->valuesAtTail
.local(local
), to
->variablesAtHead
.local(local
), from
->variablesAtTail
.local(local
));
1744 if (!to
->cfaHasVisited
)
1747 to
->cfaShouldRevisit
|= changed
;
1752 inline bool AbstractState::mergeToSuccessors(Graph
& graph
, BasicBlock
* basicBlock
)
1754 Node
* terminal
= basicBlock
->last();
1756 ASSERT(terminal
->isTerminal());
1758 switch (terminal
->op()) {
1760 ASSERT(basicBlock
->cfaBranchDirection
== InvalidBranchDirection
);
1761 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1762 dataLogF(" Merging to block #%u.\n", terminal
->takenBlockIndex());
1764 return merge(basicBlock
, graph
.m_blocks
[terminal
->takenBlockIndex()].get());
1768 ASSERT(basicBlock
->cfaBranchDirection
!= InvalidBranchDirection
);
1769 bool changed
= false;
1770 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1771 dataLogF(" Merging to block #%u.\n", terminal
->takenBlockIndex());
1773 if (basicBlock
->cfaBranchDirection
!= TakeFalse
)
1774 changed
|= merge(basicBlock
, graph
.m_blocks
[terminal
->takenBlockIndex()].get());
1775 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
1776 dataLogF(" Merging to block #%u.\n", terminal
->notTakenBlockIndex());
1778 if (basicBlock
->cfaBranchDirection
!= TakeTrue
)
1779 changed
|= merge(basicBlock
, graph
.m_blocks
[terminal
->notTakenBlockIndex()].get());
1785 ASSERT(basicBlock
->cfaBranchDirection
== InvalidBranchDirection
);
1789 RELEASE_ASSERT_NOT_REACHED();
1794 inline bool AbstractState::mergeVariableBetweenBlocks(AbstractValue
& destination
, AbstractValue
& source
, Node
* destinationNode
, Node
* sourceNode
)
1796 if (!destinationNode
)
1799 ASSERT_UNUSED(sourceNode
, sourceNode
);
1801 // FIXME: We could do some sparse conditional propagation here!
1803 return destination
.merge(source
);
1806 void AbstractState::dump(PrintStream
& out
)
1809 for (size_t i
= 0; i
< m_block
->size(); ++i
) {
1810 Node
* node
= m_block
->at(i
);
1811 AbstractValue
& value
= forNode(node
);
1812 if (value
.isClear())
1818 out
.printf("@%lu:", static_cast<unsigned long>(node
->index()));
1823 } } // namespace JSC::DFG
1825 #endif // ENABLE(DFG_JIT)