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 "NumberConstructor.h"
40 #include "Operations.h"
41 #include "PutByIdStatus.h"
42 #include "StringObject.h"
44 #include <wtf/CheckedArithmetic.h>
46 namespace JSC { namespace DFG {
48 template<typename AbstractStateType>
49 AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state)
50 : m_codeBlock(graph.m_codeBlock)
55 if (m_graph.m_form == SSA)
56 m_phiChildren = std::make_unique<PhiChildren>(m_graph);
59 template<typename AbstractStateType>
60 AbstractInterpreter<AbstractStateType>::~AbstractInterpreter()
64 template<typename AbstractStateType>
65 typename AbstractInterpreter<AbstractStateType>::BooleanResult
66 AbstractInterpreter<AbstractStateType>::booleanResult(
67 Node* node, AbstractValue& value)
69 JSValue childConst = value.value();
71 if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic)->globalExec()))
72 return DefinitelyTrue;
73 return DefinitelyFalse;
76 // Next check if we can fold because we know that the source is an object or string and does not equal undefined.
77 if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) {
79 for (unsigned i = value.m_structure.size(); i--;) {
80 RegisteredStructure structure = value.m_structure[i];
81 if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
82 || structure->typeInfo().type() == StringType) {
88 return DefinitelyTrue;
91 return UnknownBooleanResult;
94 template<typename AbstractStateType>
95 void AbstractInterpreter<AbstractStateType>::startExecuting()
97 ASSERT(m_state.block());
98 ASSERT(m_state.isValid());
100 m_state.setDidClobber(false);
103 template<typename AbstractStateType>
104 void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node)
106 m_graph.doToChildren(
109 filterEdgeByUse(edge);
113 template<typename AbstractStateType>
114 void AbstractInterpreter<AbstractStateType>::executeKnownEdgeTypes(Node* node)
116 // Some use kinds are required to not have checks, because we know somehow that the incoming
117 // value will already have the type we want. In those cases, AI may not be smart enough to
118 // prove that this is indeed the case. But the existance of the edge is enough to prove that
119 // it is indeed the case. Taking advantage of this is not optional, since otherwise the DFG
120 // and FTL backends may emit checks in a node that lacks a valid exit origin.
121 m_graph.doToChildren(
124 if (mayHaveTypeCheck(edge.useKind()))
127 filterEdgeByUse(edge);
131 template<typename AbstractStateType>
132 void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge)
134 if (!(forNode(edge).m_type & ~typeFilterFor(edge.useKind())))
137 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);
140 template<typename AbstractStateType>
141 void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
143 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
146 enum class ToThisResult {
152 inline ToThisResult isToThisAnIdentity(VM& vm, bool isStrictMode, AbstractValue& valueForNode)
154 // We look at the type first since that will cover most cases and does not require iterating all the structures.
156 if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther))
157 return ToThisResult::Identity;
159 if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther)))
160 return ToThisResult::Identity;
163 if (JSValue value = valueForNode.value()) {
164 if (value.isCell()) {
165 auto* toThisMethod = value.asCell()->classInfo(vm)->methodTable.toThis;
166 if (toThisMethod == &JSObject::toThis)
167 return ToThisResult::Identity;
168 if (toThisMethod == &JSScope::toThis) {
170 return ToThisResult::Undefined;
171 return ToThisResult::GlobalThis;
176 if ((isStrictMode || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) {
177 bool allStructuresAreJSScope = !valueForNode.m_structure.isClear();
178 bool overridesToThis = false;
179 valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
180 TypeInfo type = structure->typeInfo();
181 ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == BigIntType);
183 ASSERT(type.isObject());
184 // We don't need to worry about strings/symbols here since either:
185 // 1) We are in strict mode and strings/symbols are not wrapped
186 // 2) The AI has proven that the type of this is a subtype of object
187 if (type.isObject() && type.overridesToThis())
188 overridesToThis = true;
190 // If all the structures are JSScope's ones, we know the details of JSScope::toThis() operation.
191 allStructuresAreJSScope &= structure->classInfo()->methodTable.toThis == JSScope::info()->methodTable.toThis;
193 if (!overridesToThis)
194 return ToThisResult::Identity;
195 if (allStructuresAreJSScope) {
197 return ToThisResult::Undefined;
198 return ToThisResult::GlobalThis;
202 return ToThisResult::Dynamic;
205 template<typename AbstractStateType>
206 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
210 m_state.createValueForNode(node);
212 switch (node->op()) {
215 case Int52Constant: {
216 setBuiltInConstant(node, *node->constant());
220 case LazyJSConstant: {
221 LazyJSValue value = node->lazyJSValue();
222 switch (value.kind()) {
223 case LazyJSValue::KnownValue:
224 setConstant(node, value.value()->value());
226 case LazyJSValue::SingleCharacterString:
227 case LazyJSValue::KnownStringImpl:
228 case LazyJSValue::NewStringImpl:
229 forNode(node).setType(m_graph, SpecString);
235 case IdentityWithProfile:
237 forNode(node) = forNode(node->child1());
238 if (forNode(node).value())
239 m_state.setFoundConstants(true);
243 case ExtractCatchLocal:
244 case ExtractOSREntryLocal: {
245 forNode(node).makeBytecodeTop();
250 VariableAccessData* variableAccessData = node->variableAccessData();
251 AbstractValue value = m_state.variables().operand(variableAccessData->local().offset());
252 // The value in the local should already be checked.
253 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
255 m_state.setFoundConstants(true);
256 forNode(node) = value;
261 StackAccessData* data = node->stackAccessData();
262 AbstractValue value = m_state.variables().operand(data->local);
263 // The value in the local should already be checked.
264 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
266 m_state.setFoundConstants(true);
267 forNode(node) = value;
272 m_state.variables().operand(node->local()) = forNode(node->child1());
277 m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1());
282 // Don't need to do anything. A MovHint only informs us about what would have happened
283 // in bytecode, but this code is just concerned with what is actually happening during
289 // This is just a hint telling us that the OSR state of the local is no longer inside the
295 // Assert that the state of arguments has been set. SetArgument means that someone set
296 // the argument values out-of-band, and currently this always means setting to a
298 ASSERT(!m_state.variables().operand(node->local()).isClear());
301 case InitializeEntrypointArguments: {
302 unsigned entrypointIndex = node->entrypointIndex();
303 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
304 for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) {
305 AbstractValue& value = m_state.variables().argument(argument);
306 switch (argumentFormats[argument]) {
308 value.setType(SpecInt32Only);
311 value.setType(SpecBoolean);
314 value.setType(m_graph, SpecCell);
317 value.makeBytecodeTop();
320 DFG_CRASH(m_graph, node, "Bad flush format for argument");
328 case ForwardVarargs: {
329 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
330 // itself into a straight-line sequence of GetStack/PutStack.
331 // https://bugs.webkit.org/show_bug.cgi?id=143071
332 clobberWorld(node->origin.semantic, clobberLimit);
333 LoadVarargsData* data = node->loadVarargsData();
334 m_state.variables().operand(data->count).setType(SpecInt32Only);
335 for (unsigned i = data->limit - 1; i--;)
336 m_state.variables().operand(data->start.offset() + i).makeHeapTop();
346 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
347 clobberWorld(node->origin.semantic, clobberLimit);
348 forNode(node).setType(m_graph, SpecInt32Only);
352 JSValue left = forNode(node->child1()).value();
353 JSValue right = forNode(node->child2()).value();
354 if (left && right && left.isInt32() && right.isInt32()) {
355 int32_t a = left.asInt32();
356 int32_t b = right.asInt32();
357 switch (node->op()) {
359 setConstant(node, JSValue(a & b));
362 setConstant(node, JSValue(a | b));
365 setConstant(node, JSValue(a ^ b));
368 setConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
371 setConstant(node, JSValue(a << static_cast<uint32_t>(b)));
374 setConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
377 RELEASE_ASSERT_NOT_REACHED();
383 if (node->op() == BitAnd
384 && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
385 isBoolInt32Speculation(forNode(node->child2()).m_type))) {
386 forNode(node).setType(SpecBoolInt32);
390 forNode(node).setType(SpecInt32Only);
394 case UInt32ToNumber: {
395 JSValue child = forNode(node->child1()).value();
396 if (doesOverflow(node->arithMode())) {
398 if (child && child.isAnyInt()) {
399 int64_t machineInt = child.asAnyInt();
400 setConstant(node, jsNumber(static_cast<uint32_t>(machineInt)));
403 forNode(node).setType(SpecAnyInt);
406 if (child && child.isInt32()) {
407 uint32_t value = child.asInt32();
408 setConstant(node, jsNumber(value));
411 forNode(node).setType(SpecAnyIntAsDouble);
414 if (child && child.isInt32()) {
415 int32_t value = child.asInt32();
417 setConstant(node, jsNumber(value));
421 forNode(node).setType(SpecInt32Only);
425 case BooleanToNumber: {
426 JSValue concreteValue = forNode(node->child1()).value();
428 if (concreteValue.isBoolean())
429 setConstant(node, jsNumber(concreteValue.asBoolean()));
431 setConstant(node, *m_graph.freeze(concreteValue));
434 AbstractValue& value = forNode(node);
435 value = forNode(node->child1());
436 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
437 m_state.setFoundConstants(true);
438 if (value.m_type & SpecBoolean) {
439 value.merge(SpecBoolInt32);
440 value.filter(~SpecBoolean);
445 case DoubleAsInt32: {
446 JSValue child = forNode(node->child1()).value();
447 if (child && child.isNumber()) {
448 double asDouble = child.asNumber();
449 int32_t asInt = JSC::toInt32(asDouble);
450 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
451 setConstant(node, JSValue(asInt));
455 forNode(node).setType(SpecInt32Only);
460 JSValue child = forNode(node->child1()).value();
462 if (child.isNumber()) {
464 setConstant(node, child);
466 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
469 if (child.isBoolean()) {
470 setConstant(node, jsNumber(child.asBoolean()));
473 if (child.isUndefinedOrNull()) {
474 setConstant(node, jsNumber(0));
479 if (isBooleanSpeculation(forNode(node->child1()).m_type)) {
480 forNode(node).setType(SpecBoolInt32);
484 forNode(node).setType(SpecInt32Only);
489 JSValue child = forNode(node->child1()).value();
490 if (std::optional<double> number = child.toNumberFromPrimitive()) {
491 setConstant(node, jsDoubleNumber(*number));
495 SpeculatedType type = forNode(node->child1()).m_type;
496 switch (node->child1().useKind()) {
498 if (type & SpecOther) {
500 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
502 if (type & SpecBoolean) {
503 type &= ~SpecBoolean;
504 type |= SpecBoolInt32; // True becomes 1, false becomes 0.
506 type &= SpecBytecodeNumber;
516 RELEASE_ASSERT_NOT_REACHED();
518 forNode(node).setType(type);
519 forNode(node).fixTypeForRepresentation(m_graph, node);
524 JSValue child = forNode(node->child1()).value();
525 if (child && child.isAnyInt()) {
526 setConstant(node, child);
530 forNode(node).setType(SpecAnyInt);
535 JSValue value = forNode(node->child1()).value();
537 setConstant(node, value);
541 forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
542 forNode(node).fixTypeForRepresentation(m_graph, node);
547 ASSERT(node->binaryUseKind() == UntypedUse);
548 clobberWorld(node->origin.semantic, clobberLimit);
549 forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber);
554 forNode(node).setType(m_graph, SpecString);
559 JSValue left = forNode(node->child1()).value();
560 JSValue right = forNode(node->child2()).value();
561 switch (node->binaryUseKind()) {
563 if (left && right && left.isInt32() && right.isInt32()) {
564 if (!shouldCheckOverflow(node->arithMode())) {
565 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
568 JSValue result = jsNumber(left.asNumber() + right.asNumber());
569 if (result.isInt32()) {
570 setConstant(node, result);
574 forNode(node).setType(SpecInt32Only);
577 if (left && right && left.isAnyInt() && right.isAnyInt()) {
578 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt());
579 if (result.isAnyInt()) {
580 setConstant(node, result);
584 forNode(node).setType(SpecAnyInt);
587 if (left && right && left.isNumber() && right.isNumber()) {
588 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
591 forNode(node).setType(
593 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
596 RELEASE_ASSERT_NOT_REACHED();
602 case AtomicsIsLockFree: {
603 if (node->child1().useKind() != Int32Use)
604 clobberWorld(node->origin.semantic, clobberLimit);
605 forNode(node).setType(SpecBoolInt32);
610 JSValue operand = forNode(node->child1()).value();
611 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
612 uint32_t value = toUInt32(*number);
613 setConstant(node, jsNumber(clz32(value)));
616 switch (node->child1().useKind()) {
621 clobberWorld(node->origin.semantic, clobberLimit);
624 forNode(node).setType(SpecInt32Only);
629 unsigned numberOfChildren = 0;
630 unsigned numberOfRemovedChildren = 0;
631 std::optional<unsigned> nonEmptyIndex;
632 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
633 Edge& edge = node->children.child(i);
638 JSValue childConstant = m_state.forNode(edge).value();
639 if (!childConstant) {
643 if (!childConstant.isString()) {
647 if (asString(childConstant)->length()) {
652 ++numberOfRemovedChildren;
655 if (numberOfRemovedChildren) {
656 m_state.setFoundConstants(true);
657 if (numberOfRemovedChildren == numberOfChildren) {
658 // Propagate the last child. This is the way taken in the constant folding phase.
659 forNode(node) = forNode(node->children.child(numberOfChildren - 1));
662 if ((numberOfRemovedChildren + 1) == numberOfChildren) {
663 ASSERT(nonEmptyIndex);
664 forNode(node) = forNode(node->children.child(nonEmptyIndex.value()));
668 forNode(node).set(m_graph, m_vm.stringStructure.get());
673 JSValue left = forNode(node->child1()).value();
674 JSValue right = forNode(node->child2()).value();
675 switch (node->binaryUseKind()) {
677 if (left && right && left.isInt32() && right.isInt32()) {
678 if (!shouldCheckOverflow(node->arithMode())) {
679 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
682 JSValue result = jsNumber(left.asNumber() - right.asNumber());
683 if (result.isInt32()) {
684 setConstant(node, result);
688 forNode(node).setType(SpecInt32Only);
691 if (left && right && left.isAnyInt() && right.isAnyInt()) {
692 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt());
693 if (result.isAnyInt() || !shouldCheckOverflow(node->arithMode())) {
694 setConstant(node, result);
698 forNode(node).setType(SpecAnyInt);
701 if (left && right && left.isNumber() && right.isNumber()) {
702 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
705 forNode(node).setType(
706 typeOfDoubleDifference(
707 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
710 clobberWorld(node->origin.semantic, clobberLimit);
711 forNode(node).setType(m_graph, SpecBytecodeNumber);
714 RELEASE_ASSERT_NOT_REACHED();
721 JSValue child = forNode(node->child1()).value();
722 switch (node->child1().useKind()) {
724 if (child && child.isInt32()) {
725 if (!shouldCheckOverflow(node->arithMode())) {
726 setConstant(node, jsNumber(-child.asInt32()));
730 if (shouldCheckNegativeZero(node->arithMode()))
731 doubleResult = -child.asNumber();
733 doubleResult = 0 - child.asNumber();
734 JSValue valueResult = jsNumber(doubleResult);
735 if (valueResult.isInt32()) {
736 setConstant(node, valueResult);
740 forNode(node).setType(SpecInt32Only);
743 if (child && child.isAnyInt()) {
745 if (shouldCheckNegativeZero(node->arithMode()))
746 doubleResult = -child.asNumber();
748 doubleResult = 0 - child.asNumber();
749 JSValue valueResult = jsNumber(doubleResult);
750 if (valueResult.isAnyInt()) {
751 setConstant(node, valueResult);
755 forNode(node).setType(SpecAnyInt);
758 if (child && child.isNumber()) {
759 setConstant(node, jsDoubleNumber(-child.asNumber()));
762 forNode(node).setType(
763 typeOfDoubleNegation(
764 forNode(node->child1()).m_type));
767 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind());
768 clobberWorld(node->origin.semantic, clobberLimit);
769 forNode(node).setType(SpecBytecodeNumber);
776 JSValue left = forNode(node->child1()).value();
777 JSValue right = forNode(node->child2()).value();
778 switch (node->binaryUseKind()) {
780 if (left && right && left.isInt32() && right.isInt32()) {
781 if (!shouldCheckOverflow(node->arithMode())) {
782 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
785 double doubleResult = left.asNumber() * right.asNumber();
786 if (!shouldCheckNegativeZero(node->arithMode()))
787 doubleResult += 0; // Sanitizes zero.
788 JSValue valueResult = jsNumber(doubleResult);
789 if (valueResult.isInt32()) {
790 setConstant(node, valueResult);
794 forNode(node).setType(SpecInt32Only);
797 if (left && right && left.isAnyInt() && right.isAnyInt()) {
798 double doubleResult = left.asNumber() * right.asNumber();
799 if (!shouldCheckNegativeZero(node->arithMode()))
801 JSValue valueResult = jsNumber(doubleResult);
802 if (valueResult.isAnyInt()) {
803 setConstant(node, valueResult);
807 forNode(node).setType(SpecAnyInt);
810 if (left && right && left.isNumber() && right.isNumber()) {
811 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
814 forNode(node).setType(
816 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
819 clobberWorld(node->origin.semantic, clobberLimit);
820 forNode(node).setType(m_graph, SpecBytecodeNumber);
823 RELEASE_ASSERT_NOT_REACHED();
830 JSValue left = forNode(node->child1()).value();
831 JSValue right = forNode(node->child2()).value();
832 switch (node->binaryUseKind()) {
834 if (left && right && left.isInt32() && right.isInt32()) {
835 double doubleResult = left.asNumber() / right.asNumber();
836 if (!shouldCheckOverflow(node->arithMode()))
837 doubleResult = toInt32(doubleResult);
838 else if (!shouldCheckNegativeZero(node->arithMode()))
839 doubleResult += 0; // Sanitizes zero.
840 JSValue valueResult = jsNumber(doubleResult);
841 if (valueResult.isInt32()) {
842 setConstant(node, valueResult);
846 forNode(node).setType(SpecInt32Only);
849 if (left && right && left.isNumber() && right.isNumber()) {
850 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
853 forNode(node).setType(
854 typeOfDoubleQuotient(
855 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
858 clobberWorld(node->origin.semantic, clobberLimit);
859 forNode(node).setType(m_graph, SpecBytecodeNumber);
862 RELEASE_ASSERT_NOT_REACHED();
869 JSValue left = forNode(node->child1()).value();
870 JSValue right = forNode(node->child2()).value();
871 switch (node->binaryUseKind()) {
873 if (left && right && left.isInt32() && right.isInt32()) {
874 double doubleResult = fmod(left.asNumber(), right.asNumber());
875 if (!shouldCheckOverflow(node->arithMode()))
876 doubleResult = toInt32(doubleResult);
877 else if (!shouldCheckNegativeZero(node->arithMode()))
878 doubleResult += 0; // Sanitizes zero.
879 JSValue valueResult = jsNumber(doubleResult);
880 if (valueResult.isInt32()) {
881 setConstant(node, valueResult);
885 forNode(node).setType(SpecInt32Only);
888 if (left && right && left.isNumber() && right.isNumber()) {
889 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
892 forNode(node).setType(
893 typeOfDoubleBinaryOp(
894 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
897 RELEASE_ASSERT_NOT_REACHED();
904 JSValue left = forNode(node->child1()).value();
905 JSValue right = forNode(node->child2()).value();
906 switch (node->binaryUseKind()) {
908 if (left && right && left.isInt32() && right.isInt32()) {
909 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
912 forNode(node).setType(SpecInt32Only);
915 if (left && right && left.isNumber() && right.isNumber()) {
916 double a = left.asNumber();
917 double b = right.asNumber();
918 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
921 forNode(node).setType(
923 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
926 RELEASE_ASSERT_NOT_REACHED();
933 JSValue left = forNode(node->child1()).value();
934 JSValue right = forNode(node->child2()).value();
935 switch (node->binaryUseKind()) {
937 if (left && right && left.isInt32() && right.isInt32()) {
938 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
941 forNode(node).setType(SpecInt32Only);
944 if (left && right && left.isNumber() && right.isNumber()) {
945 double a = left.asNumber();
946 double b = right.asNumber();
947 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
950 forNode(node).setType(
952 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
955 RELEASE_ASSERT_NOT_REACHED();
962 JSValue child = forNode(node->child1()).value();
963 switch (node->child1().useKind()) {
965 if (std::optional<double> number = child.toNumberFromPrimitive()) {
966 JSValue result = jsNumber(fabs(*number));
967 if (result.isInt32()) {
968 setConstant(node, result);
972 forNode(node).setType(SpecInt32Only);
975 if (std::optional<double> number = child.toNumberFromPrimitive()) {
976 setConstant(node, jsDoubleNumber(fabs(*number)));
979 forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
982 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind());
983 clobberWorld(node->origin.semantic, clobberLimit);
984 forNode(node).setType(SpecFullNumber);
991 JSValue childY = forNode(node->child2()).value();
992 if (childY && childY.isNumber()) {
993 if (!childY.asNumber()) {
994 setConstant(node, jsDoubleNumber(1));
998 JSValue childX = forNode(node->child1()).value();
999 if (childX && childX.isNumber()) {
1000 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
1004 forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1009 forNode(node).setType(m_graph, SpecDoubleReal);
1017 JSValue operand = forNode(node->child1()).value();
1018 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
1019 double roundedValue = 0;
1020 if (node->op() == ArithRound)
1021 roundedValue = jsRound(*number);
1022 else if (node->op() == ArithFloor)
1023 roundedValue = floor(*number);
1024 else if (node->op() == ArithCeil)
1025 roundedValue = ceil(*number);
1027 ASSERT(node->op() == ArithTrunc);
1028 roundedValue = trunc(*number);
1031 if (node->child1().useKind() == UntypedUse) {
1032 setConstant(node, jsNumber(roundedValue));
1035 if (producesInteger(node->arithRoundingMode())) {
1036 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
1037 if (roundedValueAsInt32 == roundedValue) {
1038 if (shouldCheckNegativeZero(node->arithRoundingMode())) {
1039 if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
1040 setConstant(node, jsNumber(roundedValueAsInt32));
1044 setConstant(node, jsNumber(roundedValueAsInt32));
1049 setConstant(node, jsDoubleNumber(roundedValue));
1053 if (node->child1().useKind() == DoubleRepUse) {
1054 if (producesInteger(node->arithRoundingMode()))
1055 forNode(node).setType(SpecInt32Only);
1056 else if (node->child1().useKind() == DoubleRepUse)
1057 forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
1059 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind());
1060 clobberWorld(node->origin.semantic, clobberLimit);
1061 forNode(node).setType(SpecFullNumber);
1067 executeDoubleUnaryOpEffects(node, clobberLimit, sqrt);
1071 executeDoubleUnaryOpEffects(node, clobberLimit, [](double value) -> double { return static_cast<float>(value); });
1075 executeDoubleUnaryOpEffects(node, clobberLimit, arithUnaryFunction(node->arithUnaryType()));
1079 switch (booleanResult(node, forNode(node->child1()))) {
1080 case DefinitelyTrue:
1081 setConstant(node, jsBoolean(false));
1083 case DefinitelyFalse:
1084 setConstant(node, jsBoolean(true));
1087 forNode(node).setType(SpecBoolean);
1094 if (JSValue key = forNode(node->child1()).value()) {
1095 if (std::optional<uint32_t> hash = concurrentJSMapHash(key)) {
1096 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32
1097 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large
1098 // unsigned values becoming doubles. This casting between signed and unsigned
1099 // happens in the assembly code we emit when we don't constant fold this node.
1100 setConstant(node, jsNumber(static_cast<int32_t>(*hash)));
1104 forNode(node).setType(SpecInt32Only);
1108 case NormalizeMapKey: {
1109 if (JSValue key = forNode(node->child1()).value()) {
1110 setConstant(node, *m_graph.freeze(normalizeMapKey(key)));
1114 SpeculatedType typeMaybeNormalized = (SpecFullNumber & ~SpecInt32Only);
1115 if (!(forNode(node->child1()).m_type & typeMaybeNormalized)) {
1116 m_state.setFoundConstants(true);
1117 forNode(node) = forNode(node->child1());
1121 forNode(node).makeHeapTop();
1126 forNode(node).setType(m_graph, SpecString);
1131 forNode(node).setType(m_graph, SpecString);
1135 case LoadKeyFromMapBucket:
1136 case LoadValueFromMapBucket:
1137 case ExtractValueFromWeakMapGet:
1138 forNode(node).makeHeapTop();
1142 case GetMapBucketHead:
1143 if (node->child1().useKind() == MapObjectUse)
1144 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1146 ASSERT(node->child1().useKind() == SetObjectUse);
1147 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1151 case GetMapBucketNext:
1152 if (node->bucketOwnerType() == BucketOwnerType::Map)
1153 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1155 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
1156 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1161 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1165 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1173 forNode(node).makeBytecodeTop();
1180 case NumberIsInteger:
1182 case IsObjectOrNull:
1184 case IsCellWithType:
1185 case IsTypedArrayView: {
1186 AbstractValue child = forNode(node->child1());
1187 if (child.value()) {
1188 bool constantWasSet = true;
1189 switch (node->op()) {
1190 case IsCellWithType:
1191 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType()));
1194 setConstant(node, jsBoolean(
1195 child.value().isCell()
1196 ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
1197 : child.value().isUndefined()));
1200 setConstant(node, jsBoolean(child.value().isBoolean()));
1203 setConstant(node, jsBoolean(child.value().isNumber()));
1205 case NumberIsInteger:
1206 setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value())));
1209 setConstant(node, jsBoolean(child.value().isObject()));
1211 case IsObjectOrNull:
1212 if (child.value().isObject()) {
1213 JSObject* object = asObject(child.value());
1214 if (object->type() == JSFunctionType)
1215 setConstant(node, jsBoolean(false));
1216 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1217 setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
1219 // FIXME: This could just call getCallData.
1220 // https://bugs.webkit.org/show_bug.cgi?id=144457
1221 constantWasSet = false;
1224 setConstant(node, jsBoolean(child.value().isNull()));
1227 if (child.value().isObject()) {
1228 JSObject* object = asObject(child.value());
1229 if (object->type() == JSFunctionType)
1230 setConstant(node, jsBoolean(true));
1231 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1232 setConstant(node, jsBoolean(false));
1234 // FIXME: This could just call getCallData.
1235 // https://bugs.webkit.org/show_bug.cgi?id=144457
1236 constantWasSet = false;
1239 setConstant(node, jsBoolean(false));
1242 setConstant(node, jsBoolean(child.value().isEmpty()));
1244 case IsTypedArrayView:
1245 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType)));
1248 constantWasSet = false;
1255 // FIXME: This code should really use AbstractValue::isType() and
1256 // AbstractValue::couldBeType().
1257 // https://bugs.webkit.org/show_bug.cgi?id=146870
1259 bool constantWasSet = false;
1260 switch (node->op()) {
1262 if (child.m_type && !(child.m_type & SpecEmpty)) {
1263 setConstant(node, jsBoolean(false));
1264 constantWasSet = true;
1268 if (child.m_type && !(child.m_type & ~SpecEmpty)) {
1269 setConstant(node, jsBoolean(true));
1270 constantWasSet = true;
1277 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1278 // https://bugs.webkit.org/show_bug.cgi?id=144456
1280 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
1281 setConstant(node, jsBoolean(false));
1282 constantWasSet = true;
1288 if (!(child.m_type & ~SpecBoolean)) {
1289 setConstant(node, jsBoolean(true));
1290 constantWasSet = true;
1294 if (!(child.m_type & SpecBoolean)) {
1295 setConstant(node, jsBoolean(false));
1296 constantWasSet = true;
1302 if (!(child.m_type & ~SpecFullNumber)) {
1303 setConstant(node, jsBoolean(true));
1304 constantWasSet = true;
1308 if (!(child.m_type & SpecFullNumber)) {
1309 setConstant(node, jsBoolean(false));
1310 constantWasSet = true;
1316 case NumberIsInteger:
1317 if (!(child.m_type & ~SpecInt32Only)) {
1318 setConstant(node, jsBoolean(true));
1319 constantWasSet = true;
1323 if (!(child.m_type & SpecFullNumber)) {
1324 setConstant(node, jsBoolean(false));
1325 constantWasSet = true;
1332 if (!(child.m_type & ~SpecObject)) {
1333 setConstant(node, jsBoolean(true));
1334 constantWasSet = true;
1338 if (!(child.m_type & SpecObject)) {
1339 setConstant(node, jsBoolean(false));
1340 constantWasSet = true;
1345 case IsObjectOrNull:
1346 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1347 // https://bugs.webkit.org/show_bug.cgi?id=144456
1349 // These expressions are complicated to parse. A helpful way to parse this is that
1350 // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
1351 // disjoint set from S". Things like "T - S" means that, provided that S is a
1352 // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
1353 // mean the "union of T and S".
1355 // Is the child's type an object that isn't an other-object (i.e. object that could
1356 // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
1358 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1359 setConstant(node, jsBoolean(true));
1360 constantWasSet = true;
1364 // Is the child's type definitely not either of: an object that isn't a function,
1365 // or either undefined or null? Then: we should fold this to false. This means
1366 // for example that if it's any non-function object, including those that have
1367 // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
1368 // if it's undefined-or-null, since the type bits don't distinguish between
1369 // undefined (which should fold to false) and null (which should fold to true).
1370 if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
1371 setConstant(node, jsBoolean(false));
1372 constantWasSet = true;
1378 if (!(child.m_type & ~SpecFunction)) {
1379 setConstant(node, jsBoolean(true));
1380 constantWasSet = true;
1384 if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) {
1385 setConstant(node, jsBoolean(false));
1386 constantWasSet = true;
1391 case IsCellWithType:
1392 if (!(child.m_type & ~node->speculatedTypeForQuery())) {
1393 setConstant(node, jsBoolean(true));
1394 constantWasSet = true;
1397 if (!(child.m_type & node->speculatedTypeForQuery())) {
1398 setConstant(node, jsBoolean(false));
1399 constantWasSet = true;
1404 case IsTypedArrayView:
1405 if (!(child.m_type & ~SpecTypedArrayView)) {
1406 setConstant(node, jsBoolean(true));
1407 constantWasSet = true;
1410 if (!(child.m_type & SpecTypedArrayView)) {
1411 setConstant(node, jsBoolean(false));
1412 constantWasSet = true;
1423 forNode(node).setType(SpecBoolean);
1428 JSValue child = forNode(node->child1()).value();
1429 AbstractValue& abstractChild = forNode(node->child1());
1431 JSValue typeString = jsTypeStringForValue(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1432 setConstant(node, *m_graph.freeze(typeString));
1436 if (isFullNumberSpeculation(abstractChild.m_type)) {
1437 setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString()));
1441 if (isStringSpeculation(abstractChild.m_type)) {
1442 setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString()));
1446 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1447 // https://bugs.webkit.org/show_bug.cgi?id=144456
1448 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1449 setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString()));
1453 if (isFunctionSpeculation(abstractChild.m_type)) {
1454 setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString()));
1458 if (isBooleanSpeculation(abstractChild.m_type)) {
1459 setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString()));
1463 if (isSymbolSpeculation(abstractChild.m_type)) {
1464 setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString()));
1468 forNode(node).setType(m_graph, SpecStringIdent);
1473 case CompareBelowEq: {
1474 JSValue leftConst = forNode(node->child1()).value();
1475 JSValue rightConst = forNode(node->child2()).value();
1476 if (leftConst && rightConst) {
1477 if (leftConst.isInt32() && rightConst.isInt32()) {
1478 uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
1479 uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
1480 switch (node->op()) {
1482 setConstant(node, jsBoolean(a < b));
1484 case CompareBelowEq:
1485 setConstant(node, jsBoolean(a <= b));
1488 RELEASE_ASSERT_NOT_REACHED();
1495 if (node->child1() == node->child2()) {
1496 switch (node->op()) {
1498 setConstant(node, jsBoolean(false));
1500 case CompareBelowEq:
1501 setConstant(node, jsBoolean(true));
1504 DFG_CRASH(m_graph, node, "Unexpected node type");
1509 forNode(node).setType(SpecBoolean);
1515 case CompareGreater:
1516 case CompareGreaterEq:
1518 JSValue leftConst = forNode(node->child1()).value();
1519 JSValue rightConst = forNode(node->child2()).value();
1520 if (leftConst && rightConst) {
1521 if (leftConst.isNumber() && rightConst.isNumber()) {
1522 double a = leftConst.asNumber();
1523 double b = rightConst.asNumber();
1524 switch (node->op()) {
1526 setConstant(node, jsBoolean(a < b));
1529 setConstant(node, jsBoolean(a <= b));
1531 case CompareGreater:
1532 setConstant(node, jsBoolean(a > b));
1534 case CompareGreaterEq:
1535 setConstant(node, jsBoolean(a >= b));
1538 setConstant(node, jsBoolean(a == b));
1541 RELEASE_ASSERT_NOT_REACHED();
1547 if (leftConst.isString() && rightConst.isString()) {
1548 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1549 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1552 if (node->op() == CompareEq)
1553 result = WTF::equal(a, b);
1554 else if (node->op() == CompareLess)
1555 result = codePointCompare(a, b) < 0;
1556 else if (node->op() == CompareLessEq)
1557 result = codePointCompare(a, b) <= 0;
1558 else if (node->op() == CompareGreater)
1559 result = codePointCompare(a, b) > 0;
1560 else if (node->op() == CompareGreaterEq)
1561 result = codePointCompare(a, b) >= 0;
1563 RELEASE_ASSERT_NOT_REACHED();
1564 setConstant(node, jsBoolean(result));
1569 if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) {
1570 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst)));
1575 if (node->op() == CompareEq) {
1576 SpeculatedType leftType = forNode(node->child1()).m_type;
1577 SpeculatedType rightType = forNode(node->child2()).m_type;
1578 if (!valuesCouldBeEqual(leftType, rightType)) {
1579 setConstant(node, jsBoolean(false));
1583 if (leftType == SpecOther)
1584 std::swap(leftType, rightType);
1585 if (rightType == SpecOther) {
1586 // Undefined and Null are always equal when compared to eachother.
1587 if (!(leftType & ~SpecOther)) {
1588 setConstant(node, jsBoolean(true));
1592 // Any other type compared to Null or Undefined is always false
1593 // as long as the MasqueradesAsUndefined watchpoint is valid.
1595 // MasqueradesAsUndefined only matters for SpecObjectOther, other
1596 // cases are always "false".
1597 if (!(leftType & (SpecObjectOther | SpecOther))) {
1598 setConstant(node, jsBoolean(false));
1602 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) {
1603 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1604 m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint());
1605 setConstant(node, jsBoolean(false));
1611 if (node->child1() == node->child2()) {
1612 if (node->isBinaryUseKind(Int32Use) ||
1613 node->isBinaryUseKind(Int52RepUse) ||
1614 node->isBinaryUseKind(StringUse) ||
1615 node->isBinaryUseKind(BooleanUse) ||
1616 node->isBinaryUseKind(SymbolUse) ||
1617 node->isBinaryUseKind(StringIdentUse) ||
1618 node->isBinaryUseKind(ObjectUse) ||
1619 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) ||
1620 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
1621 switch (node->op()) {
1623 case CompareGreater:
1624 setConstant(node, jsBoolean(false));
1627 case CompareGreaterEq:
1629 setConstant(node, jsBoolean(true));
1632 DFG_CRASH(m_graph, node, "Unexpected node type");
1639 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse)
1640 clobberWorld(node->origin.semantic, clobberLimit);
1641 forNode(node).setType(SpecBoolean);
1645 case CompareStrictEq: {
1646 Node* leftNode = node->child1().node();
1647 Node* rightNode = node->child2().node();
1648 JSValue left = forNode(leftNode).value();
1649 JSValue right = forNode(rightNode).value();
1650 if (left && right) {
1651 if (left.isString() && right.isString()) {
1652 // We need this case because JSValue::strictEqual is otherwise too racy for
1653 // string comparisons.
1654 const StringImpl* a = asString(left)->tryGetValueImpl();
1655 const StringImpl* b = asString(right)->tryGetValueImpl();
1657 setConstant(node, jsBoolean(WTF::equal(a, b)));
1661 setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
1666 if (node->isBinaryUseKind(UntypedUse)) {
1667 // FIXME: Revisit this condition when introducing BigInt to JSC.
1668 auto isNonStringCellConstant = [] (JSValue value) {
1669 return value && value.isCell() && !value.isString();
1672 if (isNonStringCellConstant(left) || isNonStringCellConstant(right)) {
1673 m_state.setFoundConstants(true);
1674 forNode(node).setType(SpecBoolean);
1679 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1680 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1681 if (!(leftLUB & rightLUB)) {
1682 setConstant(node, jsBoolean(false));
1686 if (node->child1() == node->child2()) {
1687 if (node->isBinaryUseKind(BooleanUse) ||
1688 node->isBinaryUseKind(Int32Use) ||
1689 node->isBinaryUseKind(Int52RepUse) ||
1690 node->isBinaryUseKind(StringUse) ||
1691 node->isBinaryUseKind(StringIdentUse) ||
1692 node->isBinaryUseKind(SymbolUse) ||
1693 node->isBinaryUseKind(ObjectUse) ||
1694 node->isBinaryUseKind(MiscUse, UntypedUse) ||
1695 node->isBinaryUseKind(UntypedUse, MiscUse) ||
1696 node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
1697 node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
1698 node->isBinaryUseKind(StringUse, UntypedUse) ||
1699 node->isBinaryUseKind(UntypedUse, StringUse)) {
1700 setConstant(node, jsBoolean(true));
1705 forNode(node).setType(SpecBoolean);
1709 case CompareEqPtr: {
1710 Node* childNode = node->child1().node();
1711 JSValue childValue = forNode(childNode).value();
1713 setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
1717 forNode(node).setType(SpecBoolean);
1721 case StringCharCodeAt:
1722 forNode(node).setType(SpecInt32Only);
1725 case StringFromCharCode:
1726 forNode(node).setType(m_graph, SpecString);
1730 forNode(node).set(m_graph, m_vm.stringStructure.get());
1736 case AtomicsCompareExchange:
1737 case AtomicsExchange:
1743 if (node->op() != GetByVal)
1744 clobberWorld(node->origin.semantic, clobberLimit);
1745 switch (node->arrayMode().type()) {
1746 case Array::SelectUsingPredictions:
1747 case Array::Unprofiled:
1748 case Array::SelectUsingArguments:
1749 RELEASE_ASSERT_NOT_REACHED();
1751 case Array::ForceExit:
1752 m_state.setIsValid(false);
1754 case Array::Undecided: {
1755 JSValue index = forNode(m_graph.child(node, 1)).value();
1756 if (index && index.isInt32() && index.asInt32() >= 0) {
1757 setConstant(node, jsUndefined());
1760 forNode(node).setType(SpecOther);
1763 case Array::Generic:
1764 clobberWorld(node->origin.semantic, clobberLimit);
1765 forNode(node).makeHeapTop();
1768 if (node->arrayMode().isOutOfBounds()) {
1769 // If the watchpoint was still valid we could totally set this to be
1770 // SpecString | SpecOther. Except that we'd have to be careful. If we
1771 // tested the watchpoint state here then it could change by the time
1772 // we got to the backend. So to do this right, we'd have to get the
1773 // fixup phase to check the watchpoint state and then bake into the
1774 // GetByVal operation the fact that we're using a watchpoint, using
1775 // something like Array::SaneChain (except not quite, because that
1776 // implies an in-bounds access). None of this feels like it's worth it,
1777 // so we're going with TOP for now. The same thing applies to
1778 // clobbering the world.
1779 clobberWorld(node->origin.semantic, clobberLimit);
1780 forNode(node).makeHeapTop();
1782 forNode(node).set(m_graph, m_vm.stringStructure.get());
1784 case Array::DirectArguments:
1785 case Array::ScopedArguments:
1786 forNode(node).makeHeapTop();
1789 if (node->arrayMode().isOutOfBounds()) {
1790 clobberWorld(node->origin.semantic, clobberLimit);
1791 forNode(node).makeHeapTop();
1793 forNode(node).setType(SpecInt32Only);
1796 if (node->arrayMode().isOutOfBounds()) {
1797 clobberWorld(node->origin.semantic, clobberLimit);
1798 forNode(node).makeHeapTop();
1799 } else if (node->arrayMode().isSaneChain())
1800 forNode(node).setType(SpecBytecodeDouble);
1802 forNode(node).setType(SpecDoubleReal);
1804 case Array::Contiguous:
1805 case Array::ArrayStorage:
1806 case Array::SlowPutArrayStorage:
1807 if (node->arrayMode().isOutOfBounds())
1808 clobberWorld(node->origin.semantic, clobberLimit);
1809 forNode(node).makeHeapTop();
1811 case Array::Int8Array:
1812 forNode(node).setType(SpecInt32Only);
1814 case Array::Int16Array:
1815 forNode(node).setType(SpecInt32Only);
1817 case Array::Int32Array:
1818 forNode(node).setType(SpecInt32Only);
1820 case Array::Uint8Array:
1821 forNode(node).setType(SpecInt32Only);
1823 case Array::Uint8ClampedArray:
1824 forNode(node).setType(SpecInt32Only);
1826 case Array::Uint16Array:
1827 forNode(node).setType(SpecInt32Only);
1829 case Array::Uint32Array:
1830 if (node->shouldSpeculateInt32())
1831 forNode(node).setType(SpecInt32Only);
1832 else if (enableInt52() && node->shouldSpeculateAnyInt())
1833 forNode(node).setType(SpecAnyInt);
1835 forNode(node).setType(SpecAnyIntAsDouble);
1837 case Array::Float32Array:
1838 forNode(node).setType(SpecFullDouble);
1840 case Array::Float64Array:
1841 forNode(node).setType(SpecFullDouble);
1844 RELEASE_ASSERT_NOT_REACHED();
1850 case PutByValDirect:
1852 case PutByValAlias: {
1853 switch (node->arrayMode().modeForPut().type()) {
1854 case Array::ForceExit:
1855 m_state.setIsValid(false);
1857 case Array::Generic:
1858 clobberWorld(node->origin.semantic, clobberLimit);
1861 if (node->arrayMode().isOutOfBounds())
1862 clobberWorld(node->origin.semantic, clobberLimit);
1865 if (node->arrayMode().isOutOfBounds())
1866 clobberWorld(node->origin.semantic, clobberLimit);
1868 case Array::Contiguous:
1869 case Array::ArrayStorage:
1870 if (node->arrayMode().isOutOfBounds())
1871 clobberWorld(node->origin.semantic, clobberLimit);
1873 case Array::SlowPutArrayStorage:
1874 if (node->arrayMode().mayStoreToHole())
1875 clobberWorld(node->origin.semantic, clobberLimit);
1884 clobberWorld(node->origin.semantic, clobberLimit);
1885 forNode(node).setType(SpecBytecodeNumber);
1889 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1891 // FIXME: We could do better here if we prove that the
1892 // incoming value has only a single structure.
1893 RegisteredStructureSet structureSet;
1894 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)));
1895 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)));
1896 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)));
1898 forNode(node).set(m_graph, structureSet);
1902 case ArrayIndexOf: {
1903 forNode(node).setType(SpecInt32Only);
1908 clobberWorld(node->origin.semantic, clobberLimit);
1909 forNode(node).makeHeapTop();
1912 case GetMyArgumentByVal:
1913 case GetMyArgumentByValOutOfBounds: {
1914 JSValue index = forNode(node->child2()).m_value;
1915 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame;
1917 if (index && index.isUInt32()) {
1918 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
1919 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
1920 // paths as unreachable, or to return undefined. We could implement that eventually.
1922 Checked<unsigned, RecordOverflow> argumentIndexChecked = index.asUInt32();
1923 argumentIndexChecked += node->numberOfArgumentsToSkip();
1924 unsigned argumentIndex;
1925 if (argumentIndexChecked.safeGet(argumentIndex) != CheckedState::DidOverflow) {
1926 if (inlineCallFrame) {
1927 if (argumentIndex < inlineCallFrame->argumentCountIncludingThis - 1) {
1928 forNode(node) = m_state.variables().operand(
1929 virtualRegisterForArgument(argumentIndex + 1) + inlineCallFrame->stackOffset);
1930 m_state.setFoundConstants(true);
1934 if (argumentIndex < m_state.variables().numberOfArguments() - 1) {
1935 forNode(node) = m_state.variables().argument(argumentIndex + 1);
1936 m_state.setFoundConstants(true);
1943 if (inlineCallFrame) {
1944 // We have a bound on the types even though it's random access. Take advantage of this.
1946 AbstractValue result;
1947 for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->argumentCountIncludingThis; ++i) {
1949 m_state.variables().operand(
1950 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
1953 if (node->op() == GetMyArgumentByValOutOfBounds)
1954 result.merge(SpecOther);
1957 m_state.setFoundConstants(true);
1959 forNode(node) = result;
1963 forNode(node).makeHeapTop();
1968 case RegExpExecNonGlobalOrSticky:
1969 if (node->op() == RegExpExec) {
1970 if (node->child2().useKind() == RegExpObjectUse
1971 && node->child3().useKind() == StringUse) {
1972 // This doesn't clobber the world since there are no conversions to perform.
1974 clobberWorld(node->origin.semantic, clobberLimit);
1977 if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
1978 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
1979 if (!globalObject->isHavingABadTime()) {
1980 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
1981 RegisteredStructureSet structureSet;
1982 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
1983 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayWithGroupsStructure()));
1984 forNode(node).set(m_graph, structureSet);
1985 forNode(node).merge(SpecOther);
1990 forNode(node).setType(m_graph, SpecOther | SpecArray);
1994 if (node->child2().useKind() == RegExpObjectUse
1995 && node->child3().useKind() == StringUse) {
1996 // This doesn't clobber the world since there are no conversions to perform.
1998 clobberWorld(node->origin.semantic, clobberLimit);
1999 forNode(node).setType(SpecBoolean);
2002 case RegExpMatchFast:
2003 ASSERT(node->child2().useKind() == RegExpObjectUse);
2004 ASSERT(node->child3().useKind() == StringUse);
2005 forNode(node).setType(m_graph, SpecOther | SpecArray);
2008 case RegExpMatchFastGlobal:
2009 ASSERT(node->child2().useKind() == StringUse);
2010 forNode(node).setType(m_graph, SpecOther | SpecArray);
2014 case StringReplaceRegExp:
2015 if (node->child1().useKind() == StringUse
2016 && node->child2().useKind() == RegExpObjectUse
2017 && node->child3().useKind() == StringUse) {
2018 // This doesn't clobber the world. It just reads and writes regexp state.
2020 clobberWorld(node->origin.semantic, clobberLimit);
2021 forNode(node).set(m_graph, m_vm.stringStructure.get());
2028 Node* child = node->child1().node();
2029 BooleanResult result = booleanResult(node, forNode(child));
2030 if (result == DefinitelyTrue) {
2031 m_state.setBranchDirection(TakeTrue);
2034 if (result == DefinitelyFalse) {
2035 m_state.setBranchDirection(TakeFalse);
2038 // FIXME: The above handles the trivial cases of sparse conditional
2039 // constant propagation, but we can do better:
2040 // We can specialize the source variable's value on each direction of
2042 m_state.setBranchDirection(TakeBoth);
2047 // Nothing to do for now.
2048 // FIXME: Do sparse conditional things.
2056 m_state.setIsValid(false);
2060 case ThrowStaticError:
2062 case DirectTailCall:
2063 case TailCallVarargs:
2064 case TailCallForwardVarargs:
2065 clobberWorld(node->origin.semantic, clobberLimit);
2066 m_state.setIsValid(false);
2070 JSValue childConst = forNode(node->child1()).value();
2071 if (childConst && childConst.isNumber()) {
2072 setConstant(node, childConst);
2076 ASSERT(node->child1().useKind() == UntypedUse);
2078 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) {
2079 m_state.setFoundConstants(true);
2080 forNode(node) = forNode(node->child1());
2084 clobberWorld(node->origin.semantic, clobberLimit);
2086 forNode(node).setType(m_graph, SpecHeapTop & ~SpecObject);
2091 JSValue childConst = forNode(node->child1()).value();
2092 if (childConst && childConst.isNumber()) {
2093 setConstant(node, childConst);
2097 ASSERT(node->child1().useKind() == UntypedUse);
2099 if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
2100 m_state.setFoundConstants(true);
2101 forNode(node) = forNode(node->child1());
2105 clobberWorld(node->origin.semantic, clobberLimit);
2106 forNode(node).setType(m_graph, SpecBytecodeNumber);
2111 case CallStringConstructor: {
2112 switch (node->child1().useKind()) {
2113 case StringObjectUse:
2114 // This also filters that the StringObject has the primordial StringObject
2118 m_graph.registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()));
2120 case StringOrStringObjectUse:
2128 clobberWorld(node->origin.semantic, clobberLimit);
2131 RELEASE_ASSERT_NOT_REACHED();
2134 forNode(node).set(m_graph, m_vm.stringStructure.get());
2138 case NumberToStringWithRadix: {
2139 JSValue radixValue = forNode(node->child2()).m_value;
2140 if (radixValue && radixValue.isInt32()) {
2141 int32_t radix = radixValue.asInt32();
2142 if (2 <= radix && radix <= 36) {
2143 m_state.setFoundConstants(true);
2144 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2148 clobberWorld(node->origin.semantic, clobberLimit);
2149 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2153 case NumberToStringWithValidRadixConstant: {
2154 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2158 case NewStringObject: {
2159 ASSERT(node->structure()->classInfo() == StringObject::info());
2160 forNode(node).set(m_graph, node->structure());
2167 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2170 case NewArrayWithSpread:
2171 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2172 // We've compiled assuming we're not having a bad time, so to be consistent
2173 // with StructureRegisterationPhase we must say we produce an original array
2174 // allocation structure.
2177 m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
2181 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
2187 if (!m_graph.canDoFastSpread(node, forNode(node->child1())))
2188 clobberWorld(node->origin.semantic, clobberLimit);
2191 m_graph, m_vm.fixedArrayStructure.get());
2194 case NewArrayBuffer:
2197 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2200 case NewArrayWithSize:
2201 forNode(node).setType(m_graph, SpecArray);
2205 switch (node->child1().useKind()) {
2209 clobberWorld(node->origin.semantic, clobberLimit);
2212 RELEASE_ASSERT_NOT_REACHED();
2217 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(
2218 node->typedArrayType()));
2222 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
2226 AbstractValue& source = forNode(node->child1());
2227 AbstractValue& destination = forNode(node);
2228 bool strictMode = m_graph.executableFor(node->origin.semantic)->isStrictMode();
2230 ToThisResult result = isToThisAnIdentity(m_vm, strictMode, source);
2231 if (result != ToThisResult::Dynamic) {
2233 case ToThisResult::Identity:
2234 m_state.setFoundConstants(true);
2235 destination = source;
2237 case ToThisResult::Undefined:
2238 setConstant(node, jsUndefined());
2240 case ToThisResult::GlobalThis:
2241 m_state.setFoundConstants(true);
2242 destination.setType(m_graph, SpecObject);
2244 case ToThisResult::Dynamic:
2245 RELEASE_ASSERT_NOT_REACHED();
2251 destination.makeHeapTop();
2253 destination = source;
2254 destination.merge(SpecObject);
2260 if (JSValue base = forNode(node->child1()).m_value) {
2261 if (auto* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2262 if (FunctionRareData* rareData = function->rareData()) {
2263 if (Structure* structure = rareData->objectAllocationStructure()) {
2264 // FIXME: we should be able to allocate a poly proto object here:
2265 // https://bugs.webkit.org/show_bug.cgi?id=177517
2266 if (structure->hasMonoProto()) {
2267 m_graph.freeze(rareData);
2268 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet());
2269 m_state.setFoundConstants(true);
2270 forNode(node).set(m_graph, structure);
2277 forNode(node).setType(m_graph, SpecFinalObject);
2282 ASSERT(!!node->structure().get());
2283 forNode(node).set(m_graph, node->structure());
2287 case CallObjectConstructor: {
2288 AbstractValue& source = forNode(node->child1());
2289 AbstractValue& destination = forNode(node);
2291 if (!(source.m_type & ~SpecObject)) {
2292 m_state.setFoundConstants(true);
2293 destination = source;
2297 if (node->op() == ToObject)
2298 clobberWorld(node->origin.semantic, clobberLimit);
2299 forNode(node).setType(m_graph, SpecObject);
2303 case PhantomNewObject:
2304 case PhantomNewFunction:
2305 case PhantomNewGeneratorFunction:
2306 case PhantomNewAsyncGeneratorFunction:
2307 case PhantomNewAsyncFunction:
2308 case PhantomCreateActivation:
2309 case PhantomDirectArguments:
2310 case PhantomClonedArguments:
2311 case PhantomCreateRest:
2313 case PhantomNewArrayWithSpread:
2314 case PhantomNewArrayBuffer:
2315 case PhantomNewRegexp:
2317 m_state.setDidClobber(true); // Prevent constant folding.
2318 // This claims to return bottom.
2324 case MaterializeNewObject: {
2325 forNode(node).set(m_graph, node->structureSet());
2330 // We don't use the more precise withScopeStructure() here because it is a LazyProperty and may not yet be allocated.
2331 forNode(node).setType(m_graph, SpecObjectOther);
2334 case CreateActivation:
2335 case MaterializeCreateActivation:
2337 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
2340 case CreateDirectArguments:
2341 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
2344 case CreateScopedArguments:
2345 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
2348 case CreateClonedArguments:
2349 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2350 forNode(node).setType(m_graph, SpecObject);
2353 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
2356 case NewGeneratorFunction:
2358 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
2361 case NewAsyncGeneratorFunction:
2363 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncGeneratorFunctionStructure());
2366 case NewAsyncFunction:
2368 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
2372 JSGlobalObject* globalObject = m_codeBlock->globalObjectFor(node->origin.semantic);
2373 Structure* structure = JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>());
2374 forNode(node).set(m_graph, structure);
2379 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
2380 InferredValue* singleton = executable->singletonFunction();
2381 if (JSValue value = singleton->inferredValue()) {
2382 m_graph.watchpoints().addLazily(singleton);
2383 JSFunction* function = jsCast<JSFunction*>(value);
2384 setConstant(node, *m_graph.freeze(function));
2388 forNode(node).setType(m_graph, SpecFunction);
2391 case GetArgumentCountIncludingThis:
2392 forNode(node).setType(SpecInt32Only);
2395 case SetArgumentCountIncludingThis:
2399 forNode(node).setType(SpecInt32Only);
2403 JSValue base = forNode(node->child1()).m_value;
2405 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2406 if (!getterSetter->isGetterNull()) {
2407 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
2412 forNode(node).setType(m_graph, SpecObject);
2417 JSValue base = forNode(node->child1()).m_value;
2419 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2420 if (!getterSetter->isSetterNull()) {
2421 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
2426 forNode(node).setType(m_graph, SpecObject);
2431 if (JSValue base = forNode(node->child1()).m_value) {
2432 if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2433 setConstant(node, *m_graph.freeze(function->scope()));
2437 forNode(node).setType(m_graph, SpecObjectOther);
2441 JSValue child = forNode(node->child1()).value();
2443 setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next())));
2446 forNode(node).setType(m_graph, SpecObjectOther);
2450 case GetGlobalObject: {
2451 JSValue child = forNode(node->child1()).value();
2453 setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject())));
2457 if (forNode(node->child1()).m_structure.isFinite()) {
2458 JSGlobalObject* globalObject = nullptr;
2460 forNode(node->child1()).m_structure.forEach(
2461 [&] (RegisteredStructure structure) {
2463 globalObject = structure->globalObject();
2464 else if (globalObject != structure->globalObject())
2467 if (globalObject && ok) {
2468 setConstant(node, *m_graph.freeze(JSValue(globalObject)));
2473 forNode(node).setType(m_graph, SpecObjectOther);
2477 case GetGlobalThis: {
2478 forNode(node).setType(m_graph, SpecObject);
2483 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
2484 setConstant(node, *m_graph.freeze(value));
2487 forNode(node).makeBytecodeTop();
2493 case GetRegExpObjectLastIndex:
2494 forNode(node).makeHeapTop();
2497 case SetRegExpObjectLastIndex:
2498 case RecordRegExpCachedResult:
2501 case GetFromArguments:
2502 forNode(node).makeHeapTop();
2505 case PutToArguments:
2509 forNode(node).makeHeapTop();
2513 // FIXME: This should constant fold at least as well as the normal GetById case.
2514 // https://bugs.webkit.org/show_bug.cgi?id=156422
2515 forNode(node).makeHeapTop();
2519 case GetByIdFlush: {
2520 if (!node->prediction()) {
2521 m_state.setIsValid(false);
2525 AbstractValue& value = forNode(node->child1());
2526 if (value.m_structure.isFinite()
2527 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
2528 UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
2529 GetByIdStatus status = GetByIdStatus::computeFor(value.m_structure.toStructureSet(), uid);
2530 if (status.isSimple()) {
2531 // Figure out what the result is going to be - is it TOP, a constant, or maybe
2532 // something more subtle?
2533 AbstractValue result;
2534 for (unsigned i = status.numVariants(); i--;) {
2535 // This thing won't give us a variant that involves prototypes. If it did, we'd
2536 // have more work to do here.
2537 DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty());
2540 m_graph.inferredValueForProperty(
2541 value, uid, status[i].offset(), m_state.structureClobberState()));
2543 m_state.setFoundConstants(true);
2544 forNode(node) = result;
2549 clobberWorld(node->origin.semantic, clobberLimit);
2550 forNode(node).makeHeapTop();
2554 case GetByValWithThis:
2555 case GetByIdWithThis:
2556 clobberWorld(node->origin.semantic, clobberLimit);
2557 forNode(node).makeHeapTop();
2560 case GetArrayLength: {
2561 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2562 forNode(node->child1()).m_value, node->arrayMode());
2564 setConstant(node, jsNumber(view->length()));
2567 forNode(node).setType(SpecInt32Only);
2571 case GetArrayMask: {
2572 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
2574 setConstant(node, jsNumber(view->butterflyIndexingMask()));
2577 forNode(node).setType(SpecInt32Only);
2581 case GetVectorLength: {
2582 forNode(node).setType(SpecInt32Only);
2588 // FIXME: This could decide if the delete will be successful based on the set of structures that
2589 // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
2590 clobberWorld(node->origin.semantic, clobberLimit);
2591 forNode(node).setType(SpecBoolean);
2595 case CheckStructure: {
2596 AbstractValue& value = forNode(node->child1());
2598 const RegisteredStructureSet& set = node->structureSet();
2600 // It's interesting that we could have proven that the object has a larger structure set
2601 // that includes the set we're testing. In that case we could make the structure check
2602 // more efficient. We currently don't.
2604 if (value.m_structure.isSubsetOf(set))
2605 m_state.setFoundConstants(true);
2607 SpeculatedType admittedTypes = SpecNone;
2608 switch (node->child1().useKind()) {
2611 admittedTypes = SpecNone;
2613 case CellOrOtherUse:
2614 admittedTypes = SpecOther;
2617 DFG_CRASH(m_graph, node, "Bad use kind");
2621 filter(value, set, admittedTypes);
2625 case CheckStructureOrEmpty: {
2626 AbstractValue& value = forNode(node->child1());
2628 bool mayBeEmpty = value.m_type & SpecEmpty;
2630 m_state.setFoundConstants(true);
2632 SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone;
2633 filter(value, node->structureSet(), admittedTypes);
2637 case CheckStructureImmediate: {
2638 // FIXME: This currently can only reason about one structure at a time.
2639 // https://bugs.webkit.org/show_bug.cgi?id=136988
2641 AbstractValue& value = forNode(node->child1());
2642 const RegisteredStructureSet& set = node->structureSet();
2644 if (value.value()) {
2645 if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) {
2646 if (set.contains(m_graph.registerStructure(structure))) {
2647 m_state.setFoundConstants(true);
2651 m_state.setIsValid(false);
2655 if (m_phiChildren) {
2656 bool allGood = true;
2657 m_phiChildren->forAllTransitiveIncomingValues(
2659 [&] (Node* incoming) {
2660 if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) {
2661 if (set.contains(m_graph.registerStructure(structure)))
2667 m_state.setFoundConstants(true);
2672 if (RegisteredStructure structure = set.onlyStructure()) {
2673 filterByValue(node->child1(), *m_graph.freeze(structure.get()));
2677 // Aw shucks, we can't do anything!
2682 if (!forNode(node->child1()).m_structure.isClear()) {
2683 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
2684 m_state.setFoundConstants(true);
2687 clobberLimit, node->transition()->previous, node->transition()->next);
2688 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
2693 case AllocatePropertyStorage:
2694 case ReallocatePropertyStorage:
2695 case NukeStructureAndSetButterfly:
2696 // FIXME: We don't model the fact that the structureID is nuked, simply because currently
2697 // nobody would currently benefit from having that information. But it's a bug nonetheless.
2698 forNode(node).clear(); // The result is not a JS value.
2700 case CheckSubClass: {
2701 JSValue constant = forNode(node->child1()).value();
2703 if (constant.isCell() && constant.asCell()->inherits(m_vm, node->classInfo())) {
2704 m_state.setFoundConstants(true);
2710 AbstractValue& value = forNode(node->child1());
2712 if (value.m_structure.isSubClassOf(node->classInfo()))
2713 m_state.setFoundConstants(true);
2715 filterClassInfo(value, node->classInfo());
2718 case CallDOMGetter: {
2719 CallDOMGetterData* callDOMGetterData = node->callDOMGetterData();
2720 DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet;
2721 if (!snippet || snippet->effect.writes)
2722 clobberWorld(node->origin.semantic, clobberLimit);
2723 if (callDOMGetterData->domJIT)
2724 forNode(node).setType(m_graph, callDOMGetterData->domJIT->resultType());
2726 forNode(node).makeBytecodeTop();
2730 const DOMJIT::Signature* signature = node->signature();
2731 if (signature->effect.writes)
2732 clobberWorld(node->origin.semantic, clobberLimit);
2733 forNode(node).setType(m_graph, signature->result);
2737 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2738 m_state.setFoundConstants(true);
2741 switch (node->arrayMode().type()) {
2743 filter(node->child1(), SpecString);
2747 case Array::Contiguous:
2748 case Array::Undecided:
2749 case Array::ArrayStorage:
2750 case Array::SlowPutArrayStorage:
2752 case Array::DirectArguments:
2753 filter(node->child1(), SpecDirectArguments);
2755 case Array::ScopedArguments:
2756 filter(node->child1(), SpecScopedArguments);
2758 case Array::Int8Array:
2759 filter(node->child1(), SpecInt8Array);
2761 case Array::Int16Array:
2762 filter(node->child1(), SpecInt16Array);
2764 case Array::Int32Array:
2765 filter(node->child1(), SpecInt32Array);
2767 case Array::Uint8Array:
2768 filter(node->child1(), SpecUint8Array);
2770 case Array::Uint8ClampedArray:
2771 filter(node->child1(), SpecUint8ClampedArray);
2773 case Array::Uint16Array:
2774 filter(node->child1(), SpecUint16Array);
2776 case Array::Uint32Array:
2777 filter(node->child1(), SpecUint32Array);
2779 case Array::Float32Array:
2780 filter(node->child1(), SpecFloat32Array);
2782 case Array::Float64Array:
2783 filter(node->child1(), SpecFloat64Array);
2785 case Array::AnyTypedArray:
2786 filter(node->child1(), SpecTypedArrayView);
2789 RELEASE_ASSERT_NOT_REACHED();
2792 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2796 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2797 m_state.setFoundConstants(true);
2800 ASSERT(node->arrayMode().conversion() == Array::Convert);
2801 clobberStructures(clobberLimit);
2802 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2805 case ArrayifyToStructure: {
2806 AbstractValue& value = forNode(node->child1());
2807 if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure())))
2808 m_state.setFoundConstants(true);
2809 clobberStructures(clobberLimit);
2811 // We have a bunch of options of how to express the abstract set at this point. Let set S
2812 // be the set of structures that the value had before clobbering and assume that all of
2813 // them are watchable. The new value should be the least expressible upper bound of the
2814 // intersection of "values that currently have structure = node->structure()" and "values
2815 // that have structure in S plus any structure transition-reachable from S". Assume that
2816 // node->structure() is not in S but it is transition-reachable from S. Then we would
2817 // like to say that the result is "values that have structure = node->structure() until
2818 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
2819 // we must choose between:
2821 // 1) "values that currently have structure = node->structure()". This is a valid
2822 // superset of the value that we really want, and it's specific enough to satisfy the
2823 // preconditions of the array access that this is guarding. It's also specific enough
2824 // to allow relevant optimizations in the case that we didn't have a contradiction
2825 // like in this example. Notice that in the abscence of any contradiction, this result
2826 // is precise rather than being a conservative LUB.
2828 // 2) "values that currently hava structure in S plus any structure transition-reachable
2829 // from S". This is also a valid superset of the value that we really want, but it's
2830 // not specific enough to satisfy the preconditions of the array access that this is
2831 // guarding - so playing such shenanigans would preclude us from having assertions on
2832 // the typing preconditions of any array accesses. This would also not be a desirable
2833 // answer in the absence of a contradiction.
2835 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
2836 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
2838 value.set(m_graph, node->structure());
2841 case GetIndexedPropertyStorage: {
2842 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2843 forNode(node->child1()).m_value, node->arrayMode());
2845 m_state.setFoundConstants(true);
2846 forNode(node).clear();
2849 case ConstantStoragePointer: {
2850 forNode(node).clear();
2854 case GetTypedArrayByteOffset: {
2855 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
2857 setConstant(node, jsNumber(view->byteOffset()));
2860 forNode(node).setType(SpecInt32Only);
2864 case GetPrototypeOf: {
2865 AbstractValue& value = forNode(node->child1());
2866 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
2867 bool canFold = !value.m_structure.isClear();
2869 value.m_structure.forEach([&] (RegisteredStructure structure) {
2870 auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
2871 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
2872 if (getPrototypeMethod != defaultGetPrototype) {
2877 if (structure->hasPolyProto()) {
2882 prototype = structure->storedPrototype();
2883 else if (prototype != structure->storedPrototype())
2887 if (prototype && canFold) {
2888 setConstant(node, *m_graph.freeze(prototype));
2893 switch (node->child1().useKind()) {
2896 case FinalObjectUse:
2899 clobberWorld(node->origin.semantic, clobberLimit);
2902 forNode(node).setType(m_graph, SpecObject | SpecOther);
2907 StorageAccessData& data = node->storageAccessData();
2908 UniquedStringImpl* uid = m_graph.identifiers()[data.identifierNumber];
2910 // FIXME: The part of this that handles inferred property types relies on AI knowing the structure
2911 // right now. That's probably not optimal. In some cases, we may perform an optimization (usually
2912 // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure
2913 // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely
2914 // on the type that ByteCodeParser was able to prove.
2915 AbstractValue value = m_graph.inferredValueForProperty(
2916 forNode(node->child2()), uid, data.offset, m_state.structureClobberState());
2918 // It's possible that the type that ByteCodeParser came up with is better.
2919 AbstractValue typeFromParsing;
2920 typeFromParsing.set(m_graph, data.inferredType, m_state.structureClobberState());
2921 value.filter(typeFromParsing);
2923 // If we decide that there does not exist any value that this can return, then it's probably
2924 // because the compilation was already invalidated.
2925 if (value.isClear())
2926 m_state.setIsValid(false);
2928 forNode(node) = value;
2930 m_state.setFoundConstants(true);
2934 case GetGetterSetterByOffset: {
2935 StorageAccessData& data = node->storageAccessData();
2936 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
2937 if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) {
2938 setConstant(node, *m_graph.freeze(result));
2942 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->getterSetterStructure());
2946 case MultiGetByOffset: {
2947 // This code will filter the base value in a manner that is possibly different (either more
2948 // or less precise) than the way it would be filtered if this was strength-reduced to a
2949 // CheckStructure. This is fine. It's legal for different passes over the code to prove
2950 // different things about the code, so long as all of them are sound. That even includes
2951 // one guy proving that code should never execute (due to a contradiction) and another guy
2952 // not finding that contradiction. If someone ever proved that there would be a
2953 // contradiction then there must always be a contradiction even if subsequent passes don't
2954 // realize it. This is the case here.
2956 // Ordinarily you have to be careful with calling setFoundConstants()
2957 // because of the effect on compile times, but this node is FTL-only.
2958 m_state.setFoundConstants(true);
2960 UniquedStringImpl* uid = m_graph.identifiers()[node->multiGetByOffsetData().identifierNumber];
2962 AbstractValue base = forNode(node->child1());
2963 RegisteredStructureSet baseSet;
2964 AbstractValue result;
2965 for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
2966 RegisteredStructureSet set = getCase.set();
2972 switch (getCase.method().kind()) {
2973 case GetByOffsetMethod::Constant: {
2974 AbstractValue thisResult;
2977 *getCase.method().constant(),
2978 m_state.structureClobberState());
2979 result.merge(thisResult);
2983 case GetByOffsetMethod::Load: {
2985 m_graph.inferredValueForProperty(
2986 set, uid, m_state.structureClobberState()));
2991 result.makeHeapTop();
2996 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
2997 m_state.setIsValid(false);
2999 forNode(node) = result;
3007 case MultiPutByOffset: {
3008 RegisteredStructureSet newSet;
3009 TransitionVector transitions;
3011 // Ordinarily you have to be careful with calling setFoundConstants()
3012 // because of the effect on compile times, but this node is FTL-only.
3013 m_state.setFoundConstants(true);
3015 AbstractValue base = forNode(node->child1());
3016 AbstractValue originalValue = forNode(node->child2());
3017 AbstractValue resultingValue;
3019 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
3020 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
3021 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure());
3022 thisSet.filter(base);
3023 if (thisSet.isEmpty())
3026 AbstractValue thisValue = originalValue;
3027 thisValue.filter(m_graph, variant.requiredType());
3028 resultingValue.merge(thisValue);
3030 if (variant.kind() == PutByIdVariant::Transition) {
3031 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
3032 if (thisSet.onlyStructure() != newStructure) {
3034 Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
3035 } // else this is really a replace.
3036 newSet.add(newStructure);
3038 ASSERT(variant.kind() == PutByIdVariant::Replace);
3039 newSet.merge(thisSet);
3043 observeTransitions(clobberLimit, transitions);
3044 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
3045 m_state.setIsValid(false);
3046 forNode(node->child2()) = resultingValue;
3047 if (!!originalValue && !resultingValue)
3048 m_state.setIsValid(false);
3052 case GetExecutable: {
3053 JSValue value = forNode(node->child1()).value();
3055 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
3057 setConstant(node, *m_graph.freeze(function->executable()));
3061 forNode(node).setType(m_graph, SpecCellOther);
3066 JSValue value = forNode(node->child1()).value();
3067 if (value == node->cellOperand()->value()) {
3068 m_state.setFoundConstants(true);
3072 filterByValue(node->child1(), *node->cellOperand());
3076 case AssertNotEmpty:
3077 case CheckNotEmpty: {
3078 AbstractValue& value = forNode(node->child1());