2 * Copyright (C) 2013-2017 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.
30 #include "ArrayConstructor.h"
31 #include "DFGAbstractInterpreter.h"
32 #include "DOMJITGetterSetter.h"
33 #include "DOMJITSignature.h"
34 #include "GetByIdStatus.h"
35 #include "GetterSetter.h"
36 #include "HashMapImpl.h"
37 #include "JITOperations.h"
38 #include "MathCommon.h"
39 #include "Operations.h"
40 #include "PutByIdStatus.h"
41 #include "StringObject.h"
43 #include <wtf/CheckedArithmetic.h>
45 namespace JSC { namespace DFG {
47 template<typename AbstractStateType>
48 AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state)
49 : m_codeBlock(graph.m_codeBlock)
54 if (m_graph.m_form == SSA)
55 m_phiChildren = std::make_unique<PhiChildren>(m_graph);
58 template<typename AbstractStateType>
59 AbstractInterpreter<AbstractStateType>::~AbstractInterpreter()
63 template<typename AbstractStateType>
64 typename AbstractInterpreter<AbstractStateType>::BooleanResult
65 AbstractInterpreter<AbstractStateType>::booleanResult(
66 Node* node, AbstractValue& value)
68 JSValue childConst = value.value();
70 if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic)->globalExec()))
71 return DefinitelyTrue;
72 return DefinitelyFalse;
75 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
76 if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
78 for (unsigned i = value.m_structure.size(); i--;) {
79 RegisteredStructure structure = value.m_structure[i];
80 if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
81 || structure->typeInfo().type() == StringType) {
87 return DefinitelyTrue;
90 return UnknownBooleanResult;
93 template<typename AbstractStateType>
94 void AbstractInterpreter<AbstractStateType>::startExecuting()
96 ASSERT(m_state.block());
97 ASSERT(m_state.isValid());
99 m_state.setDidClobber(false);
102 template<typename AbstractStateType>
103 void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node)
105 m_graph.doToChildren(
108 filterEdgeByUse(edge);
112 template<typename AbstractStateType>
113 void AbstractInterpreter<AbstractStateType>::executeKnownEdgeTypes(Node* node)
115 // Some use kinds are required to not have checks, because we know somehow that the incoming
116 // value will already have the type we want. In those cases, AI may not be smart enough to
117 // prove that this is indeed the case. But the existance of the edge is enough to prove that
118 // it is indeed the case. Taking advantage of this is not optional, since otherwise the DFG
119 // and FTL backends may emit checks in a node that lacks a valid exit origin.
120 m_graph.doToChildren(
123 if (mayHaveTypeCheck(edge.useKind()))
126 filterEdgeByUse(edge);
130 template<typename AbstractStateType>
131 void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
133 if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())))
136 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(), AbstractInterpreterInvalidType, node->op(), edge->op(), edge.useKind(), forNode(edge).m_type);
139 template<typename AbstractStateType>
140 void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
142 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
145 enum class ToThisResult {
151 inline ToThisResult isToThisAnIdentity(VM& vm, bool isStrictMode, AbstractValue& valueForNode)
153 // We look at the type first since that will cover most cases and does not require iterating all the structures.
155 if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther))
156 return ToThisResult::Identity;
158 if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther)))
159 return ToThisResult::Identity;
162 if (JSValue value = valueForNode.value()) {
163 if (value.isCell()) {
164 auto* toThisMethod = value.asCell()->classInfo(vm)->methodTable.toThis;
165 if (toThisMethod == &JSObject::toThis)
166 return ToThisResult::Identity;
167 if (toThisMethod == &JSScope::toThis) {
169 return ToThisResult::Undefined;
170 return ToThisResult::GlobalThis;
175 if ((isStrictMode || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) {
176 bool allStructuresAreJSScope = !valueForNode.m_structure.isClear();
177 bool overridesToThis = false;
178 valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
179 TypeInfo type = structure->typeInfo();
180 ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == BigIntType);
182 ASSERT(type.isObject());
183 // We don't need to worry about strings/symbols here since either:
184 // 1) We are in strict mode and strings/symbols are not wrapped
185 // 2) The AI has proven that the type of this is a subtype of object
186 if (type.isObject() && type.overridesToThis())
187 overridesToThis = true;
189 // If all the structures are JSScope's ones, we know the details of JSScope::toThis() operation.
190 allStructuresAreJSScope &= structure->classInfo()->methodTable.toThis == JSScope::info()->methodTable.toThis;
192 if (!overridesToThis)
193 return ToThisResult::Identity;
194 if (allStructuresAreJSScope) {
196 return ToThisResult::Undefined;
197 return ToThisResult::GlobalThis;
201 return ToThisResult::Dynamic;
204 template<typename AbstractStateType>
205 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
209 m_state.createValueForNode(node);
211 switch (node->op()) {
214 case Int52Constant: {
215 setBuiltInConstant(node, *node->constant());
219 case LazyJSConstant: {
220 LazyJSValue value = node->lazyJSValue();
221 switch (value.kind()) {
222 case LazyJSValue::KnownValue:
223 setConstant(node, value.value()->value());
225 case LazyJSValue::SingleCharacterString:
226 case LazyJSValue::KnownStringImpl:
227 case LazyJSValue::NewStringImpl:
228 forNode(node).setType(m_graph, SpecString);
234 case IdentityWithProfile:
236 forNode(node) = forNode(node->child1());
237 if (forNode(node).value())
238 m_state.setFoundConstants(true);
242 case ExtractCatchLocal:
243 case ExtractOSREntryLocal: {
244 forNode(node).makeBytecodeTop();
249 VariableAccessData* variableAccessData = node->variableAccessData();
250 AbstractValue value = m_state.variables().operand(variableAccessData->local().offset());
251 // The value in the local should already be checked.
252 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
254 m_state.setFoundConstants(true);
255 forNode(node) = value;
260 StackAccessData* data = node->stackAccessData();
261 AbstractValue value = m_state.variables().operand(data->local);
262 // The value in the local should already be checked.
263 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
265 m_state.setFoundConstants(true);
266 forNode(node) = value;
271 m_state.variables().operand(node->local()) = forNode(node->child1());
276 m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1());
281 // Don't need to do anything. A MovHint only informs us about what would have happened
282 // in bytecode, but this code is just concerned with what is actually happening during
288 // This is just a hint telling us that the OSR state of the local is no longer inside the
294 // Assert that the state of arguments has been set. SetArgument means that someone set
295 // the argument values out-of-band, and currently this always means setting to a
297 ASSERT(!m_state.variables().operand(node->local()).isClear());
300 case InitializeEntrypointArguments: {
301 unsigned entrypointIndex = node->entrypointIndex();
302 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
303 for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) {
304 AbstractValue& value = m_state.variables().argument(argument);
305 switch (argumentFormats[argument]) {
307 value.setType(SpecInt32Only);
310 value.setType(SpecBoolean);
313 value.setType(m_graph, SpecCell);
316 value.makeBytecodeTop();
319 DFG_CRASH(m_graph, node, "Bad flush format for argument");
327 case ForwardVarargs: {
328 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
329 // itself into a straight-line sequence of GetStack/PutStack.
330 // https://bugs.webkit.org/show_bug.cgi?id=143071
331 clobberWorld(node->origin.semantic, clobberLimit);
332 LoadVarargsData* data = node->loadVarargsData();
333 m_state.variables().operand(data->count).setType(SpecInt32Only);
334 for (unsigned i = data->limit - 1; i--;)
335 m_state.variables().operand(data->start.offset() + i).makeHeapTop();
345 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
346 clobberWorld(node->origin.semantic, clobberLimit);
347 forNode(node).setType(m_graph, SpecInt32Only);
351 JSValue left = forNode(node->child1()).value();
352 JSValue right = forNode(node->child2()).value();
353 if (left && right && left.isInt32() && right.isInt32()) {
354 int32_t a = left.asInt32();
355 int32_t b = right.asInt32();
356 switch (node->op()) {
358 setConstant(node, JSValue(a & b));
361 setConstant(node, JSValue(a | b));
364 setConstant(node, JSValue(a ^ b));
367 setConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
370 setConstant(node, JSValue(a << static_cast<uint32_t>(b)));
373 setConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
376 RELEASE_ASSERT_NOT_REACHED();
382 if (node->op() == BitAnd
383 && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
384 isBoolInt32Speculation(forNode(node->child2()).m_type))) {
385 forNode(node).setType(SpecBoolInt32);
389 forNode(node).setType(SpecInt32Only);
393 case UInt32ToNumber: {
394 JSValue child = forNode(node->child1()).value();
395 if (doesOverflow(node->arithMode())) {
397 if (child && child.isAnyInt()) {
398 int64_t machineInt = child.asAnyInt();
399 setConstant(node, jsNumber(static_cast<uint32_t>(machineInt)));
402 forNode(node).setType(SpecAnyInt);
405 if (child && child.isInt32()) {
406 uint32_t value = child.asInt32();
407 setConstant(node, jsNumber(value));
410 forNode(node).setType(SpecAnyIntAsDouble);
413 if (child && child.isInt32()) {
414 int32_t value = child.asInt32();
416 setConstant(node, jsNumber(value));
420 forNode(node).setType(SpecInt32Only);
424 case BooleanToNumber: {
425 JSValue concreteValue = forNode(node->child1()).value();
427 if (concreteValue.isBoolean())
428 setConstant(node, jsNumber(concreteValue.asBoolean()));
430 setConstant(node, *m_graph.freeze(concreteValue));
433 AbstractValue& value = forNode(node);
434 value = forNode(node->child1());
435 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
436 m_state.setFoundConstants(true);
437 if (value.m_type & SpecBoolean) {
438 value.merge(SpecBoolInt32);
439 value.filter(~SpecBoolean);
444 case DoubleAsInt32: {
445 JSValue child = forNode(node->child1()).value();
446 if (child && child.isNumber()) {
447 double asDouble = child.asNumber();
448 int32_t asInt = JSC::toInt32(asDouble);
449 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
450 setConstant(node, JSValue(asInt));
454 forNode(node).setType(SpecInt32Only);
459 JSValue child = forNode(node->child1()).value();
461 if (child.isNumber()) {
463 setConstant(node, child);
465 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
468 if (child.isBoolean()) {
469 setConstant(node, jsNumber(child.asBoolean()));
472 if (child.isUndefinedOrNull()) {
473 setConstant(node, jsNumber(0));
478 if (isBooleanSpeculation(forNode(node->child1()).m_type)) {
479 forNode(node).setType(SpecBoolInt32);
483 forNode(node).setType(SpecInt32Only);
488 JSValue child = forNode(node->child1()).value();
489 if (std::optional<double> number = child.toNumberFromPrimitive()) {
490 setConstant(node, jsDoubleNumber(*number));
494 SpeculatedType type = forNode(node->child1()).m_type;
495 switch (node->child1().useKind()) {
497 if (type & SpecOther) {
499 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
501 if (type & SpecBoolean) {
502 type &= ~SpecBoolean;
503 type |= SpecBoolInt32; // True becomes 1, false becomes 0.
505 type &= SpecBytecodeNumber;
515 RELEASE_ASSERT_NOT_REACHED();
517 forNode(node).setType(type);
518 forNode(node).fixTypeForRepresentation(m_graph, node);
523 JSValue child = forNode(node->child1()).value();
524 if (child && child.isAnyInt()) {
525 setConstant(node, child);
529 forNode(node).setType(SpecAnyInt);
534 JSValue value = forNode(node->child1()).value();
536 setConstant(node, value);
540 forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
541 forNode(node).fixTypeForRepresentation(m_graph, node);
546 ASSERT(node->binaryUseKind() == UntypedUse);
547 clobberWorld(node->origin.semantic, clobberLimit);
548 forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber);
553 forNode(node).setType(m_graph, SpecString);
558 JSValue left = forNode(node->child1()).value();
559 JSValue right = forNode(node->child2()).value();
560 switch (node->binaryUseKind()) {
562 if (left && right && left.isInt32() && right.isInt32()) {
563 if (!shouldCheckOverflow(node->arithMode())) {
564 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
567 JSValue result = jsNumber(left.asNumber() + right.asNumber());
568 if (result.isInt32()) {
569 setConstant(node, result);
573 forNode(node).setType(SpecInt32Only);
576 if (left && right && left.isAnyInt() && right.isAnyInt()) {
577 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt());
578 if (result.isAnyInt()) {
579 setConstant(node, result);
583 forNode(node).setType(SpecAnyInt);
586 if (left && right && left.isNumber() && right.isNumber()) {
587 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
590 forNode(node).setType(
592 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
595 RELEASE_ASSERT_NOT_REACHED();
601 case AtomicsIsLockFree: {
602 if (node->child1().useKind() != Int32Use)
603 clobberWorld(node->origin.semantic, clobberLimit);
604 forNode(node).setType(SpecBoolInt32);
609 JSValue operand = forNode(node->child1()).value();
610 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
611 uint32_t value = toUInt32(*number);
612 setConstant(node, jsNumber(clz32(value)));
615 switch (node->child1().useKind()) {
620 clobberWorld(node->origin.semantic, clobberLimit);
623 forNode(node).setType(SpecInt32Only);
628 unsigned numberOfChildren = 0;
629 unsigned numberOfRemovedChildren = 0;
630 std::optional<unsigned> nonEmptyIndex;
631 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
632 Edge& edge = node->children.child(i);
637 JSValue childConstant = m_state.forNode(edge).value();
638 if (!childConstant) {
642 if (!childConstant.isString()) {
646 if (asString(childConstant)->length()) {
651 ++numberOfRemovedChildren;
654 if (numberOfRemovedChildren) {
655 m_state.setFoundConstants(true);
656 if (numberOfRemovedChildren == numberOfChildren) {
657 // Propagate the last child. This is the way taken in the constant folding phase.
658 forNode(node) = forNode(node->children.child(numberOfChildren - 1));
661 if ((numberOfRemovedChildren + 1) == numberOfChildren) {
662 ASSERT(nonEmptyIndex);
663 forNode(node) = forNode(node->children.child(nonEmptyIndex.value()));
667 forNode(node).set(m_graph, m_vm.stringStructure.get());
672 JSValue left = forNode(node->child1()).value();
673 JSValue right = forNode(node->child2()).value();
674 switch (node->binaryUseKind()) {
676 if (left && right && left.isInt32() && right.isInt32()) {
677 if (!shouldCheckOverflow(node->arithMode())) {
678 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
681 JSValue result = jsNumber(left.asNumber() - right.asNumber());
682 if (result.isInt32()) {
683 setConstant(node, result);
687 forNode(node).setType(SpecInt32Only);
690 if (left && right && left.isAnyInt() && right.isAnyInt()) {
691 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt());
692 if (result.isAnyInt() || !shouldCheckOverflow(node->arithMode())) {
693 setConstant(node, result);
697 forNode(node).setType(SpecAnyInt);
700 if (left && right && left.isNumber() && right.isNumber()) {
701 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
704 forNode(node).setType(
705 typeOfDoubleDifference(
706 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
709 clobberWorld(node->origin.semantic, clobberLimit);
710 forNode(node).setType(m_graph, SpecBytecodeNumber);
713 RELEASE_ASSERT_NOT_REACHED();
720 JSValue child = forNode(node->child1()).value();
721 switch (node->child1().useKind()) {
723 if (child && child.isInt32()) {
724 if (!shouldCheckOverflow(node->arithMode())) {
725 setConstant(node, jsNumber(-child.asInt32()));
729 if (shouldCheckNegativeZero(node->arithMode()))
730 doubleResult = -child.asNumber();
732 doubleResult = 0 - child.asNumber();
733 JSValue valueResult = jsNumber(doubleResult);
734 if (valueResult.isInt32()) {
735 setConstant(node, valueResult);
739 forNode(node).setType(SpecInt32Only);
742 if (child && child.isAnyInt()) {
744 if (shouldCheckNegativeZero(node->arithMode()))
745 doubleResult = -child.asNumber();
747 doubleResult = 0 - child.asNumber();
748 JSValue valueResult = jsNumber(doubleResult);
749 if (valueResult.isAnyInt()) {
750 setConstant(node, valueResult);
754 forNode(node).setType(SpecAnyInt);
757 if (child && child.isNumber()) {
758 setConstant(node, jsDoubleNumber(-child.asNumber()));
761 forNode(node).setType(
762 typeOfDoubleNegation(
763 forNode(node->child1()).m_type));
766 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
767 forNode(node).setType(SpecBytecodeNumber);
774 JSValue left = forNode(node->child1()).value();
775 JSValue right = forNode(node->child2()).value();
776 switch (node->binaryUseKind()) {
778 if (left && right && left.isInt32() && right.isInt32()) {
779 if (!shouldCheckOverflow(node->arithMode())) {
780 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
783 double doubleResult = left.asNumber() * right.asNumber();
784 if (!shouldCheckNegativeZero(node->arithMode()))
785 doubleResult += 0; // Sanitizes zero.
786 JSValue valueResult = jsNumber(doubleResult);
787 if (valueResult.isInt32()) {
788 setConstant(node, valueResult);
792 forNode(node).setType(SpecInt32Only);
795 if (left && right && left.isAnyInt() && right.isAnyInt()) {
796 double doubleResult = left.asNumber() * right.asNumber();
797 if (!shouldCheckNegativeZero(node->arithMode()))
799 JSValue valueResult = jsNumber(doubleResult);
800 if (valueResult.isAnyInt()) {
801 setConstant(node, valueResult);
805 forNode(node).setType(SpecAnyInt);
808 if (left && right && left.isNumber() && right.isNumber()) {
809 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
812 forNode(node).setType(
814 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
817 clobberWorld(node->origin.semantic, clobberLimit);
818 forNode(node).setType(m_graph, SpecBytecodeNumber);
821 RELEASE_ASSERT_NOT_REACHED();
828 JSValue left = forNode(node->child1()).value();
829 JSValue right = forNode(node->child2()).value();
830 switch (node->binaryUseKind()) {
832 if (left && right && left.isInt32() && right.isInt32()) {
833 double doubleResult = left.asNumber() / right.asNumber();
834 if (!shouldCheckOverflow(node->arithMode()))
835 doubleResult = toInt32(doubleResult);
836 else if (!shouldCheckNegativeZero(node->arithMode()))
837 doubleResult += 0; // Sanitizes zero.
838 JSValue valueResult = jsNumber(doubleResult);
839 if (valueResult.isInt32()) {
840 setConstant(node, valueResult);
844 forNode(node).setType(SpecInt32Only);
847 if (left && right && left.isNumber() && right.isNumber()) {
848 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
851 forNode(node).setType(
852 typeOfDoubleQuotient(
853 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
856 clobberWorld(node->origin.semantic, clobberLimit);
857 forNode(node).setType(m_graph, SpecBytecodeNumber);
860 RELEASE_ASSERT_NOT_REACHED();
867 JSValue left = forNode(node->child1()).value();
868 JSValue right = forNode(node->child2()).value();
869 switch (node->binaryUseKind()) {
871 if (left && right && left.isInt32() && right.isInt32()) {
872 double doubleResult = fmod(left.asNumber(), right.asNumber());
873 if (!shouldCheckOverflow(node->arithMode()))
874 doubleResult = toInt32(doubleResult);
875 else if (!shouldCheckNegativeZero(node->arithMode()))
876 doubleResult += 0; // Sanitizes zero.
877 JSValue valueResult = jsNumber(doubleResult);
878 if (valueResult.isInt32()) {
879 setConstant(node, valueResult);
883 forNode(node).setType(SpecInt32Only);
886 if (left && right && left.isNumber() && right.isNumber()) {
887 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
890 forNode(node).setType(
891 typeOfDoubleBinaryOp(
892 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
895 RELEASE_ASSERT_NOT_REACHED();
902 JSValue left = forNode(node->child1()).value();
903 JSValue right = forNode(node->child2()).value();
904 switch (node->binaryUseKind()) {
906 if (left && right && left.isInt32() && right.isInt32()) {
907 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
910 forNode(node).setType(SpecInt32Only);
913 if (left && right && left.isNumber() && right.isNumber()) {
914 double a = left.asNumber();
915 double b = right.asNumber();
916 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
919 forNode(node).setType(
921 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
924 RELEASE_ASSERT_NOT_REACHED();
931 JSValue left = forNode(node->child1()).value();
932 JSValue right = forNode(node->child2()).value();
933 switch (node->binaryUseKind()) {
935 if (left && right && left.isInt32() && right.isInt32()) {
936 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
939 forNode(node).setType(SpecInt32Only);
942 if (left && right && left.isNumber() && right.isNumber()) {
943 double a = left.asNumber();
944 double b = right.asNumber();
945 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
948 forNode(node).setType(
950 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
953 RELEASE_ASSERT_NOT_REACHED();
960 JSValue child = forNode(node->child1()).value();
961 switch (node->child1().useKind()) {
963 if (std::optional<double> number = child.toNumberFromPrimitive()) {
964 JSValue result = jsNumber(fabs(*number));
965 if (result.isInt32()) {
966 setConstant(node, result);
970 forNode(node).setType(SpecInt32Only);
973 if (std::optional<double> number = child.toNumberFromPrimitive()) {
974 setConstant(node, jsDoubleNumber(fabs(*number)));
977 forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
980 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
981 forNode(node).setType(SpecFullNumber);
988 JSValue childY = forNode(node->child2()).value();
989 if (childY && childY.isNumber()) {
990 if (!childY.asNumber()) {
991 setConstant(node, jsDoubleNumber(1));
995 JSValue childX = forNode(node->child1()).value();
996 if (childX && childX.isNumber()) {
997 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
1001 forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1006 forNode(node).setType(m_graph, SpecDoubleReal);
1014 JSValue operand = forNode(node->child1()).value();
1015 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
1016 double roundedValue = 0;
1017 if (node->op() == ArithRound)
1018 roundedValue = jsRound(*number);
1019 else if (node->op() == ArithFloor)
1020 roundedValue = floor(*number);
1021 else if (node->op() == ArithCeil)
1022 roundedValue = ceil(*number);
1024 ASSERT(node->op() == ArithTrunc);
1025 roundedValue = trunc(*number);
1028 if (node->child1().useKind() == UntypedUse) {
1029 setConstant(node, jsNumber(roundedValue));
1032 if (producesInteger(node->arithRoundingMode())) {
1033 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
1034 if (roundedValueAsInt32 == roundedValue) {
1035 if (shouldCheckNegativeZero(node->arithRoundingMode())) {
1036 if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
1037 setConstant(node, jsNumber(roundedValueAsInt32));
1041 setConstant(node, jsNumber(roundedValueAsInt32));
1046 setConstant(node, jsDoubleNumber(roundedValue));
1050 if (node->child1().useKind() == DoubleRepUse) {
1051 if (producesInteger(node->arithRoundingMode()))
1052 forNode(node).setType(SpecInt32Only);
1053 else if (node->child1().useKind() == DoubleRepUse)
1054 forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
1056 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
1057 forNode(node).setType(SpecFullNumber);
1063 executeDoubleUnaryOpEffects(node, sqrt);
1067 executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
1071 executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
1075 switch (booleanResult(node, forNode(node->child1()))) {
1076 case DefinitelyTrue:
1077 setConstant(node, jsBoolean(false));
1079 case DefinitelyFalse:
1080 setConstant(node, jsBoolean(true));
1083 forNode(node).setType(SpecBoolean);
1090 if (JSValue key = forNode(node->child1()).value()) {
1091 if (std::optional<uint32_t> hash = concurrentJSMapHash(key)) {
1092 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32
1093 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large
1094 // unsigned values becoming doubles. This casting between signed and unsigned
1095 // happens in the assembly code we emit when we don't constant fold this node.
1096 setConstant(node, jsNumber(static_cast<int32_t>(*hash)));
1100 forNode(node).setType(SpecInt32Only);
1104 case NormalizeMapKey: {
1105 if (JSValue key = forNode(node->child1()).value()) {
1106 setConstant(node, *m_graph.freeze(normalizeMapKey(key)));
1110 SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
1111 if (!(forNode(node->child1()).m_type & typeMaybeNormalized)) {
1112 m_state.setFoundConstants(true);
1113 forNode(node) = forNode(node->child1());
1117 forNode(node).makeHeapTop();
1122 forNode(node).setType(m_graph, SpecString);
1127 forNode(node).setType(m_graph, SpecString);
1131 case LoadKeyFromMapBucket:
1132 case LoadValueFromMapBucket:
1133 case ExtractValueFromWeakMapGet:
1134 forNode(node).makeHeapTop();
1138 case GetMapBucketHead:
1139 if (node->child1().useKind() == MapObjectUse)
1140 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1142 ASSERT(node->child1().useKind() == SetObjectUse);
1143 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1147 case GetMapBucketNext:
1148 if (node->bucketOwnerType() == BucketOwnerType::Map)
1149 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1151 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
1152 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1157 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1161 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1165 forNode(node).makeBytecodeTop();
1173 case IsObjectOrNull:
1175 case IsCellWithType:
1176 case IsTypedArrayView: {
1177 AbstractValue child = forNode(node->child1());
1178 if (child.value()) {
1179 bool constantWasSet = true;
1180 switch (node->op()) {
1181 case IsCellWithType:
1182 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType()));
1185 setConstant(node, jsBoolean(
1186 child.value().isCell()
1187 ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
1188 : child.value().isUndefined()));
1191 setConstant(node, jsBoolean(child.value().isBoolean()));
1194 setConstant(node, jsBoolean(child.value().isNumber()));
1197 setConstant(node, jsBoolean(child.value().isObject()));
1199 case IsObjectOrNull:
1200 if (child.value().isObject()) {
1201 JSObject* object = asObject(child.value());
1202 if (object->type() == JSFunctionType)
1203 setConstant(node, jsBoolean(false));
1204 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1205 setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
1207 // FIXME: This could just call getCallData.
1208 // https://bugs.webkit.org/show_bug.cgi?id=144457
1209 constantWasSet = false;
1212 setConstant(node, jsBoolean(child.value().isNull()));
1215 if (child.value().isObject()) {
1216 JSObject* object = asObject(child.value());
1217 if (object->type() == JSFunctionType)
1218 setConstant(node, jsBoolean(true));
1219 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1220 setConstant(node, jsBoolean(false));
1222 // FIXME: This could just call getCallData.
1223 // https://bugs.webkit.org/show_bug.cgi?id=144457
1224 constantWasSet = false;
1227 setConstant(node, jsBoolean(false));
1230 setConstant(node, jsBoolean(child.value().isEmpty()));
1232 case IsTypedArrayView:
1233 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType)));
1236 constantWasSet = false;
1243 // FIXME: This code should really use AbstractValue::isType() and
1244 // AbstractValue::couldBeType().
1245 // https://bugs.webkit.org/show_bug.cgi?id=146870
1247 bool constantWasSet = false;
1248 switch (node->op()) {
1250 if (child.m_type && !(child.m_type & SpecEmpty)) {
1251 setConstant(node, jsBoolean(false));
1252 constantWasSet = true;
1256 if (child.m_type && !(child.m_type & ~SpecEmpty)) {
1257 setConstant(node, jsBoolean(true));
1258 constantWasSet = true;
1265 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1266 // https://bugs.webkit.org/show_bug.cgi?id=144456
1268 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
1269 setConstant(node, jsBoolean(false));
1270 constantWasSet = true;
1276 if (!(child.m_type & ~SpecBoolean)) {
1277 setConstant(node, jsBoolean(true));
1278 constantWasSet = true;
1282 if (!(child.m_type & SpecBoolean)) {
1283 setConstant(node, jsBoolean(false));
1284 constantWasSet = true;
1290 if (!(child.m_type & ~SpecFullNumber)) {
1291 setConstant(node, jsBoolean(true));
1292 constantWasSet = true;
1296 if (!(child.m_type & SpecFullNumber)) {
1297 setConstant(node, jsBoolean(false));
1298 constantWasSet = true;
1304 if (!(child.m_type & ~SpecObject)) {
1305 setConstant(node, jsBoolean(true));
1306 constantWasSet = true;
1310 if (!(child.m_type & SpecObject)) {
1311 setConstant(node, jsBoolean(false));
1312 constantWasSet = true;
1317 case IsObjectOrNull:
1318 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1319 // https://bugs.webkit.org/show_bug.cgi?id=144456
1321 // These expressions are complicated to parse. A helpful way to parse this is that
1322 // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
1323 // disjoint set from S". Things like "T - S" means that, provided that S is a
1324 // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
1325 // mean the "union of T and S".
1327 // Is the child's type an object that isn't an other-object (i.e. object that could
1328 // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
1330 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1331 setConstant(node, jsBoolean(true));
1332 constantWasSet = true;
1336 // Is the child's type definitely not either of: an object that isn't a function,
1337 // or either undefined or null? Then: we should fold this to false. This means
1338 // for example that if it's any non-function object, including those that have
1339 // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
1340 // if it's undefined-or-null, since the type bits don't distinguish between
1341 // undefined (which should fold to false) and null (which should fold to true).
1342 if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
1343 setConstant(node, jsBoolean(false));
1344 constantWasSet = true;
1350 if (!(child.m_type & ~SpecFunction)) {
1351 setConstant(node, jsBoolean(true));
1352 constantWasSet = true;
1356 if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) {
1357 setConstant(node, jsBoolean(false));
1358 constantWasSet = true;
1363 case IsCellWithType:
1364 if (!(child.m_type & ~node->speculatedTypeForQuery())) {
1365 setConstant(node, jsBoolean(true));
1366 constantWasSet = true;
1369 if (!(child.m_type & node->speculatedTypeForQuery())) {
1370 setConstant(node, jsBoolean(false));
1371 constantWasSet = true;
1376 case IsTypedArrayView:
1377 if (!(child.m_type & ~SpecTypedArrayView)) {
1378 setConstant(node, jsBoolean(true));
1379 constantWasSet = true;
1382 if (!(child.m_type & SpecTypedArrayView)) {
1383 setConstant(node, jsBoolean(false));
1384 constantWasSet = true;
1395 forNode(node).setType(SpecBoolean);
1400 JSValue child = forNode(node->child1()).value();
1401 AbstractValue& abstractChild = forNode(node->child1());
1403 JSValue typeString = jsTypeStringForValue(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1404 setConstant(node, *m_graph.freeze(typeString));
1408 if (isFullNumberSpeculation(abstractChild.m_type)) {
1409 setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString()));
1413 if (isStringSpeculation(abstractChild.m_type)) {
1414 setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString()));
1418 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1419 // https://bugs.webkit.org/show_bug.cgi?id=144456
1420 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1421 setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString()));
1425 if (isFunctionSpeculation(abstractChild.m_type)) {
1426 setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString()));
1430 if (isBooleanSpeculation(abstractChild.m_type)) {
1431 setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString()));
1435 if (isSymbolSpeculation(abstractChild.m_type)) {
1436 setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString()));
1440 forNode(node).setType(m_graph, SpecStringIdent);
1445 case CompareBelowEq: {
1446 JSValue leftConst = forNode(node->child1()).value();
1447 JSValue rightConst = forNode(node->child2()).value();
1448 if (leftConst && rightConst) {
1449 if (leftConst.isInt32() && rightConst.isInt32()) {
1450 uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
1451 uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
1452 switch (node->op()) {
1454 setConstant(node, jsBoolean(a < b));
1456 case CompareBelowEq:
1457 setConstant(node, jsBoolean(a <= b));
1460 RELEASE_ASSERT_NOT_REACHED();
1467 if (node->child1() == node->child2()) {
1468 switch (node->op()) {
1470 setConstant(node, jsBoolean(false));
1472 case CompareBelowEq:
1473 setConstant(node, jsBoolean(true));
1476 DFG_CRASH(m_graph, node, "Unexpected node type");
1481 forNode(node).setType(SpecBoolean);
1487 case CompareGreater:
1488 case CompareGreaterEq:
1490 JSValue leftConst = forNode(node->child1()).value();
1491 JSValue rightConst = forNode(node->child2()).value();
1492 if (leftConst && rightConst) {
1493 if (leftConst.isNumber() && rightConst.isNumber()) {
1494 double a = leftConst.asNumber();
1495 double b = rightConst.asNumber();
1496 switch (node->op()) {
1498 setConstant(node, jsBoolean(a < b));
1501 setConstant(node, jsBoolean(a <= b));
1503 case CompareGreater:
1504 setConstant(node, jsBoolean(a > b));
1506 case CompareGreaterEq:
1507 setConstant(node, jsBoolean(a >= b));
1510 setConstant(node, jsBoolean(a == b));
1513 RELEASE_ASSERT_NOT_REACHED();
1519 if (leftConst.isString() && rightConst.isString()) {
1520 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1521 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1524 if (node->op() == CompareEq)
1525 result = WTF::equal(a, b);
1526 else if (node->op() == CompareLess)
1527 result = codePointCompare(a, b) < 0;
1528 else if (node->op() == CompareLessEq)
1529 result = codePointCompare(a, b) <= 0;
1530 else if (node->op() == CompareGreater)
1531 result = codePointCompare(a, b) > 0;
1532 else if (node->op() == CompareGreaterEq)
1533 result = codePointCompare(a, b) >= 0;
1535 RELEASE_ASSERT_NOT_REACHED();
1536 setConstant(node, jsBoolean(result));
1541 if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) {
1542 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst)));
1547 if (node->op() == CompareEq) {
1548 SpeculatedType leftType = forNode(node->child1()).m_type;
1549 SpeculatedType rightType = forNode(node->child2()).m_type;
1550 if (!valuesCouldBeEqual(leftType, rightType)) {
1551 setConstant(node, jsBoolean(false));
1555 if (leftType == SpecOther)
1556 std::swap(leftType, rightType);
1557 if (rightType == SpecOther) {
1558 // Undefined and Null are always equal when compared to eachother.
1559 if (!(leftType & ~SpecOther)) {
1560 setConstant(node, jsBoolean(true));
1564 // Any other type compared to Null or Undefined is always false
1565 // as long as the MasqueradesAsUndefined watchpoint is valid.
1567 // MasqueradesAsUndefined only matters for SpecObjectOther, other
1568 // cases are always "false".
1569 if (!(leftType & (SpecObjectOther | SpecOther))) {
1570 setConstant(node, jsBoolean(false));
1574 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) {
1575 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1576 m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint());
1577 setConstant(node, jsBoolean(false));
1583 if (node->child1() == node->child2()) {
1584 if (node->isBinaryUseKind(Int32Use) ||
1585 node->isBinaryUseKind(Int52RepUse) ||
1586 node->isBinaryUseKind(StringUse) ||
1587 node->isBinaryUseKind(BooleanUse) ||
1588 node->isBinaryUseKind(SymbolUse) ||
1589 node->isBinaryUseKind(StringIdentUse) ||
1590 node->isBinaryUseKind(ObjectUse) ||
1591 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) ||
1592 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
1593 switch (node->op()) {
1595 case CompareGreater:
1596 setConstant(node, jsBoolean(false));
1599 case CompareGreaterEq:
1601 setConstant(node, jsBoolean(true));
1604 DFG_CRASH(m_graph, node, "Unexpected node type");
1611 forNode(node).setType(SpecBoolean);
1615 case CompareStrictEq: {
1616 Node* leftNode = node->child1().node();
1617 Node* rightNode = node->child2().node();
1618 JSValue left = forNode(leftNode).value();
1619 JSValue right = forNode(rightNode).value();
1620 if (left && right) {
1621 if (left.isString() && right.isString()) {
1622 // We need this case because JSValue::strictEqual is otherwise too racy for
1623 // string comparisons.
1624 const StringImpl* a = asString(left)->tryGetValueImpl();
1625 const StringImpl* b = asString(right)->tryGetValueImpl();
1627 setConstant(node, jsBoolean(WTF::equal(a, b)));
1631 setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
1636 if (node->isBinaryUseKind(UntypedUse)) {
1637 // FIXME: Revisit this condition when introducing BigInt to JSC.
1638 auto isNonStringCellConstant = [] (JSValue value) {
1639 return value && value.isCell() && !value.isString();
1642 if (isNonStringCellConstant(left) || isNonStringCellConstant(right)) {
1643 m_state.setFoundConstants(true);
1644 forNode(node).setType(SpecBoolean);
1649 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1650 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1651 if (!(leftLUB & rightLUB)) {
1652 setConstant(node, jsBoolean(false));
1656 if (node->child1() == node->child2()) {
1657 if (node->isBinaryUseKind(BooleanUse) ||
1658 node->isBinaryUseKind(Int32Use) ||
1659 node->isBinaryUseKind(Int52RepUse) ||
1660 node->isBinaryUseKind(StringUse) ||
1661 node->isBinaryUseKind(StringIdentUse) ||
1662 node->isBinaryUseKind(SymbolUse) ||
1663 node->isBinaryUseKind(ObjectUse) ||
1664 node->isBinaryUseKind(MiscUse, UntypedUse) ||
1665 node->isBinaryUseKind(UntypedUse, MiscUse) ||
1666 node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
1667 node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
1668 node->isBinaryUseKind(StringUse, UntypedUse) ||
1669 node->isBinaryUseKind(UntypedUse, StringUse)) {
1670 setConstant(node, jsBoolean(true));
1675 forNode(node).setType(SpecBoolean);
1679 case CompareEqPtr: {
1680 Node* childNode = node->child1().node();
1681 JSValue childValue = forNode(childNode).value();
1683 setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
1687 forNode(node).setType(SpecBoolean);
1691 case StringCharCodeAt:
1692 forNode(node).setType(SpecInt32Only);
1695 case StringFromCharCode:
1696 forNode(node).setType(m_graph, SpecString);
1700 forNode(node).set(m_graph, m_vm.stringStructure.get());
1706 case AtomicsCompareExchange:
1707 case AtomicsExchange:
1713 if (node->op() != GetByVal)
1714 clobberWorld(node->origin.semantic, clobberLimit);
1715 switch (node->arrayMode().type()) {
1716 case Array::SelectUsingPredictions:
1717 case Array::Unprofiled:
1718 case Array::SelectUsingArguments:
1719 RELEASE_ASSERT_NOT_REACHED();
1721 case Array::ForceExit:
1722 m_state.setIsValid(false);
1724 case Array::Undecided: {
1725 JSValue index = forNode(node->child2()).value();
1726 if (index && index.isInt32() && index.asInt32() >= 0) {
1727 setConstant(node, jsUndefined());
1730 forNode(node).setType(SpecOther);
1733 case Array::Generic:
1734 clobberWorld(node->origin.semantic, clobberLimit);
1735 forNode(node).makeHeapTop();
1738 if (node->arrayMode().isOutOfBounds()) {
1739 // If the watchpoint was still valid we could totally set this to be
1740 // SpecString | SpecOther. Except that we'd have to be careful. If we
1741 // tested the watchpoint state here then it could change by the time
1742 // we got to the backend. So to do this right, we'd have to get the
1743 // fixup phase to check the watchpoint state and then bake into the
1744 // GetByVal operation the fact that we're using a watchpoint, using
1745 // something like Array::SaneChain (except not quite, because that
1746 // implies an in-bounds access). None of this feels like it's worth it,
1747 // so we're going with TOP for now. The same thing applies to
1748 // clobbering the world.
1749 clobberWorld(node->origin.semantic, clobberLimit);
1750 forNode(node).makeHeapTop();
1752 forNode(node).set(m_graph, m_vm.stringStructure.get());
1754 case Array::DirectArguments:
1755 case Array::ScopedArguments:
1756 forNode(node).makeHeapTop();
1759 if (node->arrayMode().isOutOfBounds()) {
1760 clobberWorld(node->origin.semantic, clobberLimit);
1761 forNode(node).makeHeapTop();
1763 forNode(node).setType(SpecInt32Only);
1766 if (node->arrayMode().isOutOfBounds()) {
1767 clobberWorld(node->origin.semantic, clobberLimit);
1768 forNode(node).makeHeapTop();
1769 } else if (node->arrayMode().isSaneChain())
1770 forNode(node).setType(SpecBytecodeDouble);
1772 forNode(node).setType(SpecDoubleReal);
1774 case Array::Contiguous:
1775 case Array::ArrayStorage:
1776 case Array::SlowPutArrayStorage:
1777 if (node->arrayMode().isOutOfBounds())
1778 clobberWorld(node->origin.semantic, clobberLimit);
1779 forNode(node).makeHeapTop();
1781 case Array::Int8Array:
1782 forNode(node).setType(SpecInt32Only);
1784 case Array::Int16Array:
1785 forNode(node).setType(SpecInt32Only);
1787 case Array::Int32Array:
1788 forNode(node).setType(SpecInt32Only);
1790 case Array::Uint8Array:
1791 forNode(node).setType(SpecInt32Only);
1793 case Array::Uint8ClampedArray:
1794 forNode(node).setType(SpecInt32Only);
1796 case Array::Uint16Array:
1797 forNode(node).setType(SpecInt32Only);
1799 case Array::Uint32Array:
1800 if (node->shouldSpeculateInt32())
1801 forNode(node).setType(SpecInt32Only);
1802 else if (enableInt52() && node->shouldSpeculateAnyInt())
1803 forNode(node).setType(SpecAnyInt);
1805 forNode(node).setType(SpecAnyIntAsDouble);
1807 case Array::Float32Array:
1808 forNode(node).setType(SpecFullDouble);
1810 case Array::Float64Array:
1811 forNode(node).setType(SpecFullDouble);
1814 RELEASE_ASSERT_NOT_REACHED();
1820 case PutByValDirect:
1822 case PutByValAlias: {
1823 switch (node->arrayMode().modeForPut().type()) {
1824 case Array::ForceExit:
1825 m_state.setIsValid(false);
1827 case Array::Generic:
1828 clobberWorld(node->origin.semantic, clobberLimit);
1831 if (node->arrayMode().isOutOfBounds())
1832 clobberWorld(node->origin.semantic, clobberLimit);
1835 if (node->arrayMode().isOutOfBounds())
1836 clobberWorld(node->origin.semantic, clobberLimit);
1838 case Array::Contiguous:
1839 case Array::ArrayStorage:
1840 if (node->arrayMode().isOutOfBounds())
1841 clobberWorld(node->origin.semantic, clobberLimit);
1843 case Array::SlowPutArrayStorage:
1844 if (node->arrayMode().mayStoreToHole())
1845 clobberWorld(node->origin.semantic, clobberLimit);
1854 clobberWorld(node->origin.semantic, clobberLimit);
1855 forNode(node).setType(SpecBytecodeNumber);
1859 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1861 // FIXME: We could do better here if we prove that the
1862 // incoming value has only a single structure.
1863 RegisteredStructureSet structureSet;
1864 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)));
1865 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)));
1866 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)));
1868 forNode(node).set(m_graph, structureSet);
1872 case ArrayIndexOf: {
1873 forNode(node).setType(SpecInt32Only);
1878 clobberWorld(node->origin.semantic, clobberLimit);
1879 forNode(node).makeHeapTop();
1882 case GetMyArgumentByVal:
1883 case GetMyArgumentByValOutOfBounds: {
1884 JSValue index = forNode(node->child2()).m_value;
1885 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame;
1887 if (index && index.isUInt32()) {
1888 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
1889 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
1890 // paths as unreachable, or to return undefined. We could implement that eventually.
1892 Checked<unsigned, RecordOverflow> argumentIndexChecked = index.asUInt32();
1893 argumentIndexChecked += node->numberOfArgumentsToSkip();
1894 unsigned argumentIndex;
1895 if (argumentIndexChecked.safeGet(argumentIndex) != CheckedState::DidOverflow) {
1896 if (inlineCallFrame) {
1897 if (argumentIndex < inlineCallFrame->argumentCountIncludingThis - 1) {
1898 forNode(node) = m_state.variables().operand(
1899 virtualRegisterForArgument(argumentIndex + 1) + inlineCallFrame->stackOffset);
1900 m_state.setFoundConstants(true);
1904 if (argumentIndex < m_state.variables().numberOfArguments() - 1) {
1905 forNode(node) = m_state.variables().argument(argumentIndex + 1);
1906 m_state.setFoundConstants(true);
1913 if (inlineCallFrame) {
1914 // We have a bound on the types even though it's random access. Take advantage of this.
1916 AbstractValue result;
1917 for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->argumentCountIncludingThis; ++i) {
1919 m_state.variables().operand(
1920 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
1923 if (node->op() == GetMyArgumentByValOutOfBounds)
1924 result.merge(SpecOther);
1927 m_state.setFoundConstants(true);
1929 forNode(node) = result;
1933 forNode(node).makeHeapTop();
1938 if (node->child2().useKind() == RegExpObjectUse
1939 && node->child3().useKind() == StringUse) {
1940 // This doesn't clobber the world since there are no conversions to perform.
1942 clobberWorld(node->origin.semantic, clobberLimit);
1943 if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
1944 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
1945 if (!globalObject->isHavingABadTime()) {
1946 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
1947 RegisteredStructureSet structureSet;
1948 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
1949 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayWithGroupsStructure()));
1950 forNode(node).set(m_graph, structureSet);
1951 forNode(node).merge(SpecOther);
1956 forNode(node).setType(m_graph, SpecOther | SpecArray);
1960 if (node->child2().useKind() == RegExpObjectUse
1961 && node->child3().useKind() == StringUse) {
1962 // This doesn't clobber the world since there are no conversions to perform.
1964 clobberWorld(node->origin.semantic, clobberLimit);
1965 forNode(node).setType(SpecBoolean);
1969 case StringReplaceRegExp:
1970 if (node->child1().useKind() == StringUse
1971 && node->child2().useKind() == RegExpObjectUse
1972 && node->child3().useKind() == StringUse) {
1973 // This doesn't clobber the world. It just reads and writes regexp state.
1975 clobberWorld(node->origin.semantic, clobberLimit);
1976 forNode(node).set(m_graph, m_vm.stringStructure.get());
1983 Node* child = node->child1().node();
1984 BooleanResult result = booleanResult(node, forNode(child));
1985 if (result == DefinitelyTrue) {
1986 m_state.setBranchDirection(TakeTrue);
1989 if (result == DefinitelyFalse) {
1990 m_state.setBranchDirection(TakeFalse);
1993 // FIXME: The above handles the trivial cases of sparse conditional
1994 // constant propagation, but we can do better:
1995 // We can specialize the source variable's value on each direction of
1997 m_state.setBranchDirection(TakeBoth);
2002 // Nothing to do for now.
2003 // FIXME: Do sparse conditional things.
2011 m_state.setIsValid(false);
2015 case ThrowStaticError:
2017 case DirectTailCall:
2018 case TailCallVarargs:
2019 case TailCallForwardVarargs:
2020 clobberWorld(node->origin.semantic, clobberLimit);
2021 m_state.setIsValid(false);
2025 JSValue childConst = forNode(node->child1()).value();
2026 if (childConst && childConst.isNumber()) {
2027 setConstant(node, childConst);
2031 ASSERT(node->child1().useKind() == UntypedUse);
2033 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) {
2034 m_state.setFoundConstants(true);
2035 forNode(node) = forNode(node->child1());
2039 clobberWorld(node->origin.semantic, clobberLimit);
2041 forNode(node).setType(m_graph, SpecHeapTop & ~SpecObject);
2046 JSValue childConst = forNode(node->child1()).value();
2047 if (childConst && childConst.isNumber()) {
2048 setConstant(node, childConst);
2052 ASSERT(node->child1().useKind() == UntypedUse);
2054 if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
2055 m_state.setFoundConstants(true);
2056 forNode(node) = forNode(node->child1());
2060 clobberWorld(node->origin.semantic, clobberLimit);
2061 forNode(node).setType(m_graph, SpecBytecodeNumber);
2066 case CallStringConstructor: {
2067 switch (node->child1().useKind()) {
2068 case StringObjectUse:
2069 // This also filters that the StringObject has the primordial StringObject
2073 m_graph.registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()));
2075 case StringOrStringObjectUse:
2083 clobberWorld(node->origin.semantic, clobberLimit);
2086 RELEASE_ASSERT_NOT_REACHED();
2089 forNode(node).set(m_graph, m_vm.stringStructure.get());
2093 case NumberToStringWithRadix: {
2094 JSValue radixValue = forNode(node->child2()).m_value;
2095 if (radixValue && radixValue.isInt32()) {
2096 int32_t radix = radixValue.asInt32();
2097 if (2 <= radix && radix <= 36) {
2098 m_state.setFoundConstants(true);
2099 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2103 clobberWorld(node->origin.semantic, clobberLimit);
2104 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2108 case NumberToStringWithValidRadixConstant: {
2109 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2113 case NewStringObject: {
2114 ASSERT(node->structure()->classInfo() == StringObject::info());
2115 forNode(node).set(m_graph, node->structure());
2122 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2125 case NewArrayWithSpread:
2126 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2127 // We've compiled assuming we're not having a bad time, so to be consistent
2128 // with StructureRegisterationPhase we must say we produce an original array
2129 // allocation structure.
2132 m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
2136 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
2143 m_graph, m_vm.fixedArrayStructure.get());
2146 case NewArrayBuffer:
2149 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2152 case NewArrayWithSize:
2153 forNode(node).setType(m_graph, SpecArray);
2157 switch (node->child1().useKind()) {
2161 clobberWorld(node->origin.semantic, clobberLimit);
2164 RELEASE_ASSERT_NOT_REACHED();
2169 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(
2170 node->typedArrayType()));
2174 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
2178 AbstractValue& source = forNode(node->child1());
2179 AbstractValue& destination = forNode(node);
2180 bool strictMode = m_graph.executableFor(node->origin.semantic)->isStrictMode();
2182 ToThisResult result = isToThisAnIdentity(m_vm, strictMode, source);
2183 if (result != ToThisResult::Dynamic) {
2185 case ToThisResult::Identity:
2186 m_state.setFoundConstants(true);
2187 destination = source;
2189 case ToThisResult::Undefined:
2190 setConstant(node, jsUndefined());
2192 case ToThisResult::GlobalThis:
2193 m_state.setFoundConstants(true);
2194 destination.setType(m_graph, SpecObject);
2196 case ToThisResult::Dynamic:
2197 RELEASE_ASSERT_NOT_REACHED();
2203 destination.makeHeapTop();
2205 destination = source;
2206 destination.merge(SpecObject);
2212 // FIXME: We can fold this to NewObject if the incoming callee is a constant.
2213 forNode(node).setType(m_graph, SpecFinalObject);
2218 ASSERT(!!node->structure().get());
2219 forNode(node).set(m_graph, node->structure());
2223 case CallObjectConstructor: {
2224 AbstractValue& source = forNode(node->child1());
2225 AbstractValue& destination = forNode(node);
2227 if (!(source.m_type & ~SpecObject)) {
2228 m_state.setFoundConstants(true);
2229 destination = source;
2233 if (node->op() == ToObject)
2234 clobberWorld(node->origin.semantic, clobberLimit);
2235 forNode(node).setType(m_graph, SpecObject);
2239 case PhantomNewObject:
2240 case PhantomNewFunction:
2241 case PhantomNewGeneratorFunction:
2242 case PhantomNewAsyncGeneratorFunction:
2243 case PhantomNewAsyncFunction:
2244 case PhantomCreateActivation:
2245 case PhantomDirectArguments:
2246 case PhantomClonedArguments:
2247 case PhantomCreateRest:
2249 case PhantomNewArrayWithSpread:
2250 case PhantomNewArrayBuffer:
2252 m_state.setDidClobber(true); // Prevent constant folding.
2253 // This claims to return bottom.
2259 case MaterializeNewObject: {
2260 forNode(node).set(m_graph, node->structureSet());
2265 // We don't use the more precise withScopeStructure() here because it is a LazyProperty and may not yet be allocated.
2266 forNode(node).setType(m_graph, SpecObjectOther);
2269 case CreateActivation:
2270 case MaterializeCreateActivation:
2272 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
2275 case CreateDirectArguments:
2276 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
2279 case CreateScopedArguments:
2280 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
2283 case CreateClonedArguments:
2284 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2285 forNode(node).setType(m_graph, SpecObject);
2288 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
2291 case NewGeneratorFunction:
2293 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
2296 case NewAsyncGeneratorFunction:
2298 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncGeneratorFunctionStructure());
2301 case NewAsyncFunction:
2303 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
2307 JSGlobalObject* globalObject = m_codeBlock->globalObjectFor(node->origin.semantic);
2308 Structure* structure = JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
2309 forNode(node).set(m_graph, structure);
2314 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
2315 InferredValue* singleton = executable->singletonFunction();
2316 if (JSValue value = singleton->inferredValue()) {
2317 m_graph.watchpoints().addLazily(singleton);
2318 JSFunction* function = jsCast<JSFunction*>(value);
2319 setConstant(node, *m_graph.freeze(function));
2323 forNode(node).setType(m_graph, SpecFunction);
2326 case GetArgumentCountIncludingThis:
2327 forNode(node).setType(SpecInt32Only);
2331 forNode(node).setType(SpecInt32Only);
2335 JSValue base = forNode(node->child1()).m_value;
2337 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2338 if (!getterSetter->isGetterNull()) {
2339 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
2344 forNode(node).setType(m_graph, SpecObject);
2349 JSValue base = forNode(node->child1()).m_value;
2351 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2352 if (!getterSetter->isSetterNull()) {
2353 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
2358 forNode(node).setType(m_graph, SpecObject);
2363 if (JSValue base = forNode(node->child1()).m_value) {
2364 if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2365 setConstant(node, *m_graph.freeze(function->scope()));
2369 forNode(node).setType(m_graph, SpecObjectOther);
2373 JSValue child = forNode(node->child1()).value();
2375 setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next())));
2378 forNode(node).setType(m_graph, SpecObjectOther);
2382 case GetGlobalObject: {
2383 JSValue child = forNode(node->child1()).value();
2385 setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject())));
2389 if (forNode(node->child1()).m_structure.isFinite()) {
2390 JSGlobalObject* globalObject = nullptr;
2392 forNode(node->child1()).m_structure.forEach(
2393 [&] (RegisteredStructure structure) {
2395 globalObject = structure->globalObject();
2396 else if (globalObject != structure->globalObject())
2399 if (globalObject && ok) {
2400 setConstant(node, *m_graph.freeze(JSValue(globalObject)));
2405 forNode(node).setType(m_graph, SpecObjectOther);
2409 case GetGlobalThis: {
2410 forNode(node).setType(m_graph, SpecObject);
2415 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
2416 setConstant(node, *m_graph.freeze(value));
2419 forNode(node).makeBytecodeTop();
2425 case GetRegExpObjectLastIndex:
2426 forNode(node).makeHeapTop();
2429 case SetRegExpObjectLastIndex:
2430 case RecordRegExpCachedResult:
2433 case GetFromArguments:
2434 forNode(node).makeHeapTop();
2437 case PutToArguments:
2441 forNode(node).makeHeapTop();
2445 // FIXME: This should constant fold at least as well as the normal GetById case.
2446 // https://bugs.webkit.org/show_bug.cgi?id=156422
2447 forNode(node).makeHeapTop();
2451 case GetByIdFlush: {
2452 if (!node->prediction()) {
2453 m_state.setIsValid(false);
2457 AbstractValue& value = forNode(node->child1());
2458 if (value.m_structure.isFinite()
2459 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
2460 UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
2461 GetByIdStatus status = GetByIdStatus::computeFor(value.m_structure.toStructureSet(), uid);
2462 if (status.isSimple()) {
2463 // Figure out what the result is going to be - is it TOP, a constant, or maybe
2464 // something more subtle?
2465 AbstractValue result;
2466 for (unsigned i = status.numVariants(); i--;) {
2467 // This thing won't give us a variant that involves prototypes. If it did, we'd
2468 // have more work to do here.
2469 DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty());
2472 m_graph.inferredValueForProperty(
2473 value, uid, status[i].offset(), m_state.structureClobberState()));
2475 m_state.setFoundConstants(true);
2476 forNode(node) = result;
2481 clobberWorld(node->origin.semantic, clobberLimit);
2482 forNode(node).makeHeapTop();
2486 case GetByValWithThis:
2487 case GetByIdWithThis:
2488 clobberWorld(node->origin.semantic, clobberLimit);
2489 forNode(node).makeHeapTop();
2492 case GetArrayLength: {
2493 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2494 forNode(node->child1()).m_value, node->arrayMode());
2496 setConstant(node, jsNumber(view->length()));
2499 forNode(node).setType(SpecInt32Only);
2503 case GetVectorLength: {
2504 forNode(node).setType(SpecInt32Only);
2510 // FIXME: This could decide if the delete will be successful based on the set of structures that
2511 // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
2512 clobberWorld(node->origin.semantic, clobberLimit);
2513 forNode(node).setType(SpecBoolean);
2517 case CheckStructure: {
2518 AbstractValue& value = forNode(node->child1());
2520 const RegisteredStructureSet& set = node->structureSet();
2522 // It's interesting that we could have proven that the object has a larger structure set
2523 // that includes the set we're testing. In that case we could make the structure check
2524 // more efficient. We currently don't.
2526 if (value.m_structure.isSubsetOf(set))
2527 m_state.setFoundConstants(true);
2529 SpeculatedType admittedTypes = SpecNone;
2530 switch (node->child1().useKind()) {
2533 admittedTypes = SpecNone;
2535 case CellOrOtherUse:
2536 admittedTypes = SpecOther;
2539 DFG_CRASH(m_graph, node, "Bad use kind");
2543 filter(value, set, admittedTypes);
2547 case CheckStructureOrEmpty: {
2548 AbstractValue& value = forNode(node->child1());
2550 bool mayBeEmpty = value.m_type & SpecEmpty;
2552 m_state.setFoundConstants(true);
2554 SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone;
2555 filter(value, node->structureSet(), admittedTypes);
2559 case CheckStructureImmediate: {
2560 // FIXME: This currently can only reason about one structure at a time.
2561 // https://bugs.webkit.org/show_bug.cgi?id=136988
2563 AbstractValue& value = forNode(node->child1());
2564 const RegisteredStructureSet& set = node->structureSet();
2566 if (value.value()) {
2567 if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) {
2568 if (set.contains(m_graph.registerStructure(structure))) {
2569 m_state.setFoundConstants(true);
2573 m_state.setIsValid(false);
2577 if (m_phiChildren) {
2578 bool allGood = true;
2579 m_phiChildren->forAllTransitiveIncomingValues(
2581 [&] (Node* incoming) {
2582 if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) {
2583 if (set.contains(m_graph.registerStructure(structure)))
2589 m_state.setFoundConstants(true);
2594 if (RegisteredStructure structure = set.onlyStructure()) {
2595 filterByValue(node->child1(), *m_graph.freeze(structure.get()));
2599 // Aw shucks, we can't do anything!
2604 if (!forNode(node->child1()).m_structure.isClear()) {
2605 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
2606 m_state.setFoundConstants(true);
2609 clobberLimit, node->transition()->previous, node->transition()->next);
2610 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
2615 case AllocatePropertyStorage:
2616 case ReallocatePropertyStorage:
2617 case NukeStructureAndSetButterfly:
2618 // FIXME: We don't model the fact that the structureID is nuked, simply because currently
2619 // nobody would currently benefit from having that information. But it's a bug nonetheless.
2620 forNode(node).clear(); // The result is not a JS value.
2622 case CheckSubClass: {
2623 JSValue constant = forNode(node->child1()).value();
2625 if (constant.isCell() && constant.asCell()->inherits(m_vm, node->classInfo())) {
2626 m_state.setFoundConstants(true);
2632 AbstractValue& value = forNode(node->child1());
2634 if (value.m_structure.isSubClassOf(node->classInfo()))
2635 m_state.setFoundConstants(true);
2637 filterClassInfo(value, node->classInfo());
2640 case CallDOMGetter: {
2641 CallDOMGetterData* callDOMGetterData = node->callDOMGetterData();
2642 DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet;
2643 if (!snippet || snippet->effect.writes)
2644 clobberWorld(node->origin.semantic, clobberLimit);
2645 if (callDOMGetterData->domJIT)
2646 forNode(node).setType(m_graph, callDOMGetterData->domJIT->resultType());
2648 forNode(node).makeBytecodeTop();
2652 const DOMJIT::Signature* signature = node->signature();
2653 if (signature->effect.writes)
2654 clobberWorld(node->origin.semantic, clobberLimit);
2655 forNode(node).setType(m_graph, signature->result);
2659 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2660 m_state.setFoundConstants(true);
2663 switch (node->arrayMode().type()) {
2665 filter(node->child1(), SpecString);
2669 case Array::Contiguous:
2670 case Array::Undecided:
2671 case Array::ArrayStorage:
2672 case Array::SlowPutArrayStorage:
2674 case Array::DirectArguments:
2675 filter(node->child1(), SpecDirectArguments);
2677 case Array::ScopedArguments:
2678 filter(node->child1(), SpecScopedArguments);
2680 case Array::Int8Array:
2681 filter(node->child1(), SpecInt8Array);
2683 case Array::Int16Array:
2684 filter(node->child1(), SpecInt16Array);
2686 case Array::Int32Array:
2687 filter(node->child1(), SpecInt32Array);
2689 case Array::Uint8Array:
2690 filter(node->child1(), SpecUint8Array);
2692 case Array::Uint8ClampedArray:
2693 filter(node->child1(), SpecUint8ClampedArray);
2695 case Array::Uint16Array:
2696 filter(node->child1(), SpecUint16Array);
2698 case Array::Uint32Array:
2699 filter(node->child1(), SpecUint32Array);
2701 case Array::Float32Array:
2702 filter(node->child1(), SpecFloat32Array);
2704 case Array::Float64Array:
2705 filter(node->child1(), SpecFloat64Array);
2707 case Array::AnyTypedArray:
2708 filter(node->child1(), SpecTypedArrayView);
2711 RELEASE_ASSERT_NOT_REACHED();
2714 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2718 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2719 m_state.setFoundConstants(true);
2722 ASSERT(node->arrayMode().conversion() == Array::Convert);
2723 clobberStructures(clobberLimit);
2724 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2727 case ArrayifyToStructure: {
2728 AbstractValue& value = forNode(node->child1());
2729 if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure())))
2730 m_state.setFoundConstants(true);
2731 clobberStructures(clobberLimit);
2733 // We have a bunch of options of how to express the abstract set at this point. Let set S
2734 // be the set of structures that the value had before clobbering and assume that all of
2735 // them are watchable. The new value should be the least expressible upper bound of the
2736 // intersection of "values that currently have structure = node->structure()" and "values
2737 // that have structure in S plus any structure transition-reachable from S". Assume that
2738 // node->structure() is not in S but it is transition-reachable from S. Then we would
2739 // like to say that the result is "values that have structure = node->structure() until
2740 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
2741 // we must choose between:
2743 // 1) "values that currently have structure = node->structure()". This is a valid
2744 // superset of the value that we really want, and it's specific enough to satisfy the
2745 // preconditions of the array access that this is guarding. It's also specific enough
2746 // to allow relevant optimizations in the case that we didn't have a contradiction
2747 // like in this example. Notice that in the abscence of any contradiction, this result
2748 // is precise rather than being a conservative LUB.
2750 // 2) "values that currently hava structure in S plus any structure transition-reachable
2751 // from S". This is also a valid superset of the value that we really want, but it's
2752 // not specific enough to satisfy the preconditions of the array access that this is
2753 // guarding - so playing such shenanigans would preclude us from having assertions on
2754 // the typing preconditions of any array accesses. This would also not be a desirable
2755 // answer in the absence of a contradiction.
2757 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
2758 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
2760 value.set(m_graph, node->structure());
2763 case GetIndexedPropertyStorage: {
2764 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2765 forNode(node->child1()).m_value, node->arrayMode());
2767 m_state.setFoundConstants(true);
2768 forNode(node).clear();
2771 case ConstantStoragePointer: {
2772 forNode(node).clear();
2776 case GetTypedArrayByteOffset: {
2777 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
2779 setConstant(node, jsNumber(view->byteOffset()));
2782 forNode(node).setType(SpecInt32Only);
2786 case GetPrototypeOf: {
2787 AbstractValue& value = forNode(node->child1());
2788 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
2789 bool canFold = !value.m_structure.isClear();
2791 value.m_structure.forEach([&] (RegisteredStructure structure) {
2792 auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
2793 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
2794 if (getPrototypeMethod != defaultGetPrototype) {
2799 if (structure->hasPolyProto()) {
2804 prototype = structure->storedPrototype();
2805 else if (prototype != structure->storedPrototype())
2809 if (prototype && canFold) {
2810 setConstant(node, *m_graph.freeze(prototype));
2815 switch (node->child1().useKind()) {
2818 case FinalObjectUse:
2821 clobberWorld(node->origin.semantic, clobberLimit);
2824 forNode(node).setType(m_graph, SpecObject | SpecOther);
2829 StorageAccessData& data = node->storageAccessData();
2830 UniquedStringImpl* uid = m_graph.identifiers()[data.identifierNumber];
2832 // FIXME: The part of this that handles inferred property types relies on AI knowing the structure
2833 // right now. That's probably not optimal. In some cases, we may perform an optimization (usually
2834 // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure
2835 // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely
2836 // on the type that ByteCodeParser was able to prove.
2837 AbstractValue value = m_graph.inferredValueForProperty(
2838 forNode(node->child2()), uid, data.offset, m_state.structureClobberState());
2840 // It's possible that the type that ByteCodeParser came up with is better.
2841 AbstractValue typeFromParsing;
2842 typeFromParsing.set(m_graph, data.inferredType, m_state.structureClobberState());
2843 value.filter(typeFromParsing);
2845 // If we decide that there does not exist any value that this can return, then it's probably
2846 // because the compilation was already invalidated.
2847 if (value.isClear())
2848 m_state.setIsValid(false);
2850 forNode(node) = value;
2852 m_state.setFoundConstants(true);
2856 case GetGetterSetterByOffset: {
2857 StorageAccessData& data = node->storageAccessData();
2858 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
2859 if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) {
2860 setConstant(node, *m_graph.freeze(result));
2864 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->getterSetterStructure());
2868 case MultiGetByOffset: {
2869 // This code will filter the base value in a manner that is possibly different (either more
2870 // or less precise) than the way it would be filtered if this was strength-reduced to a
2871 // CheckStructure. This is fine. It's legal for different passes over the code to prove
2872 // different things about the code, so long as all of them are sound. That even includes
2873 // one guy proving that code should never execute (due to a contradiction) and another guy
2874 // not finding that contradiction. If someone ever proved that there would be a
2875 // contradiction then there must always be a contradiction even if subsequent passes don't
2876 // realize it. This is the case here.
2878 // Ordinarily you have to be careful with calling setFoundConstants()
2879 // because of the effect on compile times, but this node is FTL-only.
2880 m_state.setFoundConstants(true);
2882 UniquedStringImpl* uid = m_graph.identifiers()[node->multiGetByOffsetData().identifierNumber];
2884 AbstractValue base = forNode(node->child1());
2885 RegisteredStructureSet baseSet;
2886 AbstractValue result;
2887 for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
2888 RegisteredStructureSet set = getCase.set();
2894 switch (getCase.method().kind()) {
2895 case GetByOffsetMethod::Constant: {
2896 AbstractValue thisResult;
2899 *getCase.method().constant(),
2900 m_state.structureClobberState());
2901 result.merge(thisResult);
2905 case GetByOffsetMethod::Load: {
2907 m_graph.inferredValueForProperty(
2908 set, uid, m_state.structureClobberState()));
2913 result.makeHeapTop();
2918 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
2919 m_state.setIsValid(false);
2921 forNode(node) = result;
2929 case MultiPutByOffset: {
2930 RegisteredStructureSet newSet;
2931 TransitionVector transitions;
2933 // Ordinarily you have to be careful with calling setFoundConstants()
2934 // because of the effect on compile times, but this node is FTL-only.
2935 m_state.setFoundConstants(true);
2937 AbstractValue base = forNode(node->child1());
2938 AbstractValue originalValue = forNode(node->child2());
2939 AbstractValue resultingValue;
2941 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
2942 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
2943 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure());
2944 thisSet.filter(base);
2945 if (thisSet.isEmpty())
2948 AbstractValue thisValue = originalValue;
2949 thisValue.filter(m_graph, variant.requiredType());
2950 resultingValue.merge(thisValue);
2952 if (variant.kind() == PutByIdVariant::Transition) {
2953 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
2954 if (thisSet.onlyStructure() != newStructure) {
2956 Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
2957 } // else this is really a replace.
2958 newSet.add(newStructure);
2960 ASSERT(variant.kind() == PutByIdVariant::Replace);
2961 newSet.merge(thisSet);
2965 observeTransitions(clobberLimit, transitions);
2966 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
2967 m_state.setIsValid(false);
2968 forNode(node->child2()) = resultingValue;
2969 if (!!originalValue && !resultingValue)
2970 m_state.setIsValid(false);
2974 case GetExecutable: {
2975 JSValue value = forNode(node->child1()).value();
2977 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
2979 setConstant(node, *m_graph.freeze(function->executable()));
2983 forNode(node).setType(m_graph, SpecCellOther);
2988 JSValue value = forNode(node->child1()).value();
2989 if (value == node->cellOperand()->value()) {
2990 m_state.setFoundConstants(true);
2994 filterByValue(node->child1(), *node->cellOperand());
2998 case CheckNotEmpty: {
2999 AbstractValue& value = forNode(node->child1());
3000 if (!(value.m_type & SpecEmpty)) {
3001 m_state.setFoundConstants(true);
3005 filter(value, ~SpecEmpty);
3009 case CheckStringIdent: {
3010 AbstractValue& value = forNode(node->child1());
3011 UniquedStringImpl* uid = node->uidOperand();
3012 ASSERT(!(value.m_type & ~SpecStringIdent)); // Edge filtering should have already ensured this.
3014 JSValue childConstant = value.value();
3015 if (childConstant) {
3016 ASSERT(childConstant.isString());
3017 if (asString(childConstant)->tryGetValueImpl() == uid) {
3018 m_state.setFoundConstants(true);
3023 filter(value, SpecStringIdent);