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 namespace JSC { namespace DFG {
45 template<typename AbstractStateType>
46 AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state)
47 : m_codeBlock(graph.m_codeBlock)
52 if (m_graph.m_form == SSA)
53 m_phiChildren = std::make_unique<PhiChildren>(m_graph);
56 template<typename AbstractStateType>
57 AbstractInterpreter<AbstractStateType>::~AbstractInterpreter()
61 template<typename AbstractStateType>
62 typename AbstractInterpreter<AbstractStateType>::BooleanResult
63 AbstractInterpreter<AbstractStateType>::booleanResult(
64 Node* node, AbstractValue& value)
66 JSValue childConst = value.value();
68 if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic)->globalExec()))
69 return DefinitelyTrue;
70 return DefinitelyFalse;
73 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
74 if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
76 for (unsigned i = value.m_structure.size(); i--;) {
77 RegisteredStructure structure = value.m_structure[i];
78 if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
79 || structure->typeInfo().type() == StringType) {
85 return DefinitelyTrue;
88 return UnknownBooleanResult;
91 template<typename AbstractStateType>
92 void AbstractInterpreter<AbstractStateType>::startExecuting()
94 ASSERT(m_state.block());
95 ASSERT(m_state.isValid());
97 m_state.setDidClobber(false);
100 template<typename AbstractStateType>
101 void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node)
103 m_graph.doToChildren(
106 filterEdgeByUse(edge);
110 template<typename AbstractStateType>
111 void AbstractInterpreter<AbstractStateType>::executeKnownEdgeTypes(Node* node)
113 // Some use kinds are required to not have checks, because we know somehow that the incoming
114 // value will already have the type we want. In those cases, AI may not be smart enough to
115 // prove that this is indeed the case. But the existance of the edge is enough to prove that
116 // it is indeed the case. Taking advantage of this is not optional, since otherwise the DFG
117 // and FTL backends may emit checks in a node that lacks a valid exit origin.
118 m_graph.doToChildren(
121 if (mayHaveTypeCheck(edge.useKind()))
124 filterEdgeByUse(edge);
128 template<typename AbstractStateType>
129 void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
131 if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())))
134 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(), AIEdgeVerificationFailed, node->op(), edge->op(), forNode(edge).m_type, typeFilterFor(edge.useKind()));
137 template<typename AbstractStateType>
138 void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
140 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
143 inline bool isToThisAnIdentity(bool isStrictMode, AbstractValue& valueForNode)
145 // We look at the type first since that will cover most cases and does not require iterating all the structures.
147 if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther))
150 if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther)))
154 if ((isStrictMode || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) {
155 bool overridesToThis = false;
156 valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
157 TypeInfo type = structure->typeInfo();
158 ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType);
160 ASSERT(type.isObject());
161 // We don't need to worry about strings/symbols here since either:
162 // 1) We are in strict mode and strings/symbols are not wrapped
163 // 2) The AI has proven that the type of this is a subtype of object
164 if (type.isObject() && type.overridesToThis())
165 overridesToThis = true;
167 return !overridesToThis;
173 template<typename AbstractStateType>
174 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
178 m_state.createValueForNode(node);
180 switch (node->op()) {
183 case Int52Constant: {
184 setBuiltInConstant(node, *node->constant());
188 case LazyJSConstant: {
189 LazyJSValue value = node->lazyJSValue();
190 switch (value.kind()) {
191 case LazyJSValue::KnownValue:
192 setConstant(node, value.value()->value());
194 case LazyJSValue::SingleCharacterString:
195 case LazyJSValue::KnownStringImpl:
196 case LazyJSValue::NewStringImpl:
197 forNode(node).setType(m_graph, SpecString);
204 forNode(node) = forNode(node->child1());
205 if (forNode(node).value())
206 m_state.setFoundConstants(true);
210 case ExtractOSREntryLocal: {
211 forNode(node).makeBytecodeTop();
216 VariableAccessData* variableAccessData = node->variableAccessData();
217 AbstractValue value = m_state.variables().operand(variableAccessData->local().offset());
218 // The value in the local should already be checked.
219 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
221 m_state.setFoundConstants(true);
222 forNode(node) = value;
227 StackAccessData* data = node->stackAccessData();
228 AbstractValue value = m_state.variables().operand(data->local);
229 // The value in the local should already be checked.
230 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
232 m_state.setFoundConstants(true);
233 forNode(node) = value;
237 case GetLocalUnlinked: {
238 AbstractValue value = m_state.variables().operand(node->unlinkedLocal().offset());
240 m_state.setFoundConstants(true);
241 forNode(node) = value;
246 m_state.variables().operand(node->local()) = forNode(node->child1());
251 m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1());
256 // Don't need to do anything. A MovHint only informs us about what would have happened
257 // in bytecode, but this code is just concerned with what is actually happening during
263 // This is just a hint telling us that the OSR state of the local is no longer inside the
269 // Assert that the state of arguments has been set. SetArgument means that someone set
270 // the argument values out-of-band, and currently this always means setting to a
272 ASSERT(!m_state.variables().operand(node->local()).isClear());
276 case ForwardVarargs: {
277 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
278 // itself into a straight-line sequence of GetStack/PutStack.
279 // https://bugs.webkit.org/show_bug.cgi?id=143071
280 clobberWorld(node->origin.semantic, clobberLimit);
281 LoadVarargsData* data = node->loadVarargsData();
282 m_state.variables().operand(data->count).setType(SpecInt32Only);
283 for (unsigned i = data->limit - 1; i--;)
284 m_state.variables().operand(data->start.offset() + i).makeHeapTop();
294 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
295 clobberWorld(node->origin.semantic, clobberLimit);
296 forNode(node).setType(m_graph, SpecInt32Only);
300 JSValue left = forNode(node->child1()).value();
301 JSValue right = forNode(node->child2()).value();
302 if (left && right && left.isInt32() && right.isInt32()) {
303 int32_t a = left.asInt32();
304 int32_t b = right.asInt32();
305 switch (node->op()) {
307 setConstant(node, JSValue(a & b));
310 setConstant(node, JSValue(a | b));
313 setConstant(node, JSValue(a ^ b));
316 setConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
319 setConstant(node, JSValue(a << static_cast<uint32_t>(b)));
322 setConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
325 RELEASE_ASSERT_NOT_REACHED();
331 if (node->op() == BitAnd
332 && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
333 isBoolInt32Speculation(forNode(node->child2()).m_type))) {
334 forNode(node).setType(SpecBoolInt32);
338 forNode(node).setType(SpecInt32Only);
342 case UInt32ToNumber: {
343 JSValue child = forNode(node->child1()).value();
344 if (doesOverflow(node->arithMode())) {
346 if (child && child.isAnyInt()) {
347 int64_t machineInt = child.asAnyInt();
348 setConstant(node, jsNumber(static_cast<uint32_t>(machineInt)));
351 forNode(node).setType(SpecAnyInt);
354 if (child && child.isInt32()) {
355 uint32_t value = child.asInt32();
356 setConstant(node, jsNumber(value));
359 forNode(node).setType(SpecAnyIntAsDouble);
362 if (child && child.isInt32()) {
363 int32_t value = child.asInt32();
365 setConstant(node, jsNumber(value));
369 forNode(node).setType(SpecInt32Only);
373 case BooleanToNumber: {
374 JSValue concreteValue = forNode(node->child1()).value();
376 if (concreteValue.isBoolean())
377 setConstant(node, jsNumber(concreteValue.asBoolean()));
379 setConstant(node, *m_graph.freeze(concreteValue));
382 AbstractValue& value = forNode(node);
383 value = forNode(node->child1());
384 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
385 m_state.setFoundConstants(true);
386 if (value.m_type & SpecBoolean) {
387 value.merge(SpecBoolInt32);
388 value.filter(~SpecBoolean);
393 case DoubleAsInt32: {
394 JSValue child = forNode(node->child1()).value();
395 if (child && child.isNumber()) {
396 double asDouble = child.asNumber();
397 int32_t asInt = JSC::toInt32(asDouble);
398 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
399 setConstant(node, JSValue(asInt));
403 forNode(node).setType(SpecInt32Only);
408 JSValue child = forNode(node->child1()).value();
410 if (child.isNumber()) {
412 setConstant(node, child);
414 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
417 if (child.isBoolean()) {
418 setConstant(node, jsNumber(child.asBoolean()));
421 if (child.isUndefinedOrNull()) {
422 setConstant(node, jsNumber(0));
427 if (isBooleanSpeculation(forNode(node->child1()).m_type)) {
428 forNode(node).setType(SpecBoolInt32);
432 forNode(node).setType(SpecInt32Only);
437 JSValue child = forNode(node->child1()).value();
438 if (std::optional<double> number = child.toNumberFromPrimitive()) {
439 setConstant(node, jsDoubleNumber(*number));
443 SpeculatedType type = forNode(node->child1()).m_type;
444 switch (node->child1().useKind()) {
446 if (type & SpecOther) {
448 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
450 if (type & SpecBoolean) {
451 type &= ~SpecBoolean;
452 type |= SpecBoolInt32; // True becomes 1, false becomes 0.
454 type &= SpecBytecodeNumber;
464 RELEASE_ASSERT_NOT_REACHED();
466 forNode(node).setType(type);
467 forNode(node).fixTypeForRepresentation(m_graph, node);
472 JSValue child = forNode(node->child1()).value();
473 if (child && child.isAnyInt()) {
474 setConstant(node, child);
478 forNode(node).setType(SpecAnyInt);
483 JSValue value = forNode(node->child1()).value();
485 setConstant(node, value);
489 forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
490 forNode(node).fixTypeForRepresentation(m_graph, node);
495 ASSERT(node->binaryUseKind() == UntypedUse);
496 clobberWorld(node->origin.semantic, clobberLimit);
497 forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber);
502 forNode(node).setType(m_graph, SpecString);
507 JSValue left = forNode(node->child1()).value();
508 JSValue right = forNode(node->child2()).value();
509 switch (node->binaryUseKind()) {
511 if (left && right && left.isInt32() && right.isInt32()) {
512 if (!shouldCheckOverflow(node->arithMode())) {
513 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
516 JSValue result = jsNumber(left.asNumber() + right.asNumber());
517 if (result.isInt32()) {
518 setConstant(node, result);
522 forNode(node).setType(SpecInt32Only);
525 if (left && right && left.isAnyInt() && right.isAnyInt()) {
526 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt());
527 if (result.isAnyInt()) {
528 setConstant(node, result);
532 forNode(node).setType(SpecAnyInt);
535 if (left && right && left.isNumber() && right.isNumber()) {
536 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
539 forNode(node).setType(
541 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
544 RELEASE_ASSERT_NOT_REACHED();
550 case AtomicsIsLockFree: {
551 if (node->child1().useKind() != Int32Use)
552 clobberWorld(node->origin.semantic, clobberLimit);
553 forNode(node).setType(SpecBoolInt32);
558 JSValue operand = forNode(node->child1()).value();
559 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
560 uint32_t value = toUInt32(*number);
561 setConstant(node, jsNumber(clz32(value)));
564 forNode(node).setType(SpecInt32Only);
569 unsigned numberOfChildren = 0;
570 unsigned numberOfRemovedChildren = 0;
571 std::optional<unsigned> nonEmptyIndex;
572 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
573 Edge& edge = node->children.child(i);
578 JSValue childConstant = m_state.forNode(edge).value();
579 if (!childConstant) {
583 if (!childConstant.isString()) {
587 if (asString(childConstant)->length()) {
592 ++numberOfRemovedChildren;
595 if (numberOfRemovedChildren) {
596 m_state.setFoundConstants(true);
597 if (numberOfRemovedChildren == numberOfChildren) {
598 // Propagate the last child. This is the way taken in the constant folding phase.
599 forNode(node) = forNode(node->children.child(numberOfChildren - 1));
602 if ((numberOfRemovedChildren + 1) == numberOfChildren) {
603 ASSERT(nonEmptyIndex);
604 forNode(node) = forNode(node->children.child(nonEmptyIndex.value()));
608 forNode(node).set(m_graph, m_vm.stringStructure.get());
613 JSValue left = forNode(node->child1()).value();
614 JSValue right = forNode(node->child2()).value();
615 switch (node->binaryUseKind()) {
617 if (left && right && left.isInt32() && right.isInt32()) {
618 if (!shouldCheckOverflow(node->arithMode())) {
619 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
622 JSValue result = jsNumber(left.asNumber() - right.asNumber());
623 if (result.isInt32()) {
624 setConstant(node, result);
628 forNode(node).setType(SpecInt32Only);
631 if (left && right && left.isAnyInt() && right.isAnyInt()) {
632 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt());
633 if (result.isAnyInt() || !shouldCheckOverflow(node->arithMode())) {
634 setConstant(node, result);
638 forNode(node).setType(SpecAnyInt);
641 if (left && right && left.isNumber() && right.isNumber()) {
642 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
645 forNode(node).setType(
646 typeOfDoubleDifference(
647 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
650 clobberWorld(node->origin.semantic, clobberLimit);
651 forNode(node).setType(m_graph, SpecBytecodeNumber);
654 RELEASE_ASSERT_NOT_REACHED();
661 JSValue child = forNode(node->child1()).value();
662 switch (node->child1().useKind()) {
664 if (child && child.isInt32()) {
665 if (!shouldCheckOverflow(node->arithMode())) {
666 setConstant(node, jsNumber(-child.asInt32()));
670 if (shouldCheckNegativeZero(node->arithMode()))
671 doubleResult = -child.asNumber();
673 doubleResult = 0 - child.asNumber();
674 JSValue valueResult = jsNumber(doubleResult);
675 if (valueResult.isInt32()) {
676 setConstant(node, valueResult);
680 forNode(node).setType(SpecInt32Only);
683 if (child && child.isAnyInt()) {
685 if (shouldCheckNegativeZero(node->arithMode()))
686 doubleResult = -child.asNumber();
688 doubleResult = 0 - child.asNumber();
689 JSValue valueResult = jsNumber(doubleResult);
690 if (valueResult.isAnyInt()) {
691 setConstant(node, valueResult);
695 forNode(node).setType(SpecAnyInt);
698 if (child && child.isNumber()) {
699 setConstant(node, jsDoubleNumber(-child.asNumber()));
702 forNode(node).setType(
703 typeOfDoubleNegation(
704 forNode(node->child1()).m_type));
707 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
708 forNode(node).setType(SpecBytecodeNumber);
715 JSValue left = forNode(node->child1()).value();
716 JSValue right = forNode(node->child2()).value();
717 switch (node->binaryUseKind()) {
719 if (left && right && left.isInt32() && right.isInt32()) {
720 if (!shouldCheckOverflow(node->arithMode())) {
721 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
724 double doubleResult = left.asNumber() * right.asNumber();
725 if (!shouldCheckNegativeZero(node->arithMode()))
726 doubleResult += 0; // Sanitizes zero.
727 JSValue valueResult = jsNumber(doubleResult);
728 if (valueResult.isInt32()) {
729 setConstant(node, valueResult);
733 forNode(node).setType(SpecInt32Only);
736 if (left && right && left.isAnyInt() && right.isAnyInt()) {
737 double doubleResult = left.asNumber() * right.asNumber();
738 if (!shouldCheckNegativeZero(node->arithMode()))
740 JSValue valueResult = jsNumber(doubleResult);
741 if (valueResult.isAnyInt()) {
742 setConstant(node, valueResult);
746 forNode(node).setType(SpecAnyInt);
749 if (left && right && left.isNumber() && right.isNumber()) {
750 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
753 forNode(node).setType(
755 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
758 clobberWorld(node->origin.semantic, clobberLimit);
759 forNode(node).setType(m_graph, SpecBytecodeNumber);
762 RELEASE_ASSERT_NOT_REACHED();
769 JSValue left = forNode(node->child1()).value();
770 JSValue right = forNode(node->child2()).value();
771 switch (node->binaryUseKind()) {
773 if (left && right && left.isInt32() && right.isInt32()) {
774 double doubleResult = left.asNumber() / right.asNumber();
775 if (!shouldCheckOverflow(node->arithMode()))
776 doubleResult = toInt32(doubleResult);
777 else if (!shouldCheckNegativeZero(node->arithMode()))
778 doubleResult += 0; // Sanitizes zero.
779 JSValue valueResult = jsNumber(doubleResult);
780 if (valueResult.isInt32()) {
781 setConstant(node, valueResult);
785 forNode(node).setType(SpecInt32Only);
788 if (left && right && left.isNumber() && right.isNumber()) {
789 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
792 forNode(node).setType(
793 typeOfDoubleQuotient(
794 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
797 clobberWorld(node->origin.semantic, clobberLimit);
798 forNode(node).setType(m_graph, SpecBytecodeNumber);
801 RELEASE_ASSERT_NOT_REACHED();
808 JSValue left = forNode(node->child1()).value();
809 JSValue right = forNode(node->child2()).value();
810 switch (node->binaryUseKind()) {
812 if (left && right && left.isInt32() && right.isInt32()) {
813 double doubleResult = fmod(left.asNumber(), right.asNumber());
814 if (!shouldCheckOverflow(node->arithMode()))
815 doubleResult = toInt32(doubleResult);
816 else if (!shouldCheckNegativeZero(node->arithMode()))
817 doubleResult += 0; // Sanitizes zero.
818 JSValue valueResult = jsNumber(doubleResult);
819 if (valueResult.isInt32()) {
820 setConstant(node, valueResult);
824 forNode(node).setType(SpecInt32Only);
827 if (left && right && left.isNumber() && right.isNumber()) {
828 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
831 forNode(node).setType(
832 typeOfDoubleBinaryOp(
833 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
836 RELEASE_ASSERT_NOT_REACHED();
843 JSValue left = forNode(node->child1()).value();
844 JSValue right = forNode(node->child2()).value();
845 switch (node->binaryUseKind()) {
847 if (left && right && left.isInt32() && right.isInt32()) {
848 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
851 forNode(node).setType(SpecInt32Only);
854 if (left && right && left.isNumber() && right.isNumber()) {
855 double a = left.asNumber();
856 double b = right.asNumber();
857 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
860 forNode(node).setType(
862 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
865 RELEASE_ASSERT_NOT_REACHED();
872 JSValue left = forNode(node->child1()).value();
873 JSValue right = forNode(node->child2()).value();
874 switch (node->binaryUseKind()) {
876 if (left && right && left.isInt32() && right.isInt32()) {
877 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
880 forNode(node).setType(SpecInt32Only);
883 if (left && right && left.isNumber() && right.isNumber()) {
884 double a = left.asNumber();
885 double b = right.asNumber();
886 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
889 forNode(node).setType(
891 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
894 RELEASE_ASSERT_NOT_REACHED();
901 JSValue child = forNode(node->child1()).value();
902 switch (node->child1().useKind()) {
904 if (std::optional<double> number = child.toNumberFromPrimitive()) {
905 JSValue result = jsNumber(fabs(*number));
906 if (result.isInt32()) {
907 setConstant(node, result);
911 forNode(node).setType(SpecInt32Only);
914 if (std::optional<double> number = child.toNumberFromPrimitive()) {
915 setConstant(node, jsDoubleNumber(fabs(*number)));
918 forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
921 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
922 forNode(node).setType(SpecFullNumber);
929 JSValue childY = forNode(node->child2()).value();
930 if (childY && childY.isNumber()) {
931 if (!childY.asNumber()) {
932 setConstant(node, jsDoubleNumber(1));
936 JSValue childX = forNode(node->child1()).value();
937 if (childX && childX.isNumber()) {
938 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
942 forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
947 forNode(node).setType(m_graph, SpecDoubleReal);
955 JSValue operand = forNode(node->child1()).value();
956 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
957 double roundedValue = 0;
958 if (node->op() == ArithRound)
959 roundedValue = jsRound(*number);
960 else if (node->op() == ArithFloor)
961 roundedValue = floor(*number);
962 else if (node->op() == ArithCeil)
963 roundedValue = ceil(*number);
965 ASSERT(node->op() == ArithTrunc);
966 roundedValue = trunc(*number);
969 if (node->child1().useKind() == UntypedUse) {
970 setConstant(node, jsNumber(roundedValue));
973 if (producesInteger(node->arithRoundingMode())) {
974 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
975 if (roundedValueAsInt32 == roundedValue) {
976 if (shouldCheckNegativeZero(node->arithRoundingMode())) {
977 if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
978 setConstant(node, jsNumber(roundedValueAsInt32));
982 setConstant(node, jsNumber(roundedValueAsInt32));
987 setConstant(node, jsDoubleNumber(roundedValue));
991 if (node->child1().useKind() == DoubleRepUse) {
992 if (producesInteger(node->arithRoundingMode()))
993 forNode(node).setType(SpecInt32Only);
994 else if (node->child1().useKind() == DoubleRepUse)
995 forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
997 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
998 forNode(node).setType(SpecFullNumber);
1004 executeDoubleUnaryOpEffects(node, sqrt);
1008 executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
1012 executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
1016 switch (booleanResult(node, forNode(node->child1()))) {
1017 case DefinitelyTrue:
1018 setConstant(node, jsBoolean(false));
1020 case DefinitelyFalse:
1021 setConstant(node, jsBoolean(true));
1024 forNode(node).setType(SpecBoolean);
1031 if (JSValue key = forNode(node->child1()).value()) {
1032 if (std::optional<uint32_t> hash = concurrentJSMapHash(key)) {
1033 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32
1034 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large
1035 // unsigned values becoming doubles. This casting between signed and unsigned
1036 // happens in the assembly code we emit when we don't constant fold this node.
1037 setConstant(node, jsNumber(static_cast<int32_t>(*hash)));
1041 forNode(node).setType(SpecInt32Only);
1046 forNode(node).setType(m_graph, SpecString);
1050 case LoadFromJSMapBucket:
1051 forNode(node).makeHeapTop();
1055 forNode(node).setType(m_graph, SpecCellOther);
1058 case IsNonEmptyMapBucket:
1059 forNode(node).setType(SpecBoolean);
1067 case IsObjectOrNull:
1069 case IsCellWithType:
1070 case IsTypedArrayView: {
1071 AbstractValue child = forNode(node->child1());
1072 if (child.value()) {
1073 bool constantWasSet = true;
1074 switch (node->op()) {
1075 case IsCellWithType:
1076 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType()));
1079 setConstant(node, jsBoolean(
1080 child.value().isCell()
1081 ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
1082 : child.value().isUndefined()));
1085 setConstant(node, jsBoolean(child.value().isBoolean()));
1088 setConstant(node, jsBoolean(child.value().isNumber()));
1091 setConstant(node, jsBoolean(child.value().isObject()));
1093 case IsObjectOrNull:
1094 if (child.value().isObject()) {
1095 JSObject* object = asObject(child.value());
1096 if (object->type() == JSFunctionType)
1097 setConstant(node, jsBoolean(false));
1098 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1099 setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
1101 // FIXME: This could just call getCallData.
1102 // https://bugs.webkit.org/show_bug.cgi?id=144457
1103 constantWasSet = false;
1106 setConstant(node, jsBoolean(child.value().isNull()));
1109 if (child.value().isObject()) {
1110 JSObject* object = asObject(child.value());
1111 if (object->type() == JSFunctionType)
1112 setConstant(node, jsBoolean(true));
1113 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1114 setConstant(node, jsBoolean(false));
1116 // FIXME: This could just call getCallData.
1117 // https://bugs.webkit.org/show_bug.cgi?id=144457
1118 constantWasSet = false;
1121 setConstant(node, jsBoolean(false));
1124 setConstant(node, jsBoolean(child.value().isEmpty()));
1126 case IsTypedArrayView:
1127 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType)));
1130 constantWasSet = false;
1137 // FIXME: This code should really use AbstractValue::isType() and
1138 // AbstractValue::couldBeType().
1139 // https://bugs.webkit.org/show_bug.cgi?id=146870
1141 bool constantWasSet = false;
1142 switch (node->op()) {
1144 if (child.m_type && !(child.m_type & SpecEmpty)) {
1145 setConstant(node, jsBoolean(false));
1146 constantWasSet = true;
1150 if (child.m_type && !(child.m_type & ~SpecEmpty)) {
1151 setConstant(node, jsBoolean(true));
1152 constantWasSet = true;
1159 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1160 // https://bugs.webkit.org/show_bug.cgi?id=144456
1162 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
1163 setConstant(node, jsBoolean(false));
1164 constantWasSet = true;
1170 if (!(child.m_type & ~SpecBoolean)) {
1171 setConstant(node, jsBoolean(true));
1172 constantWasSet = true;
1176 if (!(child.m_type & SpecBoolean)) {
1177 setConstant(node, jsBoolean(false));
1178 constantWasSet = true;
1184 if (!(child.m_type & ~SpecFullNumber)) {
1185 setConstant(node, jsBoolean(true));
1186 constantWasSet = true;
1190 if (!(child.m_type & SpecFullNumber)) {
1191 setConstant(node, jsBoolean(false));
1192 constantWasSet = true;
1198 if (!(child.m_type & ~SpecObject)) {
1199 setConstant(node, jsBoolean(true));
1200 constantWasSet = true;
1204 if (!(child.m_type & SpecObject)) {
1205 setConstant(node, jsBoolean(false));
1206 constantWasSet = true;
1211 case IsObjectOrNull:
1212 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1213 // https://bugs.webkit.org/show_bug.cgi?id=144456
1215 // These expressions are complicated to parse. A helpful way to parse this is that
1216 // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
1217 // disjoint set from S". Things like "T - S" means that, provided that S is a
1218 // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
1219 // mean the "union of T and S".
1221 // Is the child's type an object that isn't an other-object (i.e. object that could
1222 // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
1224 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1225 setConstant(node, jsBoolean(true));
1226 constantWasSet = true;
1230 // Is the child's type definitely not either of: an object that isn't a function,
1231 // or either undefined or null? Then: we should fold this to false. This means
1232 // for example that if it's any non-function object, including those that have
1233 // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
1234 // if it's undefined-or-null, since the type bits don't distinguish between
1235 // undefined (which should fold to false) and null (which should fold to true).
1236 if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
1237 setConstant(node, jsBoolean(false));
1238 constantWasSet = true;
1244 if (!(child.m_type & ~SpecFunction)) {
1245 setConstant(node, jsBoolean(true));
1246 constantWasSet = true;
1250 if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) {
1251 setConstant(node, jsBoolean(false));
1252 constantWasSet = true;
1257 case IsCellWithType:
1258 if (!(child.m_type & ~node->speculatedTypeForQuery())) {
1259 setConstant(node, jsBoolean(true));
1260 constantWasSet = true;
1263 if (!(child.m_type & node->speculatedTypeForQuery())) {
1264 setConstant(node, jsBoolean(false));
1265 constantWasSet = true;
1270 case IsTypedArrayView:
1271 if (!(child.m_type & ~SpecTypedArrayView)) {
1272 setConstant(node, jsBoolean(true));
1273 constantWasSet = true;
1276 if (!(child.m_type & SpecTypedArrayView)) {
1277 setConstant(node, jsBoolean(false));
1278 constantWasSet = true;
1289 forNode(node).setType(SpecBoolean);
1294 JSValue child = forNode(node->child1()).value();
1295 AbstractValue& abstractChild = forNode(node->child1());
1297 JSValue typeString = jsTypeStringForValue(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1298 setConstant(node, *m_graph.freeze(typeString));
1302 if (isFullNumberSpeculation(abstractChild.m_type)) {
1303 setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString()));
1307 if (isStringSpeculation(abstractChild.m_type)) {
1308 setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString()));
1312 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1313 // https://bugs.webkit.org/show_bug.cgi?id=144456
1314 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1315 setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString()));
1319 if (isFunctionSpeculation(abstractChild.m_type)) {
1320 setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString()));
1324 if (isBooleanSpeculation(abstractChild.m_type)) {
1325 setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString()));
1329 if (isSymbolSpeculation(abstractChild.m_type)) {
1330 setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString()));
1334 forNode(node).setType(m_graph, SpecStringIdent);
1340 case CompareGreater:
1341 case CompareGreaterEq:
1343 JSValue leftConst = forNode(node->child1()).value();
1344 JSValue rightConst = forNode(node->child2()).value();
1345 if (leftConst && rightConst) {
1346 if (leftConst.isNumber() && rightConst.isNumber()) {
1347 double a = leftConst.asNumber();
1348 double b = rightConst.asNumber();
1349 switch (node->op()) {
1351 setConstant(node, jsBoolean(a < b));
1354 setConstant(node, jsBoolean(a <= b));
1356 case CompareGreater:
1357 setConstant(node, jsBoolean(a > b));
1359 case CompareGreaterEq:
1360 setConstant(node, jsBoolean(a >= b));
1363 setConstant(node, jsBoolean(a == b));
1366 RELEASE_ASSERT_NOT_REACHED();
1372 if (leftConst.isString() && rightConst.isString()) {
1373 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1374 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1377 if (node->op() == CompareEq)
1378 result = WTF::equal(a, b);
1379 else if (node->op() == CompareLess)
1380 result = codePointCompare(a, b) < 0;
1381 else if (node->op() == CompareLessEq)
1382 result = codePointCompare(a, b) <= 0;
1383 else if (node->op() == CompareGreater)
1384 result = codePointCompare(a, b) > 0;
1385 else if (node->op() == CompareGreaterEq)
1386 result = codePointCompare(a, b) >= 0;
1388 RELEASE_ASSERT_NOT_REACHED();
1389 setConstant(node, jsBoolean(result));
1394 if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) {
1395 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst)));
1400 if (node->op() == CompareEq) {
1401 SpeculatedType leftType = forNode(node->child1()).m_type;
1402 SpeculatedType rightType = forNode(node->child2()).m_type;
1403 if (!valuesCouldBeEqual(leftType, rightType)) {
1404 setConstant(node, jsBoolean(false));
1408 if (leftType == SpecOther)
1409 std::swap(leftType, rightType);
1410 if (rightType == SpecOther) {
1411 // Undefined and Null are always equal when compared to eachother.
1412 if (!(leftType & ~SpecOther)) {
1413 setConstant(node, jsBoolean(true));
1417 // Any other type compared to Null or Undefined is always false
1418 // as long as the MasqueradesAsUndefined watchpoint is valid.
1420 // MasqueradesAsUndefined only matters for SpecObjectOther, other
1421 // cases are always "false".
1422 if (!(leftType & (SpecObjectOther | SpecOther))) {
1423 setConstant(node, jsBoolean(false));
1427 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) {
1428 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1429 m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint());
1430 setConstant(node, jsBoolean(false));
1436 if (node->child1() == node->child2()) {
1437 if (node->isBinaryUseKind(Int32Use) ||
1438 node->isBinaryUseKind(Int52RepUse) ||
1439 node->isBinaryUseKind(StringUse) ||
1440 node->isBinaryUseKind(BooleanUse) ||
1441 node->isBinaryUseKind(SymbolUse) ||
1442 node->isBinaryUseKind(StringIdentUse) ||
1443 node->isBinaryUseKind(ObjectUse) ||
1444 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) ||
1445 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
1446 switch (node->op()) {
1448 case CompareGreater:
1449 setConstant(node, jsBoolean(false));
1452 case CompareGreaterEq:
1454 setConstant(node, jsBoolean(true));
1457 DFG_CRASH(m_graph, node, "Unexpected node type");
1464 forNode(node).setType(SpecBoolean);
1468 case CompareStrictEq: {
1469 Node* leftNode = node->child1().node();
1470 Node* rightNode = node->child2().node();
1471 JSValue left = forNode(leftNode).value();
1472 JSValue right = forNode(rightNode).value();
1473 if (left && right) {
1474 if (left.isString() && right.isString()) {
1475 // We need this case because JSValue::strictEqual is otherwise too racy for
1476 // string comparisons.
1477 const StringImpl* a = asString(left)->tryGetValueImpl();
1478 const StringImpl* b = asString(right)->tryGetValueImpl();
1480 setConstant(node, jsBoolean(WTF::equal(a, b)));
1484 setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
1489 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1490 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1491 if (!(leftLUB & rightLUB)) {
1492 setConstant(node, jsBoolean(false));
1496 if (node->child1() == node->child2()) {
1497 if (node->isBinaryUseKind(BooleanUse) ||
1498 node->isBinaryUseKind(Int32Use) ||
1499 node->isBinaryUseKind(Int52RepUse) ||
1500 node->isBinaryUseKind(StringUse) ||
1501 node->isBinaryUseKind(StringIdentUse) ||
1502 node->isBinaryUseKind(SymbolUse) ||
1503 node->isBinaryUseKind(ObjectUse) ||
1504 node->isBinaryUseKind(MiscUse, UntypedUse) ||
1505 node->isBinaryUseKind(UntypedUse, MiscUse) ||
1506 node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
1507 node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
1508 node->isBinaryUseKind(StringUse, UntypedUse) ||
1509 node->isBinaryUseKind(UntypedUse, StringUse)) {
1510 setConstant(node, jsBoolean(true));
1515 forNode(node).setType(SpecBoolean);
1519 case CompareEqPtr: {
1520 Node* childNode = node->child1().node();
1521 JSValue childValue = forNode(childNode).value();
1523 setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
1527 forNode(node).setType(SpecBoolean);
1531 case StringCharCodeAt:
1532 forNode(node).setType(SpecInt32Only);
1535 case StringFromCharCode:
1536 forNode(node).setType(m_graph, SpecString);
1540 forNode(node).set(m_graph, m_vm.stringStructure.get());
1546 case AtomicsCompareExchange:
1547 case AtomicsExchange:
1553 if (node->op() != GetByVal)
1554 clobberWorld(node->origin.semantic, clobberLimit);
1555 switch (node->arrayMode().type()) {
1556 case Array::SelectUsingPredictions:
1557 case Array::Unprofiled:
1558 case Array::SelectUsingArguments:
1559 RELEASE_ASSERT_NOT_REACHED();
1561 case Array::ForceExit:
1562 m_state.setIsValid(false);
1564 case Array::Undecided: {
1565 JSValue index = forNode(node->child2()).value();
1566 if (index && index.isInt32() && index.asInt32() >= 0) {
1567 setConstant(node, jsUndefined());
1570 forNode(node).setType(SpecOther);
1573 case Array::Generic:
1574 clobberWorld(node->origin.semantic, clobberLimit);
1575 forNode(node).makeHeapTop();
1578 if (node->arrayMode().isOutOfBounds()) {
1579 // If the watchpoint was still valid we could totally set this to be
1580 // SpecString | SpecOther. Except that we'd have to be careful. If we
1581 // tested the watchpoint state here then it could change by the time
1582 // we got to the backend. So to do this right, we'd have to get the
1583 // fixup phase to check the watchpoint state and then bake into the
1584 // GetByVal operation the fact that we're using a watchpoint, using
1585 // something like Array::SaneChain (except not quite, because that
1586 // implies an in-bounds access). None of this feels like it's worth it,
1587 // so we're going with TOP for now. The same thing applies to
1588 // clobbering the world.
1589 clobberWorld(node->origin.semantic, clobberLimit);
1590 forNode(node).makeHeapTop();
1592 forNode(node).set(m_graph, m_vm.stringStructure.get());
1594 case Array::DirectArguments:
1595 case Array::ScopedArguments:
1596 forNode(node).makeHeapTop();
1599 if (node->arrayMode().isOutOfBounds()) {
1600 clobberWorld(node->origin.semantic, clobberLimit);
1601 forNode(node).makeHeapTop();
1603 forNode(node).setType(SpecInt32Only);
1606 if (node->arrayMode().isOutOfBounds()) {
1607 clobberWorld(node->origin.semantic, clobberLimit);
1608 forNode(node).makeHeapTop();
1609 } else if (node->arrayMode().isSaneChain())
1610 forNode(node).setType(SpecBytecodeDouble);
1612 forNode(node).setType(SpecDoubleReal);
1614 case Array::Contiguous:
1615 case Array::ArrayStorage:
1616 case Array::SlowPutArrayStorage:
1617 if (node->arrayMode().isOutOfBounds())
1618 clobberWorld(node->origin.semantic, clobberLimit);
1619 forNode(node).makeHeapTop();
1621 case Array::Int8Array:
1622 forNode(node).setType(SpecInt32Only);
1624 case Array::Int16Array:
1625 forNode(node).setType(SpecInt32Only);
1627 case Array::Int32Array:
1628 forNode(node).setType(SpecInt32Only);
1630 case Array::Uint8Array:
1631 forNode(node).setType(SpecInt32Only);
1633 case Array::Uint8ClampedArray:
1634 forNode(node).setType(SpecInt32Only);
1636 case Array::Uint16Array:
1637 forNode(node).setType(SpecInt32Only);
1639 case Array::Uint32Array:
1640 if (node->shouldSpeculateInt32())
1641 forNode(node).setType(SpecInt32Only);
1642 else if (enableInt52() && node->shouldSpeculateAnyInt())
1643 forNode(node).setType(SpecAnyInt);
1645 forNode(node).setType(SpecAnyIntAsDouble);
1647 case Array::Float32Array:
1648 forNode(node).setType(SpecFullDouble);
1650 case Array::Float64Array:
1651 forNode(node).setType(SpecFullDouble);
1654 RELEASE_ASSERT_NOT_REACHED();
1660 case PutByValDirect:
1662 case PutByValAlias: {
1663 switch (node->arrayMode().modeForPut().type()) {
1664 case Array::ForceExit:
1665 m_state.setIsValid(false);
1667 case Array::Generic:
1668 clobberWorld(node->origin.semantic, clobberLimit);
1671 if (node->arrayMode().isOutOfBounds())
1672 clobberWorld(node->origin.semantic, clobberLimit);
1675 if (node->arrayMode().isOutOfBounds())
1676 clobberWorld(node->origin.semantic, clobberLimit);
1678 case Array::Contiguous:
1679 case Array::ArrayStorage:
1680 if (node->arrayMode().isOutOfBounds())
1681 clobberWorld(node->origin.semantic, clobberLimit);
1683 case Array::SlowPutArrayStorage:
1684 if (node->arrayMode().mayStoreToHole())
1685 clobberWorld(node->origin.semantic, clobberLimit);
1694 clobberWorld(node->origin.semantic, clobberLimit);
1695 forNode(node).setType(SpecBytecodeNumber);
1699 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1701 // FIXME: We could do better here if we prove that the
1702 // incoming value has only a single structure.
1703 RegisteredStructureSet structureSet;
1704 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)));
1705 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)));
1706 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)));
1708 forNode(node).set(m_graph, structureSet);
1712 case ArrayIndexOf: {
1713 forNode(node).setType(SpecInt32Only);
1718 clobberWorld(node->origin.semantic, clobberLimit);
1719 forNode(node).makeHeapTop();
1722 case GetMyArgumentByVal:
1723 case GetMyArgumentByValOutOfBounds: {
1724 JSValue index = forNode(node->child2()).m_value;
1725 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame;
1727 if (index && index.isInt32()) {
1728 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
1729 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
1730 // paths as unreachable, or to return undefined. We could implement that eventually.
1732 unsigned argumentIndex = index.asUInt32() + node->numberOfArgumentsToSkip();
1733 if (inlineCallFrame) {
1734 if (argumentIndex < inlineCallFrame->arguments.size() - 1) {
1735 forNode(node) = m_state.variables().operand(
1736 virtualRegisterForArgument(argumentIndex + 1) + inlineCallFrame->stackOffset);
1737 m_state.setFoundConstants(true);
1741 if (argumentIndex < m_state.variables().numberOfArguments() - 1) {
1742 forNode(node) = m_state.variables().argument(argumentIndex + 1);
1743 m_state.setFoundConstants(true);
1749 if (inlineCallFrame) {
1750 // We have a bound on the types even though it's random access. Take advantage of this.
1752 AbstractValue result;
1753 for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->arguments.size(); ++i) {
1755 m_state.variables().operand(
1756 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
1759 if (node->op() == GetMyArgumentByValOutOfBounds)
1760 result.merge(SpecOther);
1763 m_state.setFoundConstants(true);
1765 forNode(node) = result;
1769 forNode(node).makeHeapTop();
1774 if (node->child2().useKind() == RegExpObjectUse
1775 && node->child3().useKind() == StringUse) {
1776 // This doesn't clobber the world since there are no conversions to perform.
1778 clobberWorld(node->origin.semantic, clobberLimit);
1779 if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
1780 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
1781 if (!globalObject->isHavingABadTime()) {
1782 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
1783 Structure* structure = globalObject->regExpMatchesArrayStructure();
1784 m_graph.registerStructure(structure);
1785 forNode(node).set(m_graph, structure);
1786 forNode(node).merge(SpecOther);
1791 forNode(node).setType(m_graph, SpecOther | SpecArray);
1795 if (node->child2().useKind() == RegExpObjectUse
1796 && node->child3().useKind() == StringUse) {
1797 // This doesn't clobber the world since there are no conversions to perform.
1799 clobberWorld(node->origin.semantic, clobberLimit);
1800 forNode(node).setType(SpecBoolean);
1804 case StringReplaceRegExp:
1805 if (node->child1().useKind() == StringUse
1806 && node->child2().useKind() == RegExpObjectUse
1807 && node->child3().useKind() == StringUse) {
1808 // This doesn't clobber the world. It just reads and writes regexp state.
1810 clobberWorld(node->origin.semantic, clobberLimit);
1811 forNode(node).set(m_graph, m_vm.stringStructure.get());
1818 Node* child = node->child1().node();
1819 BooleanResult result = booleanResult(node, forNode(child));
1820 if (result == DefinitelyTrue) {
1821 m_state.setBranchDirection(TakeTrue);
1824 if (result == DefinitelyFalse) {
1825 m_state.setBranchDirection(TakeFalse);
1828 // FIXME: The above handles the trivial cases of sparse conditional
1829 // constant propagation, but we can do better:
1830 // We can specialize the source variable's value on each direction of
1832 m_state.setBranchDirection(TakeBoth);
1837 // Nothing to do for now.
1838 // FIXME: Do sparse conditional things.
1843 m_state.setIsValid(false);
1847 case DirectTailCall:
1848 case TailCallVarargs:
1849 case TailCallForwardVarargs:
1850 clobberWorld(node->origin.semantic, clobberLimit);
1851 m_state.setIsValid(false);
1855 case ThrowStaticError:
1856 m_state.setIsValid(false);
1860 JSValue childConst = forNode(node->child1()).value();
1861 if (childConst && childConst.isNumber()) {
1862 setConstant(node, childConst);
1866 ASSERT(node->child1().useKind() == UntypedUse);
1868 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) {
1869 m_state.setFoundConstants(true);
1870 forNode(node) = forNode(node->child1());
1874 clobberWorld(node->origin.semantic, clobberLimit);
1876 forNode(node).setType(m_graph, SpecHeapTop & ~SpecObject);
1881 JSValue childConst = forNode(node->child1()).value();
1882 if (childConst && childConst.isNumber()) {
1883 setConstant(node, childConst);
1887 ASSERT(node->child1().useKind() == UntypedUse);
1889 if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
1890 m_state.setFoundConstants(true);
1891 forNode(node) = forNode(node->child1());
1895 clobberWorld(node->origin.semantic, clobberLimit);
1896 forNode(node).setType(m_graph, SpecBytecodeNumber);
1901 case CallStringConstructor: {
1902 switch (node->child1().useKind()) {
1903 case StringObjectUse:
1904 // This also filters that the StringObject has the primordial StringObject
1908 m_graph.registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()));
1910 case StringOrStringObjectUse:
1918 clobberWorld(node->origin.semantic, clobberLimit);
1921 RELEASE_ASSERT_NOT_REACHED();
1924 forNode(node).set(m_graph, m_vm.stringStructure.get());
1928 case NumberToStringWithRadix:
1929 clobberWorld(node->origin.semantic, clobberLimit);
1930 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
1933 case NewStringObject: {
1934 ASSERT(node->structure()->classInfo() == StringObject::info());
1935 forNode(node).set(m_graph, node->structure());
1942 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
1945 case NewArrayWithSpread:
1946 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
1947 // We've compiled assuming we're not having a bad time, so to be consistent
1948 // with StructureRegisterationPhase we must say we produce an original array
1949 // allocation structure.
1952 m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
1956 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
1963 m_graph, m_vm.fixedArrayStructure.get());
1966 case NewArrayBuffer:
1969 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
1972 case NewArrayWithSize:
1973 forNode(node).setType(m_graph, SpecArray);
1977 switch (node->child1().useKind()) {
1981 clobberWorld(node->origin.semantic, clobberLimit);
1984 RELEASE_ASSERT_NOT_REACHED();
1989 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(
1990 node->typedArrayType()));
1994 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
1998 AbstractValue& source = forNode(node->child1());
1999 AbstractValue& destination = forNode(node);
2000 bool strictMode = m_graph.executableFor(node->origin.semantic)->isStrictMode();
2002 if (isToThisAnIdentity(strictMode, source)) {
2003 m_state.setFoundConstants(true);
2004 destination = source;
2009 destination.makeHeapTop();
2011 destination = source;
2012 destination.merge(SpecObject);
2018 // FIXME: We can fold this to NewObject if the incoming callee is a constant.
2019 forNode(node).setType(m_graph, SpecFinalObject);
2024 ASSERT(!!node->structure().get());
2025 forNode(node).set(m_graph, node->structure());
2028 case CallObjectConstructor: {
2029 AbstractValue& source = forNode(node->child1());
2030 AbstractValue& destination = forNode(node);
2032 if (!(source.m_type & ~SpecObject)) {
2033 m_state.setFoundConstants(true);
2034 destination = source;
2038 forNode(node).setType(m_graph, SpecObject);
2042 case PhantomNewObject:
2043 case PhantomNewFunction:
2044 case PhantomNewGeneratorFunction:
2045 case PhantomNewAsyncFunction:
2046 case PhantomCreateActivation:
2047 case PhantomDirectArguments:
2048 case PhantomClonedArguments:
2049 case PhantomCreateRest:
2051 case PhantomNewArrayWithSpread:
2053 m_state.setDidClobber(true); // Prevent constant folding.
2054 // This claims to return bottom.
2060 case MaterializeNewObject: {
2061 forNode(node).set(m_graph, node->structureSet());
2065 case CreateActivation:
2066 case MaterializeCreateActivation:
2068 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
2071 case CreateDirectArguments:
2072 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
2075 case CreateScopedArguments:
2076 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
2079 case CreateClonedArguments:
2080 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2081 forNode(node).setType(m_graph, SpecObject);
2084 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
2087 case NewGeneratorFunction:
2089 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
2092 case NewAsyncFunction:
2094 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
2099 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure());
2103 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
2104 InferredValue* singleton = executable->singletonFunction();
2105 if (JSValue value = singleton->inferredValue()) {
2106 m_graph.watchpoints().addLazily(singleton);
2107 JSFunction* function = jsCast<JSFunction*>(value);
2108 setConstant(node, *m_graph.freeze(function));
2112 forNode(node).setType(m_graph, SpecFunction);
2115 case GetArgumentCountIncludingThis:
2116 forNode(node).setType(SpecInt32Only);
2120 forNode(node).setType(SpecInt32Only);
2124 JSValue base = forNode(node->child1()).m_value;
2126 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2127 if (!getterSetter->isGetterNull()) {
2128 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
2133 forNode(node).setType(m_graph, SpecObject);
2138 JSValue base = forNode(node->child1()).m_value;
2140 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2141 if (!getterSetter->isSetterNull()) {
2142 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
2147 forNode(node).setType(m_graph, SpecObject);
2152 if (JSValue base = forNode(node->child1()).m_value) {
2153 if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2154 setConstant(node, *m_graph.freeze(function->scope()));
2158 forNode(node).setType(m_graph, SpecObjectOther);
2162 JSValue child = forNode(node->child1()).value();
2164 setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next())));
2167 forNode(node).setType(m_graph, SpecObjectOther);
2171 case GetGlobalObject: {
2172 JSValue child = forNode(node->child1()).value();
2174 setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject())));
2178 if (forNode(node->child1()).m_structure.isFinite()) {
2179 JSGlobalObject* globalObject = nullptr;
2181 forNode(node->child1()).m_structure.forEach(
2182 [&] (RegisteredStructure structure) {
2184 globalObject = structure->globalObject();
2185 else if (globalObject != structure->globalObject())
2188 if (globalObject && ok) {
2189 setConstant(node, *m_graph.freeze(JSValue(globalObject)));
2194 forNode(node).setType(m_graph, SpecObjectOther);
2199 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
2200 setConstant(node, *m_graph.freeze(value));
2203 forNode(node).makeBytecodeTop();
2209 case GetRegExpObjectLastIndex:
2210 forNode(node).makeHeapTop();
2213 case SetRegExpObjectLastIndex:
2214 case RecordRegExpCachedResult:
2217 case GetFromArguments:
2218 forNode(node).makeHeapTop();
2221 case PutToArguments:
2225 forNode(node).makeHeapTop();
2229 // FIXME: This should constant fold at least as well as the normal GetById case.
2230 // https://bugs.webkit.org/show_bug.cgi?id=156422
2231 forNode(node).makeHeapTop();
2235 case GetByIdFlush: {
2236 if (!node->prediction()) {
2237 m_state.setIsValid(false);
2241 AbstractValue& value = forNode(node->child1());
2242 if (value.m_structure.isFinite()
2243 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
2244 UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
2245 GetByIdStatus status = GetByIdStatus::computeFor(value.m_structure.toStructureSet(), uid);
2246 if (status.isSimple()) {
2247 // Figure out what the result is going to be - is it TOP, a constant, or maybe
2248 // something more subtle?
2249 AbstractValue result;
2250 for (unsigned i = status.numVariants(); i--;) {
2251 // This thing won't give us a variant that involves prototypes. If it did, we'd
2252 // have more work to do here.
2253 DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty());
2256 m_graph.inferredValueForProperty(
2257 value, uid, status[i].offset(), m_state.structureClobberState()));
2259 m_state.setFoundConstants(true);
2260 forNode(node) = result;
2265 clobberWorld(node->origin.semantic, clobberLimit);
2266 forNode(node).makeHeapTop();
2270 case GetByValWithThis:
2271 case GetByIdWithThis:
2272 clobberWorld(node->origin.semantic, clobberLimit);
2273 forNode(node).makeHeapTop();
2276 case GetArrayLength: {
2277 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2278 forNode(node->child1()).m_value, node->arrayMode());
2280 setConstant(node, jsNumber(view->length()));
2283 forNode(node).setType(SpecInt32Only);
2287 case GetVectorLength: {
2288 forNode(node).setType(SpecInt32Only);
2294 // FIXME: This could decide if the delete will be successful based on the set of structures that
2295 // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
2296 clobberWorld(node->origin.semantic, clobberLimit);
2297 forNode(node).setType(SpecBoolean);
2301 case CheckStructure: {
2302 AbstractValue& value = forNode(node->child1());
2304 const RegisteredStructureSet& set = node->structureSet();
2306 // It's interesting that we could have proven that the object has a larger structure set
2307 // that includes the set we're testing. In that case we could make the structure check
2308 // more efficient. We currently don't.
2310 if (value.m_structure.isSubsetOf(set))
2311 m_state.setFoundConstants(true);
2313 SpeculatedType admittedTypes = SpecNone;
2314 switch (node->child1().useKind()) {
2317 admittedTypes = SpecNone;
2319 case CellOrOtherUse:
2320 admittedTypes = SpecOther;
2323 DFG_CRASH(m_graph, node, "Bad use kind");
2327 filter(value, set, admittedTypes);
2331 case CheckStructureImmediate: {
2332 // FIXME: This currently can only reason about one structure at a time.
2333 // https://bugs.webkit.org/show_bug.cgi?id=136988
2335 AbstractValue& value = forNode(node->child1());
2336 const RegisteredStructureSet& set = node->structureSet();
2338 if (value.value()) {
2339 if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) {
2340 if (set.contains(m_graph.registerStructure(structure))) {
2341 m_state.setFoundConstants(true);
2345 m_state.setIsValid(false);
2349 if (m_phiChildren) {
2350 bool allGood = true;
2351 m_phiChildren->forAllTransitiveIncomingValues(
2353 [&] (Node* incoming) {
2354 if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) {
2355 if (set.contains(m_graph.registerStructure(structure)))
2361 m_state.setFoundConstants(true);
2366 if (RegisteredStructure structure = set.onlyStructure()) {
2367 filterByValue(node->child1(), *m_graph.freeze(structure.get()));
2371 // Aw shucks, we can't do anything!
2376 if (!forNode(node->child1()).m_structure.isClear()) {
2377 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
2378 m_state.setFoundConstants(true);
2381 clobberLimit, node->transition()->previous, node->transition()->next);
2382 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
2387 case AllocatePropertyStorage:
2388 case ReallocatePropertyStorage:
2389 case NukeStructureAndSetButterfly:
2390 // FIXME: We don't model the fact that the structureID is nuked, simply because currently
2391 // nobody would currently benefit from having that information. But it's a bug nonetheless.
2392 forNode(node).clear(); // The result is not a JS value.
2394 case CheckSubClass: {
2395 JSValue constant = forNode(node->child1()).value();
2397 if (constant.isCell() && constant.asCell()->inherits(m_vm, node->classInfo())) {
2398 m_state.setFoundConstants(true);
2404 AbstractValue& value = forNode(node->child1());
2406 if (value.m_structure.isSubClassOf(node->classInfo()))
2407 m_state.setFoundConstants(true);
2409 filterClassInfo(value, node->classInfo());
2412 case CallDOMGetter: {
2413 CallDOMGetterData* callDOMGetterData = node->callDOMGetterData();
2414 DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet;
2415 if (snippet->effect.writes)
2416 clobberWorld(node->origin.semantic, clobberLimit);
2417 forNode(node).setType(m_graph, callDOMGetterData->domJIT->resultType());
2421 const DOMJIT::Signature* signature = node->signature();
2422 if (signature->effect.writes)
2423 clobberWorld(node->origin.semantic, clobberLimit);
2424 forNode(node).setType(m_graph, signature->result);
2428 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2429 m_state.setFoundConstants(true);
2432 switch (node->arrayMode().type()) {
2434 filter(node->child1(), SpecString);
2438 case Array::Contiguous:
2439 case Array::Undecided:
2440 case Array::ArrayStorage:
2441 case Array::SlowPutArrayStorage:
2443 case Array::DirectArguments:
2444 filter(node->child1(), SpecDirectArguments);
2446 case Array::ScopedArguments:
2447 filter(node->child1(), SpecScopedArguments);
2449 case Array::Int8Array:
2450 filter(node->child1(), SpecInt8Array);
2452 case Array::Int16Array:
2453 filter(node->child1(), SpecInt16Array);
2455 case Array::Int32Array:
2456 filter(node->child1(), SpecInt32Array);
2458 case Array::Uint8Array:
2459 filter(node->child1(), SpecUint8Array);
2461 case Array::Uint8ClampedArray:
2462 filter(node->child1(), SpecUint8ClampedArray);
2464 case Array::Uint16Array:
2465 filter(node->child1(), SpecUint16Array);
2467 case Array::Uint32Array:
2468 filter(node->child1(), SpecUint32Array);
2470 case Array::Float32Array:
2471 filter(node->child1(), SpecFloat32Array);
2473 case Array::Float64Array:
2474 filter(node->child1(), SpecFloat64Array);
2476 case Array::AnyTypedArray:
2477 filter(node->child1(), SpecTypedArrayView);
2480 RELEASE_ASSERT_NOT_REACHED();
2483 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2487 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2488 m_state.setFoundConstants(true);
2491 ASSERT(node->arrayMode().conversion() == Array::Convert);
2492 clobberStructures(clobberLimit);
2493 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2496 case ArrayifyToStructure: {
2497 AbstractValue& value = forNode(node->child1());
2498 if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure())))
2499 m_state.setFoundConstants(true);
2500 clobberStructures(clobberLimit);
2502 // We have a bunch of options of how to express the abstract set at this point. Let set S
2503 // be the set of structures that the value had before clobbering and assume that all of
2504 // them are watchable. The new value should be the least expressible upper bound of the
2505 // intersection of "values that currently have structure = node->structure()" and "values
2506 // that have structure in S plus any structure transition-reachable from S". Assume that
2507 // node->structure() is not in S but it is transition-reachable from S. Then we would
2508 // like to say that the result is "values that have structure = node->structure() until
2509 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
2510 // we must choose between:
2512 // 1) "values that currently have structure = node->structure()". This is a valid
2513 // superset of the value that we really want, and it's specific enough to satisfy the
2514 // preconditions of the array access that this is guarding. It's also specific enough
2515 // to allow relevant optimizations in the case that we didn't have a contradiction
2516 // like in this example. Notice that in the abscence of any contradiction, this result
2517 // is precise rather than being a conservative LUB.
2519 // 2) "values that currently hava structure in S plus any structure transition-reachable
2520 // from S". This is also a valid superset of the value that we really want, but it's
2521 // not specific enough to satisfy the preconditions of the array access that this is
2522 // guarding - so playing such shenanigans would preclude us from having assertions on
2523 // the typing preconditions of any array accesses. This would also not be a desirable
2524 // answer in the absence of a contradiction.
2526 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
2527 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
2529 value.set(m_graph, node->structure());
2532 case GetIndexedPropertyStorage: {
2533 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2534 forNode(node->child1()).m_value, node->arrayMode());
2536 m_state.setFoundConstants(true);
2537 forNode(node).clear();
2540 case ConstantStoragePointer: {
2541 forNode(node).clear();
2545 case GetTypedArrayByteOffset: {
2546 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
2548 setConstant(node, jsNumber(view->byteOffset()));
2551 forNode(node).setType(SpecInt32Only);
2556 StorageAccessData& data = node->storageAccessData();
2557 UniquedStringImpl* uid = m_graph.identifiers()[data.identifierNumber];
2559 // FIXME: The part of this that handles inferred property types relies on AI knowing the structure
2560 // right now. That's probably not optimal. In some cases, we may perform an optimization (usually
2561 // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure
2562 // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely
2563 // on the type that ByteCodeParser was able to prove.
2564 AbstractValue value = m_graph.inferredValueForProperty(
2565 forNode(node->child2()), uid, data.offset, m_state.structureClobberState());
2567 // It's possible that the type that ByteCodeParser came up with is better.
2568 AbstractValue typeFromParsing;
2569 typeFromParsing.set(m_graph, data.inferredType, m_state.structureClobberState());
2570 value.filter(typeFromParsing);
2572 // If we decide that there does not exist any value that this can return, then it's probably
2573 // because the compilation was already invalidated.
2574 if (value.isClear())
2575 m_state.setIsValid(false);
2577 forNode(node) = value;
2579 m_state.setFoundConstants(true);
2583 case GetGetterSetterByOffset: {
2584 StorageAccessData& data = node->storageAccessData();
2585 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
2586 if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) {
2587 setConstant(node, *m_graph.freeze(result));
2591 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->getterSetterStructure());
2595 case MultiGetByOffset: {
2596 // This code will filter the base value in a manner that is possibly different (either more
2597 // or less precise) than the way it would be filtered if this was strength-reduced to a
2598 // CheckStructure. This is fine. It's legal for different passes over the code to prove
2599 // different things about the code, so long as all of them are sound. That even includes
2600 // one guy proving that code should never execute (due to a contradiction) and another guy
2601 // not finding that contradiction. If someone ever proved that there would be a
2602 // contradiction then there must always be a contradiction even if subsequent passes don't
2603 // realize it. This is the case here.
2605 // Ordinarily you have to be careful with calling setFoundConstants()
2606 // because of the effect on compile times, but this node is FTL-only.
2607 m_state.setFoundConstants(true);
2609 UniquedStringImpl* uid = m_graph.identifiers()[node->multiGetByOffsetData().identifierNumber];
2611 AbstractValue base = forNode(node->child1());
2612 RegisteredStructureSet baseSet;
2613 AbstractValue result;
2614 for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
2615 RegisteredStructureSet set = getCase.set();
2621 switch (getCase.method().kind()) {
2622 case GetByOffsetMethod::Constant: {
2623 AbstractValue thisResult;
2626 *getCase.method().constant(),
2627 m_state.structureClobberState());
2628 result.merge(thisResult);
2632 case GetByOffsetMethod::Load: {
2634 m_graph.inferredValueForProperty(
2635 set, uid, m_state.structureClobberState()));
2640 result.makeHeapTop();
2645 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
2646 m_state.setIsValid(false);
2648 forNode(node) = result;
2656 case MultiPutByOffset: {
2657 RegisteredStructureSet newSet;
2658 TransitionVector transitions;
2660 // Ordinarily you have to be careful with calling setFoundConstants()
2661 // because of the effect on compile times, but this node is FTL-only.
2662 m_state.setFoundConstants(true);
2664 AbstractValue base = forNode(node->child1());
2665 AbstractValue originalValue = forNode(node->child2());
2666 AbstractValue resultingValue;
2668 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
2669 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
2670 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure());
2671 thisSet.filter(base);
2672 if (thisSet.isEmpty())
2675 AbstractValue thisValue = originalValue;
2676 thisValue.filter(m_graph, variant.requiredType());
2677 resultingValue.merge(thisValue);
2679 if (variant.kind() == PutByIdVariant::Transition) {
2680 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
2681 if (thisSet.onlyStructure() != newStructure) {
2683 Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
2684 } // else this is really a replace.
2685 newSet.add(newStructure);
2687 ASSERT(variant.kind() == PutByIdVariant::Replace);
2688 newSet.merge(thisSet);
2692 observeTransitions(clobberLimit, transitions);
2693 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
2694 m_state.setIsValid(false);
2695 forNode(node->child2()) = resultingValue;
2696 if (!!originalValue && !resultingValue)
2697 m_state.setIsValid(false);
2701 case GetExecutable: {
2702 JSValue value = forNode(node->child1()).value();
2704 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
2706 setConstant(node, *m_graph.freeze(function->executable()));
2710 forNode(node).setType(m_graph, SpecCellOther);
2715 JSValue value = forNode(node->child1()).value();
2716 if (value == node->cellOperand()->value()) {
2717 m_state.setFoundConstants(true);
2721 filterByValue(node->child1(), *node->cellOperand());
2725 case CheckNotEmpty: {
2726 AbstractValue& value = forNode(node->child1());
2727 if (!(value.m_type & SpecEmpty)) {
2728 m_state.setFoundConstants(true);
2732 filter(value, ~SpecEmpty);
2736 case CheckStringIdent: {
2737 AbstractValue& value = forNode(node->child1());
2738 UniquedStringImpl* uid = node->uidOperand();
2739 ASSERT(!(value.m_type & ~SpecStringIdent)); // Edge filtering should have already ensured this.
2741 JSValue childConstant = value.value();
2742 if (childConstant) {
2743 ASSERT(childConstant.isString());
2744 if (asString(childConstant)->tryGetValueImpl() == uid) {
2745 m_state.setFoundConstants(true);
2750 filter(value, SpecStringIdent);
2754 case CheckInBounds: {
2755 JSValue left = forNode(node->child1()).value();
2756 JSValue right = forNode(node->child2()).value();
2757 if (left && right && left.isInt32() && right.isInt32()
2758 && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) {
2759 m_state.setFoundConstants(true);
2767 case PutByIdDirect: {
2768 AbstractValue& value = forNode(node->child1());
2769 if (value.m_structure.isFinite()) {
2770 PutByIdStatus status = PutByIdStatus::computeFor(
2771 m_graph.globalObjectFor(node->origin.semantic),
2772 value.m_structure.toStructureSet(),
2773 m_graph.identifiers()[node->identifierNumber()],
2774 node->op() == PutByIdDirect);
2776 if (status.isSimple()) {
2777 RegisteredStructureSet newSet;
2778 TransitionVector transitions;
2780 for (unsigned i = status.numVariants(); i--;) {
2781 const PutByIdVariant& variant = status[i];
2782 if (variant.kind() == PutByIdVariant::Transition) {
2783 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
2786 m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
2787 newSet.add(newStructure);
2789 ASSERT(variant.kind() == PutByIdVariant::Replace);
2790 newSet.merge(*m_graph.addStructureSet(variant.oldStructure()));
2794 if (status.numVariants() == 1 || isFTL(m_graph.m_plan.mode))
2795 m_state.setFoundConstants(true);
2797 observeTransitions(clobberLimit, transitions);
2798 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
2799 m_state.setIsValid(false);
2804 clobberWorld(node->origin.semantic, clobberLimit);
2808 case PutByValWithThis:
2809 case PutByIdWithThis:
2810 clobberWorld(node->origin.semantic, clobberLimit);
2815 case PutGetterSetterById:
2816 case PutGetterByVal:
2817 case PutSetterByVal: {
2818 clobberWorld(node->origin.semantic, clobberLimit);
2822 case DefineDataProperty:
2823 case DefineAccessorProperty:
2824 clobberWorld(node->origin.semantic, clobberLimit);
2828 // FIXME: We can determine when the property definitely exists based on abstract
2829 // value information.
2830 clobberWorld(node->origin.semantic, clobberLimit);
2831 forNode(node).setType(SpecBoolean);
2835 case HasOwnProperty: {
2836 clobberWorld(node->origin.semantic, clobberLimit);
2837 forNode(node).setType(SpecBoolean);
2841 case GetEnumerableLength: {
2842 forNode(node).setType(SpecInt32Only);
2845 case HasGenericProperty: {
2846 forNode(node).setType(SpecBoolean);
2849 case HasStructureProperty: {
2850 forNode(node).setType(SpecBoolean);
2853 case HasIndexedProperty: {
2854 ArrayMode mode = node->arrayMode();
2855 switch (mode.type()) {
2858 case Array::Contiguous:
2859 case Array::ArrayStorage: {
2863 clobberWorld(node->origin.semantic, clobberLimit);
2867 forNode(node).setType(SpecBoolean);
2870 case GetDirectPname: {
2871 clobberWorld(node->origin.semantic, clobberLimit);
2872 forNode(node).makeHeapTop();
2875 case GetPropertyEnumerator: {
2876 forNode(node).setType(m_graph, SpecCell);
2879 case GetEnumeratorStructurePname: {
2880 forNode(node).setType(m_graph, SpecString | SpecOther);
2883 case GetEnumeratorGenericPname: {
2884 forNode(node).setType(m_graph, SpecString | SpecOther);
2887 case ToIndexString: {
2888 forNode(node).setType(m_graph, SpecString);
2893 forNode(node).makeHeapTop();
2896 case GetGlobalLexicalVariable:
2897 forNode(node).makeBytecodeTop();
2901 clobberWorld(node->origin.semantic, clobberLimit);
2902 forNode(node).makeBytecodeTop();
2906 clobberWorld(node->origin.semantic, clobberLimit);
2910 clobberWorld(node->origin.semantic, clobberLimit);
2911 forNode(node).setType(m_graph, SpecObject);
2914 case ResolveScopeForHoistingFuncDeclInEval:
2915 clobberWorld(node->origin.semantic, clobberLimit);
2916 forNode(node).makeBytecodeTop();
2919 case PutGlobalVariable:
2923 case OverridesHasInstance:
2924 forNode(node).setType(SpecBoolean);
2928 // Sadly, we don't propagate the fact that we've done InstanceOf
2929 forNode(node).setType(SpecBoolean);
2932 case InstanceOfCustom:
2933 clobberWorld(node->origin.semantic, clobberLimit);
2934 forNode(node).setType(SpecBoolean);
2938 RELEASE_ASSERT(m_graph.m_form == SSA);
2939 forNode(node) = forNode(NodeFlowProjection(node, NodeFlowProjection::Shadow));
2940 // The state of this node would have already been decided, but it may have become a
2941 // constant, in which case we'd like to know.
2942 if (forNode(node).m_value)
2943 m_state.setFoundConstants(true);
2947 NodeFlowProjection shadow(node->phi(), NodeFlowProjection::Shadow);
2948 if (shadow.isStillValid()) {
2949 m_state.createValueForNode(shadow);
2950 forNode(shadow) = forNode(node->child1());
2960 case TailCallInlinedCaller:
2963 case CallForwardVarargs:
2964 case TailCallVarargsInlinedCaller:
2965 case ConstructVarargs:
2966 case ConstructForwardVarargs:
2967 case TailCallForwardVarargsInlinedCaller:
2970 case DirectConstruct:
2971 case DirectTailCallInlinedCaller:
2972 clobberWorld(node->origin.semantic, clobberLimit);
2973 forNode(node).makeHeapTop();
2978 m_state.setIsValid(false);
2981 case InvalidationPoint:
2982 forAllValues(clobberLimit, AbstractValue::observeInvalidationPointFor);
2983 m_state.setStructureClobberState(StructuresAreWatched);
2987 case LogShadowChickenPrologue:
2988 case LogShadowChickenTail:
2992 case ProfileControlFlow:
2994 case CountExecution:
2995 case CheckTierUpInLoop:
2996 case CheckTierUpAtReturn:
2997 case CheckTypeInfoFlags:
3001 AbstractValue value = forNode(node->child1());
3002 if (value.m_type && !(value.m_type & ~SpecInt32Only)) {
3004 if (!node->child2())
3005 radix = jsNumber(0);
3007 radix = forNode(node->child2()).m_value;
3009 if (radix.isNumber()
3010 && (radix.asNumber() == 0 || radix.asNumber() == 10)) {
3011 m_state.setFoundConstants(true);
3012 forNode(node).setType(SpecInt32Only);
3017 if (node->child1().useKind() == UntypedUse)
3018 clobberWorld(node->origin.semantic, clobberLimit);
3019 forNode(node).setType(m_graph, SpecBytecodeNumber);
3024 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
3025 // This means we're already having a bad time.
3026 clobberWorld(node->origin.semantic, clobberLimit);
3027 forNode(node).setType(m_graph, SpecArray);
3032 m_graph.globalObjectFor(node->origin.semantic)->restParameterStructure());
3036 // Simplify out checks that don't actually do checking.
3037 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
3038 Edge edge = node->children.child(i);