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(), AbstractInterpreterInvalidType, node->op(), edge->op(), edge.useKind(), forNode(edge).m_type);
137 template<typename AbstractStateType>
138 void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node)
140 DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge);
143 enum class ToThisResult {
149 inline ToThisResult isToThisAnIdentity(VM& vm, bool isStrictMode, AbstractValue& valueForNode)
151 // We look at the type first since that will cover most cases and does not require iterating all the structures.
153 if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther))
154 return ToThisResult::Identity;
156 if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther)))
157 return ToThisResult::Identity;
160 if (JSValue value = valueForNode.value()) {
161 if (value.isCell()) {
162 auto* toThisMethod = value.asCell()->classInfo(vm)->methodTable.toThis;
163 if (toThisMethod == &JSObject::toThis)
164 return ToThisResult::Identity;
165 if (toThisMethod == &JSScope::toThis) {
167 return ToThisResult::Undefined;
168 return ToThisResult::GlobalThis;
173 if ((isStrictMode || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) {
174 bool allStructuresAreJSScope = !valueForNode.m_structure.isClear();
175 bool overridesToThis = false;
176 valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
177 TypeInfo type = structure->typeInfo();
178 ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType);
180 ASSERT(type.isObject());
181 // We don't need to worry about strings/symbols here since either:
182 // 1) We are in strict mode and strings/symbols are not wrapped
183 // 2) The AI has proven that the type of this is a subtype of object
184 if (type.isObject() && type.overridesToThis())
185 overridesToThis = true;
187 // If all the structures are JSScope's ones, we know the details of JSScope::toThis() operation.
188 allStructuresAreJSScope &= structure->classInfo()->methodTable.toThis == JSScope::info()->methodTable.toThis;
190 if (!overridesToThis)
191 return ToThisResult::Identity;
192 if (allStructuresAreJSScope) {
194 return ToThisResult::Undefined;
195 return ToThisResult::GlobalThis;
199 return ToThisResult::Dynamic;
202 template<typename AbstractStateType>
203 bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node)
207 m_state.createValueForNode(node);
209 switch (node->op()) {
212 case Int52Constant: {
213 setBuiltInConstant(node, *node->constant());
217 case LazyJSConstant: {
218 LazyJSValue value = node->lazyJSValue();
219 switch (value.kind()) {
220 case LazyJSValue::KnownValue:
221 setConstant(node, value.value()->value());
223 case LazyJSValue::SingleCharacterString:
224 case LazyJSValue::KnownStringImpl:
225 case LazyJSValue::NewStringImpl:
226 forNode(node).setType(m_graph, SpecString);
232 case IdentityWithProfile:
234 forNode(node) = forNode(node->child1());
235 if (forNode(node).value())
236 m_state.setFoundConstants(true);
240 case ExtractCatchLocal:
241 case ExtractOSREntryLocal: {
242 forNode(node).makeBytecodeTop();
247 VariableAccessData* variableAccessData = node->variableAccessData();
248 AbstractValue value = m_state.variables().operand(variableAccessData->local().offset());
249 // The value in the local should already be checked.
250 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat())));
252 m_state.setFoundConstants(true);
253 forNode(node) = value;
258 StackAccessData* data = node->stackAccessData();
259 AbstractValue value = m_state.variables().operand(data->local);
260 // The value in the local should already be checked.
261 DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format)));
263 m_state.setFoundConstants(true);
264 forNode(node) = value;
268 case GetLocalUnlinked: {
269 AbstractValue value = m_state.variables().operand(node->unlinkedLocal().offset());
271 m_state.setFoundConstants(true);
272 forNode(node) = value;
277 m_state.variables().operand(node->local()) = forNode(node->child1());
282 m_state.variables().operand(node->stackAccessData()->local) = forNode(node->child1());
287 // Don't need to do anything. A MovHint only informs us about what would have happened
288 // in bytecode, but this code is just concerned with what is actually happening during
294 // This is just a hint telling us that the OSR state of the local is no longer inside the
300 // Assert that the state of arguments has been set. SetArgument means that someone set
301 // the argument values out-of-band, and currently this always means setting to a
303 ASSERT(!m_state.variables().operand(node->local()).isClear());
306 case InitializeEntrypointArguments: {
307 unsigned entrypointIndex = node->entrypointIndex();
308 const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex];
309 for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) {
310 AbstractValue& value = m_state.variables().argument(argument);
311 switch (argumentFormats[argument]) {
313 value.setType(SpecInt32Only);
316 value.setType(SpecBoolean);
319 value.setType(m_graph, SpecCell);
322 value.makeBytecodeTop();
325 DFG_CRASH(m_graph, node, "Bad flush format for argument");
333 case ForwardVarargs: {
334 // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn
335 // itself into a straight-line sequence of GetStack/PutStack.
336 // https://bugs.webkit.org/show_bug.cgi?id=143071
337 clobberWorld(node->origin.semantic, clobberLimit);
338 LoadVarargsData* data = node->loadVarargsData();
339 m_state.variables().operand(data->count).setType(SpecInt32Only);
340 for (unsigned i = data->limit - 1; i--;)
341 m_state.variables().operand(data->start.offset() + i).makeHeapTop();
351 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
352 clobberWorld(node->origin.semantic, clobberLimit);
353 forNode(node).setType(m_graph, SpecInt32Only);
357 JSValue left = forNode(node->child1()).value();
358 JSValue right = forNode(node->child2()).value();
359 if (left && right && left.isInt32() && right.isInt32()) {
360 int32_t a = left.asInt32();
361 int32_t b = right.asInt32();
362 switch (node->op()) {
364 setConstant(node, JSValue(a & b));
367 setConstant(node, JSValue(a | b));
370 setConstant(node, JSValue(a ^ b));
373 setConstant(node, JSValue(a >> static_cast<uint32_t>(b)));
376 setConstant(node, JSValue(a << static_cast<uint32_t>(b)));
379 setConstant(node, JSValue(static_cast<uint32_t>(a) >> static_cast<uint32_t>(b)));
382 RELEASE_ASSERT_NOT_REACHED();
388 if (node->op() == BitAnd
389 && (isBoolInt32Speculation(forNode(node->child1()).m_type) ||
390 isBoolInt32Speculation(forNode(node->child2()).m_type))) {
391 forNode(node).setType(SpecBoolInt32);
395 forNode(node).setType(SpecInt32Only);
399 case UInt32ToNumber: {
400 JSValue child = forNode(node->child1()).value();
401 if (doesOverflow(node->arithMode())) {
403 if (child && child.isAnyInt()) {
404 int64_t machineInt = child.asAnyInt();
405 setConstant(node, jsNumber(static_cast<uint32_t>(machineInt)));
408 forNode(node).setType(SpecAnyInt);
411 if (child && child.isInt32()) {
412 uint32_t value = child.asInt32();
413 setConstant(node, jsNumber(value));
416 forNode(node).setType(SpecAnyIntAsDouble);
419 if (child && child.isInt32()) {
420 int32_t value = child.asInt32();
422 setConstant(node, jsNumber(value));
426 forNode(node).setType(SpecInt32Only);
430 case BooleanToNumber: {
431 JSValue concreteValue = forNode(node->child1()).value();
433 if (concreteValue.isBoolean())
434 setConstant(node, jsNumber(concreteValue.asBoolean()));
436 setConstant(node, *m_graph.freeze(concreteValue));
439 AbstractValue& value = forNode(node);
440 value = forNode(node->child1());
441 if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean))
442 m_state.setFoundConstants(true);
443 if (value.m_type & SpecBoolean) {
444 value.merge(SpecBoolInt32);
445 value.filter(~SpecBoolean);
450 case DoubleAsInt32: {
451 JSValue child = forNode(node->child1()).value();
452 if (child && child.isNumber()) {
453 double asDouble = child.asNumber();
454 int32_t asInt = JSC::toInt32(asDouble);
455 if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) {
456 setConstant(node, JSValue(asInt));
460 forNode(node).setType(SpecInt32Only);
465 JSValue child = forNode(node->child1()).value();
467 if (child.isNumber()) {
469 setConstant(node, child);
471 setConstant(node, JSValue(JSC::toInt32(child.asDouble())));
474 if (child.isBoolean()) {
475 setConstant(node, jsNumber(child.asBoolean()));
478 if (child.isUndefinedOrNull()) {
479 setConstant(node, jsNumber(0));
484 if (isBooleanSpeculation(forNode(node->child1()).m_type)) {
485 forNode(node).setType(SpecBoolInt32);
489 forNode(node).setType(SpecInt32Only);
494 JSValue child = forNode(node->child1()).value();
495 if (std::optional<double> number = child.toNumberFromPrimitive()) {
496 setConstant(node, jsDoubleNumber(*number));
500 SpeculatedType type = forNode(node->child1()).m_type;
501 switch (node->child1().useKind()) {
503 if (type & SpecOther) {
505 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
507 if (type & SpecBoolean) {
508 type &= ~SpecBoolean;
509 type |= SpecBoolInt32; // True becomes 1, false becomes 0.
511 type &= SpecBytecodeNumber;
521 RELEASE_ASSERT_NOT_REACHED();
523 forNode(node).setType(type);
524 forNode(node).fixTypeForRepresentation(m_graph, node);
529 JSValue child = forNode(node->child1()).value();
530 if (child && child.isAnyInt()) {
531 setConstant(node, child);
535 forNode(node).setType(SpecAnyInt);
540 JSValue value = forNode(node->child1()).value();
542 setConstant(node, value);
546 forNode(node).setType(m_graph, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN);
547 forNode(node).fixTypeForRepresentation(m_graph, node);
552 ASSERT(node->binaryUseKind() == UntypedUse);
553 clobberWorld(node->origin.semantic, clobberLimit);
554 forNode(node).setType(m_graph, SpecString | SpecBytecodeNumber);
559 forNode(node).setType(m_graph, SpecString);
564 JSValue left = forNode(node->child1()).value();
565 JSValue right = forNode(node->child2()).value();
566 switch (node->binaryUseKind()) {
568 if (left && right && left.isInt32() && right.isInt32()) {
569 if (!shouldCheckOverflow(node->arithMode())) {
570 setConstant(node, jsNumber(left.asInt32() + right.asInt32()));
573 JSValue result = jsNumber(left.asNumber() + right.asNumber());
574 if (result.isInt32()) {
575 setConstant(node, result);
579 forNode(node).setType(SpecInt32Only);
582 if (left && right && left.isAnyInt() && right.isAnyInt()) {
583 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt());
584 if (result.isAnyInt()) {
585 setConstant(node, result);
589 forNode(node).setType(SpecAnyInt);
592 if (left && right && left.isNumber() && right.isNumber()) {
593 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber()));
596 forNode(node).setType(
598 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
601 RELEASE_ASSERT_NOT_REACHED();
607 case AtomicsIsLockFree: {
608 if (node->child1().useKind() != Int32Use)
609 clobberWorld(node->origin.semantic, clobberLimit);
610 forNode(node).setType(SpecBoolInt32);
615 JSValue operand = forNode(node->child1()).value();
616 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
617 uint32_t value = toUInt32(*number);
618 setConstant(node, jsNumber(clz32(value)));
621 switch (node->child1().useKind()) {
626 clobberWorld(node->origin.semantic, clobberLimit);
629 forNode(node).setType(SpecInt32Only);
634 unsigned numberOfChildren = 0;
635 unsigned numberOfRemovedChildren = 0;
636 std::optional<unsigned> nonEmptyIndex;
637 for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
638 Edge& edge = node->children.child(i);
643 JSValue childConstant = m_state.forNode(edge).value();
644 if (!childConstant) {
648 if (!childConstant.isString()) {
652 if (asString(childConstant)->length()) {
657 ++numberOfRemovedChildren;
660 if (numberOfRemovedChildren) {
661 m_state.setFoundConstants(true);
662 if (numberOfRemovedChildren == numberOfChildren) {
663 // Propagate the last child. This is the way taken in the constant folding phase.
664 forNode(node) = forNode(node->children.child(numberOfChildren - 1));
667 if ((numberOfRemovedChildren + 1) == numberOfChildren) {
668 ASSERT(nonEmptyIndex);
669 forNode(node) = forNode(node->children.child(nonEmptyIndex.value()));
673 forNode(node).set(m_graph, m_vm.stringStructure.get());
678 JSValue left = forNode(node->child1()).value();
679 JSValue right = forNode(node->child2()).value();
680 switch (node->binaryUseKind()) {
682 if (left && right && left.isInt32() && right.isInt32()) {
683 if (!shouldCheckOverflow(node->arithMode())) {
684 setConstant(node, jsNumber(left.asInt32() - right.asInt32()));
687 JSValue result = jsNumber(left.asNumber() - right.asNumber());
688 if (result.isInt32()) {
689 setConstant(node, result);
693 forNode(node).setType(SpecInt32Only);
696 if (left && right && left.isAnyInt() && right.isAnyInt()) {
697 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt());
698 if (result.isAnyInt() || !shouldCheckOverflow(node->arithMode())) {
699 setConstant(node, result);
703 forNode(node).setType(SpecAnyInt);
706 if (left && right && left.isNumber() && right.isNumber()) {
707 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber()));
710 forNode(node).setType(
711 typeOfDoubleDifference(
712 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
715 clobberWorld(node->origin.semantic, clobberLimit);
716 forNode(node).setType(m_graph, SpecBytecodeNumber);
719 RELEASE_ASSERT_NOT_REACHED();
726 JSValue child = forNode(node->child1()).value();
727 switch (node->child1().useKind()) {
729 if (child && child.isInt32()) {
730 if (!shouldCheckOverflow(node->arithMode())) {
731 setConstant(node, jsNumber(-child.asInt32()));
735 if (shouldCheckNegativeZero(node->arithMode()))
736 doubleResult = -child.asNumber();
738 doubleResult = 0 - child.asNumber();
739 JSValue valueResult = jsNumber(doubleResult);
740 if (valueResult.isInt32()) {
741 setConstant(node, valueResult);
745 forNode(node).setType(SpecInt32Only);
748 if (child && child.isAnyInt()) {
750 if (shouldCheckNegativeZero(node->arithMode()))
751 doubleResult = -child.asNumber();
753 doubleResult = 0 - child.asNumber();
754 JSValue valueResult = jsNumber(doubleResult);
755 if (valueResult.isAnyInt()) {
756 setConstant(node, valueResult);
760 forNode(node).setType(SpecAnyInt);
763 if (child && child.isNumber()) {
764 setConstant(node, jsDoubleNumber(-child.asNumber()));
767 forNode(node).setType(
768 typeOfDoubleNegation(
769 forNode(node->child1()).m_type));
772 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
773 forNode(node).setType(SpecBytecodeNumber);
780 JSValue left = forNode(node->child1()).value();
781 JSValue right = forNode(node->child2()).value();
782 switch (node->binaryUseKind()) {
784 if (left && right && left.isInt32() && right.isInt32()) {
785 if (!shouldCheckOverflow(node->arithMode())) {
786 setConstant(node, jsNumber(left.asInt32() * right.asInt32()));
789 double doubleResult = left.asNumber() * right.asNumber();
790 if (!shouldCheckNegativeZero(node->arithMode()))
791 doubleResult += 0; // Sanitizes zero.
792 JSValue valueResult = jsNumber(doubleResult);
793 if (valueResult.isInt32()) {
794 setConstant(node, valueResult);
798 forNode(node).setType(SpecInt32Only);
801 if (left && right && left.isAnyInt() && right.isAnyInt()) {
802 double doubleResult = left.asNumber() * right.asNumber();
803 if (!shouldCheckNegativeZero(node->arithMode()))
805 JSValue valueResult = jsNumber(doubleResult);
806 if (valueResult.isAnyInt()) {
807 setConstant(node, valueResult);
811 forNode(node).setType(SpecAnyInt);
814 if (left && right && left.isNumber() && right.isNumber()) {
815 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber()));
818 forNode(node).setType(
820 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
823 clobberWorld(node->origin.semantic, clobberLimit);
824 forNode(node).setType(m_graph, SpecBytecodeNumber);
827 RELEASE_ASSERT_NOT_REACHED();
834 JSValue left = forNode(node->child1()).value();
835 JSValue right = forNode(node->child2()).value();
836 switch (node->binaryUseKind()) {
838 if (left && right && left.isInt32() && right.isInt32()) {
839 double doubleResult = left.asNumber() / right.asNumber();
840 if (!shouldCheckOverflow(node->arithMode()))
841 doubleResult = toInt32(doubleResult);
842 else if (!shouldCheckNegativeZero(node->arithMode()))
843 doubleResult += 0; // Sanitizes zero.
844 JSValue valueResult = jsNumber(doubleResult);
845 if (valueResult.isInt32()) {
846 setConstant(node, valueResult);
850 forNode(node).setType(SpecInt32Only);
853 if (left && right && left.isNumber() && right.isNumber()) {
854 setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber()));
857 forNode(node).setType(
858 typeOfDoubleQuotient(
859 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
862 clobberWorld(node->origin.semantic, clobberLimit);
863 forNode(node).setType(m_graph, SpecBytecodeNumber);
866 RELEASE_ASSERT_NOT_REACHED();
873 JSValue left = forNode(node->child1()).value();
874 JSValue right = forNode(node->child2()).value();
875 switch (node->binaryUseKind()) {
877 if (left && right && left.isInt32() && right.isInt32()) {
878 double doubleResult = fmod(left.asNumber(), right.asNumber());
879 if (!shouldCheckOverflow(node->arithMode()))
880 doubleResult = toInt32(doubleResult);
881 else if (!shouldCheckNegativeZero(node->arithMode()))
882 doubleResult += 0; // Sanitizes zero.
883 JSValue valueResult = jsNumber(doubleResult);
884 if (valueResult.isInt32()) {
885 setConstant(node, valueResult);
889 forNode(node).setType(SpecInt32Only);
892 if (left && right && left.isNumber() && right.isNumber()) {
893 setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber())));
896 forNode(node).setType(
897 typeOfDoubleBinaryOp(
898 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
901 RELEASE_ASSERT_NOT_REACHED();
908 JSValue left = forNode(node->child1()).value();
909 JSValue right = forNode(node->child2()).value();
910 switch (node->binaryUseKind()) {
912 if (left && right && left.isInt32() && right.isInt32()) {
913 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32())));
916 forNode(node).setType(SpecInt32Only);
919 if (left && right && left.isNumber() && right.isNumber()) {
920 double a = left.asNumber();
921 double b = right.asNumber();
922 setConstant(node, jsDoubleNumber(a < b ? a : (b <= a ? b : a + b)));
925 forNode(node).setType(
927 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
930 RELEASE_ASSERT_NOT_REACHED();
937 JSValue left = forNode(node->child1()).value();
938 JSValue right = forNode(node->child2()).value();
939 switch (node->binaryUseKind()) {
941 if (left && right && left.isInt32() && right.isInt32()) {
942 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32())));
945 forNode(node).setType(SpecInt32Only);
948 if (left && right && left.isNumber() && right.isNumber()) {
949 double a = left.asNumber();
950 double b = right.asNumber();
951 setConstant(node, jsDoubleNumber(a > b ? a : (b >= a ? b : a + b)));
954 forNode(node).setType(
956 forNode(node->child1()).m_type, forNode(node->child2()).m_type));
959 RELEASE_ASSERT_NOT_REACHED();
966 JSValue child = forNode(node->child1()).value();
967 switch (node->child1().useKind()) {
969 if (std::optional<double> number = child.toNumberFromPrimitive()) {
970 JSValue result = jsNumber(fabs(*number));
971 if (result.isInt32()) {
972 setConstant(node, result);
976 forNode(node).setType(SpecInt32Only);
979 if (std::optional<double> number = child.toNumberFromPrimitive()) {
980 setConstant(node, jsDoubleNumber(fabs(*number)));
983 forNode(node).setType(typeOfDoubleAbs(forNode(node->child1()).m_type));
986 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
987 forNode(node).setType(SpecFullNumber);
994 JSValue childY = forNode(node->child2()).value();
995 if (childY && childY.isNumber()) {
996 if (!childY.asNumber()) {
997 setConstant(node, jsDoubleNumber(1));
1001 JSValue childX = forNode(node->child1()).value();
1002 if (childX && childX.isNumber()) {
1003 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber())));
1007 forNode(node).setType(typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type));
1012 forNode(node).setType(m_graph, SpecDoubleReal);
1020 JSValue operand = forNode(node->child1()).value();
1021 if (std::optional<double> number = operand.toNumberFromPrimitive()) {
1022 double roundedValue = 0;
1023 if (node->op() == ArithRound)
1024 roundedValue = jsRound(*number);
1025 else if (node->op() == ArithFloor)
1026 roundedValue = floor(*number);
1027 else if (node->op() == ArithCeil)
1028 roundedValue = ceil(*number);
1030 ASSERT(node->op() == ArithTrunc);
1031 roundedValue = trunc(*number);
1034 if (node->child1().useKind() == UntypedUse) {
1035 setConstant(node, jsNumber(roundedValue));
1038 if (producesInteger(node->arithRoundingMode())) {
1039 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
1040 if (roundedValueAsInt32 == roundedValue) {
1041 if (shouldCheckNegativeZero(node->arithRoundingMode())) {
1042 if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
1043 setConstant(node, jsNumber(roundedValueAsInt32));
1047 setConstant(node, jsNumber(roundedValueAsInt32));
1052 setConstant(node, jsDoubleNumber(roundedValue));
1056 if (node->child1().useKind() == DoubleRepUse) {
1057 if (producesInteger(node->arithRoundingMode()))
1058 forNode(node).setType(SpecInt32Only);
1059 else if (node->child1().useKind() == DoubleRepUse)
1060 forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
1062 DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse);
1063 forNode(node).setType(SpecFullNumber);
1069 executeDoubleUnaryOpEffects(node, sqrt);
1073 executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); });
1077 executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
1081 switch (booleanResult(node, forNode(node->child1()))) {
1082 case DefinitelyTrue:
1083 setConstant(node, jsBoolean(false));
1085 case DefinitelyFalse:
1086 setConstant(node, jsBoolean(true));
1089 forNode(node).setType(SpecBoolean);
1096 if (JSValue key = forNode(node->child1()).value()) {
1097 if (std::optional<uint32_t> hash = concurrentJSMapHash(key)) {
1098 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32
1099 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large
1100 // unsigned values becoming doubles. This casting between signed and unsigned
1101 // happens in the assembly code we emit when we don't constant fold this node.
1102 setConstant(node, jsNumber(static_cast<int32_t>(*hash)));
1106 forNode(node).setType(SpecInt32Only);
1111 forNode(node).setType(m_graph, SpecString);
1116 forNode(node).setType(m_graph, SpecString);
1120 case LoadKeyFromMapBucket:
1121 case LoadValueFromMapBucket:
1122 forNode(node).makeHeapTop();
1126 case GetMapBucketHead:
1127 if (node->child1().useKind() == MapObjectUse)
1128 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1130 ASSERT(node->child1().useKind() == SetObjectUse);
1131 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1135 case GetMapBucketNext:
1136 if (node->bucketOwnerType() == BucketOwnerType::Map)
1137 forNode(node).set(m_graph, m_vm.hashMapBucketMapStructure.get());
1139 ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
1140 forNode(node).set(m_graph, m_vm.hashMapBucketSetStructure.get());
1149 forNode(node).makeHeapTop();
1157 case IsObjectOrNull:
1159 case IsCellWithType:
1160 case IsTypedArrayView: {
1161 AbstractValue child = forNode(node->child1());
1162 if (child.value()) {
1163 bool constantWasSet = true;
1164 switch (node->op()) {
1165 case IsCellWithType:
1166 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType()));
1169 setConstant(node, jsBoolean(
1170 child.value().isCell()
1171 ? child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))
1172 : child.value().isUndefined()));
1175 setConstant(node, jsBoolean(child.value().isBoolean()));
1178 setConstant(node, jsBoolean(child.value().isNumber()));
1181 setConstant(node, jsBoolean(child.value().isObject()));
1183 case IsObjectOrNull:
1184 if (child.value().isObject()) {
1185 JSObject* object = asObject(child.value());
1186 if (object->type() == JSFunctionType)
1187 setConstant(node, jsBoolean(false));
1188 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1189 setConstant(node, jsBoolean(!child.value().asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic))));
1191 // FIXME: This could just call getCallData.
1192 // https://bugs.webkit.org/show_bug.cgi?id=144457
1193 constantWasSet = false;
1196 setConstant(node, jsBoolean(child.value().isNull()));
1199 if (child.value().isObject()) {
1200 JSObject* object = asObject(child.value());
1201 if (object->type() == JSFunctionType)
1202 setConstant(node, jsBoolean(true));
1203 else if (!(object->inlineTypeFlags() & TypeOfShouldCallGetCallData))
1204 setConstant(node, jsBoolean(false));
1206 // FIXME: This could just call getCallData.
1207 // https://bugs.webkit.org/show_bug.cgi?id=144457
1208 constantWasSet = false;
1211 setConstant(node, jsBoolean(false));
1214 setConstant(node, jsBoolean(child.value().isEmpty()));
1216 case IsTypedArrayView:
1217 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType)));
1220 constantWasSet = false;
1227 // FIXME: This code should really use AbstractValue::isType() and
1228 // AbstractValue::couldBeType().
1229 // https://bugs.webkit.org/show_bug.cgi?id=146870
1231 bool constantWasSet = false;
1232 switch (node->op()) {
1234 if (child.m_type && !(child.m_type & SpecEmpty)) {
1235 setConstant(node, jsBoolean(false));
1236 constantWasSet = true;
1240 if (child.m_type && !(child.m_type & ~SpecEmpty)) {
1241 setConstant(node, jsBoolean(true));
1242 constantWasSet = true;
1249 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1250 // https://bugs.webkit.org/show_bug.cgi?id=144456
1252 if (!(child.m_type & (SpecOther | SpecObjectOther))) {
1253 setConstant(node, jsBoolean(false));
1254 constantWasSet = true;
1260 if (!(child.m_type & ~SpecBoolean)) {
1261 setConstant(node, jsBoolean(true));
1262 constantWasSet = true;
1266 if (!(child.m_type & SpecBoolean)) {
1267 setConstant(node, jsBoolean(false));
1268 constantWasSet = true;
1274 if (!(child.m_type & ~SpecFullNumber)) {
1275 setConstant(node, jsBoolean(true));
1276 constantWasSet = true;
1280 if (!(child.m_type & SpecFullNumber)) {
1281 setConstant(node, jsBoolean(false));
1282 constantWasSet = true;
1288 if (!(child.m_type & ~SpecObject)) {
1289 setConstant(node, jsBoolean(true));
1290 constantWasSet = true;
1294 if (!(child.m_type & SpecObject)) {
1295 setConstant(node, jsBoolean(false));
1296 constantWasSet = true;
1301 case IsObjectOrNull:
1302 // FIXME: Use the masquerades-as-undefined watchpoint thingy.
1303 // https://bugs.webkit.org/show_bug.cgi?id=144456
1305 // These expressions are complicated to parse. A helpful way to parse this is that
1306 // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
1307 // disjoint set from S". Things like "T - S" means that, provided that S is a
1308 // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
1309 // mean the "union of T and S".
1311 // Is the child's type an object that isn't an other-object (i.e. object that could
1312 // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
1314 if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1315 setConstant(node, jsBoolean(true));
1316 constantWasSet = true;
1320 // Is the child's type definitely not either of: an object that isn't a function,
1321 // or either undefined or null? Then: we should fold this to false. This means
1322 // for example that if it's any non-function object, including those that have
1323 // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
1324 // if it's undefined-or-null, since the type bits don't distinguish between
1325 // undefined (which should fold to false) and null (which should fold to true).
1326 if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
1327 setConstant(node, jsBoolean(false));
1328 constantWasSet = true;
1334 if (!(child.m_type & ~SpecFunction)) {
1335 setConstant(node, jsBoolean(true));
1336 constantWasSet = true;
1340 if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) {
1341 setConstant(node, jsBoolean(false));
1342 constantWasSet = true;
1347 case IsCellWithType:
1348 if (!(child.m_type & ~node->speculatedTypeForQuery())) {
1349 setConstant(node, jsBoolean(true));
1350 constantWasSet = true;
1353 if (!(child.m_type & node->speculatedTypeForQuery())) {
1354 setConstant(node, jsBoolean(false));
1355 constantWasSet = true;
1360 case IsTypedArrayView:
1361 if (!(child.m_type & ~SpecTypedArrayView)) {
1362 setConstant(node, jsBoolean(true));
1363 constantWasSet = true;
1366 if (!(child.m_type & SpecTypedArrayView)) {
1367 setConstant(node, jsBoolean(false));
1368 constantWasSet = true;
1379 forNode(node).setType(SpecBoolean);
1384 JSValue child = forNode(node->child1()).value();
1385 AbstractValue& abstractChild = forNode(node->child1());
1387 JSValue typeString = jsTypeStringForValue(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child);
1388 setConstant(node, *m_graph.freeze(typeString));
1392 if (isFullNumberSpeculation(abstractChild.m_type)) {
1393 setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString()));
1397 if (isStringSpeculation(abstractChild.m_type)) {
1398 setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString()));
1402 // FIXME: We could use the masquerades-as-undefined watchpoint here.
1403 // https://bugs.webkit.org/show_bug.cgi?id=144456
1404 if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
1405 setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString()));
1409 if (isFunctionSpeculation(abstractChild.m_type)) {
1410 setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString()));
1414 if (isBooleanSpeculation(abstractChild.m_type)) {
1415 setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString()));
1419 if (isSymbolSpeculation(abstractChild.m_type)) {
1420 setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString()));
1424 forNode(node).setType(m_graph, SpecStringIdent);
1429 case CompareBelowEq: {
1430 JSValue leftConst = forNode(node->child1()).value();
1431 JSValue rightConst = forNode(node->child2()).value();
1432 if (leftConst && rightConst) {
1433 if (leftConst.isInt32() && rightConst.isInt32()) {
1434 uint32_t a = static_cast<uint32_t>(leftConst.asInt32());
1435 uint32_t b = static_cast<uint32_t>(rightConst.asInt32());
1436 switch (node->op()) {
1438 setConstant(node, jsBoolean(a < b));
1440 case CompareBelowEq:
1441 setConstant(node, jsBoolean(a <= b));
1444 RELEASE_ASSERT_NOT_REACHED();
1451 if (node->child1() == node->child2()) {
1452 switch (node->op()) {
1454 setConstant(node, jsBoolean(false));
1456 case CompareBelowEq:
1457 setConstant(node, jsBoolean(true));
1460 DFG_CRASH(m_graph, node, "Unexpected node type");
1465 forNode(node).setType(SpecBoolean);
1471 case CompareGreater:
1472 case CompareGreaterEq:
1474 JSValue leftConst = forNode(node->child1()).value();
1475 JSValue rightConst = forNode(node->child2()).value();
1476 if (leftConst && rightConst) {
1477 if (leftConst.isNumber() && rightConst.isNumber()) {
1478 double a = leftConst.asNumber();
1479 double b = rightConst.asNumber();
1480 switch (node->op()) {
1482 setConstant(node, jsBoolean(a < b));
1485 setConstant(node, jsBoolean(a <= b));
1487 case CompareGreater:
1488 setConstant(node, jsBoolean(a > b));
1490 case CompareGreaterEq:
1491 setConstant(node, jsBoolean(a >= b));
1494 setConstant(node, jsBoolean(a == b));
1497 RELEASE_ASSERT_NOT_REACHED();
1503 if (leftConst.isString() && rightConst.isString()) {
1504 const StringImpl* a = asString(leftConst)->tryGetValueImpl();
1505 const StringImpl* b = asString(rightConst)->tryGetValueImpl();
1508 if (node->op() == CompareEq)
1509 result = WTF::equal(a, b);
1510 else if (node->op() == CompareLess)
1511 result = codePointCompare(a, b) < 0;
1512 else if (node->op() == CompareLessEq)
1513 result = codePointCompare(a, b) <= 0;
1514 else if (node->op() == CompareGreater)
1515 result = codePointCompare(a, b) > 0;
1516 else if (node->op() == CompareGreaterEq)
1517 result = codePointCompare(a, b) >= 0;
1519 RELEASE_ASSERT_NOT_REACHED();
1520 setConstant(node, jsBoolean(result));
1525 if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) {
1526 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst)));
1531 if (node->op() == CompareEq) {
1532 SpeculatedType leftType = forNode(node->child1()).m_type;
1533 SpeculatedType rightType = forNode(node->child2()).m_type;
1534 if (!valuesCouldBeEqual(leftType, rightType)) {
1535 setConstant(node, jsBoolean(false));
1539 if (leftType == SpecOther)
1540 std::swap(leftType, rightType);
1541 if (rightType == SpecOther) {
1542 // Undefined and Null are always equal when compared to eachother.
1543 if (!(leftType & ~SpecOther)) {
1544 setConstant(node, jsBoolean(true));
1548 // Any other type compared to Null or Undefined is always false
1549 // as long as the MasqueradesAsUndefined watchpoint is valid.
1551 // MasqueradesAsUndefined only matters for SpecObjectOther, other
1552 // cases are always "false".
1553 if (!(leftType & (SpecObjectOther | SpecOther))) {
1554 setConstant(node, jsBoolean(false));
1558 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) {
1559 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1560 m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint());
1561 setConstant(node, jsBoolean(false));
1567 if (node->child1() == node->child2()) {
1568 if (node->isBinaryUseKind(Int32Use) ||
1569 node->isBinaryUseKind(Int52RepUse) ||
1570 node->isBinaryUseKind(StringUse) ||
1571 node->isBinaryUseKind(BooleanUse) ||
1572 node->isBinaryUseKind(SymbolUse) ||
1573 node->isBinaryUseKind(StringIdentUse) ||
1574 node->isBinaryUseKind(ObjectUse) ||
1575 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) ||
1576 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) {
1577 switch (node->op()) {
1579 case CompareGreater:
1580 setConstant(node, jsBoolean(false));
1583 case CompareGreaterEq:
1585 setConstant(node, jsBoolean(true));
1588 DFG_CRASH(m_graph, node, "Unexpected node type");
1595 forNode(node).setType(SpecBoolean);
1599 case CompareStrictEq: {
1600 Node* leftNode = node->child1().node();
1601 Node* rightNode = node->child2().node();
1602 JSValue left = forNode(leftNode).value();
1603 JSValue right = forNode(rightNode).value();
1604 if (left && right) {
1605 if (left.isString() && right.isString()) {
1606 // We need this case because JSValue::strictEqual is otherwise too racy for
1607 // string comparisons.
1608 const StringImpl* a = asString(left)->tryGetValueImpl();
1609 const StringImpl* b = asString(right)->tryGetValueImpl();
1611 setConstant(node, jsBoolean(WTF::equal(a, b)));
1615 setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
1620 if (node->isBinaryUseKind(UntypedUse)) {
1621 // FIXME: Revisit this condition when introducing BigInt to JSC.
1622 auto isNonStringCellConstant = [] (JSValue value) {
1623 return value && value.isCell() && !value.isString();
1626 if (isNonStringCellConstant(left) || isNonStringCellConstant(right)) {
1627 m_state.setFoundConstants(true);
1628 forNode(node).setType(SpecBoolean);
1633 SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type);
1634 SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type);
1635 if (!(leftLUB & rightLUB)) {
1636 setConstant(node, jsBoolean(false));
1640 if (node->child1() == node->child2()) {
1641 if (node->isBinaryUseKind(BooleanUse) ||
1642 node->isBinaryUseKind(Int32Use) ||
1643 node->isBinaryUseKind(Int52RepUse) ||
1644 node->isBinaryUseKind(StringUse) ||
1645 node->isBinaryUseKind(StringIdentUse) ||
1646 node->isBinaryUseKind(SymbolUse) ||
1647 node->isBinaryUseKind(ObjectUse) ||
1648 node->isBinaryUseKind(MiscUse, UntypedUse) ||
1649 node->isBinaryUseKind(UntypedUse, MiscUse) ||
1650 node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
1651 node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
1652 node->isBinaryUseKind(StringUse, UntypedUse) ||
1653 node->isBinaryUseKind(UntypedUse, StringUse)) {
1654 setConstant(node, jsBoolean(true));
1659 forNode(node).setType(SpecBoolean);
1663 case CompareEqPtr: {
1664 Node* childNode = node->child1().node();
1665 JSValue childValue = forNode(childNode).value();
1667 setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
1671 forNode(node).setType(SpecBoolean);
1675 case StringCharCodeAt:
1676 forNode(node).setType(SpecInt32Only);
1679 case StringFromCharCode:
1680 forNode(node).setType(m_graph, SpecString);
1684 forNode(node).set(m_graph, m_vm.stringStructure.get());
1690 case AtomicsCompareExchange:
1691 case AtomicsExchange:
1697 if (node->op() != GetByVal)
1698 clobberWorld(node->origin.semantic, clobberLimit);
1699 switch (node->arrayMode().type()) {
1700 case Array::SelectUsingPredictions:
1701 case Array::Unprofiled:
1702 case Array::SelectUsingArguments:
1703 RELEASE_ASSERT_NOT_REACHED();
1705 case Array::ForceExit:
1706 m_state.setIsValid(false);
1708 case Array::Undecided: {
1709 JSValue index = forNode(node->child2()).value();
1710 if (index && index.isInt32() && index.asInt32() >= 0) {
1711 setConstant(node, jsUndefined());
1714 forNode(node).setType(SpecOther);
1717 case Array::Generic:
1718 clobberWorld(node->origin.semantic, clobberLimit);
1719 forNode(node).makeHeapTop();
1722 if (node->arrayMode().isOutOfBounds()) {
1723 // If the watchpoint was still valid we could totally set this to be
1724 // SpecString | SpecOther. Except that we'd have to be careful. If we
1725 // tested the watchpoint state here then it could change by the time
1726 // we got to the backend. So to do this right, we'd have to get the
1727 // fixup phase to check the watchpoint state and then bake into the
1728 // GetByVal operation the fact that we're using a watchpoint, using
1729 // something like Array::SaneChain (except not quite, because that
1730 // implies an in-bounds access). None of this feels like it's worth it,
1731 // so we're going with TOP for now. The same thing applies to
1732 // clobbering the world.
1733 clobberWorld(node->origin.semantic, clobberLimit);
1734 forNode(node).makeHeapTop();
1736 forNode(node).set(m_graph, m_vm.stringStructure.get());
1738 case Array::DirectArguments:
1739 case Array::ScopedArguments:
1740 forNode(node).makeHeapTop();
1743 if (node->arrayMode().isOutOfBounds()) {
1744 clobberWorld(node->origin.semantic, clobberLimit);
1745 forNode(node).makeHeapTop();
1747 forNode(node).setType(SpecInt32Only);
1750 if (node->arrayMode().isOutOfBounds()) {
1751 clobberWorld(node->origin.semantic, clobberLimit);
1752 forNode(node).makeHeapTop();
1753 } else if (node->arrayMode().isSaneChain())
1754 forNode(node).setType(SpecBytecodeDouble);
1756 forNode(node).setType(SpecDoubleReal);
1758 case Array::Contiguous:
1759 case Array::ArrayStorage:
1760 case Array::SlowPutArrayStorage:
1761 if (node->arrayMode().isOutOfBounds())
1762 clobberWorld(node->origin.semantic, clobberLimit);
1763 forNode(node).makeHeapTop();
1765 case Array::Int8Array:
1766 forNode(node).setType(SpecInt32Only);
1768 case Array::Int16Array:
1769 forNode(node).setType(SpecInt32Only);
1771 case Array::Int32Array:
1772 forNode(node).setType(SpecInt32Only);
1774 case Array::Uint8Array:
1775 forNode(node).setType(SpecInt32Only);
1777 case Array::Uint8ClampedArray:
1778 forNode(node).setType(SpecInt32Only);
1780 case Array::Uint16Array:
1781 forNode(node).setType(SpecInt32Only);
1783 case Array::Uint32Array:
1784 if (node->shouldSpeculateInt32())
1785 forNode(node).setType(SpecInt32Only);
1786 else if (enableInt52() && node->shouldSpeculateAnyInt())
1787 forNode(node).setType(SpecAnyInt);
1789 forNode(node).setType(SpecAnyIntAsDouble);
1791 case Array::Float32Array:
1792 forNode(node).setType(SpecFullDouble);
1794 case Array::Float64Array:
1795 forNode(node).setType(SpecFullDouble);
1798 RELEASE_ASSERT_NOT_REACHED();
1804 case PutByValDirect:
1806 case PutByValAlias: {
1807 switch (node->arrayMode().modeForPut().type()) {
1808 case Array::ForceExit:
1809 m_state.setIsValid(false);
1811 case Array::Generic:
1812 clobberWorld(node->origin.semantic, clobberLimit);
1815 if (node->arrayMode().isOutOfBounds())
1816 clobberWorld(node->origin.semantic, clobberLimit);
1819 if (node->arrayMode().isOutOfBounds())
1820 clobberWorld(node->origin.semantic, clobberLimit);
1822 case Array::Contiguous:
1823 case Array::ArrayStorage:
1824 if (node->arrayMode().isOutOfBounds())
1825 clobberWorld(node->origin.semantic, clobberLimit);
1827 case Array::SlowPutArrayStorage:
1828 if (node->arrayMode().mayStoreToHole())
1829 clobberWorld(node->origin.semantic, clobberLimit);
1838 clobberWorld(node->origin.semantic, clobberLimit);
1839 forNode(node).setType(SpecBytecodeNumber);
1843 JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
1845 // FIXME: We could do better here if we prove that the
1846 // incoming value has only a single structure.
1847 RegisteredStructureSet structureSet;
1848 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)));
1849 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)));
1850 structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)));
1852 forNode(node).set(m_graph, structureSet);
1856 case ArrayIndexOf: {
1857 forNode(node).setType(SpecInt32Only);
1862 clobberWorld(node->origin.semantic, clobberLimit);
1863 forNode(node).makeHeapTop();
1866 case GetMyArgumentByVal:
1867 case GetMyArgumentByValOutOfBounds: {
1868 JSValue index = forNode(node->child2()).m_value;
1869 InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame;
1871 if (index && index.isInt32()) {
1872 // This pretends to return TOP for accesses that are actually proven out-of-bounds because
1873 // that's the conservative thing to do. Otherwise we'd need to write more code to mark such
1874 // paths as unreachable, or to return undefined. We could implement that eventually.
1876 unsigned argumentIndex = index.asUInt32() + node->numberOfArgumentsToSkip();
1877 if (inlineCallFrame) {
1878 if (argumentIndex < inlineCallFrame->argumentCountIncludingThis - 1) {
1879 forNode(node) = m_state.variables().operand(
1880 virtualRegisterForArgument(argumentIndex + 1) + inlineCallFrame->stackOffset);
1881 m_state.setFoundConstants(true);
1885 if (argumentIndex < m_state.variables().numberOfArguments() - 1) {
1886 forNode(node) = m_state.variables().argument(argumentIndex + 1);
1887 m_state.setFoundConstants(true);
1893 if (inlineCallFrame) {
1894 // We have a bound on the types even though it's random access. Take advantage of this.
1896 AbstractValue result;
1897 for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->argumentCountIncludingThis; ++i) {
1899 m_state.variables().operand(
1900 virtualRegisterForArgument(i) + inlineCallFrame->stackOffset));
1903 if (node->op() == GetMyArgumentByValOutOfBounds)
1904 result.merge(SpecOther);
1907 m_state.setFoundConstants(true);
1909 forNode(node) = result;
1913 forNode(node).makeHeapTop();
1918 if (node->child2().useKind() == RegExpObjectUse
1919 && node->child3().useKind() == StringUse) {
1920 // This doesn't clobber the world since there are no conversions to perform.
1922 clobberWorld(node->origin.semantic, clobberLimit);
1923 if (JSValue globalObjectValue = forNode(node->child1()).m_value) {
1924 if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) {
1925 if (!globalObject->isHavingABadTime()) {
1926 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint());
1927 RegisteredStructureSet structureSet;
1928 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure()));
1929 structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayWithGroupsStructure()));
1930 forNode(node).set(m_graph, structureSet);
1931 forNode(node).merge(SpecOther);
1936 forNode(node).setType(m_graph, SpecOther | SpecArray);
1940 if (node->child2().useKind() == RegExpObjectUse
1941 && node->child3().useKind() == StringUse) {
1942 // This doesn't clobber the world since there are no conversions to perform.
1944 clobberWorld(node->origin.semantic, clobberLimit);
1945 forNode(node).setType(SpecBoolean);
1949 case StringReplaceRegExp:
1950 if (node->child1().useKind() == StringUse
1951 && node->child2().useKind() == RegExpObjectUse
1952 && node->child3().useKind() == StringUse) {
1953 // This doesn't clobber the world. It just reads and writes regexp state.
1955 clobberWorld(node->origin.semantic, clobberLimit);
1956 forNode(node).set(m_graph, m_vm.stringStructure.get());
1963 Node* child = node->child1().node();
1964 BooleanResult result = booleanResult(node, forNode(child));
1965 if (result == DefinitelyTrue) {
1966 m_state.setBranchDirection(TakeTrue);
1969 if (result == DefinitelyFalse) {
1970 m_state.setBranchDirection(TakeFalse);
1973 // FIXME: The above handles the trivial cases of sparse conditional
1974 // constant propagation, but we can do better:
1975 // We can specialize the source variable's value on each direction of
1977 m_state.setBranchDirection(TakeBoth);
1982 // Nothing to do for now.
1983 // FIXME: Do sparse conditional things.
1991 m_state.setIsValid(false);
1995 case ThrowStaticError:
1997 case DirectTailCall:
1998 case TailCallVarargs:
1999 case TailCallForwardVarargs:
2000 clobberWorld(node->origin.semantic, clobberLimit);
2001 m_state.setIsValid(false);
2005 JSValue childConst = forNode(node->child1()).value();
2006 if (childConst && childConst.isNumber()) {
2007 setConstant(node, childConst);
2011 ASSERT(node->child1().useKind() == UntypedUse);
2013 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) {
2014 m_state.setFoundConstants(true);
2015 forNode(node) = forNode(node->child1());
2019 clobberWorld(node->origin.semantic, clobberLimit);
2021 forNode(node).setType(m_graph, SpecHeapTop & ~SpecObject);
2026 JSValue childConst = forNode(node->child1()).value();
2027 if (childConst && childConst.isNumber()) {
2028 setConstant(node, childConst);
2032 ASSERT(node->child1().useKind() == UntypedUse);
2034 if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
2035 m_state.setFoundConstants(true);
2036 forNode(node) = forNode(node->child1());
2040 clobberWorld(node->origin.semantic, clobberLimit);
2041 forNode(node).setType(m_graph, SpecBytecodeNumber);
2046 case CallStringConstructor: {
2047 switch (node->child1().useKind()) {
2048 case StringObjectUse:
2049 // This also filters that the StringObject has the primordial StringObject
2053 m_graph.registerStructure(m_graph.globalObjectFor(node->origin.semantic)->stringObjectStructure()));
2055 case StringOrStringObjectUse:
2063 clobberWorld(node->origin.semantic, clobberLimit);
2066 RELEASE_ASSERT_NOT_REACHED();
2069 forNode(node).set(m_graph, m_vm.stringStructure.get());
2073 case NumberToStringWithRadix: {
2074 JSValue radixValue = forNode(node->child2()).m_value;
2075 if (radixValue && radixValue.isInt32()) {
2076 int32_t radix = radixValue.asInt32();
2077 if (2 <= radix && radix <= 36) {
2078 m_state.setFoundConstants(true);
2079 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2083 clobberWorld(node->origin.semantic, clobberLimit);
2084 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2088 case NumberToStringWithValidRadixConstant: {
2089 forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
2093 case NewStringObject: {
2094 ASSERT(node->structure()->classInfo() == StringObject::info());
2095 forNode(node).set(m_graph, node->structure());
2102 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2105 case NewArrayWithSpread:
2106 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2107 // We've compiled assuming we're not having a bad time, so to be consistent
2108 // with StructureRegisterationPhase we must say we produce an original array
2109 // allocation structure.
2112 m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous));
2116 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous));
2123 m_graph, m_vm.fixedArrayStructure.get());
2126 case NewArrayBuffer:
2129 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()));
2132 case NewArrayWithSize:
2133 forNode(node).setType(m_graph, SpecArray);
2137 switch (node->child1().useKind()) {
2141 clobberWorld(node->origin.semantic, clobberLimit);
2144 RELEASE_ASSERT_NOT_REACHED();
2149 m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently(
2150 node->typedArrayType()));
2154 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure());
2158 AbstractValue& source = forNode(node->child1());
2159 AbstractValue& destination = forNode(node);
2160 bool strictMode = m_graph.executableFor(node->origin.semantic)->isStrictMode();
2162 ToThisResult result = isToThisAnIdentity(m_vm, strictMode, source);
2163 if (result != ToThisResult::Dynamic) {
2165 case ToThisResult::Identity:
2166 m_state.setFoundConstants(true);
2167 destination = source;
2169 case ToThisResult::Undefined:
2170 setConstant(node, jsUndefined());
2172 case ToThisResult::GlobalThis:
2173 m_state.setFoundConstants(true);
2174 destination.setType(m_graph, SpecObject);
2176 case ToThisResult::Dynamic:
2177 RELEASE_ASSERT_NOT_REACHED();
2183 destination.makeHeapTop();
2185 destination = source;
2186 destination.merge(SpecObject);
2192 // FIXME: We can fold this to NewObject if the incoming callee is a constant.
2193 forNode(node).setType(m_graph, SpecFinalObject);
2198 ASSERT(!!node->structure().get());
2199 forNode(node).set(m_graph, node->structure());
2203 case CallObjectConstructor: {
2204 AbstractValue& source = forNode(node->child1());
2205 AbstractValue& destination = forNode(node);
2207 if (!(source.m_type & ~SpecObject)) {
2208 m_state.setFoundConstants(true);
2209 destination = source;
2213 if (node->op() == ToObject)
2214 clobberWorld(node->origin.semantic, clobberLimit);
2215 forNode(node).setType(m_graph, SpecObject);
2219 case PhantomNewObject:
2220 case PhantomNewFunction:
2221 case PhantomNewGeneratorFunction:
2222 case PhantomNewAsyncGeneratorFunction:
2223 case PhantomNewAsyncFunction:
2224 case PhantomCreateActivation:
2225 case PhantomDirectArguments:
2226 case PhantomClonedArguments:
2227 case PhantomCreateRest:
2229 case PhantomNewArrayWithSpread:
2231 m_state.setDidClobber(true); // Prevent constant folding.
2232 // This claims to return bottom.
2238 case MaterializeNewObject: {
2239 forNode(node).set(m_graph, node->structureSet());
2244 // We don't use the more precise withScopeStructure() here because it is a LazyProperty and may not yet be allocated.
2245 forNode(node).setType(m_graph, SpecObjectOther);
2248 case CreateActivation:
2249 case MaterializeCreateActivation:
2251 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure());
2254 case CreateDirectArguments:
2255 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure());
2258 case CreateScopedArguments:
2259 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure());
2262 case CreateClonedArguments:
2263 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) {
2264 forNode(node).setType(m_graph, SpecObject);
2267 forNode(node).set(m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure());
2270 case NewGeneratorFunction:
2272 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure());
2275 case NewAsyncGeneratorFunction:
2277 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncGeneratorFunctionStructure());
2280 case NewAsyncFunction:
2282 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure());
2287 m_graph, m_codeBlock->globalObjectFor(node->origin.semantic)->functionStructure());
2291 if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) {
2292 InferredValue* singleton = executable->singletonFunction();
2293 if (JSValue value = singleton->inferredValue()) {
2294 m_graph.watchpoints().addLazily(singleton);
2295 JSFunction* function = jsCast<JSFunction*>(value);
2296 setConstant(node, *m_graph.freeze(function));
2300 forNode(node).setType(m_graph, SpecFunction);
2303 case GetArgumentCountIncludingThis:
2304 forNode(node).setType(SpecInt32Only);
2308 forNode(node).setType(SpecInt32Only);
2312 JSValue base = forNode(node->child1()).m_value;
2314 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2315 if (!getterSetter->isGetterNull()) {
2316 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently()));
2321 forNode(node).setType(m_graph, SpecObject);
2326 JSValue base = forNode(node->child1()).m_value;
2328 GetterSetter* getterSetter = jsCast<GetterSetter*>(base);
2329 if (!getterSetter->isSetterNull()) {
2330 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently()));
2335 forNode(node).setType(m_graph, SpecObject);
2340 if (JSValue base = forNode(node->child1()).m_value) {
2341 if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) {
2342 setConstant(node, *m_graph.freeze(function->scope()));
2346 forNode(node).setType(m_graph, SpecObjectOther);
2350 JSValue child = forNode(node->child1()).value();
2352 setConstant(node, *m_graph.freeze(JSValue(jsCast<JSScope*>(child.asCell())->next())));
2355 forNode(node).setType(m_graph, SpecObjectOther);
2359 case GetGlobalObject: {
2360 JSValue child = forNode(node->child1()).value();
2362 setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject())));
2366 if (forNode(node->child1()).m_structure.isFinite()) {
2367 JSGlobalObject* globalObject = nullptr;
2369 forNode(node->child1()).m_structure.forEach(
2370 [&] (RegisteredStructure structure) {
2372 globalObject = structure->globalObject();
2373 else if (globalObject != structure->globalObject())
2376 if (globalObject && ok) {
2377 setConstant(node, *m_graph.freeze(JSValue(globalObject)));
2382 forNode(node).setType(m_graph, SpecObjectOther);
2386 case GetGlobalThis: {
2387 forNode(node).setType(m_graph, SpecObject);
2392 if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) {
2393 setConstant(node, *m_graph.freeze(value));
2396 forNode(node).makeBytecodeTop();
2402 case GetRegExpObjectLastIndex:
2403 forNode(node).makeHeapTop();
2406 case SetRegExpObjectLastIndex:
2407 case RecordRegExpCachedResult:
2410 case GetFromArguments:
2411 forNode(node).makeHeapTop();
2414 case PutToArguments:
2418 forNode(node).makeHeapTop();
2422 // FIXME: This should constant fold at least as well as the normal GetById case.
2423 // https://bugs.webkit.org/show_bug.cgi?id=156422
2424 forNode(node).makeHeapTop();
2428 case GetByIdFlush: {
2429 if (!node->prediction()) {
2430 m_state.setIsValid(false);
2434 AbstractValue& value = forNode(node->child1());
2435 if (value.m_structure.isFinite()
2436 && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) {
2437 UniquedStringImpl* uid = m_graph.identifiers()[node->identifierNumber()];
2438 GetByIdStatus status = GetByIdStatus::computeFor(value.m_structure.toStructureSet(), uid);
2439 if (status.isSimple()) {
2440 // Figure out what the result is going to be - is it TOP, a constant, or maybe
2441 // something more subtle?
2442 AbstractValue result;
2443 for (unsigned i = status.numVariants(); i--;) {
2444 // This thing won't give us a variant that involves prototypes. If it did, we'd
2445 // have more work to do here.
2446 DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty());
2449 m_graph.inferredValueForProperty(
2450 value, uid, status[i].offset(), m_state.structureClobberState()));
2452 m_state.setFoundConstants(true);
2453 forNode(node) = result;
2458 clobberWorld(node->origin.semantic, clobberLimit);
2459 forNode(node).makeHeapTop();
2463 case GetByValWithThis:
2464 case GetByIdWithThis:
2465 clobberWorld(node->origin.semantic, clobberLimit);
2466 forNode(node).makeHeapTop();
2469 case GetArrayLength: {
2470 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2471 forNode(node->child1()).m_value, node->arrayMode());
2473 setConstant(node, jsNumber(view->length()));
2476 forNode(node).setType(SpecInt32Only);
2480 case GetVectorLength: {
2481 forNode(node).setType(SpecInt32Only);
2487 // FIXME: This could decide if the delete will be successful based on the set of structures that
2488 // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611
2489 clobberWorld(node->origin.semantic, clobberLimit);
2490 forNode(node).setType(SpecBoolean);
2494 case CheckStructure: {
2495 AbstractValue& value = forNode(node->child1());
2497 const RegisteredStructureSet& set = node->structureSet();
2499 // It's interesting that we could have proven that the object has a larger structure set
2500 // that includes the set we're testing. In that case we could make the structure check
2501 // more efficient. We currently don't.
2503 if (value.m_structure.isSubsetOf(set))
2504 m_state.setFoundConstants(true);
2506 SpeculatedType admittedTypes = SpecNone;
2507 switch (node->child1().useKind()) {
2510 admittedTypes = SpecNone;
2512 case CellOrOtherUse:
2513 admittedTypes = SpecOther;
2516 DFG_CRASH(m_graph, node, "Bad use kind");
2520 filter(value, set, admittedTypes);
2524 case CheckStructureOrEmpty: {
2525 AbstractValue& value = forNode(node->child1());
2527 bool mayBeEmpty = value.m_type & SpecEmpty;
2529 m_state.setFoundConstants(true);
2531 SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone;
2532 filter(value, node->structureSet(), admittedTypes);
2536 case CheckStructureImmediate: {
2537 // FIXME: This currently can only reason about one structure at a time.
2538 // https://bugs.webkit.org/show_bug.cgi?id=136988
2540 AbstractValue& value = forNode(node->child1());
2541 const RegisteredStructureSet& set = node->structureSet();
2543 if (value.value()) {
2544 if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) {
2545 if (set.contains(m_graph.registerStructure(structure))) {
2546 m_state.setFoundConstants(true);
2550 m_state.setIsValid(false);
2554 if (m_phiChildren) {
2555 bool allGood = true;
2556 m_phiChildren->forAllTransitiveIncomingValues(
2558 [&] (Node* incoming) {
2559 if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) {
2560 if (set.contains(m_graph.registerStructure(structure)))
2566 m_state.setFoundConstants(true);
2571 if (RegisteredStructure structure = set.onlyStructure()) {
2572 filterByValue(node->child1(), *m_graph.freeze(structure.get()));
2576 // Aw shucks, we can't do anything!
2581 if (!forNode(node->child1()).m_structure.isClear()) {
2582 if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next)
2583 m_state.setFoundConstants(true);
2586 clobberLimit, node->transition()->previous, node->transition()->next);
2587 forNode(node->child1()).changeStructure(m_graph, node->transition()->next);
2592 case GetButterflyWithoutCaging:
2593 case AllocatePropertyStorage:
2594 case ReallocatePropertyStorage:
2595 case NukeStructureAndSetButterfly:
2596 // FIXME: We don't model the fact that the structureID is nuked, simply because currently
2597 // nobody would currently benefit from having that information. But it's a bug nonetheless.
2598 forNode(node).clear(); // The result is not a JS value.
2600 case CheckSubClass: {
2601 JSValue constant = forNode(node->child1()).value();
2603 if (constant.isCell() && constant.asCell()->inherits(m_vm, node->classInfo())) {
2604 m_state.setFoundConstants(true);
2610 AbstractValue& value = forNode(node->child1());
2612 if (value.m_structure.isSubClassOf(node->classInfo()))
2613 m_state.setFoundConstants(true);
2615 filterClassInfo(value, node->classInfo());
2618 case CallDOMGetter: {
2619 CallDOMGetterData* callDOMGetterData = node->callDOMGetterData();
2620 DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet;
2621 if (!snippet || snippet->effect.writes)
2622 clobberWorld(node->origin.semantic, clobberLimit);
2623 if (callDOMGetterData->domJIT)
2624 forNode(node).setType(m_graph, callDOMGetterData->domJIT->resultType());
2626 forNode(node).makeBytecodeTop();
2630 const DOMJIT::Signature* signature = node->signature();
2631 if (signature->effect.writes)
2632 clobberWorld(node->origin.semantic, clobberLimit);
2633 forNode(node).setType(m_graph, signature->result);
2637 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2638 m_state.setFoundConstants(true);
2641 switch (node->arrayMode().type()) {
2643 filter(node->child1(), SpecString);
2647 case Array::Contiguous:
2648 case Array::Undecided:
2649 case Array::ArrayStorage:
2650 case Array::SlowPutArrayStorage:
2652 case Array::DirectArguments:
2653 filter(node->child1(), SpecDirectArguments);
2655 case Array::ScopedArguments:
2656 filter(node->child1(), SpecScopedArguments);
2658 case Array::Int8Array:
2659 filter(node->child1(), SpecInt8Array);
2661 case Array::Int16Array:
2662 filter(node->child1(), SpecInt16Array);
2664 case Array::Int32Array:
2665 filter(node->child1(), SpecInt32Array);
2667 case Array::Uint8Array:
2668 filter(node->child1(), SpecUint8Array);
2670 case Array::Uint8ClampedArray:
2671 filter(node->child1(), SpecUint8ClampedArray);
2673 case Array::Uint16Array:
2674 filter(node->child1(), SpecUint16Array);
2676 case Array::Uint32Array:
2677 filter(node->child1(), SpecUint32Array);
2679 case Array::Float32Array:
2680 filter(node->child1(), SpecFloat32Array);
2682 case Array::Float64Array:
2683 filter(node->child1(), SpecFloat64Array);
2685 case Array::AnyTypedArray:
2686 filter(node->child1(), SpecTypedArrayView);
2689 RELEASE_ASSERT_NOT_REACHED();
2692 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2696 if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
2697 m_state.setFoundConstants(true);
2700 ASSERT(node->arrayMode().conversion() == Array::Convert);
2701 clobberStructures(clobberLimit);
2702 filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering());
2705 case ArrayifyToStructure: {
2706 AbstractValue& value = forNode(node->child1());
2707 if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure())))
2708 m_state.setFoundConstants(true);
2709 clobberStructures(clobberLimit);
2711 // We have a bunch of options of how to express the abstract set at this point. Let set S
2712 // be the set of structures that the value had before clobbering and assume that all of
2713 // them are watchable. The new value should be the least expressible upper bound of the
2714 // intersection of "values that currently have structure = node->structure()" and "values
2715 // that have structure in S plus any structure transition-reachable from S". Assume that
2716 // node->structure() is not in S but it is transition-reachable from S. Then we would
2717 // like to say that the result is "values that have structure = node->structure() until
2718 // we invalidate", but there is no way to express this using the AbstractValue syntax. So
2719 // we must choose between:
2721 // 1) "values that currently have structure = node->structure()". This is a valid
2722 // superset of the value that we really want, and it's specific enough to satisfy the
2723 // preconditions of the array access that this is guarding. It's also specific enough
2724 // to allow relevant optimizations in the case that we didn't have a contradiction
2725 // like in this example. Notice that in the abscence of any contradiction, this result
2726 // is precise rather than being a conservative LUB.
2728 // 2) "values that currently hava structure in S plus any structure transition-reachable
2729 // from S". This is also a valid superset of the value that we really want, but it's
2730 // not specific enough to satisfy the preconditions of the array access that this is
2731 // guarding - so playing such shenanigans would preclude us from having assertions on
2732 // the typing preconditions of any array accesses. This would also not be a desirable
2733 // answer in the absence of a contradiction.
2735 // Note that it's tempting to simply say that the resulting value is BOTTOM because of
2736 // the contradiction. That would be wrong, since we haven't hit an invalidation point,
2738 value.set(m_graph, node->structure());
2741 case GetIndexedPropertyStorage: {
2742 JSArrayBufferView* view = m_graph.tryGetFoldableView(
2743 forNode(node->child1()).m_value, node->arrayMode());
2745 m_state.setFoundConstants(true);
2746 forNode(node).clear();
2749 case ConstantStoragePointer: {
2750 forNode(node).clear();
2754 case GetTypedArrayByteOffset: {
2755 JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value);
2757 setConstant(node, jsNumber(view->byteOffset()));
2760 forNode(node).setType(SpecInt32Only);
2764 case GetPrototypeOf: {
2765 AbstractValue& value = forNode(node->child1());
2766 if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
2767 bool canFold = !value.m_structure.isClear();
2769 value.m_structure.forEach([&] (RegisteredStructure structure) {
2770 auto getPrototypeMethod = structure->classInfo()->methodTable.getPrototype;
2771 MethodTable::GetPrototypeFunctionPtr defaultGetPrototype = JSObject::getPrototype;
2772 if (getPrototypeMethod != defaultGetPrototype) {
2777 if (structure->hasPolyProto()) {
2782 prototype = structure->storedPrototype();
2783 else if (prototype != structure->storedPrototype())
2787 if (prototype && canFold) {
2788 setConstant(node, *m_graph.freeze(prototype));
2793 switch (node->child1().useKind()) {
2796 case FinalObjectUse:
2799 clobberWorld(node->origin.semantic, clobberLimit);
2802 forNode(node).setType(m_graph, SpecObject | SpecOther);
2807 StorageAccessData& data = node->storageAccessData();
2808 UniquedStringImpl* uid = m_graph.identifiers()[data.identifierNumber];
2810 // FIXME: The part of this that handles inferred property types relies on AI knowing the structure
2811 // right now. That's probably not optimal. In some cases, we may perform an optimization (usually
2812 // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure
2813 // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely
2814 // on the type that ByteCodeParser was able to prove.
2815 AbstractValue value = m_graph.inferredValueForProperty(
2816 forNode(node->child2()), uid, data.offset, m_state.structureClobberState());
2818 // It's possible that the type that ByteCodeParser came up with is better.
2819 AbstractValue typeFromParsing;
2820 typeFromParsing.set(m_graph, data.inferredType, m_state.structureClobberState());
2821 value.filter(typeFromParsing);
2823 // If we decide that there does not exist any value that this can return, then it's probably
2824 // because the compilation was already invalidated.
2825 if (value.isClear())
2826 m_state.setIsValid(false);
2828 forNode(node) = value;
2830 m_state.setFoundConstants(true);
2834 case GetGetterSetterByOffset: {
2835 StorageAccessData& data = node->storageAccessData();
2836 JSValue result = m_graph.tryGetConstantProperty(forNode(node->child2()), data.offset);
2837 if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) {
2838 setConstant(node, *m_graph.freeze(result));
2842 forNode(node).set(m_graph, m_graph.globalObjectFor(node->origin.semantic)->getterSetterStructure());
2846 case MultiGetByOffset: {
2847 // This code will filter the base value in a manner that is possibly different (either more
2848 // or less precise) than the way it would be filtered if this was strength-reduced to a
2849 // CheckStructure. This is fine. It's legal for different passes over the code to prove
2850 // different things about the code, so long as all of them are sound. That even includes
2851 // one guy proving that code should never execute (due to a contradiction) and another guy
2852 // not finding that contradiction. If someone ever proved that there would be a
2853 // contradiction then there must always be a contradiction even if subsequent passes don't
2854 // realize it. This is the case here.
2856 // Ordinarily you have to be careful with calling setFoundConstants()
2857 // because of the effect on compile times, but this node is FTL-only.
2858 m_state.setFoundConstants(true);
2860 UniquedStringImpl* uid = m_graph.identifiers()[node->multiGetByOffsetData().identifierNumber];
2862 AbstractValue base = forNode(node->child1());
2863 RegisteredStructureSet baseSet;
2864 AbstractValue result;
2865 for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
2866 RegisteredStructureSet set = getCase.set();
2872 switch (getCase.method().kind()) {
2873 case GetByOffsetMethod::Constant: {
2874 AbstractValue thisResult;
2877 *getCase.method().constant(),
2878 m_state.structureClobberState());
2879 result.merge(thisResult);
2883 case GetByOffsetMethod::Load: {
2885 m_graph.inferredValueForProperty(
2886 set, uid, m_state.structureClobberState()));
2891 result.makeHeapTop();
2896 if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction)
2897 m_state.setIsValid(false);
2899 forNode(node) = result;
2907 case MultiPutByOffset: {
2908 RegisteredStructureSet newSet;
2909 TransitionVector transitions;
2911 // Ordinarily you have to be careful with calling setFoundConstants()
2912 // because of the effect on compile times, but this node is FTL-only.
2913 m_state.setFoundConstants(true);
2915 AbstractValue base = forNode(node->child1());
2916 AbstractValue originalValue = forNode(node->child2());
2917 AbstractValue resultingValue;
2919 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
2920 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
2921 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure());
2922 thisSet.filter(base);
2923 if (thisSet.isEmpty())
2926 AbstractValue thisValue = originalValue;
2927 thisValue.filter(m_graph, variant.requiredType());
2928 resultingValue.merge(thisValue);
2930 if (variant.kind() == PutByIdVariant::Transition) {
2931 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure());
2932 if (thisSet.onlyStructure() != newStructure) {
2934 Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure));
2935 } // else this is really a replace.
2936 newSet.add(newStructure);
2938 ASSERT(variant.kind() == PutByIdVariant::Replace);
2939 newSet.merge(thisSet);
2943 observeTransitions(clobberLimit, transitions);
2944 if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction)
2945 m_state.setIsValid(false);
2946 forNode(node->child2()) = resultingValue;
2947 if (!!originalValue && !resultingValue)
2948 m_state.setIsValid(false);
2952 case GetExecutable: {
2953 JSValue value = forNode(node->child1()).value();
2955 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
2957 setConstant(node, *m_graph.freeze(function->executable()));
2961 forNode(node).setType(m_graph, SpecCellOther);
2966 JSValue value = forNode(node->child1()).value();
2967 if (value == node->cellOperand()->value()) {
2968 m_state.setFoundConstants(true);
2972 filterByValue(node->child1(), *node->cellOperand());
2976 case CheckNotEmpty: {
2977 AbstractValue& value = forNode(node->child1());
2978 if (!(value.m_type & SpecEmpty)) {
2979 m_state.setFoundConstants(true);
2983 filter(value, ~SpecEmpty);
2987 case CheckStringIdent: {
2988 AbstractValue& value = forNode(node->child1());
2989 UniquedStringImpl* uid = node->uidOperand();
2990 ASSERT(!(value.m_type & ~SpecStringIdent)); // Edge filtering should have already ensured this.
2992 JSValue childConstant = value.value();
2993 if (childConstant) {
2994 ASSERT(childConstant.isString());
2995 if (asString(childConstant)->tryGetValueImpl() == uid) {
2996 m_state.setFoundConstants(true);
3001 filter(value, SpecStringIdent);
3005 case CheckInBounds: {
3006 JSValue left = forNode(node->child1()).value();
3007 JSValue right = forNode(node->child2()).value();
3008 if (left && right && left.isInt32() && right.isInt32()
3009 && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) {
3010 m_state.setFoundConstants(true);
3018 case PutByIdDirect: {
3019 AbstractValue& value = forNode(node->child1());
3020 if (value.m_structure.isFinite()) {
3021 PutByIdStatus status = PutByIdStatus::computeFor(
3022 m_graph.globalObjectFor(node->origin.semantic),
3023 value.m_structure.toStructureSet(),
3024 m_graph.identifiers()[node->identifierNumber()],
3025 node->op() == PutByIdDirect);