2 * Copyright (C) 2013-2015 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 "GetterSetter.h"
34 #include "JITOperations.h"
35 #include "MathCommon.h"
36 #include "Operations.h"
37 #include "PutByIdStatus.h"
38 #include "StringObject.h"
40 namespace JSC { namespace DFG {
42 template<typename AbstractStateType>
43 AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state)
44 : m_codeBlock(graph.m_codeBlock)
48 if (m_graph.m_form == SSA)
49 m_phiChildren = std::make_unique<PhiChildren>(m_graph);
52 template<typename AbstractStateType>
53 AbstractInterpreter<AbstractStateType>::~AbstractInterpreter()
57 template<typename AbstractStateType>
58 typename AbstractInterpreter<AbstractStateType>::BooleanResult
59 AbstractInterpreter<AbstractStateType>::booleanResult(
60 Node* node, AbstractValue& value)
62 JSValue childConst = value.value();
64 if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic)->globalExec()))
65 return DefinitelyTrue;
66 return DefinitelyFalse;
69 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
70 if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
72 for (unsigned i = value.m_structure.size(); i--;) {
73 Structure* structure = value.m_structure[i];
74 if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
75 || structure->typeInfo().type() == StringType) {
81 return DefinitelyTrue;
84 return UnknownBooleanResult;
87 template<typename AbstractStateType>
88 void AbstractInterpreter<AbstractStateType>::startExecuting()
90 ASSERT(m_state.block());
91 ASSERT(m_state.isValid());
93 m_state.setDidClobber(false);
96 template<typename AbstractStateType>
97 void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node)
99 DFG_NODE_DO_TO_CHILDREN(m_graph, node, filterEdgeByUse);
102 template<typename AbstractStateType>
103 void AbstractInterpreter<AbstractStateType>::executeEdges(unsigned indexInBlock)
105 executeEdges(m_state.block()->at(indexInBlock));
108 template<typename AbstractStateType>
109 void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
111 if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())))
114 DFG_CRASH(m_graph, node, toCString("Edge verification error: ", node, "->", edge, " was expected to have type ", SpeculationDump(typeFilterFor(edge.useKind())), " but has type ", SpeculationDump(forNode(edge).m_type), " (", forNode(edge).m_type, ")").data());
117 template<typename AbstractStateType>
118 void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
120 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
123 template<typename AbstractStateType>
124 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
126 if (!ASSERT_DISABLED)
129 m_state.createValueForNode(node);
131 switch (node->op()) {
134 case Int52Constant: {
135 setBuiltInConstant(node, *node->constant());
140 forNode(node) = forNode(node->child1());
141 if (forNode(node).value())
142 m_state.setFoundConstants(true);
146 case ExtractOSREntryLocal: {
147 forNode(node).makeBytecodeTop();
152 VariableAccessData* variableAccessData = node->variableAccessData();
153 AbstractValue value = m_state.variables().operand(variableAccessData->local().offset());
154 // The value in the local should already be checked.
155 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
157 m_state.setFoundConstants(true);
158 forNode(node) = value;
163 StackAccessData* data = node->stackAccessData();
164 AbstractValue value = m_state.variables().operand(data->local);
165 // The value in the local should already be checked.
166 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
168 m_state.setFoundConstants(true);
169 forNode(node) = value;
173 case GetLocalUnlinked: {
174 AbstractValue value = m_state.variables().operand(node->unlinkedLocal().offset());
176 m_state.setFoundConstants(true);
177 forNode(node) = value;
182 m_state.variables().operand(node->local()) = forNode(node->child1());
187 m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1());
192 // Don't need to do anything. A MovHint only informs us about what would have happened
193 // in bytecode, but this code is just concerned with what is actually happening during
199 // This is just a hint telling us that the OSR state of the local is no longer inside the
205 // Assert that the state of arguments has been set. SetArgument means that someone set
206 // the argument values out-of-band, and currently this always means setting to a
208 ASSERT(!m_state.variables().operand(node->local()).isClear());
212 case ForwardVarargs: {
213 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
214 // itself into a straight-line sequence of GetStack/PutStack.
215 // https://bugs.webkit.org/show_bug.cgi?id=143071
216 clobberWorld(node->origin.semantic, clobberLimit);
217 LoadVarargsData* data = node->loadVarargsData();
218 m_state.variables().operand(data->count).setType(SpecInt32);
219 for (unsigned i = data->limit - 1; i--;)
220 m_state.variables().operand(data->start.offset() + i).makeHeapTop();
230 JSValue left = forNode(node->child1()).value();
231 JSValue right = forNode(node->child2()).value();
232 if (left && right && left.isInt32() && right.isInt32()) {
233 int32_t a = left.asInt32();
234 int32_t b = right.asInt32();
235 switch (node->op()) {
237 setConstant(node, JSValue(a & b));
240 setConstant(node, JSValue(a | b));
243 setConstant(node, JSValue(a ^ b));
246 setConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
249 setConstant(node, JSValue(a << static_cast<uint32_t>(b)));
252 setConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
255 RELEASE_ASSERT_NOT_REACHED();
260 forNode(node).setType(SpecInt32);
264 case UInt32ToNumber: {
265 JSValue child = forNode(node->child1()).value();
266 if (doesOverflow(node->arithMode())) {
267 if (child && child.isInt32()) {
268 uint32_t value = child.asInt32();
269 setConstant(node, jsNumber(value));
272 forNode(node).setType(SpecInt52AsDouble);
275 if (child && child.isInt32()) {
276 int32_t value = child.asInt32();
278 setConstant(node, jsNumber(value));
282 forNode(node).setType(SpecInt32);
286 case BooleanToNumber: {
287 JSValue concreteValue = forNode(node->child1()).value();
289 if (concreteValue.isBoolean())
290 setConstant(node, jsNumber(concreteValue.asBoolean()));
292 setConstant(node, *m_graph.freeze(concreteValue));
295 AbstractValue& value = forNode(node);
296 value = forNode(node->child1());
297 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
298 m_state.setFoundConstants(true);
299 if (value.m_type & SpecBoolean) {
300 value.merge(SpecInt32);
301 value.filter(~SpecBoolean);
306 case DoubleAsInt32: {
307 JSValue child = forNode(node->child1()).value();
308 if (child && child.isNumber()) {
309 double asDouble = child.asNumber();
310 int32_t asInt = JSC::toInt32(asDouble);
311 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
312 setConstant(node, JSValue(asInt));
316 forNode(node).setType(SpecInt32);
321 JSValue child = forNode(node->child1()).value();
323 if (child.isNumber()) {
325 setConstant(node, child);
327 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
330 if (child.isBoolean()) {
331 setConstant(node, jsNumber(child.asBoolean()));
334 if (child.isUndefinedOrNull()) {
335 setConstant(node, jsNumber(0));
340 forNode(node).setType(SpecInt32);
345 JSValue child = forNode(node->child1()).value();
346 if (child && child.isNumber()) {
347 setConstant(node, jsDoubleNumber(child.asNumber()));
350 forNode(node).setType(m_graph, forNode(node->child1()).m_type);
351 forNode(node).fixTypeForRepresentation(node);
356 JSValue child = forNode(node->child1()).value();
357 if (child && child.isMachineInt()) {
358 setConstant(node, child);
362 forNode(node).setType(SpecInt32);
367 JSValue value = forNode(node->child1()).value();
369 setConstant(node, value);
373 forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
374 forNode(node).fixTypeForRepresentation(node);
379 ASSERT(node->binaryUseKind() == UntypedUse);
380 clobberWorld(node->origin.semantic, clobberLimit);
381 forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber);
386 JSValue left = forNode(node->child1()).value();
387 JSValue right = forNode(node->child2()).value();
388 switch (node->binaryUseKind()) {
390 if (left && right && left.isInt32() && right.isInt32()) {
391 if (!shouldCheckOverflow(node->arithMode())) {
392 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
395 JSValue result = jsNumber(left.asNumber() + right.asNumber());
396 if (result.isInt32()) {
397 setConstant(node, result);
401 forNode(node).setType(SpecInt32);
404 if (left && right && left.isMachineInt() && right.isMachineInt()) {
405 JSValue result = jsNumber(left.asMachineInt() + right.asMachineInt());
406 if (result.isMachineInt()) {
407 setConstant(node, result);
411 forNode(node).setType(SpecMachineInt);
414 if (left && right && left.isNumber() && right.isNumber()) {
415 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
418 forNode(node).setType(
420 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
423 RELEASE_ASSERT_NOT_REACHED();
430 JSValue operand = forNode(node->child1()).value();
431 if (operand && operand.isNumber()) {
432 uint32_t value = toUInt32(operand.asNumber());
433 setConstant(node, jsNumber(clz32(value)));
436 forNode(node).setType(SpecInt32);
441 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
446 JSValue left = forNode(node->child1()).value();
447 JSValue right = forNode(node->child2()).value();
448 switch (node->binaryUseKind()) {
450 if (left && right && left.isInt32() && right.isInt32()) {
451 if (!shouldCheckOverflow(node->arithMode())) {
452 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
455 JSValue result = jsNumber(left.asNumber() - right.asNumber());
456 if (result.isInt32()) {
457 setConstant(node, result);
461 forNode(node).setType(SpecInt32);
464 if (left && right && left.isMachineInt() && right.isMachineInt()) {
465 JSValue result = jsNumber(left.asMachineInt() - right.asMachineInt());
466 if (result.isMachineInt() || !shouldCheckOverflow(node->arithMode())) {
467 setConstant(node, result);
471 forNode(node).setType(SpecMachineInt);
474 if (left && right && left.isNumber() && right.isNumber()) {
475 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
478 forNode(node).setType(
479 typeOfDoubleDifference(
480 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
483 RELEASE_ASSERT_NOT_REACHED();
490 JSValue child = forNode(node->child1()).value();
491 switch (node->child1().useKind()) {
493 if (child && child.isInt32()) {
494 if (!shouldCheckOverflow(node->arithMode())) {
495 setConstant(node, jsNumber(-child.asInt32()));
499 if (shouldCheckNegativeZero(node->arithMode()))
500 doubleResult = -child.asNumber();
502 doubleResult = 0 - child.asNumber();
503 JSValue valueResult = jsNumber(doubleResult);
504 if (valueResult.isInt32()) {
505 setConstant(node, valueResult);
509 forNode(node).setType(SpecInt32);
512 if (child && child.isMachineInt()) {
514 if (shouldCheckNegativeZero(node->arithMode()))
515 doubleResult = -child.asNumber();
517 doubleResult = 0 - child.asNumber();
518 JSValue valueResult = jsNumber(doubleResult);
519 if (valueResult.isMachineInt()) {
520 setConstant(node, valueResult);
524 forNode(node).setType(SpecMachineInt);
527 if (child && child.isNumber()) {
528 setConstant(node, jsDoubleNumber(-child.asNumber()));
531 forNode(node).setType(
532 typeOfDoubleNegation(
533 forNode(node->child1()).m_type));
536 RELEASE_ASSERT_NOT_REACHED();
543 JSValue left = forNode(node->child1()).value();
544 JSValue right = forNode(node->child2()).value();
545 switch (node->binaryUseKind()) {
547 if (left && right && left.isInt32() && right.isInt32()) {
548 if (!shouldCheckOverflow(node->arithMode())) {
549 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
552 double doubleResult = left.asNumber() * right.asNumber();
553 if (!shouldCheckNegativeZero(node->arithMode()))
554 doubleResult += 0; // Sanitizes zero.
555 JSValue valueResult = jsNumber(doubleResult);
556 if (valueResult.isInt32()) {
557 setConstant(node, valueResult);
561 forNode(node).setType(SpecInt32);
564 if (left && right && left.isMachineInt() && right.isMachineInt()) {
565 double doubleResult = left.asNumber() * right.asNumber();
566 if (!shouldCheckNegativeZero(node->arithMode()))
568 JSValue valueResult = jsNumber(doubleResult);
569 if (valueResult.isMachineInt()) {
570 setConstant(node, valueResult);
574 forNode(node).setType(SpecMachineInt);
577 if (left && right && left.isNumber() && right.isNumber()) {
578 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
581 forNode(node).setType(
583 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
586 RELEASE_ASSERT_NOT_REACHED();
593 JSValue left = forNode(node->child1()).value();
594 JSValue right = forNode(node->child2()).value();
595 switch (node->binaryUseKind()) {
597 if (left && right && left.isInt32() && right.isInt32()) {
598 double doubleResult = left.asNumber() / right.asNumber();
599 if (!shouldCheckOverflow(node->arithMode()))
600 doubleResult = toInt32(doubleResult);
601 else if (!shouldCheckNegativeZero(node->arithMode()))
602 doubleResult += 0; // Sanitizes zero.
603 JSValue valueResult = jsNumber(doubleResult);
604 if (valueResult.isInt32()) {
605 setConstant(node, valueResult);
609 forNode(node).setType(SpecInt32);
612 if (left && right && left.isNumber() && right.isNumber()) {
613 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
616 forNode(node).setType(
617 typeOfDoubleQuotient(
618 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
621 RELEASE_ASSERT_NOT_REACHED();
628 JSValue left = forNode(node->child1()).value();
629 JSValue right = forNode(node->child2()).value();
630 switch (node->binaryUseKind()) {
632 if (left && right && left.isInt32() && right.isInt32()) {
633 double doubleResult = fmod(left.asNumber(), right.asNumber());
634 if (!shouldCheckOverflow(node->arithMode()))
635 doubleResult = toInt32(doubleResult);
636 else if (!shouldCheckNegativeZero(node->arithMode()))
637 doubleResult += 0; // Sanitizes zero.
638 JSValue valueResult = jsNumber(doubleResult);
639 if (valueResult.isInt32()) {
640 setConstant(node, valueResult);
644 forNode(node).setType(SpecInt32);
647 if (left && right && left.isNumber() && right.isNumber()) {
648 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
651 forNode(node).setType(
652 typeOfDoubleBinaryOp(
653 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
656 RELEASE_ASSERT_NOT_REACHED();
663 JSValue left = forNode(node->child1()).value();
664 JSValue right = forNode(node->child2()).value();
665 switch (node->binaryUseKind()) {
667 if (left && right && left.isInt32() && right.isInt32()) {
668 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
671 forNode(node).setType(SpecInt32);
674 if (left && right && left.isNumber() && right.isNumber()) {
675 double a = left.asNumber();
676 double b = right.asNumber();
677 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
680 forNode(node).setType(
682 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
685 RELEASE_ASSERT_NOT_REACHED();
692 JSValue left = forNode(node->child1()).value();
693 JSValue right = forNode(node->child2()).value();
694 switch (node->binaryUseKind()) {
696 if (left && right && left.isInt32() && right.isInt32()) {
697 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
700 forNode(node).setType(SpecInt32);
703 if (left && right && left.isNumber() && right.isNumber()) {
704 double a = left.asNumber();
705 double b = right.asNumber();
706 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
709 forNode(node).setType(
711 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
714 RELEASE_ASSERT_NOT_REACHED();
721 JSValue child = forNode(node->child1()).value();
722 switch (node->child1().useKind()) {
724 if (child && child.isInt32()) {
725 JSValue result = jsNumber(fabs(child.asNumber()));
726 if (result.isInt32()) {
727 setConstant(node, result);
731 forNode(node).setType(SpecInt32);
734 if (child && child.isNumber()) {
735 setConstant(node, jsDoubleNumber(child.asNumber()));
738 forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
741 RELEASE_ASSERT_NOT_REACHED();
748 JSValue childY = forNode(node->child2()).value();
749 if (childY && childY.isNumber()) {
750 if (!childY.asNumber()) {
751 setConstant(node, jsDoubleNumber(1));
755 JSValue childX = forNode(node->child1()).value();
756 if (childX && childX.isNumber()) {
757 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
761 forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
766 JSValue child = forNode(node->child1()).value();
767 if (child && child.isNumber()) {
768 setConstant(node, jsDoubleNumber(sqrt(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(static_cast<float>(child.asNumber())));
781 forNode(node).setType(typeOfDoubleFRound(forNode(node->child1()).m_type));
786 JSValue child = forNode(node->child1()).value();
787 if (false && child && child.isNumber()) {
788 setConstant(node, jsDoubleNumber(sin(child.asNumber())));
791 forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type));
796 JSValue child = forNode(node->child1()).value();
797 if (false && child && child.isNumber()) {
798 setConstant(node, jsDoubleNumber(cos(child.asNumber())));
801 forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type));
806 JSValue child = forNode(node->child1()).value();
807 if (child && child.isNumber()) {
808 setConstant(node, jsDoubleNumber(log(child.asNumber())));
811 forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type));
816 switch (booleanResult(node, forNode(node->child1()))) {
818 setConstant(node, jsBoolean(false));
820 case DefinitelyFalse:
821 setConstant(node, jsBoolean(true));
824 forNode(node).setType(SpecBoolean);
837 AbstractValue child = forNode(node->child1());
839 bool constantWasSet = true;
840 switch (node->op()) {
842 setConstant(node, jsBoolean(
843 child.value().isCell()
844 ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
845 : child.value().isUndefined()));
848 setConstant(node, jsBoolean(child.value().isBoolean()));
851 setConstant(node, jsBoolean(child.value().isNumber()));
854 setConstant(node, jsBoolean(isJSString(child.value())));
857 setConstant(node, jsBoolean(child.value().isObject()));
860 if (child.value().isObject()) {
861 JSObject* object = asObject(child.value());
862 if (object->type() == JSFunctionType)
863 setConstant(node, jsBoolean(false));
864 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
865 setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
867 // FIXME: This could just call getCallData.
868 // https://bugs.webkit.org/show_bug.cgi?id=144457
869 constantWasSet = false;
872 setConstant(node, jsBoolean(child.value().isNull()));
875 if (child.value().isObject()) {
876 JSObject* object = asObject(child.value());
877 if (object->type() == JSFunctionType)
878 setConstant(node, jsBoolean(true));
879 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
880 setConstant(node, jsBoolean(false));
882 // FIXME: This could just call getCallData.
883 // https://bugs.webkit.org/show_bug.cgi?id=144457
884 constantWasSet = false;
887 setConstant(node, jsBoolean(false));
890 constantWasSet = false;
897 bool constantWasSet = false;
898 switch (node->op()) {
900 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
901 // https://bugs.webkit.org/show_bug.cgi?id=144456
903 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
904 setConstant(node, jsBoolean(false));
905 constantWasSet = true;
911 if (!(child.m_type & ~SpecBoolean)) {
912 setConstant(node, jsBoolean(true));
913 constantWasSet = true;
917 if (!(child.m_type & SpecBoolean)) {
918 setConstant(node, jsBoolean(false));
919 constantWasSet = true;
925 if (!(child.m_type & ~SpecFullNumber)) {
926 setConstant(node, jsBoolean(true));
927 constantWasSet = true;
931 if (!(child.m_type & SpecFullNumber)) {
932 setConstant(node, jsBoolean(false));
933 constantWasSet = true;
939 if (!(child.m_type & ~SpecString)) {
940 setConstant(node, jsBoolean(true));
941 constantWasSet = true;
945 if (!(child.m_type & SpecString)) {
946 setConstant(node, jsBoolean(false));
947 constantWasSet = true;
953 if (!(child.m_type & ~SpecObject)) {
954 setConstant(node, jsBoolean(true));
955 constantWasSet = true;
959 if (!(child.m_type & SpecObject)) {
960 setConstant(node, jsBoolean(false));
961 constantWasSet = true;
967 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
968 // https://bugs.webkit.org/show_bug.cgi?id=144456
970 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
971 setConstant(node, jsBoolean(true));
972 constantWasSet = true;
976 if (!(child.m_type & (SpecObject - SpecFunction))) {
977 setConstant(node, jsBoolean(false));
978 constantWasSet = true;
984 if (!(child.m_type & ~SpecFunction)) {
985 setConstant(node, jsBoolean(true));
986 constantWasSet = true;
990 if (!(child.m_type & (SpecFunction | SpecObjectOther))) {
991 setConstant(node, jsBoolean(false));
992 constantWasSet = true;
1002 forNode(node).setType(SpecBoolean);
1007 VM* vm = m_codeBlock->vm();
1008 JSValue child = forNode(node->child1()).value();
1009 AbstractValue& abstractChild = forNode(node->child1());
1011 JSValue typeString = jsTypeStringForValue(*vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1012 setConstant(node, *m_graph.freeze(typeString));
1016 if (isFullNumberSpeculation(abstractChild.m_type)) {
1017 setConstant(node, *m_graph.freeze(vm->smallStrings.numberString()));
1021 if (isStringSpeculation(abstractChild.m_type)) {
1022 setConstant(node, *m_graph.freeze(vm->smallStrings.stringString()));
1026 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1027 // https://bugs.webkit.org/show_bug.cgi?id=144456
1028 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther))) {
1029 setConstant(node, *m_graph.freeze(vm->smallStrings.objectString()));
1033 if (isFunctionSpeculation(abstractChild.m_type)) {
1034 setConstant(node, *m_graph.freeze(vm->smallStrings.functionString()));
1038 if (isBooleanSpeculation(abstractChild.m_type)) {
1039 setConstant(node, *m_graph.freeze(vm->smallStrings.booleanString()));
1043 forNode(node).setType(m_graph, SpecStringIdent);
1049 case CompareGreater:
1050 case CompareGreaterEq:
1052 case CompareEqConstant: {
1053 JSValue leftConst = forNode(node->child1()).value();
1054 JSValue rightConst = forNode(node->child2()).value();
1055 if (leftConst && rightConst) {
1056 if (leftConst.isNumber() && rightConst.isNumber()) {
1057 double a = leftConst.asNumber();
1058 double b = rightConst.asNumber();
1059 switch (node->op()) {
1061 setConstant(node, jsBoolean(a < b));
1064 setConstant(node, jsBoolean(a <= b));
1066 case CompareGreater:
1067 setConstant(node, jsBoolean(a > b));
1069 case CompareGreaterEq:
1070 setConstant(node, jsBoolean(a >= b));
1073 setConstant(node, jsBoolean(a == b));
1076 RELEASE_ASSERT_NOT_REACHED();
1082 if (node->op() == CompareEq && leftConst.isString() && rightConst.isString()) {
1083 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1084 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1086 setConstant(node, jsBoolean(WTF::equal(a, b)));
1092 if (node->op() == CompareEqConstant || node->op() == CompareEq) {
1093 SpeculatedType leftType = forNode(node->child1()).m_type;
1094 SpeculatedType rightType = forNode(node->child2()).m_type;
1095 if (!valuesCouldBeEqual(leftType, rightType)) {
1096 setConstant(node, jsBoolean(false));
1101 forNode(node).setType(SpecBoolean);
1105 case CompareStrictEq: {
1106 Node* leftNode = node->child1().node();
1107 Node* rightNode = node->child2().node();
1108 JSValue left = forNode(leftNode).value();
1109 JSValue right = forNode(rightNode).value();
1110 if (left && right) {
1111 if (left.isString() && right.isString()) {
1112 // We need this case because JSValue::strictEqual is otherwise too racy for
1113 // string comparisons.
1114 const StringImpl* a = asString(left)->tryGetValueImpl();
1115 const StringImpl* b = asString(right)->tryGetValueImpl();
1117 setConstant(node, jsBoolean(WTF::equal(a, b)));
1121 setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
1126 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1127 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1128 if (!(leftLUB & rightLUB)) {
1129 setConstant(node, jsBoolean(false));
1133 forNode(node).setType(SpecBoolean);
1137 case StringCharCodeAt:
1138 forNode(node).setType(SpecInt32);
1141 case StringFromCharCode:
1142 forNode(node).setType(m_graph, SpecString);
1146 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
1150 switch (node->arrayMode().type()) {
1151 case Array::SelectUsingPredictions:
1152 case Array::Unprofiled:
1153 case Array::Undecided:
1154 RELEASE_ASSERT_NOT_REACHED();
1156 case Array::ForceExit:
1157 m_state.setIsValid(false);
1159 case Array::Generic:
1160 clobberWorld(node->origin.semantic, clobberLimit);
1161 forNode(node).makeHeapTop();
1164 if (node->arrayMode().isOutOfBounds()) {
1165 // If the watchpoint was still valid we could totally set this to be
1166 // SpecString | SpecOther. Except that we'd have to be careful. If we
1167 // tested the watchpoint state here then it could change by the time
1168 // we got to the backend. So to do this right, we'd have to get the
1169 // fixup phase to check the watchpoint state and then bake into the
1170 // GetByVal operation the fact that we're using a watchpoint, using
1171 // something like Array::SaneChain (except not quite, because that
1172 // implies an in-bounds access). None of this feels like it's worth it,
1173 // so we're going with TOP for now. The same thing applies to
1174 // clobbering the world.
1175 clobberWorld(node->origin.semantic, clobberLimit);
1176 forNode(node).makeHeapTop();
1178 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
1180 case Array::DirectArguments:
1181 case Array::ScopedArguments:
1182 forNode(node).makeHeapTop();
1185 if (node->arrayMode().isOutOfBounds()) {
1186 clobberWorld(node->origin.semantic, clobberLimit);
1187 forNode(node).makeHeapTop();
1189 forNode(node).setType(SpecInt32);
1192 if (node->arrayMode().isOutOfBounds()) {
1193 clobberWorld(node->origin.semantic, clobberLimit);
1194 forNode(node).makeHeapTop();
1195 } else if (node->arrayMode().isSaneChain())
1196 forNode(node).setType(SpecBytecodeDouble);
1198 forNode(node).setType(SpecDoubleReal);
1200 case Array::Contiguous:
1201 case Array::ArrayStorage:
1202 case Array::SlowPutArrayStorage:
1203 if (node->arrayMode().isOutOfBounds())
1204 clobberWorld(node->origin.semantic, clobberLimit);
1205 forNode(node).makeHeapTop();
1207 case Array::Int8Array:
1208 forNode(node).setType(SpecInt32);
1210 case Array::Int16Array:
1211 forNode(node).setType(SpecInt32);
1213 case Array::Int32Array:
1214 forNode(node).setType(SpecInt32);
1216 case Array::Uint8Array:
1217 forNode(node).setType(SpecInt32);
1219 case Array::Uint8ClampedArray:
1220 forNode(node).setType(SpecInt32);
1222 case Array::Uint16Array:
1223 forNode(node).setType(SpecInt32);
1225 case Array::Uint32Array:
1226 if (node->shouldSpeculateInt32())
1227 forNode(node).setType(SpecInt32);
1228 else if (enableInt52() && node->shouldSpeculateMachineInt())
1229 forNode(node).setType(SpecInt52);
1231 forNode(node).setType(SpecInt52AsDouble);
1233 case Array::Float32Array:
1234 forNode(node).setType(SpecFullDouble);
1236 case Array::Float64Array:
1237 forNode(node).setType(SpecFullDouble);
1240 RELEASE_ASSERT_NOT_REACHED();
1246 case PutByValDirect:
1248 case PutByValAlias: {
1249 switch (node->arrayMode().modeForPut().type()) {
1250 case Array::ForceExit:
1251 m_state.setIsValid(false);
1253 case Array::Generic:
1254 clobberWorld(node->origin.semantic, clobberLimit);
1257 if (node->arrayMode().isOutOfBounds())
1258 clobberWorld(node->origin.semantic, clobberLimit);
1261 if (node->arrayMode().isOutOfBounds())
1262 clobberWorld(node->origin.semantic, clobberLimit);
1264 case Array::Contiguous:
1265 case Array::ArrayStorage:
1266 if (node->arrayMode().isOutOfBounds())
1267 clobberWorld(node->origin.semantic, clobberLimit);
1269 case Array::SlowPutArrayStorage:
1270 if (node->arrayMode().mayStoreToHole())
1271 clobberWorld(node->origin.semantic, clobberLimit);
1280 clobberWorld(node->origin.semantic, clobberLimit);
1281 forNode(node).setType(SpecBytecodeNumber);
1285 clobberWorld(node->origin.semantic, clobberLimit);
1286 forNode(node).makeHeapTop();
1289 case GetMyArgumentByVal: {
1290 JSValue index = forNode(node->child2()).m_value;
1291 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame;
1293 if (index && index.isInt32()) {
1294 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
1295 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
1296 // paths as unreachable, and it's almost certainly not worth the effort.
1298 if (inlineCallFrame) {
1299 if (index.asUInt32() < inlineCallFrame->arguments.size() - 1) {
1300 forNode(node) = m_state.variables().operand(
1301 virtualRegisterForArgument(index.asInt32() + 1) + inlineCallFrame->stackOffset);
1302 m_state.setFoundConstants(true);
1306 if (index.asUInt32() < m_state.variables().numberOfArguments() - 1) {
1307 forNode(node) = m_state.variables().argument(index.asInt32() + 1);
1308 m_state.setFoundConstants(true);
1314 if (inlineCallFrame) {
1315 // We have a bound on the types even though it's random access. Take advantage of this.
1317 AbstractValue result;
1318 for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;) {
1320 m_state.variables().operand(
1321 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
1325 m_state.setFoundConstants(true);
1326 forNode(node) = result;
1330 forNode(node).makeHeapTop();
1335 forNode(node).makeHeapTop();
1339 forNode(node).setType(SpecBoolean);
1346 Node* child = node->child1().node();
1347 BooleanResult result = booleanResult(node, forNode(child));
1348 if (result == DefinitelyTrue) {
1349 m_state.setBranchDirection(TakeTrue);
1352 if (result == DefinitelyFalse) {
1353 m_state.setBranchDirection(TakeFalse);
1356 // FIXME: The above handles the trivial cases of sparse conditional
1357 // constant propagation, but we can do better:
1358 // We can specialize the source variable's value on each direction of
1360 m_state.setBranchDirection(TakeBoth);
1365 // Nothing to do for now.
1366 // FIXME: Do sparse conditional things.
1371 m_state.setIsValid(false);
1375 case ThrowReferenceError:
1376 m_state.setIsValid(false);
1380 JSValue childConst = forNode(node->child1()).value();
1381 if (childConst && childConst.isNumber()) {
1382 setConstant(node, childConst);
1386 ASSERT(node->child1().useKind() == UntypedUse);
1388 if (!forNode(node->child1()).m_type) {
1389 m_state.setIsValid(false);
1393 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecCellOther))) {
1394 m_state.setFoundConstants(true);
1395 forNode(node) = forNode(node->child1());
1399 clobberWorld(node->origin.semantic, clobberLimit);
1401 forNode(node).setType(m_graph, (SpecHeapTop & ~SpecCell) | SpecString | SpecCellOther);
1406 case CallStringConstructor: {
1407 switch (node->child1().useKind()) {
1408 case StringObjectUse:
1409 // This also filters that the StringObject has the primordial StringObject
1413 m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure());
1415 case StringOrStringObjectUse:
1419 clobberWorld(node->origin.semantic, clobberLimit);
1422 RELEASE_ASSERT_NOT_REACHED();
1425 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
1429 case NewStringObject: {
1430 ASSERT(node->structure()->classInfo() == StringObject::info());
1431 forNode(node).set(m_graph, node->structure());
1438 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
1441 case NewArrayBuffer:
1444 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
1447 case NewArrayWithSize:
1448 forNode(node).setType(m_graph, SpecArray);
1452 switch (node->child1().useKind()) {
1456 clobberWorld(node->origin.semantic, clobberLimit);
1459 RELEASE_ASSERT_NOT_REACHED();
1464 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructure(
1465 node->typedArrayType()));
1469 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
1473 AbstractValue& source = forNode(node->child1());
1474 AbstractValue& destination = forNode(node);
1476 if (m_graph.executableFor(node->origin.semantic)->isStrictMode())
1477 destination.makeHeapTop();
1479 destination = source;
1480 destination.merge(SpecObject);
1486 // FIXME: We can fold this to NewObject if the incoming callee is a constant.
1487 forNode(node).setType(m_graph, SpecFinalObject);
1492 ASSERT(node->structure());
1493 forNode(node).set(m_graph, node->structure());
1496 case PhantomNewObject:
1497 case PhantomNewFunction:
1498 case PhantomDirectArguments:
1499 case PhantomClonedArguments:
1501 m_state.setDidClobber(true); // Prevent constant folding.
1502 // This claims to return bottom.
1508 case MaterializeNewObject: {
1511 m_phiChildren->forAllTransitiveIncomingValues(
1512 m_graph.varArgChild(node, 0).node(),
1513 [&] (Node* incoming) {
1514 set.add(incoming->castConstant<Structure*>());
1517 forNode(node).set(m_graph, set);
1521 case CreateActivation:
1523 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
1526 case CreateDirectArguments:
1527 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
1530 case CreateScopedArguments:
1531 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
1534 case CreateClonedArguments:
1535 forNode(node).setType(m_graph, SpecObjectOther);
1540 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure());
1544 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_codeBlock->ownerExecutable())) {
1545 InferredValue* singleton = executable->singletonFunction();
1546 if (JSValue value = singleton->inferredValue()) {
1547 m_graph.watchpoints().addLazily(singleton);
1548 JSFunction* function = jsCast<JSFunction*>(value);
1549 setConstant(node, *m_graph.freeze(function));
1553 forNode(node).setType(m_graph, SpecFunction);
1556 case GetArgumentCount:
1557 forNode(node).setType(SpecInt32);
1561 JSValue base = forNode(node->child1()).m_value;
1563 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
1564 if (!getterSetter->isGetterNull()) {
1565 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
1570 forNode(node).setType(m_graph, SpecObject);
1575 JSValue base = forNode(node->child1()).m_value;
1577 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
1578 if (!getterSetter->isSetterNull()) {
1579 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
1584 forNode(node).setType(m_graph, SpecObject);
1589 if (JSValue base = forNode(node->child1()).m_value) {
1590 if (JSFunction* function = jsDynamicCast<JSFunction*>(base)) {
1591 setConstant(node, *m_graph.freeze(function->scope()));
1595 forNode(node).setType(m_graph, SpecObjectOther);
1599 JSValue child = forNode(node->child1()).value();
1601 setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next())));
1604 forNode(node).setType(m_graph, SpecObjectOther);
1609 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
1610 setConstant(node, *m_graph.freeze(value));
1613 forNode(node).makeHeapTop();
1619 case GetFromArguments:
1620 forNode(node).makeHeapTop();
1623 case PutToArguments:
1627 case GetByIdFlush: {
1628 if (!node->prediction()) {
1629 m_state.setIsValid(false);
1633 AbstractValue& value = forNode(node->child1());
1634 if (!value.m_structure.isTop() && !value.m_structure.isClobbered()
1635 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
1636 GetByIdStatus status = GetByIdStatus::computeFor(
1637 value.m_structure.set(), m_graph.identifiers()[node->identifierNumber()]);
1638 if (status.isSimple()) {
1639 // Figure out what the result is going to be - is it TOP, a constant, or maybe
1640 // something more subtle?
1641 AbstractValue result;
1642 for (unsigned i = status.numVariants(); i--;) {
1643 DFG_ASSERT(m_graph, node, !status[i].alternateBase());
1644 JSValue constantResult =
1645 m_graph.tryGetConstantProperty(value, status[i].offset());
1646 if (!constantResult) {
1647 result.makeHeapTop();
1651 AbstractValue thisResult;
1653 m_graph, *m_graph.freeze(constantResult),
1654 m_state.structureClobberState());
1655 result.merge(thisResult);
1657 if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
1658 m_state.setFoundConstants(true);
1659 forNode(node) = result;
1664 clobberWorld(node->origin.semantic, clobberLimit);
1665 forNode(node).makeHeapTop();
1669 case GetArrayLength: {
1670 JSArrayBufferView* view = m_graph.tryGetFoldableView(
1671 forNode(node->child1()).m_value, node->arrayMode());
1673 setConstant(node, jsNumber(view->length()));
1676 forNode(node).setType(SpecInt32);
1680 case CheckStructure: {
1681 AbstractValue& value = forNode(node->child1());
1682 ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this.
1684 StructureSet& set = node->structureSet();
1686 // It's interesting that we could have proven that the object has a larger structure set
1687 // that includes the set we're testing. In that case we could make the structure check
1688 // more efficient. We currently don't.
1690 if (value.m_structure.isSubsetOf(set)) {
1691 m_state.setFoundConstants(true);
1699 case CheckStructureImmediate: {
1700 // FIXME: This currently can only reason about one structure at a time.
1701 // https://bugs.webkit.org/show_bug.cgi?id=136988
1703 AbstractValue& value = forNode(node->child1());
1704 StructureSet& set = node->structureSet();
1706 if (value.value()) {
1707 if (Structure* structure = jsDynamicCast<Structure*>(value.value())) {
1708 if (set.contains(structure)) {
1709 m_state.setFoundConstants(true);
1713 m_state.setIsValid(false);
1717 if (m_phiChildren) {
1718 bool allGood = true;
1719 m_phiChildren->forAllTransitiveIncomingValues(
1721 [&] (Node* incoming) {
1722 if (Structure* structure = incoming->dynamicCastConstant<Structure*>()) {
1723 if (set.contains(structure))
1729 m_state.setFoundConstants(true);
1734 if (Structure* structure = set.onlyStructure()) {
1735 filterByValue(node->child1(), *m_graph.freeze(structure));
1739 // Aw shucks, we can't do anything!
1744 if (!forNode(node->child1()).m_structure.isClear()) {
1745 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
1746 m_state.setFoundConstants(true);
1749 clobberLimit, node->transition()->previous, node->transition()->next);
1750 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
1755 case AllocatePropertyStorage:
1756 case ReallocatePropertyStorage:
1757 forNode(node).clear(); // The result is not a JS value.
1760 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
1761 m_state.setFoundConstants(true);
1764 switch (node->arrayMode().type()) {
1766 filter(node->child1(), SpecString);
1770 case Array::Contiguous:
1771 case Array::ArrayStorage:
1772 case Array::SlowPutArrayStorage:
1774 case Array::DirectArguments:
1775 filter(node->child1(), SpecDirectArguments);
1777 case Array::ScopedArguments:
1778 filter(node->child1(), SpecScopedArguments);
1780 case Array::Int8Array:
1781 filter(node->child1(), SpecInt8Array);
1783 case Array::Int16Array:
1784 filter(node->child1(), SpecInt16Array);
1786 case Array::Int32Array:
1787 filter(node->child1(), SpecInt32Array);
1789 case Array::Uint8Array:
1790 filter(node->child1(), SpecUint8Array);
1792 case Array::Uint8ClampedArray:
1793 filter(node->child1(), SpecUint8ClampedArray);
1795 case Array::Uint16Array:
1796 filter(node->child1(), SpecUint16Array);
1798 case Array::Uint32Array:
1799 filter(node->child1(), SpecUint32Array);
1801 case Array::Float32Array:
1802 filter(node->child1(), SpecFloat32Array);
1804 case Array::Float64Array:
1805 filter(node->child1(), SpecFloat64Array);
1808 RELEASE_ASSERT_NOT_REACHED();
1811 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
1815 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
1816 m_state.setFoundConstants(true);
1819 ASSERT(node->arrayMode().conversion() == Array::Convert);
1820 clobberStructures(clobberLimit);
1821 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
1824 case ArrayifyToStructure: {
1825 AbstractValue& value = forNode(node->child1());
1826 if (value.m_structure.isSubsetOf(StructureSet(node->structure())))
1827 m_state.setFoundConstants(true);
1828 clobberStructures(clobberLimit);
1830 // We have a bunch of options of how to express the abstract set at this point. Let set S
1831 // be the set of structures that the value had before clobbering and assume that all of
1832 // them are watchable. The new value should be the least expressible upper bound of the
1833 // intersection of "values that currently have structure = node->structure()" and "values
1834 // that have structure in S plus any structure transition-reachable from S". Assume that
1835 // node->structure() is not in S but it is transition-reachable from S. Then we would
1836 // like to say that the result is "values that have structure = node->structure() until
1837 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
1838 // we must choose between:
1840 // 1) "values that currently have structure = node->structure()". This is a valid
1841 // superset of the value that we really want, and it's specific enough to satisfy the
1842 // preconditions of the array access that this is guarding. It's also specific enough
1843 // to allow relevant optimizations in the case that we didn't have a contradiction
1844 // like in this example. Notice that in the abscence of any contradiction, this result
1845 // is precise rather than being a conservative LUB.
1847 // 2) "values that currently hava structure in S plus any structure transition-reachable
1848 // from S". This is also a valid superset of the value that we really want, but it's
1849 // not specific enough to satisfy the preconditions of the array access that this is
1850 // guarding - so playing such shenanigans would preclude us from having assertions on
1851 // the typing preconditions of any array accesses. This would also not be a desirable
1852 // answer in the absence of a contradiction.
1854 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
1855 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
1857 value.set(m_graph, node->structure());
1860 case GetIndexedPropertyStorage: {
1861 JSArrayBufferView* view = m_graph.tryGetFoldableView(
1862 forNode(node->child1()).m_value, node->arrayMode());
1864 m_state.setFoundConstants(true);
1865 forNode(node).clear();
1868 case ConstantStoragePointer: {
1869 forNode(node).clear();
1873 case GetTypedArrayByteOffset: {
1874 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
1876 setConstant(node, jsNumber(view->byteOffset()));
1879 forNode(node).setType(SpecInt32);
1884 StorageAccessData& data = node->storageAccessData();
1885 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
1887 setConstant(node, *m_graph.freeze(result));
1891 forNode(node).makeHeapTop();
1895 case GetGetterSetterByOffset: {
1896 StorageAccessData& data = node->storageAccessData();
1897 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
1898 if (result && jsDynamicCast<GetterSetter*>(result)) {
1899 setConstant(node, *m_graph.freeze(result));
1903 forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get());
1907 case MultiGetByOffset: {
1908 // This code will filter the base value in a manner that is possibly different (either more
1909 // or less precise) than the way it would be filtered if this was strength-reduced to a
1910 // CheckStructure. This is fine. It's legal for different passes over the code to prove
1911 // different things about the code, so long as all of them are sound. That even includes
1912 // one guy proving that code should never execute (due to a contradiction) and another guy
1913 // not finding that contradiction. If someone ever proved that there would be a
1914 // contradiction then there must always be a contradiction even if subsequent passes don't
1915 // realize it. This is the case here.
1917 // Ordinarily you have to be careful with calling setFoundConstants()
1918 // because of the effect on compile times, but this node is FTL-only.
1919 m_state.setFoundConstants(true);
1921 AbstractValue base = forNode(node->child1());
1922 StructureSet baseSet;
1923 AbstractValue result;
1924 for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
1925 GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
1926 StructureSet set = variant.structureSet();
1932 JSValue baseForLoad;
1933 if (variant.alternateBase())
1934 baseForLoad = variant.alternateBase();
1936 baseForLoad = base.m_value;
1937 JSValue constantResult =
1938 m_graph.tryGetConstantProperty(
1939 baseForLoad, variant.baseStructure(), variant.offset());
1940 if (!constantResult) {
1941 result.makeHeapTop();
1944 AbstractValue thisResult;
1947 *m_graph.freeze(constantResult),
1948 m_state.structureClobberState());
1949 result.merge(thisResult);
1952 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
1953 m_state.setIsValid(false);
1955 forNode(node) = result;
1963 case MultiPutByOffset: {
1964 StructureSet newSet;
1965 TransitionVector transitions;
1967 // Ordinarily you have to be careful with calling setFoundConstants()
1968 // because of the effect on compile times, but this node is FTL-only.
1969 m_state.setFoundConstants(true);
1971 AbstractValue base = forNode(node->child1());
1973 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
1974 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
1975 StructureSet thisSet = variant.oldStructure();
1976 thisSet.filter(base);
1977 if (thisSet.isEmpty())
1979 if (variant.kind() == PutByIdVariant::Transition) {
1980 if (thisSet.onlyStructure() != variant.newStructure()) {
1982 Transition(variant.oldStructureForTransition(), variant.newStructure()));
1983 } // else this is really a replace.
1984 newSet.add(variant.newStructure());
1986 ASSERT(variant.kind() == PutByIdVariant::Replace);
1987 newSet.merge(thisSet);
1991 observeTransitions(clobberLimit, transitions);
1992 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
1993 m_state.setIsValid(false);
1997 case GetExecutable: {
1998 JSValue value = forNode(node->child1()).value();
2000 JSFunction* function = jsDynamicCast<JSFunction*>(value);
2002 setConstant(node, *m_graph.freeze(function->executable()));
2006 forNode(node).setType(m_graph, SpecCellOther);
2011 JSValue value = forNode(node->child1()).value();
2012 if (value == node->cellOperand()->value()) {
2013 m_state.setFoundConstants(true);
2017 filterByValue(node->child1(), *node->cellOperand());
2021 case CheckNotEmpty: {
2022 AbstractValue& value = forNode(node->child1());
2023 if (!(value.m_type & SpecEmpty)) {
2024 m_state.setFoundConstants(true);
2028 filter(value, ~SpecEmpty);
2032 case CheckInBounds: {
2033 JSValue left = forNode(node->child1()).value();
2034 JSValue right = forNode(node->child2()).value();
2035 if (left && right && left.isInt32() && right.isInt32()
2036 && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) {
2037 m_state.setFoundConstants(true);
2045 case PutByIdDirect: {
2046 AbstractValue& value = forNode(node->child1());
2047 if (!value.m_structure.isTop() && !value.m_structure.isClobbered()) {
2048 PutByIdStatus status = PutByIdStatus::computeFor(
2049 m_graph.globalObjectFor(node->origin.semantic),
2050 value.m_structure.set(),
2051 m_graph.identifiers()[node->identifierNumber()],
2052 node->op() == PutByIdDirect);
2054 if (status.isSimple()) {
2055 StructureSet newSet;
2056 TransitionVector transitions;
2058 for (unsigned i = status.numVariants(); i--;) {
2059 const PutByIdVariant& variant = status[i];
2060 if (variant.kind() == PutByIdVariant::Transition) {
2063 variant.oldStructureForTransition(), variant.newStructure()));
2064 m_graph.registerStructure(variant.newStructure());
2065 newSet.add(variant.newStructure());
2067 ASSERT(variant.kind() == PutByIdVariant::Replace);
2068 newSet.merge(variant.oldStructure());
2072 if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
2073 m_state.setFoundConstants(true);
2075 observeTransitions(clobberLimit, transitions);
2076 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
2077 m_state.setIsValid(false);
2082 clobberWorld(node->origin.semantic, clobberLimit);
2087 // FIXME: We can determine when the property definitely exists based on abstract
2088 // value information.
2089 clobberWorld(node->origin.semantic, clobberLimit);
2090 forNode(node).setType(SpecBoolean);
2094 case GetEnumerableLength: {
2095 forNode(node).setType(SpecInt32);
2098 case HasGenericProperty: {
2099 forNode(node).setType(SpecBoolean);
2102 case HasStructureProperty: {
2103 forNode(node).setType(SpecBoolean);
2106 case HasIndexedProperty: {
2107 ArrayMode mode = node->arrayMode();
2108 switch (mode.type()) {
2111 case Array::Contiguous:
2112 case Array::ArrayStorage: {
2116 clobberWorld(node->origin.semantic, clobberLimit);
2120 forNode(node).setType(SpecBoolean);
2123 case GetDirectPname: {
2124 clobberWorld(node->origin.semantic, clobberLimit);
2125 forNode(node).makeHeapTop();
2128 case GetPropertyEnumerator: {
2129 forNode(node).setType(m_graph, SpecCell);
2132 case GetEnumeratorStructurePname: {
2133 forNode(node).setType(m_graph, SpecString | SpecOther);
2136 case GetEnumeratorGenericPname: {
2137 forNode(node).setType(m_graph, SpecString | SpecOther);
2140 case ToIndexString: {
2141 forNode(node).setType(m_graph, SpecString);
2146 forNode(node).makeHeapTop();
2149 case VarInjectionWatchpoint:
2154 case CheckHasInstance:
2155 // Sadly, we don't propagate the fact that we've done CheckHasInstance
2159 // Again, sadly, we don't propagate the fact that we've done InstanceOf
2160 forNode(node).setType(SpecBoolean);
2164 RELEASE_ASSERT(m_graph.m_form == SSA);
2165 // The state of this node would have already been decided, but it may have become a
2166 // constant, in which case we'd like to know.
2167 if (forNode(node).m_value)
2168 m_state.setFoundConstants(true);
2172 m_state.createValueForNode(node->phi());
2173 forNode(node->phi()) = forNode(node->child1());
2184 case NativeConstruct:
2186 case CallForwardVarargs:
2187 case ConstructVarargs:
2188 case ConstructForwardVarargs:
2189 clobberWorld(node->origin.semantic, clobberLimit);
2190 forNode(node).makeHeapTop();
2195 m_state.setIsValid(false);
2198 case InvalidationPoint:
2199 forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor);
2200 m_state.setStructureClobberState(StructuresAreWatched);
2203 case CheckWatchdogTimer:
2207 case ProfileWillCall:
2208 case ProfileDidCall:
2210 case ProfileControlFlow:
2212 case CountExecution:
2213 case CheckTierUpInLoop:
2214 case CheckTierUpAtReturn:
2218 // Simplify out checks that don't actually do checking.
2219 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
2220 Edge edge = node->children.child(i);
2223 if (edge.isProved() || edge.willNotHaveCheck()) {
2224 m_state.setFoundConstants(true);
2231 case StoreBarrier: {
2232 filter(node->child1(), SpecCell);
2236 case StoreBarrierWithNullCheck: {
2240 case CheckTierUpAndOSREnter:
2249 DFG_CRASH(m_graph, node, "Unexpected node type");
2253 return m_state.isValid();
2256 template<typename AbstractStateType>
2257 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBlock)
2259 return executeEffects(indexInBlock, m_state.block()->at(indexInBlock));
2262 template<typename AbstractStateType>
2263 bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock)
2265 Node* node = m_state.block()->at(indexInBlock);
2269 return executeEffects(indexInBlock, node);
2272 template<typename AbstractStateType>
2273 bool AbstractInterpreter<AbstractStateType>::execute(Node* node)
2277 return executeEffects(UINT_MAX, node);
2280 template<typename AbstractStateType>
2281 void AbstractInterpreter<AbstractStateType>::clobberWorld(
2282 const CodeOrigin&, unsigned clobberLimit)
2284 clobberStructures(clobberLimit);
2287 template<typename AbstractStateType>
2288 template<typename Functor>
2289 void AbstractInterpreter<AbstractStateType>::forAllValues(
2290 unsigned clobberLimit, Functor& functor)
2292 SamplingRegion samplingRegion("DFG AI For All Values");
2293 if (clobberLimit >= m_state.block()->size())
2294 clobberLimit = m_state.block()->size();
2297 ASSERT(clobberLimit <= m_state.block()->size());
2298 for (size_t i = clobberLimit; i--;)
2299 functor(forNode(m_state.block()->at(i)));
2300 if (m_graph.m_form == SSA) {
2301 HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin();
2302 HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end();
2303 for (; iter != end; ++iter)
2304 functor(forNode(*iter));
2306 for (size_t i = m_state.variables().numberOfArguments(); i--;)
2307 functor(m_state.variables().argument(i));
2308 for (size_t i = m_state.variables().numberOfLocals(); i--;)
2309 functor(m_state.variables().local(i));
2312 template<typename AbstractStateType>
2313 void AbstractInterpreter<AbstractStateType>::clobberStructures(unsigned clobberLimit)
2315 SamplingRegion samplingRegion("DFG AI Clobber Structures");
2316 forAllValues(clobberLimit, AbstractValue::clobberStructuresFor);
2320 template<typename AbstractStateType>
2321 void AbstractInterpreter<AbstractStateType>::observeTransition(
2322 unsigned clobberLimit, Structure* from, Structure* to)
2324 AbstractValue::TransitionObserver transitionObserver(from, to);
2325 forAllValues(clobberLimit, transitionObserver);
2327 ASSERT(!from->dfgShouldWatch()); // We don't need to claim to be in a clobbered state because 'from' was never watchable (during the time we were compiling), hence no constants ever introduced into the DFG IR that ever had a watchable structure would ever have the same structure as from.
2330 template<typename AbstractStateType>
2331 void AbstractInterpreter<AbstractStateType>::observeTransitions(
2332 unsigned clobberLimit, const TransitionVector& vector)
2334 AbstractValue::TransitionsObserver transitionsObserver(vector);
2335 forAllValues(clobberLimit, transitionsObserver);
2337 if (!ASSERT_DISABLED) {
2338 // We don't need to claim to be in a clobbered state because none of the Transition::previous structures are watchable.
2339 for (unsigned i = vector.size(); i--;)
2340 ASSERT(!vector[i].previous->dfgShouldWatch());
2344 template<typename AbstractStateType>
2345 void AbstractInterpreter<AbstractStateType>::setDidClobber()
2347 m_state.setDidClobber(true);
2348 m_state.setStructureClobberState(StructuresAreClobbered);
2351 template<typename AbstractStateType>
2352 void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) const
2354 const_cast<AbstractInterpreter<AbstractStateType>*>(this)->dump(out);
2357 template<typename AbstractStateType>
2358 void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out)
2360 CommaPrinter comma(" ");
2361 HashSet<Node*> seen;
2362 if (m_graph.m_form == SSA) {
2363 HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtHead.begin();
2364 HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtHead.end();
2365 for (; iter != end; ++iter) {
2368 AbstractValue& value = forNode(node);
2369 if (value.isClear())
2371 out.print(comma, node, ":", value);
2374 for (size_t i = 0; i < m_state.block()->size(); ++i) {
2375 Node* node = m_state.block()->at(i);
2377 AbstractValue& value = forNode(node);
2378 if (value.isClear())
2380 out.print(comma, node, ":", value);
2382 if (m_graph.m_form == SSA) {
2383 HashSet<Node*>::iterator iter = m_state.block()->ssa->liveAtTail.begin();
2384 HashSet<Node*>::iterator end = m_state.block()->ssa->liveAtTail.end();
2385 for (; iter != end; ++iter) {
2387 if (seen.contains(node))
2389 AbstractValue& value = forNode(node);
2390 if (value.isClear())
2392 out.print(comma, node, ":", value);
2397 template<typename AbstractStateType>
2398 FiltrationResult AbstractInterpreter<AbstractStateType>::filter(
2399 AbstractValue& value, const StructureSet& set)
2401 if (value.filter(m_graph, set) == FiltrationOK)
2402 return FiltrationOK;
2403 m_state.setIsValid(false);
2404 return Contradiction;
2407 template<typename AbstractStateType>
2408 FiltrationResult AbstractInterpreter<AbstractStateType>::filterArrayModes(
2409 AbstractValue& value, ArrayModes arrayModes)
2411 if (value.filterArrayModes(arrayModes) == FiltrationOK)
2412 return FiltrationOK;
2413 m_state.setIsValid(false);
2414 return Contradiction;
2417 template<typename AbstractStateType>
2418 FiltrationResult AbstractInterpreter<AbstractStateType>::filter(
2419 AbstractValue& value, SpeculatedType type)
2421 if (value.filter(type) == FiltrationOK)
2422 return FiltrationOK;
2423 m_state.setIsValid(false);
2424 return Contradiction;
2427 template<typename AbstractStateType>
2428 FiltrationResult AbstractInterpreter<AbstractStateType>::filterByValue(
2429 AbstractValue& abstractValue, FrozenValue concreteValue)
2431 if (abstractValue.filterByValue(concreteValue) == FiltrationOK)
2432 return FiltrationOK;
2433 m_state.setIsValid(false);
2434 return Contradiction;
2437 } } // namespace JSC::DFG
2439 #endif // ENABLE(DFG_JIT)
2441 #endif // DFGAbstractInterpreterInlines_h