2 * Copyright (C) 2013, 2014 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.
26 #ifndef DFGAbstractInterpreterInlines_h
27 #define DFGAbstractInterpreterInlines_h
31 #include "DFGAbstractInterpreter.h"
32 #include "GetByIdStatus.h"
33 #include "Operations.h"
34 #include "PutByIdStatus.h"
35 #include "StringObject.h"
37 namespace JSC
{ namespace DFG
{
39 template<typename AbstractStateType
>
40 AbstractInterpreter
<AbstractStateType
>::AbstractInterpreter(Graph
& graph
, AbstractStateType
& state
)
41 : m_codeBlock(graph
.m_codeBlock
)
47 template<typename AbstractStateType
>
48 AbstractInterpreter
<AbstractStateType
>::~AbstractInterpreter()
52 template<typename AbstractStateType
>
53 typename AbstractInterpreter
<AbstractStateType
>::BooleanResult
54 AbstractInterpreter
<AbstractStateType
>::booleanResult(
55 Node
* node
, AbstractValue
& value
)
57 JSValue childConst
= value
.value();
59 if (childConst
.toBoolean(m_codeBlock
->globalObjectFor(node
->origin
.semantic
)->globalExec()))
60 return DefinitelyTrue
;
61 return DefinitelyFalse
;
64 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
65 if (isCellSpeculation(value
.m_type
)
66 && value
.m_currentKnownStructure
.hasSingleton()) {
67 Structure
* structure
= value
.m_currentKnownStructure
.singleton();
68 if (!structure
->masqueradesAsUndefined(m_codeBlock
->globalObjectFor(node
->origin
.semantic
))
69 && structure
->typeInfo().type() != StringType
)
70 return DefinitelyTrue
;
73 return UnknownBooleanResult
;
76 template<typename AbstractStateType
>
77 bool AbstractInterpreter
<AbstractStateType
>::startExecuting(Node
* node
)
79 ASSERT(m_state
.block());
80 ASSERT(m_state
.isValid());
82 m_state
.setDidClobber(false);
84 node
->setCanExit(false);
86 return node
->shouldGenerate();
89 template<typename AbstractStateType
>
90 bool AbstractInterpreter
<AbstractStateType
>::startExecuting(unsigned indexInBlock
)
92 return startExecuting(m_state
.block()->at(indexInBlock
));
95 template<typename AbstractStateType
>
96 void AbstractInterpreter
<AbstractStateType
>::executeEdges(Node
* node
)
98 DFG_NODE_DO_TO_CHILDREN(m_graph
, node
, filterEdgeByUse
);
101 template<typename AbstractStateType
>
102 void AbstractInterpreter
<AbstractStateType
>::executeEdges(unsigned indexInBlock
)
104 executeEdges(m_state
.block()->at(indexInBlock
));
107 template<typename AbstractStateType
>
108 void AbstractInterpreter
<AbstractStateType
>::verifyEdge(Node
*, Edge edge
)
110 RELEASE_ASSERT(!(forNode(edge
).m_type
& ~typeFilterFor(edge
.useKind())));
113 template<typename AbstractStateType
>
114 void AbstractInterpreter
<AbstractStateType
>::verifyEdges(Node
* node
)
116 DFG_NODE_DO_TO_CHILDREN(m_graph
, node
, verifyEdge
);
119 template<typename AbstractStateType
>
120 bool AbstractInterpreter
<AbstractStateType
>::executeEffects(unsigned clobberLimit
, Node
* node
)
122 if (!ASSERT_DISABLED
)
125 m_state
.createValueForNode(node
);
127 switch (node
->op()) {
132 case PhantomArguments
: {
133 setBuiltInConstant(node
, m_graph
.valueOfJSConstant(node
));
138 forNode(node
) = forNode(node
->child1());
143 ASSERT(m_graph
.m_form
== SSA
);
144 VariableAccessData
* variable
= node
->variableAccessData();
145 AbstractValue
& value
= m_state
.variables().operand(variable
->local().offset());
146 ASSERT(value
.isHeapTop());
147 FiltrationResult result
=
148 value
.filter(typeFilterFor(useKindFor(variable
->flushFormat())));
149 ASSERT_UNUSED(result
, result
== FiltrationOK
);
150 forNode(node
) = value
;
154 case ExtractOSREntryLocal
: {
155 if (!(node
->unlinkedLocal().isArgument())
156 && m_graph
.m_lazyVars
.get(node
->unlinkedLocal().toLocal())) {
157 // This is kind of pessimistic - we could know in some cases that the
158 // DFG code at the point of the OSR had already initialized the lazy
159 // variable. But maybe this is fine, since we're inserting OSR
160 // entrypoints very early in the pipeline - so any lazy initializations
161 // ought to be hoisted out anyway.
162 forNode(node
).makeBytecodeTop();
164 forNode(node
).makeHeapTop();
169 VariableAccessData
* variableAccessData
= node
->variableAccessData();
170 AbstractValue value
= m_state
.variables().operand(variableAccessData
->local().offset());
171 if (!variableAccessData
->isCaptured()) {
173 node
->setCanExit(true);
176 m_state
.setFoundConstants(true);
177 forNode(node
) = value
;
181 case GetLocalUnlinked
: {
182 AbstractValue value
= m_state
.variables().operand(node
->unlinkedLocal().offset());
184 m_state
.setFoundConstants(true);
185 forNode(node
) = value
;
190 m_state
.variables().operand(node
->local().offset()) = forNode(node
->child1());
195 // Don't need to do anything. A MovHint only informs us about what would have happened
196 // in bytecode, but this code is just concerned with what is actually happening during
202 // Assert that the state of arguments has been set.
203 ASSERT(!m_state
.block()->valuesAtHead
.operand(node
->local()).isClear());
212 JSValue left
= forNode(node
->child1()).value();
213 JSValue right
= forNode(node
->child2()).value();
214 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
215 int32_t a
= left
.asInt32();
216 int32_t b
= right
.asInt32();
217 switch (node
->op()) {
219 setConstant(node
, JSValue(a
& b
));
222 setConstant(node
, JSValue(a
| b
));
225 setConstant(node
, JSValue(a
^ b
));
228 setConstant(node
, JSValue(a
>> static_cast<uint32_t>(b
)));
231 setConstant(node
, JSValue(a
<< static_cast<uint32_t>(b
)));
234 setConstant(node
, JSValue(static_cast<uint32_t>(a
) >> static_cast<uint32_t>(b
)));
237 RELEASE_ASSERT_NOT_REACHED();
242 forNode(node
).setType(SpecInt32
);
246 case UInt32ToNumber
: {
247 JSValue child
= forNode(node
->child1()).value();
248 if (doesOverflow(node
->arithMode())) {
249 if (child
&& child
.isInt32()) {
250 uint32_t value
= child
.asInt32();
251 setConstant(node
, jsNumber(value
));
254 forNode(node
).setType(SpecInt52AsDouble
);
257 if (child
&& child
.isInt32()) {
258 int32_t value
= child
.asInt32();
260 setConstant(node
, jsNumber(value
));
264 forNode(node
).setType(SpecInt32
);
265 node
->setCanExit(true);
269 case BooleanToNumber
: {
270 JSValue concreteValue
= forNode(node
->child1()).value();
272 if (concreteValue
.isBoolean())
273 setConstant(node
, jsNumber(concreteValue
.asBoolean()));
275 setConstant(node
, concreteValue
);
278 AbstractValue
& value
= forNode(node
);
279 value
= forNode(node
->child1());
280 if (node
->child1().useKind() == UntypedUse
&& !(value
.m_type
& ~SpecBoolean
))
281 m_state
.setFoundConstants(true);
282 if (value
.m_type
& SpecBoolean
) {
283 value
.merge(SpecInt32
);
284 value
.filter(~SpecBoolean
);
289 case DoubleAsInt32
: {
290 JSValue child
= forNode(node
->child1()).value();
291 if (child
&& child
.isNumber()) {
292 double asDouble
= child
.asNumber();
293 int32_t asInt
= JSC::toInt32(asDouble
);
294 if (bitwise_cast
<int64_t>(static_cast<double>(asInt
)) == bitwise_cast
<int64_t>(asDouble
)) {
295 setConstant(node
, JSValue(asInt
));
299 node
->setCanExit(true);
300 forNode(node
).setType(SpecInt32
);
305 JSValue child
= forNode(node
->child1()).value();
307 if (child
.isNumber()) {
309 setConstant(node
, child
);
311 setConstant(node
, JSValue(JSC::toInt32(child
.asDouble())));
314 if (child
.isBoolean()) {
315 setConstant(node
, jsNumber(child
.asBoolean()));
318 if (child
.isUndefinedOrNull()) {
319 setConstant(node
, jsNumber(0));
324 forNode(node
).setType(SpecInt32
);
329 JSValue child
= forNode(node
->child1()).value();
330 if (child
&& child
.isNumber()) {
331 setConstant(node
, jsDoubleNumber(child
.asNumber()));
334 forNode(node
).setType(forNode(node
->child1()).m_type
);
335 forNode(node
).fixTypeForRepresentation(node
);
340 JSValue child
= forNode(node
->child1()).value();
341 if (child
&& child
.isMachineInt()) {
342 setConstant(node
, child
);
346 forNode(node
).setType(SpecInt32
);
351 JSValue value
= forNode(node
->child1()).value();
353 setConstant(node
, value
);
357 forNode(node
).setType(forNode(node
->child1()).m_type
& ~SpecDoubleImpureNaN
);
358 forNode(node
).fixTypeForRepresentation(node
);
363 ASSERT(node
->binaryUseKind() == UntypedUse
);
364 clobberWorld(node
->origin
.semantic
, clobberLimit
);
365 forNode(node
).setType(SpecString
| SpecBytecodeNumber
);
370 JSValue left
= forNode(node
->child1()).value();
371 JSValue right
= forNode(node
->child2()).value();
372 switch (node
->binaryUseKind()) {
374 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
375 if (!shouldCheckOverflow(node
->arithMode())) {
376 setConstant(node
, jsNumber(left
.asInt32() + right
.asInt32()));
379 JSValue result
= jsNumber(left
.asNumber() + right
.asNumber());
380 if (result
.isInt32()) {
381 setConstant(node
, result
);
385 forNode(node
).setType(SpecInt32
);
386 if (shouldCheckOverflow(node
->arithMode()))
387 node
->setCanExit(true);
390 if (left
&& right
&& left
.isMachineInt() && right
.isMachineInt()) {
391 JSValue result
= jsNumber(left
.asMachineInt() + right
.asMachineInt());
392 if (result
.isMachineInt()) {
393 setConstant(node
, result
);
397 forNode(node
).setType(SpecMachineInt
);
398 if (!forNode(node
->child1()).isType(SpecInt32
)
399 || !forNode(node
->child2()).isType(SpecInt32
))
400 node
->setCanExit(true);
403 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
404 setConstant(node
, jsDoubleNumber(left
.asNumber() + right
.asNumber()));
407 forNode(node
).setType(
409 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
412 RELEASE_ASSERT_NOT_REACHED();
419 node
->setCanExit(true);
420 forNode(node
).set(m_graph
, m_graph
.m_vm
.stringStructure
.get());
425 JSValue left
= forNode(node
->child1()).value();
426 JSValue right
= forNode(node
->child2()).value();
427 switch (node
->binaryUseKind()) {
429 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
430 if (!shouldCheckOverflow(node
->arithMode())) {
431 setConstant(node
, jsNumber(left
.asInt32() - right
.asInt32()));
434 JSValue result
= jsNumber(left
.asNumber() - right
.asNumber());
435 if (result
.isInt32()) {
436 setConstant(node
, result
);
440 forNode(node
).setType(SpecInt32
);
441 if (shouldCheckOverflow(node
->arithMode()))
442 node
->setCanExit(true);
445 if (left
&& right
&& left
.isMachineInt() && right
.isMachineInt()) {
446 JSValue result
= jsNumber(left
.asMachineInt() - right
.asMachineInt());
447 if (result
.isMachineInt() || !shouldCheckOverflow(node
->arithMode())) {
448 setConstant(node
, result
);
452 forNode(node
).setType(SpecMachineInt
);
453 if (!forNode(node
->child1()).isType(SpecInt32
)
454 || !forNode(node
->child2()).isType(SpecInt32
))
455 node
->setCanExit(true);
458 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
459 setConstant(node
, jsDoubleNumber(left
.asNumber() - right
.asNumber()));
462 forNode(node
).setType(
463 typeOfDoubleDifference(
464 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
467 RELEASE_ASSERT_NOT_REACHED();
474 JSValue child
= forNode(node
->child1()).value();
475 switch (node
->child1().useKind()) {
477 if (child
&& child
.isInt32()) {
478 if (!shouldCheckOverflow(node
->arithMode())) {
479 setConstant(node
, jsNumber(-child
.asInt32()));
483 if (shouldCheckNegativeZero(node
->arithMode()))
484 doubleResult
= -child
.asNumber();
486 doubleResult
= 0 - child
.asNumber();
487 JSValue valueResult
= jsNumber(doubleResult
);
488 if (valueResult
.isInt32()) {
489 setConstant(node
, valueResult
);
493 forNode(node
).setType(SpecInt32
);
494 if (shouldCheckOverflow(node
->arithMode()))
495 node
->setCanExit(true);
498 if (child
&& child
.isMachineInt()) {
500 if (shouldCheckNegativeZero(node
->arithMode()))
501 doubleResult
= -child
.asNumber();
503 doubleResult
= 0 - child
.asNumber();
504 JSValue valueResult
= jsNumber(doubleResult
);
505 if (valueResult
.isMachineInt()) {
506 setConstant(node
, valueResult
);
510 forNode(node
).setType(SpecMachineInt
);
511 if (m_state
.forNode(node
->child1()).couldBeType(SpecInt52
))
512 node
->setCanExit(true);
513 if (shouldCheckNegativeZero(node
->arithMode()))
514 node
->setCanExit(true);
517 if (child
&& child
.isNumber()) {
518 setConstant(node
, jsDoubleNumber(-child
.asNumber()));
521 forNode(node
).setType(
522 typeOfDoubleNegation(
523 forNode(node
->child1()).m_type
));
526 RELEASE_ASSERT_NOT_REACHED();
533 JSValue left
= forNode(node
->child1()).value();
534 JSValue right
= forNode(node
->child2()).value();
535 switch (node
->binaryUseKind()) {
537 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
538 if (!shouldCheckOverflow(node
->arithMode())) {
539 setConstant(node
, jsNumber(left
.asInt32() * right
.asInt32()));
542 double doubleResult
= left
.asNumber() * right
.asNumber();
543 if (!shouldCheckNegativeZero(node
->arithMode()))
544 doubleResult
+= 0; // Sanitizes zero.
545 JSValue valueResult
= jsNumber(doubleResult
);
546 if (valueResult
.isInt32()) {
547 setConstant(node
, valueResult
);
551 forNode(node
).setType(SpecInt32
);
552 if (shouldCheckOverflow(node
->arithMode()))
553 node
->setCanExit(true);
556 if (left
&& right
&& left
.isMachineInt() && right
.isMachineInt()) {
557 double doubleResult
= left
.asNumber() * right
.asNumber();
558 if (!shouldCheckNegativeZero(node
->arithMode()))
560 JSValue valueResult
= jsNumber(doubleResult
);
561 if (valueResult
.isMachineInt()) {
562 setConstant(node
, valueResult
);
566 forNode(node
).setType(SpecMachineInt
);
567 node
->setCanExit(true);
570 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
571 setConstant(node
, jsDoubleNumber(left
.asNumber() * right
.asNumber()));
574 forNode(node
).setType(
576 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
579 RELEASE_ASSERT_NOT_REACHED();
586 JSValue left
= forNode(node
->child1()).value();
587 JSValue right
= forNode(node
->child2()).value();
588 switch (node
->binaryUseKind()) {
590 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
591 double doubleResult
= left
.asNumber() / right
.asNumber();
592 if (!shouldCheckOverflow(node
->arithMode()))
593 doubleResult
= toInt32(doubleResult
);
594 else if (!shouldCheckNegativeZero(node
->arithMode()))
595 doubleResult
+= 0; // Sanitizes zero.
596 JSValue valueResult
= jsNumber(doubleResult
);
597 if (valueResult
.isInt32()) {
598 setConstant(node
, valueResult
);
602 forNode(node
).setType(SpecInt32
);
603 node
->setCanExit(true);
606 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
607 setConstant(node
, jsDoubleNumber(left
.asNumber() / right
.asNumber()));
610 forNode(node
).setType(
611 typeOfDoubleQuotient(
612 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
615 RELEASE_ASSERT_NOT_REACHED();
622 JSValue left
= forNode(node
->child1()).value();
623 JSValue right
= forNode(node
->child2()).value();
624 switch (node
->binaryUseKind()) {
626 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
627 double doubleResult
= fmod(left
.asNumber(), right
.asNumber());
628 if (!shouldCheckOverflow(node
->arithMode()))
629 doubleResult
= toInt32(doubleResult
);
630 else if (!shouldCheckNegativeZero(node
->arithMode()))
631 doubleResult
+= 0; // Sanitizes zero.
632 JSValue valueResult
= jsNumber(doubleResult
);
633 if (valueResult
.isInt32()) {
634 setConstant(node
, valueResult
);
638 forNode(node
).setType(SpecInt32
);
639 node
->setCanExit(true);
642 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
643 setConstant(node
, jsDoubleNumber(fmod(left
.asNumber(), right
.asNumber())));
646 forNode(node
).setType(
647 typeOfDoubleBinaryOp(
648 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
651 RELEASE_ASSERT_NOT_REACHED();
658 JSValue left
= forNode(node
->child1()).value();
659 JSValue right
= forNode(node
->child2()).value();
660 switch (node
->binaryUseKind()) {
662 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
663 setConstant(node
, jsNumber(std::min(left
.asInt32(), right
.asInt32())));
666 forNode(node
).setType(SpecInt32
);
667 node
->setCanExit(true);
670 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
671 double a
= left
.asNumber();
672 double b
= right
.asNumber();
673 setConstant(node
, jsDoubleNumber(a
< b
? a
: (b
<= a
? b
: a
+ b
)));
676 forNode(node
).setType(
678 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
681 RELEASE_ASSERT_NOT_REACHED();
688 JSValue left
= forNode(node
->child1()).value();
689 JSValue right
= forNode(node
->child2()).value();
690 switch (node
->binaryUseKind()) {
692 if (left
&& right
&& left
.isInt32() && right
.isInt32()) {
693 setConstant(node
, jsNumber(std::max(left
.asInt32(), right
.asInt32())));
696 forNode(node
).setType(SpecInt32
);
697 node
->setCanExit(true);
700 if (left
&& right
&& left
.isNumber() && right
.isNumber()) {
701 double a
= left
.asNumber();
702 double b
= right
.asNumber();
703 setConstant(node
, jsDoubleNumber(a
> b
? a
: (b
>= a
? b
: a
+ b
)));
706 forNode(node
).setType(
708 forNode(node
->child1()).m_type
, forNode(node
->child2()).m_type
));
711 RELEASE_ASSERT_NOT_REACHED();
718 JSValue child
= forNode(node
->child1()).value();
719 switch (node
->child1().useKind()) {
721 if (child
&& child
.isInt32()) {
722 JSValue result
= jsNumber(fabs(child
.asNumber()));
723 if (result
.isInt32()) {
724 setConstant(node
, result
);
728 forNode(node
).setType(SpecInt32
);
729 node
->setCanExit(true);
732 if (child
&& child
.isNumber()) {
733 setConstant(node
, jsDoubleNumber(child
.asNumber()));
736 forNode(node
).setType(typeOfDoubleAbs(forNode(node
->child1()).m_type
));
739 RELEASE_ASSERT_NOT_REACHED();
746 JSValue child
= forNode(node
->child1()).value();
747 if (child
&& child
.isNumber()) {
748 setConstant(node
, jsDoubleNumber(sqrt(child
.asNumber())));
751 forNode(node
).setType(typeOfDoubleUnaryOp(forNode(node
->child1()).m_type
));
756 JSValue child
= forNode(node
->child1()).value();
757 if (child
&& child
.isNumber()) {
758 setConstant(node
, jsDoubleNumber(static_cast<float>(child
.asNumber())));
761 forNode(node
).setType(typeOfDoubleFRound(forNode(node
->child1()).m_type
));
766 JSValue child
= forNode(node
->child1()).value();
767 if (child
&& child
.isNumber()) {
768 setConstant(node
, jsDoubleNumber(sin(child
.asNumber())));
771 forNode(node
).setType(typeOfDoubleUnaryOp(forNode(node
->child1()).m_type
));
776 JSValue child
= forNode(node
->child1()).value();
777 if (child
&& child
.isNumber()) {
778 setConstant(node
, jsDoubleNumber(cos(child
.asNumber())));
781 forNode(node
).setType(typeOfDoubleUnaryOp(forNode(node
->child1()).m_type
));
786 switch (booleanResult(node
, forNode(node
->child1()))) {
788 setConstant(node
, jsBoolean(false));
790 case DefinitelyFalse
:
791 setConstant(node
, jsBoolean(true));
794 switch (node
->child1().useKind()) {
801 case ObjectOrOtherUse
:
802 node
->setCanExit(true);
805 RELEASE_ASSERT_NOT_REACHED();
808 forNode(node
).setType(SpecBoolean
);
821 node
->op() == IsUndefined
822 && m_graph
.masqueradesAsUndefinedWatchpointIsStillValid(node
->origin
.semantic
));
823 JSValue child
= forNode(node
->child1()).value();
825 bool constantWasSet
= true;
826 switch (node
->op()) {
828 setConstant(node
, jsBoolean(
830 ? child
.asCell()->structure()->masqueradesAsUndefined(m_codeBlock
->globalObjectFor(node
->origin
.semantic
))
831 : child
.isUndefined()));
834 setConstant(node
, jsBoolean(child
.isBoolean()));
837 setConstant(node
, jsBoolean(child
.isNumber()));
840 setConstant(node
, jsBoolean(isJSString(child
)));
843 if (child
.isNull() || !child
.isObject()) {
844 setConstant(node
, jsBoolean(child
.isNull()));
847 constantWasSet
= false;
850 constantWasSet
= false;
857 forNode(node
).setType(SpecBoolean
);
862 VM
* vm
= m_codeBlock
->vm();
863 JSValue child
= forNode(node
->child1()).value();
864 AbstractValue
& abstractChild
= forNode(node
->child1());
866 JSValue typeString
= jsTypeStringForValue(*vm
, m_codeBlock
->globalObjectFor(node
->origin
.semantic
), child
);
867 setConstant(node
, typeString
);
871 if (isFullNumberSpeculation(abstractChild
.m_type
)) {
872 setConstant(node
, vm
->smallStrings
.numberString());
876 if (isStringSpeculation(abstractChild
.m_type
)) {
877 setConstant(node
, vm
->smallStrings
.stringString());
881 if (isFinalObjectSpeculation(abstractChild
.m_type
) || isArraySpeculation(abstractChild
.m_type
) || isArgumentsSpeculation(abstractChild
.m_type
)) {
882 setConstant(node
, vm
->smallStrings
.objectString());
886 if (isFunctionSpeculation(abstractChild
.m_type
)) {
887 setConstant(node
, vm
->smallStrings
.functionString());
891 if (isBooleanSpeculation(abstractChild
.m_type
)) {
892 setConstant(node
, vm
->smallStrings
.booleanString());
896 switch (node
->child1().useKind()) {
899 node
->setCanExit(true);
904 RELEASE_ASSERT_NOT_REACHED();
907 forNode(node
).set(m_graph
, m_graph
.m_vm
.stringStructure
.get());
914 case CompareGreaterEq
:
916 case CompareEqConstant
: {
917 JSValue leftConst
= forNode(node
->child1()).value();
918 JSValue rightConst
= forNode(node
->child2()).value();
919 if (leftConst
&& rightConst
) {
920 if (leftConst
.isNumber() && rightConst
.isNumber()) {
921 double a
= leftConst
.asNumber();
922 double b
= rightConst
.asNumber();
923 switch (node
->op()) {
925 setConstant(node
, jsBoolean(a
< b
));
928 setConstant(node
, jsBoolean(a
<= b
));
931 setConstant(node
, jsBoolean(a
> b
));
933 case CompareGreaterEq
:
934 setConstant(node
, jsBoolean(a
>= b
));
937 setConstant(node
, jsBoolean(a
== b
));
940 RELEASE_ASSERT_NOT_REACHED();
946 if (node
->op() == CompareEq
&& leftConst
.isString() && rightConst
.isString()) {
947 const StringImpl
* a
= asString(leftConst
)->tryGetValueImpl();
948 const StringImpl
* b
= asString(rightConst
)->tryGetValueImpl();
950 setConstant(node
, jsBoolean(WTF::equal(a
, b
)));
956 if (node
->op() == CompareEqConstant
|| node
->op() == CompareEq
) {
957 SpeculatedType leftType
= forNode(node
->child1()).m_type
;
958 SpeculatedType rightType
= forNode(node
->child2()).m_type
;
959 if (!valuesCouldBeEqual(leftType
, rightType
)) {
960 setConstant(node
, jsBoolean(false));
965 forNode(node
).setType(SpecBoolean
);
967 // This is overly conservative. But the only thing this prevents is store elimination,
968 // and how likely is it, really, that you'll have redundant stores across a comparison
969 // operation? Comparison operations are typically at the end of basic blocks, so
970 // unless we have global store elimination (super unlikely given how unprofitable that
971 // optimization is to begin with), you aren't going to be wanting to store eliminate
972 // across an equality op.
973 node
->setCanExit(true);
977 case CompareStrictEq
: {
978 Node
* leftNode
= node
->child1().node();
979 Node
* rightNode
= node
->child2().node();
980 JSValue left
= forNode(leftNode
).value();
981 JSValue right
= forNode(rightNode
).value();
983 if (left
.isString() && right
.isString()) {
984 // We need this case because JSValue::strictEqual is otherwise too racy for
985 // string comparisons.
986 const StringImpl
* a
= asString(left
)->tryGetValueImpl();
987 const StringImpl
* b
= asString(right
)->tryGetValueImpl();
989 setConstant(node
, jsBoolean(WTF::equal(a
, b
)));
993 setConstant(node
, jsBoolean(JSValue::strictEqual(0, left
, right
)));
998 SpeculatedType leftLUB
= leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode
).m_type
);
999 SpeculatedType rightLUB
= leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode
).m_type
);
1000 if (!(leftLUB
& rightLUB
)) {
1001 setConstant(node
, jsBoolean(false));
1005 forNode(node
).setType(SpecBoolean
);
1006 node
->setCanExit(true); // This is overly conservative.
1010 case StringCharCodeAt
:
1011 node
->setCanExit(true);
1012 forNode(node
).setType(SpecInt32
);
1015 case StringFromCharCode
:
1016 forNode(node
).setType(SpecString
);
1020 node
->setCanExit(true);
1021 forNode(node
).set(m_graph
, m_graph
.m_vm
.stringStructure
.get());
1025 node
->setCanExit(true);
1026 switch (node
->arrayMode().type()) {
1027 case Array::SelectUsingPredictions
:
1028 case Array::Unprofiled
:
1029 case Array::Undecided
:
1030 RELEASE_ASSERT_NOT_REACHED();
1032 case Array::ForceExit
:
1033 m_state
.setIsValid(false);
1035 case Array::Generic
:
1036 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1037 forNode(node
).makeHeapTop();
1040 if (node
->arrayMode().isOutOfBounds()) {
1041 // If the watchpoint was still valid we could totally set this to be
1042 // SpecString | SpecOther. Except that we'd have to be careful. If we
1043 // tested the watchpoint state here then it could change by the time
1044 // we got to the backend. So to do this right, we'd have to get the
1045 // fixup phase to check the watchpoint state and then bake into the
1046 // GetByVal operation the fact that we're using a watchpoint, using
1047 // something like Array::SaneChain (except not quite, because that
1048 // implies an in-bounds access). None of this feels like it's worth it,
1049 // so we're going with TOP for now. The same thing applies to
1050 // clobbering the world.
1051 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1052 forNode(node
).makeHeapTop();
1054 forNode(node
).set(m_graph
, m_graph
.m_vm
.stringStructure
.get());
1056 case Array::Arguments
:
1057 forNode(node
).makeHeapTop();
1060 if (node
->arrayMode().isOutOfBounds()) {
1061 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1062 forNode(node
).makeHeapTop();
1064 forNode(node
).setType(SpecInt32
);
1067 if (node
->arrayMode().isOutOfBounds()) {
1068 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1069 forNode(node
).makeHeapTop();
1070 } else if (node
->arrayMode().isSaneChain())
1071 forNode(node
).setType(SpecBytecodeDouble
);
1073 forNode(node
).setType(SpecDoubleReal
);
1075 case Array::Contiguous
:
1076 case Array::ArrayStorage
:
1077 case Array::SlowPutArrayStorage
:
1078 if (node
->arrayMode().isOutOfBounds())
1079 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1080 forNode(node
).makeHeapTop();
1082 case Array::Int8Array
:
1083 forNode(node
).setType(SpecInt32
);
1085 case Array::Int16Array
:
1086 forNode(node
).setType(SpecInt32
);
1088 case Array::Int32Array
:
1089 forNode(node
).setType(SpecInt32
);
1091 case Array::Uint8Array
:
1092 forNode(node
).setType(SpecInt32
);
1094 case Array::Uint8ClampedArray
:
1095 forNode(node
).setType(SpecInt32
);
1097 case Array::Uint16Array
:
1098 forNode(node
).setType(SpecInt32
);
1100 case Array::Uint32Array
:
1101 if (node
->shouldSpeculateInt32())
1102 forNode(node
).setType(SpecInt32
);
1103 else if (enableInt52() && node
->shouldSpeculateMachineInt())
1104 forNode(node
).setType(SpecInt52
);
1106 forNode(node
).setType(SpecInt52AsDouble
);
1108 case Array::Float32Array
:
1109 forNode(node
).setType(SpecFullDouble
);
1111 case Array::Float64Array
:
1112 forNode(node
).setType(SpecFullDouble
);
1115 RELEASE_ASSERT_NOT_REACHED();
1121 case PutByValDirect
:
1123 case PutByValAlias
: {
1124 node
->setCanExit(true);
1125 switch (node
->arrayMode().modeForPut().type()) {
1126 case Array::ForceExit
:
1127 m_state
.setIsValid(false);
1129 case Array::Generic
:
1130 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1133 if (node
->arrayMode().isOutOfBounds())
1134 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1137 if (node
->arrayMode().isOutOfBounds())
1138 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1140 case Array::Contiguous
:
1141 case Array::ArrayStorage
:
1142 if (node
->arrayMode().isOutOfBounds())
1143 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1145 case Array::SlowPutArrayStorage
:
1146 if (node
->arrayMode().mayStoreToHole())
1147 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1156 node
->setCanExit(true);
1157 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1158 forNode(node
).setType(SpecBytecodeNumber
);
1162 node
->setCanExit(true);
1163 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1164 forNode(node
).makeHeapTop();
1168 forNode(node
).makeHeapTop();
1172 forNode(node
).setType(SpecBoolean
);
1179 Node
* child
= node
->child1().node();
1180 BooleanResult result
= booleanResult(node
, forNode(child
));
1181 if (result
== DefinitelyTrue
) {
1182 m_state
.setBranchDirection(TakeTrue
);
1185 if (result
== DefinitelyFalse
) {
1186 m_state
.setBranchDirection(TakeFalse
);
1189 // FIXME: The above handles the trivial cases of sparse conditional
1190 // constant propagation, but we can do better:
1191 // We can specialize the source variable's value on each direction of
1193 node
->setCanExit(true); // This is overly conservative.
1194 m_state
.setBranchDirection(TakeBoth
);
1199 // Nothing to do for now.
1200 // FIXME: Do sparse conditional things.
1205 m_state
.setIsValid(false);
1209 case ThrowReferenceError
:
1210 m_state
.setIsValid(false);
1211 node
->setCanExit(true);
1215 JSValue childConst
= forNode(node
->child1()).value();
1216 if (childConst
&& childConst
.isNumber()) {
1217 setConstant(node
, childConst
);
1221 ASSERT(node
->child1().useKind() == UntypedUse
);
1223 if (!forNode(node
->child1()).m_type
) {
1224 m_state
.setIsValid(false);
1228 if (!(forNode(node
->child1()).m_type
& ~(SpecFullNumber
| SpecBoolean
| SpecString
))) {
1229 m_state
.setFoundConstants(true);
1230 forNode(node
) = forNode(node
->child1());
1234 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1236 forNode(node
).setType((SpecHeapTop
& ~SpecCell
) | SpecString
);
1241 switch (node
->child1().useKind()) {
1242 case StringObjectUse
:
1243 // This also filters that the StringObject has the primordial StringObject
1247 m_graph
.globalObjectFor(node
->origin
.semantic
)->stringObjectStructure());
1248 node
->setCanExit(true); // We could be more precise but it's likely not worth it.
1250 case StringOrStringObjectUse
:
1251 node
->setCanExit(true); // We could be more precise but it's likely not worth it.
1255 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1258 RELEASE_ASSERT_NOT_REACHED();
1261 forNode(node
).set(m_graph
, m_graph
.m_vm
.stringStructure
.get());
1265 case NewStringObject
: {
1266 ASSERT(node
->structure()->classInfo() == StringObject::info());
1267 forNode(node
).set(m_graph
, node
->structure());
1272 node
->setCanExit(true);
1275 m_graph
.globalObjectFor(node
->origin
.semantic
)->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()));
1276 m_state
.setHaveStructures(true);
1279 case NewArrayBuffer
:
1280 node
->setCanExit(true);
1283 m_graph
.globalObjectFor(node
->origin
.semantic
)->arrayStructureForIndexingTypeDuringAllocation(node
->indexingType()));
1284 m_state
.setHaveStructures(true);
1287 case NewArrayWithSize
:
1288 node
->setCanExit(true);
1289 forNode(node
).setType(SpecArray
);
1290 m_state
.setHaveStructures(true);
1294 switch (node
->child1().useKind()) {
1298 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1301 RELEASE_ASSERT_NOT_REACHED();
1306 m_graph
.globalObjectFor(node
->origin
.semantic
)->typedArrayStructure(
1307 node
->typedArrayType()));
1308 m_state
.setHaveStructures(true);
1312 forNode(node
).set(m_graph
, m_graph
.globalObjectFor(node
->origin
.semantic
)->regExpStructure());
1313 m_state
.setHaveStructures(true);
1317 AbstractValue
& source
= forNode(node
->child1());
1318 AbstractValue
& destination
= forNode(node
);
1320 if (m_graph
.executableFor(node
->origin
.semantic
)->isStrictMode())
1321 destination
.makeHeapTop();
1323 destination
= source
;
1324 destination
.merge(SpecObject
);
1330 forNode(node
).setType(SpecFinalObject
);
1334 case AllocationProfileWatchpoint
:
1335 node
->setCanExit(true);
1339 ASSERT(node
->structure());
1340 forNode(node
).set(m_graph
, node
->structure());
1341 m_state
.setHaveStructures(true);
1344 case CreateActivation
:
1346 m_graph
, m_codeBlock
->globalObjectFor(node
->origin
.semantic
)->activationStructure());
1347 m_state
.setHaveStructures(true);
1350 case FunctionReentryWatchpoint
:
1351 case TypedArrayWatchpoint
:
1354 case CreateArguments
:
1355 forNode(node
) = forNode(node
->child1());
1356 forNode(node
).filter(~SpecEmpty
);
1357 forNode(node
).merge(SpecArguments
);
1360 case TearOffActivation
:
1361 case TearOffArguments
:
1362 // Does nothing that is user-visible.
1365 case CheckArgumentsNotCreated
:
1366 if (isEmptySpeculation(
1367 m_state
.variables().operand(
1368 m_graph
.argumentsRegisterFor(node
->origin
.semantic
).offset()).m_type
))
1369 m_state
.setFoundConstants(true);
1371 node
->setCanExit(true);
1374 case GetMyArgumentsLength
:
1375 // We know that this executable does not escape its arguments, so we can optimize
1376 // the arguments a bit. Note that this is not sufficient to force constant folding
1377 // of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
1378 // We perform further optimizations on this later on.
1379 if (node
->origin
.semantic
.inlineCallFrame
) {
1381 m_graph
, jsNumber(node
->origin
.semantic
.inlineCallFrame
->arguments
.size() - 1));
1383 forNode(node
).setType(SpecInt32
);
1385 !isEmptySpeculation(
1386 m_state
.variables().operand(
1387 m_graph
.argumentsRegisterFor(node
->origin
.semantic
)).m_type
));
1390 case GetMyArgumentsLengthSafe
:
1391 // This potentially clobbers all structures if the arguments object had a getter
1392 // installed on the length property.
1393 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1394 // We currently make no guarantee about what this returns because it does not
1395 // speculate that the length property is actually a length.
1396 forNode(node
).makeHeapTop();
1399 case GetMyArgumentByVal
:
1400 node
->setCanExit(true);
1401 // We know that this executable does not escape its arguments, so we can optimize
1402 // the arguments a bit. Note that this ends up being further optimized by the
1403 // ArgumentsSimplificationPhase.
1404 forNode(node
).makeHeapTop();
1407 case GetMyArgumentByValSafe
:
1408 node
->setCanExit(true);
1409 // This potentially clobbers all structures if the property we're accessing has
1410 // a getter. We don't speculate against this.
1411 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1412 // And the result is unknown.
1413 forNode(node
).makeHeapTop();
1417 AbstractValue
& value
= forNode(node
);
1418 value
= forNode(node
->child1());
1420 if (!(value
.m_type
& SpecEmpty
)) {
1421 m_state
.setFoundConstants(true);
1425 value
.setType((value
.m_type
& ~SpecEmpty
) | SpecFunction
);
1429 case NewFunctionExpression
:
1430 case NewFunctionNoCheck
:
1432 m_graph
, m_codeBlock
->globalObjectFor(node
->origin
.semantic
)->functionStructure());
1433 m_state
.setHaveStructures(true);
1437 forNode(node
).setType(SpecFunction
);
1440 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
1443 forNode(node
).setType(SpecObjectOther
);
1447 JSValue child
= forNode(node
->child1()).value();
1449 setConstant(node
, JSValue(jsCast
<JSScope
*>(child
.asCell())->next()));
1452 forNode(node
).setType(SpecObjectOther
);
1456 case GetClosureRegisters
:
1457 forNode(node
).clear(); // The result is not a JS value.
1461 forNode(node
).makeHeapTop();
1465 clobberCapturedVars(node
->origin
.semantic
);
1470 node
->setCanExit(true);
1471 if (!node
->prediction()) {
1472 m_state
.setIsValid(false);
1475 if (isCellSpeculation(node
->child1()->prediction())) {
1476 if (Structure
* structure
= forNode(node
->child1()).bestProvenStructure()) {
1477 GetByIdStatus status
= GetByIdStatus::computeFor(
1478 m_graph
.m_vm
, structure
,
1479 m_graph
.identifiers()[node
->identifierNumber()]);
1480 if (status
.isSimple() && status
.numVariants() == 1) {
1481 // Assert things that we can't handle and that the computeFor() method
1482 // above won't be able to return.
1483 ASSERT(status
[0].structureSet().size() == 1);
1484 ASSERT(!status
[0].chain());
1486 if (status
[0].specificValue())
1487 setConstant(node
, status
[0].specificValue());
1489 forNode(node
).makeHeapTop();
1490 filter(node
->child1(), status
[0].structureSet());
1492 m_state
.setFoundConstants(true);
1493 m_state
.setHaveStructures(true);
1498 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1499 forNode(node
).makeHeapTop();
1502 case GetArrayLength
:
1503 node
->setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
1504 forNode(node
).setType(SpecInt32
);
1507 case CheckExecutable
: {
1508 // FIXME: We could track executables in AbstractValue, which would allow us to get rid of these checks
1509 // more thoroughly. https://bugs.webkit.org/show_bug.cgi?id=106200
1510 // FIXME: We could eliminate these entirely if we know the exact value that flows into this.
1511 // https://bugs.webkit.org/show_bug.cgi?id=106201
1512 node
->setCanExit(true);
1516 case CheckStructure
: {
1517 // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes).
1518 AbstractValue
& value
= forNode(node
->child1());
1519 ASSERT(!(value
.m_type
& ~SpecCell
)); // Edge filtering should have already ensured this.
1521 StructureSet
& set
= node
->structureSet();
1523 if (value
.m_currentKnownStructure
.isSubsetOf(set
)) {
1524 m_state
.setFoundConstants(true);
1528 node
->setCanExit(true);
1529 m_state
.setHaveStructures(true);
1531 // If this structure check is attempting to prove knowledge already held in
1532 // the futurePossibleStructure set then the constant folding phase should
1533 // turn this into a watchpoint instead.
1534 if (value
.m_futurePossibleStructure
.isSubsetOf(set
)
1535 && value
.m_futurePossibleStructure
.hasSingleton()) {
1536 m_state
.setFoundConstants(true);
1537 filter(value
, value
.m_futurePossibleStructure
.singleton());
1545 case StructureTransitionWatchpoint
: {
1546 AbstractValue
& value
= forNode(node
->child1());
1548 filter(value
, node
->structure());
1549 m_state
.setHaveStructures(true);
1550 node
->setCanExit(true);
1555 case PhantomPutStructure
:
1556 if (!forNode(node
->child1()).m_currentKnownStructure
.isClear()) {
1557 clobberStructures(clobberLimit
);
1558 forNode(node
->child1()).set(m_graph
, node
->structureTransitionData().newStructure
);
1559 m_state
.setHaveStructures(true);
1563 case AllocatePropertyStorage
:
1564 case ReallocatePropertyStorage
:
1565 forNode(node
).clear(); // The result is not a JS value.
1568 if (node
->arrayMode().alreadyChecked(m_graph
, node
, forNode(node
->child1()))) {
1569 m_state
.setFoundConstants(true);
1572 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.
1573 switch (node
->arrayMode().type()) {
1575 filter(node
->child1(), SpecString
);
1579 case Array::Contiguous
:
1580 case Array::ArrayStorage
:
1581 case Array::SlowPutArrayStorage
:
1583 case Array::Arguments
:
1584 filter(node
->child1(), SpecArguments
);
1586 case Array::Int8Array
:
1587 filter(node
->child1(), SpecInt8Array
);
1589 case Array::Int16Array
:
1590 filter(node
->child1(), SpecInt16Array
);
1592 case Array::Int32Array
:
1593 filter(node
->child1(), SpecInt32Array
);
1595 case Array::Uint8Array
:
1596 filter(node
->child1(), SpecUint8Array
);
1598 case Array::Uint8ClampedArray
:
1599 filter(node
->child1(), SpecUint8ClampedArray
);
1601 case Array::Uint16Array
:
1602 filter(node
->child1(), SpecUint16Array
);
1604 case Array::Uint32Array
:
1605 filter(node
->child1(), SpecUint32Array
);
1607 case Array::Float32Array
:
1608 filter(node
->child1(), SpecFloat32Array
);
1610 case Array::Float64Array
:
1611 filter(node
->child1(), SpecFloat64Array
);
1614 RELEASE_ASSERT_NOT_REACHED();
1617 filterArrayModes(node
->child1(), node
->arrayMode().arrayModesThatPassFiltering());
1618 m_state
.setHaveStructures(true);
1622 if (node
->arrayMode().alreadyChecked(m_graph
, node
, forNode(node
->child1()))) {
1623 m_state
.setFoundConstants(true);
1626 ASSERT(node
->arrayMode().conversion() == Array::Convert
1627 || node
->arrayMode().conversion() == Array::RageConvert
);
1628 node
->setCanExit(true);
1629 clobberStructures(clobberLimit
);
1630 filterArrayModes(node
->child1(), node
->arrayMode().arrayModesThatPassFiltering());
1631 m_state
.setHaveStructures(true);
1634 case ArrayifyToStructure
: {
1635 AbstractValue
& value
= forNode(node
->child1());
1636 StructureSet set
= node
->structure();
1637 if (value
.m_futurePossibleStructure
.isSubsetOf(set
)
1638 || value
.m_currentKnownStructure
.isSubsetOf(set
))
1639 m_state
.setFoundConstants(true);
1640 node
->setCanExit(true);
1641 clobberStructures(clobberLimit
);
1643 m_state
.setHaveStructures(true);
1646 case GetIndexedPropertyStorage
:
1647 case ConstantStoragePointer
: {
1648 forNode(node
).clear();
1652 case GetTypedArrayByteOffset
: {
1653 forNode(node
).setType(SpecInt32
);
1658 forNode(node
).makeHeapTop();
1662 case MultiGetByOffset
: {
1663 AbstractValue
& value
= forNode(node
->child1());
1664 ASSERT(!(value
.m_type
& ~SpecCell
)); // Edge filtering should have already ensured this.
1666 if (Structure
* structure
= value
.bestProvenStructure()) {
1668 for (unsigned i
= node
->multiGetByOffsetData().variants
.size(); i
--;) {
1669 const GetByIdVariant
& variant
= node
->multiGetByOffsetData().variants
[i
];
1670 if (!variant
.structureSet().contains(structure
))
1673 if (variant
.chain())
1676 filter(value
, structure
);
1677 forNode(node
).makeHeapTop();
1678 m_state
.setFoundConstants(true);
1687 for (unsigned i
= node
->multiGetByOffsetData().variants
.size(); i
--;)
1688 set
.addAll(node
->multiGetByOffsetData().variants
[i
].structureSet());
1690 filter(node
->child1(), set
);
1691 forNode(node
).makeHeapTop();
1699 case MultiPutByOffset
: {
1700 AbstractValue
& value
= forNode(node
->child1());
1701 ASSERT(!(value
.m_type
& ~SpecCell
)); // Edge filtering should have already ensured this.
1703 if (Structure
* structure
= value
.bestProvenStructure()) {
1705 for (unsigned i
= node
->multiPutByOffsetData().variants
.size(); i
--;) {
1706 const PutByIdVariant
& variant
= node
->multiPutByOffsetData().variants
[i
];
1707 if (variant
.oldStructure() != structure
)
1710 if (variant
.kind() == PutByIdVariant::Replace
) {
1711 filter(node
->child1(), structure
);
1712 m_state
.setFoundConstants(true);
1713 m_state
.setHaveStructures(true);
1718 ASSERT(variant
.kind() == PutByIdVariant::Transition
);
1719 clobberStructures(clobberLimit
);
1720 forNode(node
->child1()).set(m_graph
, variant
.newStructure());
1721 m_state
.setFoundConstants(true);
1722 m_state
.setHaveStructures(true);
1730 clobberStructures(clobberLimit
);
1732 StructureSet newSet
;
1733 for (unsigned i
= node
->multiPutByOffsetData().variants
.size(); i
--;) {
1734 const PutByIdVariant
& variant
= node
->multiPutByOffsetData().variants
[i
];
1735 if (variant
.kind() == PutByIdVariant::Replace
) {
1736 if (value
.m_currentKnownStructure
.contains(variant
.structure()))
1737 newSet
.addAll(variant
.structure());
1740 ASSERT(variant
.kind() == PutByIdVariant::Transition
);
1741 if (value
.m_currentKnownStructure
.contains(variant
.oldStructure()))
1742 newSet
.addAll(variant
.newStructure());
1745 // Use filter(value, set) as a way of setting the structure set. This works because
1746 // we would have already made the set be TOP before this. Filtering top is another
1748 filter(node
->child1(), newSet
);
1752 case CheckFunction
: {
1753 JSValue value
= forNode(node
->child1()).value();
1754 if (value
== node
->function()) {
1755 m_state
.setFoundConstants(true);
1760 node
->setCanExit(true); // Lies! We can do better.
1761 filterByValue(node
->child1(), node
->function());
1765 case CheckInBounds
: {
1766 JSValue left
= forNode(node
->child1()).value();
1767 JSValue right
= forNode(node
->child2()).value();
1768 if (left
&& right
&& left
.isInt32() && right
.isInt32()
1769 && static_cast<uint32_t>(left
.asInt32()) < static_cast<uint32_t>(right
.asInt32())) {
1770 m_state
.setFoundConstants(true);
1774 node
->setCanExit(true);
1781 node
->setCanExit(true);
1782 if (Structure
* structure
= forNode(node
->child1()).bestProvenStructure()) {
1783 PutByIdStatus status
= PutByIdStatus::computeFor(
1785 m_graph
.globalObjectFor(node
->origin
.semantic
),
1787 m_graph
.identifiers()[node
->identifierNumber()],
1788 node
->op() == PutByIdDirect
);
1789 if (status
.isSimple() && status
.numVariants() == 1) {
1790 if (status
[0].kind() == PutByIdVariant::Replace
) {
1791 filter(node
->child1(), structure
);
1792 m_state
.setFoundConstants(true);
1793 m_state
.setHaveStructures(true);
1796 if (status
[0].kind() == PutByIdVariant::Transition
) {
1797 clobberStructures(clobberLimit
);
1798 forNode(node
->child1()).set(m_graph
, status
[0].newStructure());
1799 m_state
.setHaveStructures(true);
1800 m_state
.setFoundConstants(true);
1805 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1809 // FIXME: We can determine when the property definitely exists based on abstract
1810 // value information.
1811 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1812 forNode(node
).setType(SpecBoolean
);
1816 forNode(node
).makeHeapTop();
1819 case VariableWatchpoint
:
1820 case VarInjectionWatchpoint
:
1821 node
->setCanExit(true);
1828 case CheckHasInstance
:
1829 node
->setCanExit(true);
1830 // Sadly, we don't propagate the fact that we've done CheckHasInstance
1834 node
->setCanExit(true);
1835 // Again, sadly, we don't propagate the fact that we've done InstanceOf
1836 forNode(node
).setType(SpecBoolean
);
1840 RELEASE_ASSERT(m_graph
.m_form
== SSA
);
1841 // The state of this node would have already been decided.
1845 m_state
.createValueForNode(node
->phi());
1846 AbstractValue
& value
= forNode(node
->child1());
1847 forNode(node
) = value
;
1848 forNode(node
->phi()) = value
;
1858 node
->setCanExit(true);
1859 clobberWorld(node
->origin
.semantic
, clobberLimit
);
1860 forNode(node
).makeHeapTop();
1864 node
->setCanExit(true);
1865 m_state
.setIsValid(false);
1868 case InvalidationPoint
:
1869 node
->setCanExit(true);
1872 case CheckWatchdogTimer
:
1873 node
->setCanExit(true);
1877 case ProfileWillCall
:
1878 case ProfileDidCall
:
1882 case CountExecution
:
1883 case CheckTierUpInLoop
:
1884 case CheckTierUpAtReturn
:
1887 case StoreBarrier
: {
1888 filter(node
->child1(), SpecCell
);
1892 case StoreBarrierWithNullCheck
: {
1896 case CheckTierUpAndOSREnter
:
1898 // We pretend that it can exit because it may want to get all state.
1899 node
->setCanExit(true);
1907 RELEASE_ASSERT_NOT_REACHED();
1911 return m_state
.isValid();
1914 template<typename AbstractStateType
>
1915 bool AbstractInterpreter
<AbstractStateType
>::executeEffects(unsigned indexInBlock
)
1917 return executeEffects(indexInBlock
, m_state
.block()->at(indexInBlock
));
1920 template<typename AbstractStateType
>
1921 bool AbstractInterpreter
<AbstractStateType
>::execute(unsigned indexInBlock
)
1923 Node
* node
= m_state
.block()->at(indexInBlock
);
1924 if (!startExecuting(node
))
1928 return executeEffects(indexInBlock
, node
);
1931 template<typename AbstractStateType
>
1932 bool AbstractInterpreter
<AbstractStateType
>::execute(Node
* node
)
1934 if (!startExecuting(node
))
1938 return executeEffects(UINT_MAX
, node
);
1941 template<typename AbstractStateType
>
1942 void AbstractInterpreter
<AbstractStateType
>::clobberWorld(
1943 const CodeOrigin
& codeOrigin
, unsigned clobberLimit
)
1945 clobberCapturedVars(codeOrigin
);
1946 clobberStructures(clobberLimit
);
1949 template<typename AbstractStateType
>
1950 void AbstractInterpreter
<AbstractStateType
>::clobberCapturedVars(const CodeOrigin
& codeOrigin
)
1952 if (codeOrigin
.inlineCallFrame
) {
1953 const BitVector
& capturedVars
= codeOrigin
.inlineCallFrame
->capturedVars
;
1954 for (size_t i
= capturedVars
.size(); i
--;) {
1955 if (!capturedVars
.quickGet(i
))
1957 m_state
.variables().local(i
).makeHeapTop();
1960 for (size_t i
= m_codeBlock
->m_numVars
; i
--;) {
1961 if (m_codeBlock
->isCaptured(virtualRegisterForLocal(i
)))
1962 m_state
.variables().local(i
).makeHeapTop();
1966 for (size_t i
= m_state
.variables().numberOfArguments(); i
--;) {
1967 if (m_codeBlock
->isCaptured(virtualRegisterForArgument(i
)))
1968 m_state
.variables().argument(i
).makeHeapTop();
1972 template<typename AbstractStateType
>
1973 void AbstractInterpreter
<AbstractStateType
>::clobberStructures(unsigned clobberLimit
)
1975 if (!m_state
.haveStructures())
1977 if (clobberLimit
>= m_state
.block()->size())
1978 clobberLimit
= m_state
.block()->size();
1981 ASSERT(clobberLimit
<= m_state
.block()->size());
1982 for (size_t i
= clobberLimit
; i
--;)
1983 forNode(m_state
.block()->at(i
)).clobberStructures();
1984 if (m_graph
.m_form
== SSA
) {
1985 HashSet
<Node
*>::iterator iter
= m_state
.block()->ssa
->liveAtHead
.begin();
1986 HashSet
<Node
*>::iterator end
= m_state
.block()->ssa
->liveAtHead
.end();
1987 for (; iter
!= end
; ++iter
)
1988 forNode(*iter
).clobberStructures();
1990 for (size_t i
= m_state
.variables().numberOfArguments(); i
--;)
1991 m_state
.variables().argument(i
).clobberStructures();
1992 for (size_t i
= m_state
.variables().numberOfLocals(); i
--;)
1993 m_state
.variables().local(i
).clobberStructures();
1994 m_state
.setHaveStructures(true);
1995 m_state
.setDidClobber(true);
1998 template<typename AbstractStateType
>
1999 void AbstractInterpreter
<AbstractStateType
>::dump(PrintStream
& out
)
2001 CommaPrinter
comma(" ");
2002 if (m_graph
.m_form
== SSA
) {
2003 HashSet
<Node
*>::iterator iter
= m_state
.block()->ssa
->liveAtHead
.begin();
2004 HashSet
<Node
*>::iterator end
= m_state
.block()->ssa
->liveAtHead
.end();
2005 for (; iter
!= end
; ++iter
) {
2007 AbstractValue
& value
= forNode(node
);
2008 if (value
.isClear())
2010 out
.print(comma
, node
, ":", value
);
2013 for (size_t i
= 0; i
< m_state
.block()->size(); ++i
) {
2014 Node
* node
= m_state
.block()->at(i
);
2015 AbstractValue
& value
= forNode(node
);
2016 if (value
.isClear())
2018 out
.print(comma
, node
, ":", value
);
2022 template<typename AbstractStateType
>
2023 FiltrationResult AbstractInterpreter
<AbstractStateType
>::filter(
2024 AbstractValue
& value
, const StructureSet
& set
)
2026 if (value
.filter(m_graph
, set
) == FiltrationOK
)
2027 return FiltrationOK
;
2028 m_state
.setIsValid(false);
2029 return Contradiction
;
2032 template<typename AbstractStateType
>
2033 FiltrationResult AbstractInterpreter
<AbstractStateType
>::filterArrayModes(
2034 AbstractValue
& value
, ArrayModes arrayModes
)
2036 if (value
.filterArrayModes(arrayModes
) == FiltrationOK
)
2037 return FiltrationOK
;
2038 m_state
.setIsValid(false);
2039 return Contradiction
;
2042 template<typename AbstractStateType
>
2043 FiltrationResult AbstractInterpreter
<AbstractStateType
>::filter(
2044 AbstractValue
& value
, SpeculatedType type
)
2046 if (value
.filter(type
) == FiltrationOK
)
2047 return FiltrationOK
;
2048 m_state
.setIsValid(false);
2049 return Contradiction
;
2052 template<typename AbstractStateType
>
2053 FiltrationResult AbstractInterpreter
<AbstractStateType
>::filterByValue(
2054 AbstractValue
& abstractValue
, JSValue concreteValue
)
2056 if (abstractValue
.filterByValue(concreteValue
) == FiltrationOK
)
2057 return FiltrationOK
;
2058 m_state
.setIsValid(false);
2059 return Contradiction
;
2062 } } // namespace JSC::DFG
2064 #endif // ENABLE(DFG_JIT)
2066 #endif // DFGAbstractInterpreterInlines_h