| /* | 
 |  * Copyright (C) 2013-2020 Apple Inc. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 |  */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #if ENABLE(DFG_JIT) | 
 |  | 
 | #include "ArrayConstructor.h" | 
 | #include "ArrayPrototype.h" | 
 | #include "CacheableIdentifierInlines.h" | 
 | #include "DFGAbstractInterpreter.h" | 
 | #include "DFGAbstractInterpreterClobberState.h" | 
 | #include "DOMJITGetterSetter.h" | 
 | #include "DOMJITSignature.h" | 
 | #include "GetByStatus.h" | 
 | #include "GetterSetter.h" | 
 | #include "HashMapImpl.h" | 
 | #include "JITOperations.h" | 
 | #include "JSAsyncGenerator.h" | 
 | #include "JSGenerator.h" | 
 | #include "JSImmutableButterfly.h" | 
 | #include "JSInternalPromise.h" | 
 | #include "JSInternalPromiseConstructor.h" | 
 | #include "JSPromiseConstructor.h" | 
 | #include "MathCommon.h" | 
 | #include "NumberConstructor.h" | 
 | #include "PutByIdStatus.h" | 
 | #include "StringObject.h" | 
 | #include "StructureCache.h" | 
 | #include "StructureRareDataInlines.h" | 
 | #include <wtf/BooleanLattice.h> | 
 | #include <wtf/CheckedArithmetic.h> | 
 |  | 
 | namespace JSC { namespace DFG { | 
 |  | 
 | template<typename AbstractStateType> | 
 | AbstractInterpreter<AbstractStateType>::AbstractInterpreter(Graph& graph, AbstractStateType& state) | 
 |     : m_codeBlock(graph.m_codeBlock) | 
 |     , m_graph(graph) | 
 |     , m_vm(m_graph.m_vm) | 
 |     , m_state(state) | 
 | { | 
 |     if (m_graph.m_form == SSA) | 
 |         m_phiChildren = makeUnique<PhiChildren>(m_graph); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | AbstractInterpreter<AbstractStateType>::~AbstractInterpreter() | 
 | { | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | TriState AbstractInterpreter<AbstractStateType>::booleanResult(Node* node, AbstractValue& value) | 
 | { | 
 |     JSValue childConst = value.value(); | 
 |     if (childConst) { | 
 |         if (childConst.toBoolean(m_codeBlock->globalObjectFor(node->origin.semantic))) | 
 |             return TriState::True; | 
 |         return TriState::False; | 
 |     } | 
 |  | 
 |     // Next check if we can fold because we know that the source is an object or string and does not equal undefined. | 
 |     if (isCellSpeculation(value.m_type) && !value.m_structure.isTop()) { | 
 |         bool allTrue = true; | 
 |         for (unsigned i = value.m_structure.size(); i--;) { | 
 |             RegisteredStructure structure = value.m_structure[i]; | 
 |             if (structure->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)) || structure->typeInfo().type() == StringType || structure->typeInfo().type() == HeapBigIntType) { | 
 |                 allTrue = false; | 
 |                 break; | 
 |             } | 
 |         } | 
 |         if (allTrue) | 
 |             return TriState::True; | 
 |     } | 
 |      | 
 |     return TriState::Indeterminate; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::startExecuting() | 
 | { | 
 |     ASSERT(m_state.block()); | 
 |     ASSERT(m_state.isValid()); | 
 |      | 
 |     m_state.setClobberState(AbstractInterpreterClobberState::NotClobbered); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | class AbstractInterpreterExecuteEdgesFunc { | 
 | public: | 
 |     AbstractInterpreterExecuteEdgesFunc(AbstractInterpreter<AbstractStateType>& interpreter) | 
 |         : m_interpreter(interpreter) | 
 |     { | 
 |     } | 
 |      | 
 |     // This func is manually written out so that we can put ALWAYS_INLINE on it. | 
 |     ALWAYS_INLINE void operator()(Edge& edge) const | 
 |     { | 
 |         m_interpreter.filterEdgeByUse(edge); | 
 |     } | 
 |      | 
 | private: | 
 |     AbstractInterpreter<AbstractStateType>& m_interpreter; | 
 | }; | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::executeEdges(Node* node) | 
 | { | 
 |     m_graph.doToChildren(node, AbstractInterpreterExecuteEdgesFunc<AbstractStateType>(*this)); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::executeKnownEdgeTypes(Node* node) | 
 | { | 
 |     // Some use kinds are required to not have checks, because we know somehow that the incoming | 
 |     // value will already have the type we want. In those cases, AI may not be smart enough to | 
 |     // prove that this is indeed the case. But the existance of the edge is enough to prove that | 
 |     // it is indeed the case. Taking advantage of this is not optional, since otherwise the DFG | 
 |     // and FTL backends may emit checks in a node that lacks a valid exit origin. | 
 |     m_graph.doToChildren( | 
 |         node, | 
 |         [&] (Edge& edge) { | 
 |             if (mayHaveTypeCheck(edge.useKind())) | 
 |                 return; | 
 |              | 
 |             filterEdgeByUse(edge); | 
 |         }); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | ALWAYS_INLINE void AbstractInterpreter<AbstractStateType>::filterByType(Edge& edge, SpeculatedType type) | 
 | { | 
 |     AbstractValue& value = m_state.forNodeWithoutFastForward(edge); | 
 |     if (value.isType(type)) { | 
 |         m_state.setProofStatus(edge, IsProved); | 
 |         return; | 
 |     } | 
 |     m_state.setProofStatus(edge, NeedsCheck); | 
 |     m_state.fastForwardAndFilterUnproven(value, type); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::verifyEdge(Node* node, Edge edge) | 
 | { | 
 |     if (!(m_state.forNodeWithoutFastForward(edge).m_type & ~typeFilterFor(edge.useKind()))) | 
 |         return; | 
 |      | 
 |     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); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::verifyEdges(Node* node) | 
 | { | 
 |     DFG_NODE_DO_TO_CHILDREN(m_graph, node, verifyEdge); | 
 | } | 
 |  | 
 | enum class ToThisResult { | 
 |     Identity, | 
 |     Undefined, | 
 |     GlobalThis, | 
 |     Dynamic, | 
 | }; | 
 | inline ToThisResult isToThisAnIdentity(VM& vm, ECMAMode ecmaMode, AbstractValue& valueForNode) | 
 | { | 
 |     // We look at the type first since that will cover most cases and does not require iterating all the structures. | 
 |     if (ecmaMode.isStrict()) { | 
 |         if (valueForNode.m_type && !(valueForNode.m_type & SpecObjectOther)) | 
 |             return ToThisResult::Identity; | 
 |     } else { | 
 |         if (valueForNode.m_type && !(valueForNode.m_type & (~SpecObject | SpecObjectOther))) | 
 |             return ToThisResult::Identity; | 
 |     } | 
 |  | 
 |     if (JSValue value = valueForNode.value()) { | 
 |         if (value.isCell()) { | 
 |             auto* toThisMethod = value.asCell()->classInfo(vm)->methodTable.toThis; | 
 |             if (toThisMethod == &JSObject::toThis) | 
 |                 return ToThisResult::Identity; | 
 |             if (toThisMethod == &JSScope::toThis) { | 
 |                 if (ecmaMode.isStrict()) | 
 |                     return ToThisResult::Undefined; | 
 |                 return ToThisResult::GlobalThis; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     if ((ecmaMode.isStrict() || (valueForNode.m_type && !(valueForNode.m_type & ~SpecObject))) && valueForNode.m_structure.isFinite()) { | 
 |         bool allStructuresAreJSScope = !valueForNode.m_structure.isClear(); | 
 |         bool overridesToThis = false; | 
 |         valueForNode.m_structure.forEach([&](RegisteredStructure structure) { | 
 |             TypeInfo type = structure->typeInfo(); | 
 |             ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == HeapBigIntType); | 
 |             if (!ecmaMode.isStrict()) | 
 |                 ASSERT(type.isObject()); | 
 |             // We don't need to worry about strings/symbols here since either: | 
 |             // 1) We are in strict mode and strings/symbols are not wrapped | 
 |             // 2) The AI has proven that the type of this is a subtype of object | 
 |             if (type.isObject() && type.overridesToThis()) | 
 |                 overridesToThis = true; | 
 |  | 
 |             // If all the structures are JSScope's ones, we know the details of JSScope::toThis() operation. | 
 |             allStructuresAreJSScope &= structure->classInfo()->methodTable.toThis == JSScope::info()->methodTable.toThis; | 
 |         }); | 
 |         if (!overridesToThis) | 
 |             return ToThisResult::Identity; | 
 |         if (allStructuresAreJSScope) { | 
 |             if (ecmaMode.isStrict()) | 
 |                 return ToThisResult::Undefined; | 
 |             return ToThisResult::GlobalThis; | 
 |         } | 
 |     } | 
 |  | 
 |     return ToThisResult::Dynamic; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::handleConstantBinaryBitwiseOp(Node* node) | 
 | { | 
 |     JSValue left = forNode(node->child1()).value(); | 
 |     JSValue right = forNode(node->child2()).value(); | 
 |     if (left && right && left.isInt32() && right.isInt32()) { | 
 |         int32_t a = left.asInt32(); | 
 |         int32_t b = right.asInt32(); | 
 |         if (node->isBinaryUseKind(UntypedUse)) | 
 |             didFoldClobberWorld(); | 
 |         NodeType op = node->op(); | 
 |         switch (op) { | 
 |         case ValueBitAnd: | 
 |         case ArithBitAnd: | 
 |             setConstant(node, JSValue(a & b)); | 
 |             break; | 
 |         case ValueBitOr: | 
 |         case ArithBitOr: | 
 |             setConstant(node, JSValue(a | b)); | 
 |             break; | 
 |         case ValueBitXor: | 
 |         case ArithBitXor: | 
 |             setConstant(node, JSValue(a ^ b)); | 
 |             break; | 
 |         case ArithBitRShift: | 
 |         case ValueBitRShift: | 
 |             setConstant(node, JSValue(a >> (static_cast<uint32_t>(b) & 0x1f))); | 
 |             break; | 
 |         case ValueBitLShift: | 
 |         case ArithBitLShift: | 
 |             setConstant(node, JSValue(a << (static_cast<uint32_t>(b) & 0x1f))); | 
 |             break; | 
 |         case BitURShift: | 
 |             setConstant(node, JSValue(static_cast<int32_t>(static_cast<uint32_t>(a) >> (static_cast<uint32_t>(b) & 0x1f)))); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |  | 
 |         return true; | 
 |     } | 
 |  | 
 |     return false; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::handleConstantDivOp(Node* node) | 
 | { | 
 |     JSValue left = forNode(node->child1()).value(); | 
 |     JSValue right = forNode(node->child2()).value(); | 
 |  | 
 |     if (left && right) { | 
 |         NodeType op = node->op(); | 
 |         bool isDivOperation = op == ValueDiv || op == ArithDiv; | 
 |  | 
 |         // Only possible case of ValueOp below is UntypedUse, | 
 |         // so we need to reflect clobberize rules. | 
 |         bool isClobbering = op == ValueDiv || op == ValueMod; | 
 |  | 
 |         if (left.isInt32() && right.isInt32()) { | 
 |             double doubleResult; | 
 |             if (isDivOperation) | 
 |                 doubleResult = left.asNumber() / right.asNumber(); | 
 |             else | 
 |                 doubleResult = fmod(left.asNumber(), right.asNumber()); | 
 |  | 
 |             if (node->hasArithMode()) { | 
 |                 if (!shouldCheckOverflow(node->arithMode())) | 
 |                     doubleResult = toInt32(doubleResult); | 
 |                 else if (!shouldCheckNegativeZero(node->arithMode())) | 
 |                     doubleResult += 0; // Sanitizes zero. | 
 |             } | 
 |  | 
 |             JSValue valueResult = jsNumber(doubleResult); | 
 |             if (valueResult.isInt32()) { | 
 |                 if (isClobbering) | 
 |                     didFoldClobberWorld(); | 
 |                 setConstant(node, valueResult); | 
 |                 return true; | 
 |             } | 
 |         } else if (left.isNumber() && right.isNumber()) { | 
 |             if (isClobbering) | 
 |                 didFoldClobberWorld(); | 
 |  | 
 |             if (isDivOperation) { | 
 |                 if (op == ValueDiv) | 
 |                     setConstant(node, jsNumber(left.asNumber() / right.asNumber())); | 
 |                 else | 
 |                     setConstant(node, jsDoubleNumber(left.asNumber() / right.asNumber())); | 
 |             } else { | 
 |                 if (op == ValueMod) | 
 |                     setConstant(node, jsNumber(fmod(left.asNumber(), right.asNumber()))); | 
 |                 else | 
 |                     setConstant(node, jsDoubleNumber(fmod(left.asNumber(), right.asNumber()))); | 
 |             } | 
 |  | 
 |             return true; | 
 |         } | 
 |     } | 
 |  | 
 |     return false; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimit, Node* node) | 
 | { | 
 |     verifyEdges(node); | 
 |      | 
 |     m_state.createValueForNode(node); | 
 |      | 
 |     switch (node->op()) { | 
 |     case JSConstant: | 
 |     case DoubleConstant: | 
 |     case Int52Constant: { | 
 |         setBuiltInConstant(node, *node->constant()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case LazyJSConstant: { | 
 |         LazyJSValue value = node->lazyJSValue(); | 
 |         switch (value.kind()) { | 
 |         case LazyJSValue::KnownValue: | 
 |             setConstant(node, value.value()->value()); | 
 |             break; | 
 |         case LazyJSValue::SingleCharacterString: | 
 |         case LazyJSValue::KnownStringImpl: | 
 |         case LazyJSValue::NewStringImpl: | 
 |             setTypeForNode(node, SpecString); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case IdentityWithProfile: | 
 |     case Identity: { | 
 |         setForNode(node, forNode(node->child1())); | 
 |         if (forNode(node).value()) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         break; | 
 |     } | 
 |          | 
 |     case ExtractCatchLocal: | 
 |     case ExtractOSREntryLocal: { | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |     } | 
 |              | 
 |     case GetLocal: { | 
 |         VariableAccessData* variableAccessData = node->variableAccessData(); | 
 |         AbstractValue value = m_state.operand(variableAccessData->operand()); | 
 |         // The value in the local should already be checked. | 
 |         DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData->flushFormat()))); | 
 |         if (value.value()) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         setForNode(node, value); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetStack: { | 
 |         StackAccessData* data = node->stackAccessData(); | 
 |         AbstractValue value = m_state.operand(data->operand); | 
 |         // The value in the local should already be checked. | 
 |         DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data->format))); | 
 |         if (value.value()) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         setForNode(node, value); | 
 |         break; | 
 |     } | 
 |          | 
 |     case SetLocal: { | 
 |         m_state.operand(node->operand()) = forNode(node->child1()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case PutStack: { | 
 |         m_state.operand(node->stackAccessData()->operand) = forNode(node->child1()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case MovHint: { | 
 |         // Don't need to do anything. A MovHint only informs us about what would have happened | 
 |         // in bytecode, but this code is just concerned with what is actually happening during | 
 |         // DFG execution. | 
 |         break; | 
 |     } | 
 |  | 
 |     case KillStack: { | 
 |         // This is just a hint telling us that the OSR state of the local is no longer inside the | 
 |         // flushed data. | 
 |         break; | 
 |     } | 
 |          | 
 |     case SetArgumentDefinitely: | 
 |     case SetArgumentMaybe: | 
 |         // Assert that the state of arguments has been set. SetArgumentDefinitely/SetArgumentMaybe means | 
 |         // that someone set the argument values out-of-band, and currently this always means setting to a | 
 |         // non-clear value. | 
 |         ASSERT(!m_state.operand(node->operand()).isClear()); | 
 |         break; | 
 |  | 
 |     case InitializeEntrypointArguments: { | 
 |         unsigned entrypointIndex = node->entrypointIndex(); | 
 |         const Vector<FlushFormat>& argumentFormats = m_graph.m_argumentFormats[entrypointIndex]; | 
 |         for (unsigned argument = 0; argument < argumentFormats.size(); ++argument) { | 
 |             AbstractValue& value = m_state.argument(argument); | 
 |             switch (argumentFormats[argument]) { | 
 |             case FlushedInt32: | 
 |                 value.setNonCellType(SpecInt32Only); | 
 |                 break; | 
 |             case FlushedBoolean: | 
 |                 value.setNonCellType(SpecBoolean); | 
 |                 break; | 
 |             case FlushedCell: | 
 |                 value.setType(m_graph, SpecCellCheck); | 
 |                 break; | 
 |             case FlushedJSValue: | 
 |                 value.makeBytecodeTop(); | 
 |                 break; | 
 |             default: | 
 |                 DFG_CRASH(m_graph, node, "Bad flush format for argument"); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case VarargsLength: { | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case LoadVarargs: | 
 |     case ForwardVarargs: { | 
 |         // FIXME: ForwardVarargs should check if the count becomes known, and if it does, it should turn | 
 |         // itself into a straight-line sequence of GetStack/PutStack. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=143071 | 
 |         switch (node->op()) { | 
 |         case LoadVarargs: | 
 |             clobberWorld(); | 
 |             break; | 
 |         case ForwardVarargs: | 
 |             break; | 
 |         default: | 
 |             DFG_CRASH(m_graph, node, "Bad opcode"); | 
 |             break; | 
 |         } | 
 |         LoadVarargsData* data = node->loadVarargsData(); | 
 |         m_state.operand(data->count).setNonCellType(SpecInt32Only); | 
 |         for (unsigned i = data->limit - 1; i--;) | 
 |             m_state.operand(data->start + i).makeHeapTop(); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ValueBitNot: { | 
 |         JSValue operand = forNode(node->child1()).value(); | 
 |         if (operand && operand.isInt32()) { | 
 |             didFoldClobberWorld(); | 
 |             int32_t a = operand.asInt32(); | 
 |             setConstant(node, JSValue(~a)); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (node->child1().useKind() == BigInt32Use) { | 
 | #if USE(BIGINT32) | 
 |             setTypeForNode(node, SpecBigInt32); | 
 | #else | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 | #endif | 
 |         } else if (node->child1().useKind() == HeapBigIntUse) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->child1().useKind() == AnyBigIntUse) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else { | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecInt32Only | SpecBigInt); | 
 |         } | 
 |  | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithBitNot: { | 
 |         JSValue operand = forNode(node->child1()).value(); | 
 |         if (operand && operand.isInt32()) { | 
 |             int32_t a = operand.asInt32(); | 
 |             setConstant(node, JSValue(~a)); | 
 |             break; | 
 |         } | 
 |  | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ValueBitXor: | 
 |     case ValueBitAnd: | 
 |     case ValueBitOr: | 
 |     case ValueBitRShift: | 
 |     case ValueBitLShift: { | 
 |         if (handleConstantBinaryBitwiseOp(node)) | 
 |             break; | 
 |  | 
 |         // FIXME: this use of binaryUseKind means that we cannot specialize to (for example) a HeapBigInt left-operand and a BigInt32 right-operand. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=210977 | 
 |         if (node->binaryUseKind() == BigInt32Use) { | 
 | #if USE(BIGINT32) | 
 |             switch (node->op()) { | 
 |             case ValueBitXor: | 
 |             case ValueBitAnd: | 
 |             case ValueBitOr: | 
 |                 setTypeForNode(node, SpecBigInt32); | 
 |                 break; | 
 |  | 
 |             // FIXME: We should have inlined implementation that always returns BigInt32. | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210847 | 
 |             case ValueBitRShift: | 
 |             case ValueBitLShift: | 
 |                 setTypeForNode(node, SpecBigInt); | 
 |                 break; | 
 |             default: | 
 |                 DFG_CRASH(m_graph, node, "Incorrect DFG op"); | 
 |             } | 
 | #else | 
 |             DFG_CRASH(m_graph, node, "No BigInt32 support"); | 
 | #endif | 
 |         } else if (node->isBinaryUseKind(HeapBigIntUse)) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->binaryUseKind() == AnyBigIntUse) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else { | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecInt32Only | SpecBigInt); | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArithBitAnd: | 
 |     case ArithBitOr: | 
 |     case ArithBitXor: | 
 |     case ArithBitRShift: | 
 |     case ArithBitLShift: | 
 |     case BitURShift: { | 
 |         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) { | 
 |             clobberWorld(); | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (handleConstantBinaryBitwiseOp(node)) | 
 |             break; | 
 |          | 
 |         if (node->op() == ArithBitAnd | 
 |             && (isBoolInt32Speculation(forNode(node->child1()).m_type) || | 
 |                 isBoolInt32Speculation(forNode(node->child2()).m_type))) { | 
 |             setNonCellTypeForNode(node, SpecBoolInt32); | 
 |             break; | 
 |         } | 
 |          | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |          | 
 |     case UInt32ToNumber: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (doesOverflow(node->arithMode())) { | 
 |             if (enableInt52()) { | 
 |                 if (child && child.isAnyInt()) { | 
 |                     int64_t machineInt = child.asAnyInt(); | 
 |                     setConstant(node, jsNumber(static_cast<uint32_t>(machineInt))); | 
 |                     break; | 
 |                 } | 
 |                 setNonCellTypeForNode(node, SpecInt52Any); | 
 |                 break; | 
 |             } | 
 |             if (child && child.isInt32()) { | 
 |                 uint32_t value = child.asInt32(); | 
 |                 setConstant(node, jsNumber(value)); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecAnyIntAsDouble); | 
 |             break; | 
 |         } | 
 |         if (child && child.isInt32()) { | 
 |             int32_t value = child.asInt32(); | 
 |             if (value >= 0) { | 
 |                 setConstant(node, jsNumber(value)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |          | 
 |     case BooleanToNumber: { | 
 |         JSValue concreteValue = forNode(node->child1()).value(); | 
 |         if (concreteValue) { | 
 |             if (concreteValue.isBoolean()) | 
 |                 setConstant(node, jsNumber(concreteValue.asBoolean())); | 
 |             else | 
 |                 setConstant(node, *m_graph.freeze(concreteValue)); | 
 |             break; | 
 |         } | 
 |         AbstractValue& value = forNode(node); | 
 |         value = forNode(node->child1()); | 
 |         if (node->child1().useKind() == UntypedUse && !(value.m_type & ~SpecBoolean)) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         if (value.m_type & SpecBoolean) { | 
 |             value.merge(SpecBoolInt32); | 
 |             value.filter(~SpecBoolean); | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case DoubleAsInt32: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (child && child.isNumber()) { | 
 |             double asDouble = child.asNumber(); | 
 |             int32_t asInt = JSC::toInt32(asDouble); | 
 |             if (bitwise_cast<int64_t>(static_cast<double>(asInt)) == bitwise_cast<int64_t>(asDouble)) { | 
 |                 setConstant(node, JSValue(asInt)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |              | 
 |     case ValueToInt32: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (child) { | 
 |             if (child.isNumber()) { | 
 |                 if (child.isInt32()) | 
 |                     setConstant(node, child); | 
 |                 else | 
 |                     setConstant(node, JSValue(JSC::toInt32(child.asDouble()))); | 
 |                 break; | 
 |             } | 
 |             if (child.isBoolean()) { | 
 |                 setConstant(node, jsNumber(child.asBoolean())); | 
 |                 break; | 
 |             } | 
 |             if (child.isUndefinedOrNull()) { | 
 |                 setConstant(node, jsNumber(0)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         if (isBooleanSpeculation(forNode(node->child1()).m_type)) { | 
 |             setNonCellTypeForNode(node, SpecBoolInt32); | 
 |             break; | 
 |         } | 
 |          | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |          | 
 |     case DoubleRep: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (Optional<double> number = child.toNumberFromPrimitive()) { | 
 |             setConstant(node, jsDoubleNumber(*number)); | 
 |             break; | 
 |         } | 
 |  | 
 |         SpeculatedType type = forNode(node->child1()).m_type; | 
 |         switch (node->child1().useKind()) { | 
 |         case NotCellNorBigIntUse: { | 
 |             if (type & SpecOther) { | 
 |                 type &= ~SpecOther; | 
 |                 type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN. | 
 |             } | 
 |             if (type & SpecBoolean) { | 
 |                 type &= ~SpecBoolean; | 
 |                 type |= SpecBoolInt32; // True becomes 1, false becomes 0. | 
 |             } | 
 |             type &= SpecBytecodeNumber; | 
 |             break; | 
 |         } | 
 |  | 
 |         case Int52RepUse: | 
 |         case NumberUse: | 
 |         case RealNumberUse: | 
 |             break; | 
 |  | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |         } | 
 |         setNonCellTypeForNode(node, type); | 
 |         forNode(node).fixTypeForRepresentation(m_graph, node); | 
 |         break; | 
 |     } | 
 |          | 
 |     case Int52Rep: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (child && child.isAnyInt()) { | 
 |             setConstant(node, child); | 
 |             break; | 
 |         } | 
 |  | 
 |         setTypeForNode(node, forNode(node->child1()).m_type); | 
 |         forNode(node).fixTypeForRepresentation(m_graph, node); | 
 |         break; | 
 |     } | 
 |          | 
 |     case ValueRep: { | 
 |         JSValue value = forNode(node->child1()).value(); | 
 |         if (value) { | 
 |             setConstant(node, value); | 
 |             break; | 
 |         } | 
 |          | 
 |         setTypeForNode(node, forNode(node->child1()).m_type & ~SpecDoubleImpureNaN); | 
 |         forNode(node).fixTypeForRepresentation(m_graph, node); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ValueSub: | 
 |     case ValueAdd: { | 
 |         if (node->isBinaryUseKind(HeapBigIntUse)) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->isBinaryUseKind(AnyBigIntUse)) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else if (node->isBinaryUseKind(BigInt32Use)) | 
 |             setTypeForNode(node, SpecBigInt32); | 
 |         else { | 
 |             DFG_ASSERT(m_graph, node, node->binaryUseKind() == UntypedUse); | 
 |             clobberWorld(); | 
 |             // FIXME: do we really need SpecString here for ValueSub? It seems like we only need it for ValueAdd. | 
 |             setTypeForNode(node, SpecString | SpecBytecodeNumber | SpecBigInt); | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case StrCat: { | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |     } | 
 |          | 
 |     case ArithAdd: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             if (left && right && left.isInt32() && right.isInt32()) { | 
 |                 if (!shouldCheckOverflow(node->arithMode())) { | 
 |                     setConstant(node, jsNumber(left.asInt32() + right.asInt32())); | 
 |                     break; | 
 |                 } | 
 |                 JSValue result = jsNumber(left.asNumber() + right.asNumber()); | 
 |                 if (result.isInt32()) { | 
 |                     setConstant(node, result); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Int52RepUse: | 
 |             if (left && right && left.isAnyInt() && right.isAnyInt()) { | 
 |                 JSValue result = jsNumber(left.asAnyInt() + right.asAnyInt()); | 
 |                 if (result.isAnyInt()) { | 
 |                     setConstant(node, result); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt52Any); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (left && right && left.isNumber() && right.isNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(left.asNumber() + right.asNumber())); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleSum( | 
 |                     forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case AtomicsIsLockFree: { | 
 |         if (m_graph.child(node, 0).useKind() != Int32Use) | 
 |             clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithClz32: { | 
 |         JSValue operand = forNode(node->child1()).value(); | 
 |         if (Optional<double> number = operand.toNumberFromPrimitive()) { | 
 |             switch (node->child1().useKind()) { | 
 |             case Int32Use: | 
 |             case KnownInt32Use: | 
 |                 break; | 
 |             default: | 
 |                 didFoldClobberWorld(); | 
 |                 break; | 
 |             } | 
 |             uint32_t value = toUInt32(*number); | 
 |             setConstant(node, jsNumber(clz(value))); | 
 |             break; | 
 |         } | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |         case KnownInt32Use: | 
 |             break; | 
 |         default: | 
 |             clobberWorld(); | 
 |             break; | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case MakeRope: { | 
 |         unsigned numberOfRemovedChildren = 0; | 
 |         for (unsigned i = 0; i < AdjacencyList::Size; ++i) { | 
 |             Edge& edge = node->children.child(i); | 
 |             if (!edge) | 
 |                 break; | 
 |             JSValue childConstant = m_state.forNode(edge).value(); | 
 |             if (!childConstant) | 
 |                 continue; | 
 |             if (!childConstant.isString()) | 
 |                 continue; | 
 |             if (asString(childConstant)->length()) | 
 |                 continue; | 
 |             ++numberOfRemovedChildren; | 
 |         } | 
 |  | 
 |         if (numberOfRemovedChildren) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         setForNode(node, m_vm.stringStructure.get()); | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArithSub: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             if (left && right && left.isInt32() && right.isInt32()) { | 
 |                 if (!shouldCheckOverflow(node->arithMode())) { | 
 |                     setConstant(node, jsNumber(left.asInt32() - right.asInt32())); | 
 |                     break; | 
 |                 } | 
 |                 JSValue result = jsNumber(left.asNumber() - right.asNumber()); | 
 |                 if (result.isInt32()) { | 
 |                     setConstant(node, result); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Int52RepUse: | 
 |             if (left && right && left.isAnyInt() && right.isAnyInt()) { | 
 |                 JSValue result = jsNumber(left.asAnyInt() - right.asAnyInt()); | 
 |                 if (result.isAnyInt()) { | 
 |                     setConstant(node, result); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt52Any); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (left && right && left.isNumber() && right.isNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(left.asNumber() - right.asNumber())); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleDifference( | 
 |                     forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             break; | 
 |         case UntypedUse: | 
 |             clobberWorld(); | 
 |             setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case ValueNegate: { | 
 |         // FIXME: we could do much smarter things for BigInts, see ValueAdd/ValueSub. | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithNegate: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |             if (child && child.isInt32()) { | 
 |                 if (!shouldCheckOverflow(node->arithMode())) { | 
 |                     setConstant(node, jsNumber(-child.asInt32())); | 
 |                     break; | 
 |                 } | 
 |                 double doubleResult; | 
 |                 if (shouldCheckNegativeZero(node->arithMode())) | 
 |                     doubleResult = -child.asNumber(); | 
 |                 else | 
 |                     doubleResult = 0 - child.asNumber(); | 
 |                 JSValue valueResult = jsNumber(doubleResult); | 
 |                 if (valueResult.isInt32()) { | 
 |                     setConstant(node, valueResult); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Int52RepUse: | 
 |             if (child && child.isAnyInt()) { | 
 |                 double doubleResult; | 
 |                 if (shouldCheckNegativeZero(node->arithMode())) | 
 |                     doubleResult = -child.asNumber(); | 
 |                 else | 
 |                     doubleResult = 0 - child.asNumber(); | 
 |                 JSValue valueResult = jsNumber(doubleResult); | 
 |                 if (valueResult.isAnyInt()) { | 
 |                     setConstant(node, valueResult); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt52Any); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (child && child.isNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(-child.asNumber())); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleNegation( | 
 |                     forNode(node->child1()).m_type)); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case Inc: | 
 |     case Dec: { | 
 |         // FIXME: support some form of constant folding here. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=204258 | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Int52RepUse: | 
 |             setNonCellTypeForNode(node, SpecInt52Any); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             setNonCellTypeForNode(node, typeOfDoubleIncOrDec(forNode(node->child1()).m_type)); | 
 |             break; | 
 |         case HeapBigIntUse: | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |             break; | 
 |         case AnyBigIntUse: | 
 |         case BigInt32Use: | 
 |             setTypeForNode(node, SpecBigInt); | 
 |             break; | 
 |         default: | 
 |             setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |             clobberWorld(); // Because of the call to ToNumeric() | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case ValuePow: { | 
 |         JSValue childX = forNode(node->child1()).value(); | 
 |         JSValue childY = forNode(node->child2()).value(); | 
 |         if (childX && childY && childX.isNumber() && childY.isNumber()) { | 
 |             // We need to call `didFoldClobberWorld` here because this path is only possible | 
 |             // when node->useKind is UntypedUse. In the case of AnyBigIntUse or friends, children will be | 
 |             // cleared by `AbstractInterpreter::executeEffects`. | 
 |             didFoldClobberWorld(); | 
 |             // Our boxing scheme here matches what we do in operationValuePow. | 
 |             setConstant(node, jsNumber(operationMathPow(childX.asNumber(), childY.asNumber()))); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (node->isBinaryUseKind(HeapBigIntUse)) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else { | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case ValueMul: { | 
 |         // FIXME: why is this code not shared with ValueSub? | 
 |         if (node->isBinaryUseKind(HeapBigIntUse)) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->isBinaryUseKind(AnyBigIntUse)) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else if (node->isBinaryUseKind(BigInt32Use)) | 
 |             setTypeForNode(node, SpecBigInt32); | 
 |         else { | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithMul: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             if (left && right && left.isInt32() && right.isInt32()) { | 
 |                 if (!shouldCheckOverflow(node->arithMode())) { | 
 |                     setConstant(node, jsNumber(left.asInt32() * right.asInt32())); | 
 |                     break; | 
 |                 } | 
 |                 double doubleResult = left.asNumber() * right.asNumber(); | 
 |                 if (!shouldCheckNegativeZero(node->arithMode())) | 
 |                     doubleResult += 0; // Sanitizes zero. | 
 |                 JSValue valueResult = jsNumber(doubleResult); | 
 |                 if (valueResult.isInt32()) { | 
 |                     setConstant(node, valueResult); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Int52RepUse: | 
 |             if (left && right && left.isAnyInt() && right.isAnyInt()) { | 
 |                 double doubleResult = left.asNumber() * right.asNumber(); | 
 |                 if (!shouldCheckNegativeZero(node->arithMode())) | 
 |                     doubleResult += 0; | 
 |                 JSValue valueResult = jsNumber(doubleResult); | 
 |                 if (valueResult.isAnyInt()) { | 
 |                     setConstant(node, valueResult); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt52Any); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (left && right && left.isNumber() && right.isNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(left.asNumber() * right.asNumber())); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleProduct( | 
 |                     forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case ValueMod: | 
 |     case ValueDiv: { | 
 |         if (handleConstantDivOp(node)) | 
 |             break; | 
 |  | 
 |         if (node->isBinaryUseKind(HeapBigIntUse)) { | 
 |             // FIXME: We will want an arithmetic mode here that allows us to speculate or dictate | 
 |             // the format of our result: | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=210982 | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         } else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use) | 
 |             setTypeForNode(node, SpecBigInt); | 
 |         else { | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithMod: | 
 |     case ArithDiv: { | 
 |         if (handleConstantDivOp(node)) | 
 |             break; | 
 |  | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (node->op() == ArithDiv) { | 
 |                 setNonCellTypeForNode(node,  | 
 |                     typeOfDoubleQuotient( | 
 |                         forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             } else { | 
 |                 setNonCellTypeForNode(node,  | 
 |                     typeOfDoubleBinaryOp( | 
 |                         forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             } | 
 |              | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithMin: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             if (left && right && left.isInt32() && right.isInt32()) { | 
 |                 setConstant(node, jsNumber(std::min(left.asInt32(), right.asInt32()))); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (left && right && left.isNumber() && right.isNumber()) { | 
 |                 double a = left.asNumber(); | 
 |                 double b = right.asNumber(); | 
 |                 // The spec for Math.min states that +0 is considered to be larger than -0. | 
 |                 double result = a < b || (!a && !b && std::signbit(a)) ? a : (b <= a ? b : a + b); | 
 |                 setConstant(node, jsDoubleNumber(result)); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleMinMax( | 
 |                     forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArithMax: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         switch (node->binaryUseKind()) { | 
 |         case Int32Use: | 
 |             if (left && right && left.isInt32() && right.isInt32()) { | 
 |                 setConstant(node, jsNumber(std::max(left.asInt32(), right.asInt32()))); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (left && right && left.isNumber() && right.isNumber()) { | 
 |                 double a = left.asNumber(); | 
 |                 double b = right.asNumber(); | 
 |                 // The spec for Math.max states that +0 is considered to be larger than -0. | 
 |                 double result = a > b || (!a && !b && !std::signbit(a)) ? a : (b >= a ? b : a + b); | 
 |                 setConstant(node, jsDoubleNumber(result)); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node,  | 
 |                 typeOfDoubleMinMax( | 
 |                     forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArithAbs: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |             if (Optional<double> number = child.toNumberFromPrimitive()) { | 
 |                 JSValue result = jsNumber(fabs(*number)); | 
 |                 if (result.isInt32()) { | 
 |                     setConstant(node, result); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case DoubleRepUse: | 
 |             if (Optional<double> number = child.toNumberFromPrimitive()) { | 
 |                 setConstant(node, jsDoubleNumber(fabs(*number))); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node, typeOfDoubleAbs(forNode(node->child1()).m_type)); | 
 |             break; | 
 |         default: | 
 |             DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind()); | 
 |             clobberWorld(); | 
 |             setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithPow: { | 
 |         JSValue childY = forNode(node->child2()).value(); | 
 |         if (childY && childY.isNumber()) { | 
 |             if (!childY.asNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(1)); | 
 |                 break; | 
 |             } | 
 |  | 
 |             JSValue childX = forNode(node->child1()).value(); | 
 |             if (childX && childX.isNumber()) { | 
 |                 setConstant(node, jsDoubleNumber(operationMathPow(childX.asNumber(), childY.asNumber()))); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setNonCellTypeForNode(node, typeOfDoublePow(forNode(node->child1()).m_type, forNode(node->child2()).m_type)); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithRandom: { | 
 |         setNonCellTypeForNode(node, SpecDoubleReal); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArithRound: | 
 |     case ArithFloor: | 
 |     case ArithCeil: | 
 |     case ArithTrunc: { | 
 |         JSValue operand = forNode(node->child1()).value(); | 
 |         if (Optional<double> number = operand.toNumberFromPrimitive()) { | 
 |             if (node->child1().useKind() != DoubleRepUse) | 
 |                 didFoldClobberWorld(); | 
 |              | 
 |             double roundedValue = 0; | 
 |             if (node->op() == ArithRound) | 
 |                 roundedValue = Math::roundDouble(*number); | 
 |             else if (node->op() == ArithFloor) | 
 |                 roundedValue = Math::floorDouble(*number); | 
 |             else if (node->op() == ArithCeil) | 
 |                 roundedValue = Math::ceilDouble(*number); | 
 |             else { | 
 |                 ASSERT(node->op() == ArithTrunc); | 
 |                 roundedValue = trunc(*number); | 
 |             } | 
 |  | 
 |             if (node->child1().useKind() == UntypedUse) { | 
 |                 setConstant(node, jsNumber(roundedValue)); | 
 |                 break; | 
 |             } | 
 |             if (producesInteger(node->arithRoundingMode())) { | 
 |                 int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue); | 
 |                 if (roundedValueAsInt32 == roundedValue) { | 
 |                     if (shouldCheckNegativeZero(node->arithRoundingMode())) { | 
 |                         if (roundedValueAsInt32 || !std::signbit(roundedValue)) { | 
 |                             setConstant(node, jsNumber(roundedValueAsInt32)); | 
 |                             break; | 
 |                         } | 
 |                     } else { | 
 |                         setConstant(node, jsNumber(roundedValueAsInt32)); | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |             } else { | 
 |                 setConstant(node, jsDoubleNumber(roundedValue)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         if (node->child1().useKind() == DoubleRepUse) { | 
 |             if (producesInteger(node->arithRoundingMode())) | 
 |                 setNonCellTypeForNode(node, SpecInt32Only); | 
 |             else if (node->child1().useKind() == DoubleRepUse) | 
 |                 setNonCellTypeForNode(node, typeOfDoubleRounding(forNode(node->child1()).m_type)); | 
 |         } else { | 
 |             DFG_ASSERT(m_graph, node, node->child1().useKind() == UntypedUse, node->child1().useKind()); | 
 |             clobberWorld(); | 
 |             setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArithSqrt: | 
 |         executeDoubleUnaryOpEffects(node, sqrt); | 
 |         break; | 
 |  | 
 |     case ArithFRound: | 
 |         executeDoubleUnaryOpEffects(node, [](double value) -> double { return static_cast<float>(value); }); | 
 |         break; | 
 |          | 
 |     case ArithUnary: | 
 |         executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType())); | 
 |         break; | 
 |              | 
 |     case LogicalNot: { | 
 |         switch (booleanResult(node, forNode(node->child1()))) { | 
 |         case TriState::True: | 
 |             setConstant(node, jsBoolean(false)); | 
 |             break; | 
 |         case TriState::False: | 
 |             setConstant(node, jsBoolean(true)); | 
 |             break; | 
 |         case TriState::Indeterminate: | 
 |             setNonCellTypeForNode(node, SpecBoolean); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case MapHash: { | 
 |         if (JSValue key = forNode(node->child1()).value()) { | 
 |             if (Optional<uint32_t> hash = concurrentJSMapHash(key)) { | 
 |                 // Although C++ code uses uint32_t for the hash, the closest type in DFG IR is Int32 | 
 |                 // and that's what MapHash returns. So, we have to cast to int32_t to avoid large | 
 |                 // unsigned values becoming doubles. This casting between signed and unsigned | 
 |                 // happens in the assembly code we emit when we don't constant fold this node. | 
 |                 setConstant(node, jsNumber(static_cast<int32_t>(*hash))); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case NormalizeMapKey: { | 
 |         if (JSValue key = forNode(node->child1()).value()) { | 
 |             setConstant(node, *m_graph.freeze(normalizeMapKey(key))); | 
 |             break; | 
 |         } | 
 |  | 
 |         SpeculatedType typesNeedingNormalization = (SpecFullNumber & ~SpecInt32Only) | SpecHeapBigInt; | 
 |         if (!(forNode(node->child1()).m_type & typesNeedingNormalization)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             forNode(node) = forNode(node->child1()); | 
 |             break; | 
 |         } | 
 |  | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |     } | 
 |  | 
 |     case StringValueOf: { | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |     } | 
 |  | 
 |     case StringSlice: { | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ToLowerCase: { | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |     } | 
 |  | 
 |     case LoadKeyFromMapBucket: | 
 |     case LoadValueFromMapBucket: | 
 |     case ExtractValueFromWeakMapGet: | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case GetMapBucket: | 
 |     case GetMapBucketHead: | 
 |         if (node->child1().useKind() == MapObjectUse) | 
 |             setForNode(node, m_vm.hashMapBucketMapStructure.get()); | 
 |         else { | 
 |             ASSERT(node->child1().useKind() == SetObjectUse); | 
 |             setForNode(node, m_vm.hashMapBucketSetStructure.get()); | 
 |         } | 
 |         break; | 
 |  | 
 |     case GetMapBucketNext: | 
 |         if (node->bucketOwnerType() == BucketOwnerType::Map) | 
 |             setForNode(node, m_vm.hashMapBucketMapStructure.get()); | 
 |         else { | 
 |             ASSERT(node->bucketOwnerType() == BucketOwnerType::Set); | 
 |             setForNode(node, m_vm.hashMapBucketSetStructure.get()); | 
 |         } | 
 |         break; | 
 |  | 
 |     case SetAdd: | 
 |         setForNode(node, m_vm.hashMapBucketSetStructure.get()); | 
 |         break; | 
 |  | 
 |     case MapSet: | 
 |         setForNode(node, m_vm.hashMapBucketMapStructure.get()); | 
 |         break; | 
 |  | 
 |     case WeakSetAdd: | 
 |     case WeakMapSet: | 
 |         break; | 
 |  | 
 |     case WeakMapGet: | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |  | 
 |     case IsEmpty: | 
 |     case TypeOfIsUndefined: | 
 |     case TypeOfIsObject: | 
 |     case TypeOfIsFunction: | 
 |     case IsUndefinedOrNull: | 
 |     case IsBoolean: | 
 |     case IsNumber: | 
 |     case IsBigInt: | 
 |     case NumberIsInteger: | 
 |     case IsObject: | 
 |     case IsCallable: | 
 |     case IsConstructor: | 
 |     case IsCellWithType: | 
 |     case IsTypedArrayView: { | 
 |         AbstractValue child = forNode(node->child1()); | 
 |         if (child.value()) { | 
 |             bool constantWasSet = true; | 
 |             switch (node->op()) { | 
 |             case IsCellWithType: | 
 |                 setConstant(node, jsBoolean(child.value().isCell() && child.value().asCell()->type() == node->queriedType())); | 
 |                 break; | 
 |             case TypeOfIsUndefined: | 
 |                 setConstant(node, jsBoolean( | 
 |                     child.value().isCell() | 
 |                     ? child.value().asCell()->structure(m_vm)->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node->origin.semantic)) | 
 |                     : child.value().isUndefined())); | 
 |                 break; | 
 |             case TypeOfIsObject: { | 
 |                 TriState result = jsTypeofIsObjectWithConcurrency<Concurrency::ConcurrentThread>(m_codeBlock->globalObjectFor(node->origin.semantic), child.value()); | 
 |                 if (result != TriState::Indeterminate) | 
 |                     setConstant(node, jsBoolean(result == TriState::True)); | 
 |                 else | 
 |                     constantWasSet = false; | 
 |                 break; | 
 |             } | 
 |             case TypeOfIsFunction: { | 
 |                 TriState result = jsTypeofIsFunctionWithConcurrency<Concurrency::ConcurrentThread>(m_codeBlock->globalObjectFor(node->origin.semantic), child.value()); | 
 |                 if (result != TriState::Indeterminate) | 
 |                     setConstant(node, jsBoolean(result == TriState::True)); | 
 |                 else | 
 |                     constantWasSet = false; | 
 |                 break; | 
 |             } | 
 |             case IsUndefinedOrNull: | 
 |                 setConstant(node, jsBoolean(child.value().isUndefinedOrNull())); | 
 |                 break; | 
 |             case IsBoolean: | 
 |                 setConstant(node, jsBoolean(child.value().isBoolean())); | 
 |                 break; | 
 |             case IsNumber: | 
 |                 setConstant(node, jsBoolean(child.value().isNumber())); | 
 |                 break; | 
 |             case IsBigInt: | 
 |                 setConstant(node, jsBoolean(child.value().isBigInt())); | 
 |                 break; | 
 |             case NumberIsInteger: | 
 |                 setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value()))); | 
 |                 break; | 
 |             case IsObject: | 
 |                 setConstant(node, jsBoolean(child.value().isObject())); | 
 |                 break; | 
 |             case IsCallable: { | 
 |                 TriState result = child.value().isCallableWithConcurrency<Concurrency::ConcurrentThread>(m_vm); | 
 |                 if (result != TriState::Indeterminate) | 
 |                     setConstant(node, jsBoolean(result == TriState::True)); | 
 |                 else | 
 |                     constantWasSet = false; | 
 |                 break; | 
 |             } | 
 |             case IsConstructor: { | 
 |                 TriState result = child.value().isConstructorWithConcurrency<Concurrency::ConcurrentThread>(m_vm); | 
 |                 if (result != TriState::Indeterminate) | 
 |                     setConstant(node, jsBoolean(result == TriState::True)); | 
 |                 else | 
 |                     constantWasSet = false; | 
 |                 break; | 
 |             } | 
 |             case IsEmpty: | 
 |                 setConstant(node, jsBoolean(child.value().isEmpty())); | 
 |                 break; | 
 |             case IsTypedArrayView: | 
 |                 setConstant(node, jsBoolean(child.value().isObject() && isTypedView(child.value().getObject()->classInfo(m_vm)->typedArrayStorageType))); | 
 |                 break; | 
 |             default: | 
 |                 constantWasSet = false; | 
 |                 break; | 
 |             } | 
 |             if (constantWasSet) | 
 |                 break; | 
 |         } | 
 |  | 
 |         if (!(child.m_type & ~SpecCell)) { | 
 |             if (child.m_structure.isFinite()) { | 
 |                 bool constantWasSet = false; | 
 |                 switch (node->op()) { | 
 |                 case IsCellWithType: { | 
 |                     bool ok = true; | 
 |                     Optional<bool> result; | 
 |                     child.m_structure.forEach( | 
 |                         [&] (RegisteredStructure structure) { | 
 |                             bool matched = structure->typeInfo().type() == node->queriedType(); | 
 |                             if (!result) | 
 |                                 result = matched; | 
 |                             else { | 
 |                                 if (result.value() != matched) | 
 |                                     ok = false; | 
 |                             } | 
 |                         }); | 
 |                     if (ok && result) { | 
 |                         setConstant(node, jsBoolean(result.value())); | 
 |                         constantWasSet = true; | 
 |                     } | 
 |                     break; | 
 |                 } | 
 |                 default: | 
 |                     break; | 
 |                 } | 
 |                 if (constantWasSet) | 
 |                     break; | 
 |             } | 
 |         } | 
 |  | 
 |         // FIXME: This code should really use AbstractValue::isType() and | 
 |         // AbstractValue::couldBeType(). | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=146870 | 
 |          | 
 |         bool constantWasSet = false; | 
 |         switch (node->op()) { | 
 |         case IsEmpty: { | 
 |             if (child.m_type && !(child.m_type & SpecEmpty)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (child.m_type && !(child.m_type & ~SpecEmpty)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |  | 
 |             break; | 
 |         } | 
 |         case TypeOfIsUndefined: | 
 |             // FIXME: Use the masquerades-as-undefined watchpoint thingy. | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=144456 | 
 |              | 
 |             if (!(child.m_type & (SpecOther | SpecObjectOther))) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |         case TypeOfIsObject: | 
 |             // FIXME: Use the masquerades-as-undefined watchpoint thingy. | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=144456 | 
 |              | 
 |             // These expressions are complicated to parse. A helpful way to parse this is that | 
 |             // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a | 
 |             // disjoint set from S". Things like "T - S" means that, provided that S is a | 
 |             // subset of T, it's the "set of all things in T but not in S". Things like "T | S" | 
 |             // mean the "union of T and S". | 
 |              | 
 |             // Is the child's type an object that isn't an other-object (i.e. object that could | 
 |             // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold | 
 |             // this to true. | 
 |             if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             // Is the child's type definitely not either of: an object that isn't a function, | 
 |             // or either undefined or null? Then: we should fold this to false. This means | 
 |             // for example that if it's any non-function object, including those that have | 
 |             // masquerades-as-undefined traps, then we don't fold. It also means we won't fold | 
 |             // if it's undefined-or-null, since the type bits don't distinguish between | 
 |             // undefined (which should fold to false) and null (which should fold to true). | 
 |             if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |         case IsUndefinedOrNull: | 
 |             if (!(child.m_type & ~SpecOther)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (!(child.m_type & SpecOther)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             break; | 
 |         case IsBoolean: | 
 |             if (!(child.m_type & ~SpecBoolean)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (!(child.m_type & SpecBoolean)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |         case IsNumber: | 
 |             if (!(child.m_type & ~SpecFullNumber)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (!(child.m_type & SpecFullNumber)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |         case IsBigInt: | 
 |             if (!(child.m_type & ~SpecBigInt)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (!(child.m_type & SpecBigInt)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |  | 
 |             // FIXME: if the SpeculatedType informs us that we won't have a BigInt32 (or that we won't have a HeapBigInt), then we can transform this node into a IsCellWithType(HeapBigIntType) (or a hypothetical IsBigInt32 node). | 
 |  | 
 |             break; | 
 |         case NumberIsInteger: | 
 |             if (!(child.m_type & ~SpecInt32Only)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (!(child.m_type & SpecFullNumber)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |  | 
 |         case IsObject: | 
 |             if (!(child.m_type & ~SpecObject)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (!(child.m_type & SpecObject)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             break; | 
 |         case TypeOfIsFunction: | 
 |         case IsCallable: | 
 |             if (!(child.m_type & ~SpecFunction)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (!(child.m_type & (SpecFunction | SpecObjectOther | SpecProxyObject))) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             break; | 
 |  | 
 |         case IsConstructor: | 
 |             // FIXME: We can speculate constructability from child's m_structure. | 
 |             // https://bugs.webkit.org/show_bug.cgi?id=211796 | 
 |             break; | 
 |  | 
 |         case IsCellWithType: { | 
 |             Optional<SpeculatedType> filter = node->speculatedTypeForQuery(); | 
 |             if (!filter) { | 
 |                 if (!(child.m_type & SpecCell)) { | 
 |                     setConstant(node, jsBoolean(false)); | 
 |                     constantWasSet = true; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |             if (!(child.m_type & ~filter.value())) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             if (!(child.m_type & filter.value())) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             break; | 
 |         } | 
 |  | 
 |         case IsTypedArrayView: | 
 |             if (!(child.m_type & ~SpecTypedArrayView)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             if (!(child.m_type & SpecTypedArrayView)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 constantWasSet = true; | 
 |                 break; | 
 |             } | 
 |             break; | 
 |  | 
 |         default: | 
 |             break; | 
 |         } | 
 |         if (constantWasSet) | 
 |             break; | 
 |          | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |  | 
 |     case TypeOf: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         AbstractValue& abstractChild = forNode(node->child1()); | 
 |         if (child) { | 
 |             if (JSString* typeString = jsTypeStringForValueWithConcurrency(m_vm, m_codeBlock->globalObjectFor(node->origin.semantic), child, Concurrency::ConcurrentThread)) { | 
 |                 setConstant(node, *m_graph.freeze(typeString)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         if (isFullNumberSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.numberString())); | 
 |             break; | 
 |         } | 
 |          | 
 |         if (isStringSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.stringString())); | 
 |             break; | 
 |         } | 
 |  | 
 |         // FIXME: We could use the masquerades-as-undefined watchpoint here. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=144456 | 
 |         if (!(abstractChild.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.objectString())); | 
 |             break; | 
 |         } | 
 |          | 
 |         if (isFunctionSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.functionString())); | 
 |             break; | 
 |         } | 
 |          | 
 |         if (isBooleanSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.booleanString())); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (isSymbolSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.symbolString())); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (isBigIntSpeculation(abstractChild.m_type)) { | 
 |             setConstant(node, *m_graph.freeze(m_vm.smallStrings.bigintString())); | 
 |             break; | 
 |         } | 
 |  | 
 |         setTypeForNode(node, SpecStringIdent); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CompareBelow: | 
 |     case CompareBelowEq: { | 
 |         JSValue leftConst = forNode(node->child1()).value(); | 
 |         JSValue rightConst = forNode(node->child2()).value(); | 
 |         if (leftConst && rightConst) { | 
 |             if (leftConst.isInt32() && rightConst.isInt32()) { | 
 |                 uint32_t a = static_cast<uint32_t>(leftConst.asInt32()); | 
 |                 uint32_t b = static_cast<uint32_t>(rightConst.asInt32()); | 
 |                 switch (node->op()) { | 
 |                 case CompareBelow: | 
 |                     setConstant(node, jsBoolean(a < b)); | 
 |                     break; | 
 |                 case CompareBelowEq: | 
 |                     setConstant(node, jsBoolean(a <= b)); | 
 |                     break; | 
 |                 default: | 
 |                     RELEASE_ASSERT_NOT_REACHED(); | 
 |                     break; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         if (node->child1() == node->child2()) { | 
 |             switch (node->op()) { | 
 |             case CompareBelow: | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 break; | 
 |             case CompareBelowEq: | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 break; | 
 |             default: | 
 |                 DFG_CRASH(m_graph, node, "Unexpected node type"); | 
 |                 break; | 
 |             } | 
 |             break; | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CompareLess: | 
 |     case CompareLessEq: | 
 |     case CompareGreater: | 
 |     case CompareGreaterEq: | 
 |     case CompareEq: { | 
 |         bool isClobbering = node->isBinaryUseKind(UntypedUse); | 
 |          | 
 |         if (isClobbering) | 
 |             didFoldClobberWorld(); | 
 |          | 
 |         JSValue leftConst = forNode(node->child1()).value(); | 
 |         JSValue rightConst = forNode(node->child2()).value(); | 
 |         if (leftConst && rightConst) { | 
 |             if (leftConst.isNumber() && rightConst.isNumber()) { | 
 |                 auto compareNumber = [&](double a, double b) { | 
 |                     switch (node->op()) { | 
 |                     case CompareLess: | 
 |                         return jsBoolean(a < b); | 
 |                     case CompareLessEq: | 
 |                         return jsBoolean(a <= b); | 
 |                     case CompareGreater: | 
 |                         return jsBoolean(a > b); | 
 |                     case CompareGreaterEq: | 
 |                         return jsBoolean(a >= b); | 
 |                     case CompareEq: | 
 |                         return jsBoolean(a == b); | 
 |                     default: | 
 |                         RELEASE_ASSERT_NOT_REACHED(); | 
 |                         break; | 
 |                     } | 
 |                 }; | 
 |                 double a = leftConst.asNumber(); | 
 |                 double b = rightConst.asNumber(); | 
 |                 setConstant(node, compareNumber(a, b)); | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (leftConst.isBigInt() && rightConst.isBigInt()) { | 
 |                 switch (node->op()) { | 
 |                 case CompareLess: | 
 |                     setConstant(node, jsBoolean(bigIntCompareResult(compareBigInt(leftConst, rightConst), JSBigInt::ComparisonMode::LessThan))); | 
 |                     break; | 
 |                 case CompareLessEq: | 
 |                     setConstant(node, jsBoolean(bigIntCompareResult(compareBigInt(leftConst, rightConst), JSBigInt::ComparisonMode::LessThanOrEqual))); | 
 |                     break; | 
 |                 case CompareGreater: | 
 |                     setConstant(node, jsBoolean(bigIntCompareResult(compareBigInt(rightConst, leftConst), JSBigInt::ComparisonMode::LessThan))); | 
 |                     break; | 
 |                 case CompareGreaterEq: | 
 |                     setConstant(node, jsBoolean(bigIntCompareResult(compareBigInt(rightConst, leftConst), JSBigInt::ComparisonMode::LessThanOrEqual))); | 
 |                     break; | 
 |                 case CompareEq: | 
 |                     setConstant(node, jsBoolean(compareBigInt(leftConst, rightConst) == JSBigInt::ComparisonResult::Equal)); | 
 |                     break; | 
 |                 default: | 
 |                     RELEASE_ASSERT_NOT_REACHED(); | 
 |                     break; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |              | 
 |             if (leftConst.isString() && rightConst.isString()) { | 
 |                 const StringImpl* a = asString(leftConst)->tryGetValueImpl(); | 
 |                 const StringImpl* b = asString(rightConst)->tryGetValueImpl(); | 
 |                 if (a && b) { | 
 |                     bool result; | 
 |                     if (node->op() == CompareEq) | 
 |                         result = WTF::equal(a, b); | 
 |                     else if (node->op() == CompareLess) | 
 |                         result = codePointCompare(a, b) < 0; | 
 |                     else if (node->op() == CompareLessEq) | 
 |                         result = codePointCompare(a, b) <= 0; | 
 |                     else if (node->op() == CompareGreater) | 
 |                         result = codePointCompare(a, b) > 0; | 
 |                     else if (node->op() == CompareGreaterEq) | 
 |                         result = codePointCompare(a, b) >= 0; | 
 |                     else | 
 |                         RELEASE_ASSERT_NOT_REACHED(); | 
 |                     setConstant(node, jsBoolean(result)); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |  | 
 |             if (node->op() == CompareEq && leftConst.isSymbol() && rightConst.isSymbol()) { | 
 |                 setConstant(node, jsBoolean(asSymbol(leftConst) == asSymbol(rightConst))); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         if (node->op() == CompareEq) { | 
 |             SpeculatedType leftType = forNode(node->child1()).m_type; | 
 |             SpeculatedType rightType = forNode(node->child2()).m_type; | 
 |             if (!valuesCouldBeEqual(leftType, rightType)) { | 
 |                 setConstant(node, jsBoolean(false)); | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (leftType == SpecOther) | 
 |                 std::swap(leftType, rightType); | 
 |             if (rightType == SpecOther) { | 
 |                 // Undefined and Null are always equal when compared to eachother. | 
 |                 if (!(leftType & ~SpecOther)) { | 
 |                     setConstant(node, jsBoolean(true)); | 
 |                     break; | 
 |                 } | 
 |  | 
 |                 // Any other type compared to Null or Undefined is always false | 
 |                 // as long as the MasqueradesAsUndefined watchpoint is valid. | 
 |                 // | 
 |                 // MasqueradesAsUndefined only matters for SpecObjectOther, other | 
 |                 // cases are always "false". | 
 |                 if (!(leftType & (SpecObjectOther | SpecOther))) { | 
 |                     setConstant(node, jsBoolean(false)); | 
 |                     break; | 
 |                 } | 
 |  | 
 |                 if (!(leftType & SpecOther) && m_graph.masqueradesAsUndefinedWatchpointIsStillValid(node->origin.semantic)) { | 
 |                     JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |                     m_graph.watchpoints().addLazily(globalObject->masqueradesAsUndefinedWatchpoint()); | 
 |                     setConstant(node, jsBoolean(false)); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |          | 
 |         if (node->child1() == node->child2()) { | 
 |             if (node->isBinaryUseKind(Int32Use) || | 
 |                 node->isBinaryUseKind(Int52RepUse) || | 
 |                 node->isBinaryUseKind(BigInt32Use) || | 
 |                 node->isBinaryUseKind(HeapBigIntUse) || | 
 |                 node->isBinaryUseKind(AnyBigIntUse) || | 
 |                 node->isBinaryUseKind(StringUse) || | 
 |                 node->isBinaryUseKind(BooleanUse) || | 
 |                 node->isBinaryUseKind(SymbolUse) || | 
 |                 node->isBinaryUseKind(StringIdentUse) || | 
 |                 node->isBinaryUseKind(ObjectUse) || | 
 |                 node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) || | 
 |                 node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) { | 
 |                 switch (node->op()) { | 
 |                 case CompareLess: | 
 |                 case CompareGreater: | 
 |                     setConstant(node, jsBoolean(false)); | 
 |                     break; | 
 |                 case CompareLessEq: | 
 |                 case CompareGreaterEq: | 
 |                 case CompareEq: | 
 |                     setConstant(node, jsBoolean(true)); | 
 |                     break; | 
 |                 default: | 
 |                     DFG_CRASH(m_graph, node, "Unexpected node type"); | 
 |                     break; | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         if (isClobbering) | 
 |             clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |              | 
 |     case CompareStrictEq: | 
 |     case SameValue: { | 
 |         Node* leftNode = node->child1().node(); | 
 |         Node* rightNode = node->child2().node(); | 
 |         JSValue left = forNode(leftNode).value(); | 
 |         JSValue right = forNode(rightNode).value(); | 
 |         if (left && right) { | 
 |             if (left.isString() && right.isString()) { | 
 |                 // We need this case because JSValue::strictEqual is otherwise too racy for | 
 |                 // string comparisons. | 
 |                 const StringImpl* a = asString(left)->tryGetValueImpl(); | 
 |                 const StringImpl* b = asString(right)->tryGetValueImpl(); | 
 |                 if (a && b) { | 
 |                     setConstant(node, jsBoolean(WTF::equal(a, b))); | 
 |                     break; | 
 |                 } | 
 |             } else { | 
 |                 if (node->op() == CompareStrictEq) | 
 |                     setConstant(node, jsBoolean(JSValue::strictEqual(nullptr, left, right))); | 
 |                 else | 
 |                     setConstant(node, jsBoolean(sameValue(nullptr, left, right))); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         // FIXME: why is this check here, and not later (after the type-based replacement by false). | 
 |         // Saam seems to agree that the two checks could be switched, I'll try that in a separate patch | 
 |         if (node->isBinaryUseKind(UntypedUse)) { | 
 |             auto isNonStringAndNonBigIntCellConstant = [] (JSValue value) { | 
 |                 return value && value.isCell() && !value.isString() && !value.isHeapBigInt(); | 
 |             }; | 
 |  | 
 |             if (isNonStringAndNonBigIntCellConstant(left) || isNonStringAndNonBigIntCellConstant(right)) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 setNonCellTypeForNode(node, SpecBoolean); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         SpeculatedType leftLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(leftNode).m_type); | 
 |         SpeculatedType rightLUB = leastUpperBoundOfStrictlyEquivalentSpeculations(forNode(rightNode).m_type); | 
 |         if (!(leftLUB & rightLUB)) { | 
 |             setConstant(node, jsBoolean(false)); | 
 |             break; | 
 |         } | 
 |          | 
 |         if (node->child1() == node->child2()) { | 
 |             // FIXME: Is there any case not involving NaN where x === x is not guaranteed to return true? | 
 |             // If not I might slightly simplify that check. | 
 |             if (node->isBinaryUseKind(BooleanUse) | 
 |                 || node->isBinaryUseKind(Int32Use) | 
 |                 || node->isBinaryUseKind(Int52RepUse) | 
 |                 || node->isBinaryUseKind(StringUse) | 
 |                 || node->isBinaryUseKind(StringIdentUse) | 
 |                 || node->isBinaryUseKind(SymbolUse) | 
 |                 || node->isBinaryUseKind(ObjectUse) | 
 |                 || node->isBinaryUseKind(MiscUse, UntypedUse) | 
 |                 || node->isBinaryUseKind(UntypedUse, MiscUse) | 
 |                 || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) | 
 |                 || node->isBinaryUseKind(NotStringVarUse, StringIdentUse) | 
 |                 || node->isBinaryUseKind(StringUse, UntypedUse) | 
 |                 || node->isBinaryUseKind(UntypedUse, StringUse) | 
 |                 || node->isBinaryUseKind(BigInt32Use) | 
 |                 || node->isBinaryUseKind(HeapBigIntUse) | 
 |                 || node->isBinaryUseKind(AnyBigIntUse)) { | 
 |                 setConstant(node, jsBoolean(true)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |          | 
 |     case CompareEqPtr: { | 
 |         Node* childNode = node->child1().node(); | 
 |         JSValue childValue = forNode(childNode).value(); | 
 |         if (childValue) { | 
 |             setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell())); | 
 |             break; | 
 |         } | 
 |          | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |          | 
 |     case StringCharCodeAt: | 
 |     case StringCodePointAt: | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |          | 
 |     case StringFromCharCode: | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |             break; | 
 |         case UntypedUse: | 
 |             clobberWorld(); | 
 |             break; | 
 |         default: | 
 |             DFG_CRASH(m_graph, node, "Bad use kind"); | 
 |             break; | 
 |         } | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |  | 
 |     case StringCharAt: | 
 |         setForNode(node, m_vm.stringStructure.get()); | 
 |         break; | 
 |              | 
 |     case GetByVal: | 
 |     case AtomicsAdd: | 
 |     case AtomicsAnd: | 
 |     case AtomicsCompareExchange: | 
 |     case AtomicsExchange: | 
 |     case AtomicsLoad: | 
 |     case AtomicsOr: | 
 |     case AtomicsStore: | 
 |     case AtomicsSub: | 
 |     case AtomicsXor: { | 
 |         if (node->op() == GetByVal) { | 
 |             auto foldGetByValOnConstantProperty = [&] (Edge& arrayEdge, Edge& indexEdge) { | 
 |                 // FIXME: We can expand this for non x86 environments. | 
 |                 // https://bugs.webkit.org/show_bug.cgi?id=134641 | 
 |                 if (!isX86()) | 
 |                     return false; | 
 |  | 
 |                 AbstractValue& arrayValue = forNode(arrayEdge); | 
 |  | 
 |                 // Check the structure set is finite. This means that this constant's structure is watched and guaranteed the one of this set. | 
 |                 // When the structure is changed, this code should be invalidated. This is important since the following code relies on the | 
 |                 // constant object's is not changed. | 
 |                 if (!arrayValue.m_structure.isFinite()) | 
 |                     return false; | 
 |  | 
 |                 JSValue arrayConstant = arrayValue.value(); | 
 |                 if (!arrayConstant) | 
 |                     return false; | 
 |  | 
 |                 JSObject* array = jsDynamicCast<JSObject*>(m_vm, arrayConstant); | 
 |                 if (!array) | 
 |                     return false; | 
 |  | 
 |                 JSValue indexConstant = forNode(indexEdge).value(); | 
 |                 if (!indexConstant || !indexConstant.isInt32() || indexConstant.asInt32() < 0) | 
 |                     return false; | 
 |                 uint32_t index = indexConstant.asUInt32(); | 
 |  | 
 |                 // Check that the early StructureID is not nuked, get the butterfly, and check the late StructureID again. | 
 |                 // And we check the indexing mode of the structure. If the indexing mode is CoW, the butterfly is | 
 |                 // definitely JSImmutableButterfly. | 
 |                 StructureID structureIDEarly = array->structureID(); | 
 |                 if (isNuked(structureIDEarly)) | 
 |                     return false; | 
 |  | 
 |                 if (node->arrayMode().arrayClass() == Array::OriginalCopyOnWriteArray) { | 
 |  | 
 |                     WTF::loadLoadFence(); | 
 |                     Butterfly* butterfly = array->butterfly(); | 
 |  | 
 |                     WTF::loadLoadFence(); | 
 |                     StructureID structureIDLate = array->structureID(); | 
 |  | 
 |                     if (structureIDEarly != structureIDLate) | 
 |                         return false; | 
 |  | 
 |                     Structure* structure = m_vm.getStructure(structureIDLate); | 
 |                     switch (node->arrayMode().type()) { | 
 |                     case Array::Int32: | 
 |                     case Array::Contiguous: | 
 |                     case Array::Double: | 
 |                         if (structure->indexingMode() != (toIndexingShape(node->arrayMode().type()) | CopyOnWrite | IsArray)) | 
 |                             return false; | 
 |                         break; | 
 |                     default: | 
 |                         return false; | 
 |                     } | 
 |                     ASSERT(isCopyOnWrite(structure->indexingMode())); | 
 |  | 
 |                     JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::fromButterfly(butterfly); | 
 |                     if (index < immutableButterfly->length()) { | 
 |                         JSValue value = immutableButterfly->get(index); | 
 |                         ASSERT(value); | 
 |                         if (value.isCell()) | 
 |                             setConstant(node, *m_graph.freeze(value.asCell())); | 
 |                         else | 
 |                             setConstant(node, value); | 
 |                         return true; | 
 |                     } | 
 |  | 
 |                     if (node->arrayMode().isOutOfBounds()) { | 
 |                         JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |                         Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(m_vm); | 
 |                         Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(m_vm); | 
 |                         if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid() | 
 |                             && objectPrototypeStructure->transitionWatchpointSetIsStillValid() | 
 |                             && globalObject->arrayPrototypeChainIsSane()) { | 
 |                             m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); | 
 |                             m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); | 
 |                             if (node->arrayMode().type() == Array::Double && node->arrayMode().isOutOfBoundsSaneChain() && !(node->flags() & NodeBytecodeUsesAsOther)) | 
 |                                 setConstant(node, jsNumber(PNaN)); | 
 |                             else | 
 |                                 setConstant(node, jsUndefined()); | 
 |                             return true; | 
 |                         } | 
 |                     } | 
 |                     return false; | 
 |                 } | 
 |  | 
 |                 if (node->arrayMode().type() == Array::ArrayStorage || node->arrayMode().type() == Array::SlowPutArrayStorage) { | 
 |                     JSValue value; | 
 |                     { | 
 |                         // ArrayStorage's Butterfly can be half-broken state. | 
 |                         auto locker = holdLock(array->cellLock()); | 
 |  | 
 |                         WTF::loadLoadFence(); | 
 |                         Butterfly* butterfly = array->butterfly(); | 
 |  | 
 |                         WTF::loadLoadFence(); | 
 |                         StructureID structureIDLate = array->structureID(); | 
 |  | 
 |                         if (structureIDEarly != structureIDLate) | 
 |                             return false; | 
 |  | 
 |                         Structure* structure = m_vm.getStructure(structureIDLate); | 
 |                         if (!hasAnyArrayStorage(structure->indexingMode())) | 
 |                             return false; | 
 |  | 
 |                         if (structure->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) | 
 |                             return false; | 
 |  | 
 |                         ArrayStorage* storage = butterfly->arrayStorage(); | 
 |                         if (index >= storage->length()) | 
 |                             return false; | 
 |  | 
 |                         if (index < storage->vectorLength()) | 
 |                             return false; | 
 |  | 
 |                         SparseArrayValueMap* map = storage->m_sparseMap.get(); | 
 |                         if (!map) | 
 |                             return false; | 
 |  | 
 |                         value = map->getConcurrently(index); | 
 |                     } | 
 |                     if (!value) | 
 |                         return false; | 
 |  | 
 |                     if (value.isCell()) | 
 |                         setConstant(node, *m_graph.freeze(value.asCell())); | 
 |                     else | 
 |                         setConstant(node, value); | 
 |                     return true; | 
 |                 } | 
 |  | 
 |                 return false; | 
 |             }; | 
 |  | 
 |             bool didFold = false; | 
 |             switch (node->arrayMode().type()) { | 
 |             case Array::Generic: | 
 |             case Array::Int32: | 
 |             case Array::Double: | 
 |             case Array::Contiguous: | 
 |             case Array::ArrayStorage: | 
 |             case Array::SlowPutArrayStorage: | 
 |                 if (foldGetByValOnConstantProperty(m_graph.child(node, 0), m_graph.child(node, 1))) { | 
 |                     if (node->arrayMode().isEffectfulOutOfBounds()) | 
 |                         didFoldClobberWorld(); | 
 |                     didFold = true; | 
 |                 } | 
 |                 break; | 
 |             default: | 
 |                 break; | 
 |             } | 
 |  | 
 |             if (didFold) | 
 |                 break; | 
 |         } | 
 |  | 
 |         if (node->op() != GetByVal) { | 
 |             unsigned numExtraArgs = numExtraAtomicsArgs(node->op()); | 
 |             Edge storageEdge = m_graph.child(node, 2 + numExtraArgs); | 
 |             if (!storageEdge) | 
 |                 clobberWorld(); | 
 |         } | 
 |         switch (node->arrayMode().type()) { | 
 |         case Array::SelectUsingPredictions: | 
 |         case Array::Unprofiled: | 
 |         case Array::SelectUsingArguments: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         case Array::ForceExit: | 
 |             m_state.setIsValid(false); | 
 |             break; | 
 |         case Array::Undecided: { | 
 |             JSValue index = forNode(m_graph.child(node, 1)).value(); | 
 |             if (index && index.isInt32() && index.asInt32() >= 0) { | 
 |                 setConstant(node, jsUndefined()); | 
 |                 break; | 
 |             } | 
 |             setNonCellTypeForNode(node, SpecOther); | 
 |             break; | 
 |         } | 
 |         case Array::Generic: | 
 |             clobberWorld(); | 
 |             makeHeapTopForNode(node); | 
 |             break; | 
 |         case Array::String: | 
 |             if (node->arrayMode().isOutOfBounds()) { | 
 |                 // If the watchpoint was still valid we could totally set this to be | 
 |                 // SpecString | SpecOther. Except that we'd have to be careful. If we | 
 |                 // tested the watchpoint state here then it could change by the time | 
 |                 // we got to the backend. So to do this right, we'd have to get the | 
 |                 // fixup phase to check the watchpoint state and then bake into the | 
 |                 // GetByVal operation the fact that we're using a watchpoint, using | 
 |                 // something like Array::InBoundsSaneChain (except not quite, because that | 
 |                 // implies an in-bounds access). None of this feels like it's worth it, | 
 |                 // so we're going with TOP for now. The same thing applies to | 
 |                 // clobbering the world. | 
 |                 clobberWorld(); | 
 |                 makeHeapTopForNode(node); | 
 |             } else | 
 |                 setForNode(node, m_vm.stringStructure.get()); | 
 |             break; | 
 |         case Array::DirectArguments: | 
 |         case Array::ScopedArguments: | 
 |             if (node->arrayMode().isOutOfBounds()) | 
 |                 clobberWorld(); | 
 |             makeHeapTopForNode(node); | 
 |             break; | 
 |         case Array::Int32: | 
 |             if (node->arrayMode().isEffectfulOutOfBounds()) { | 
 |                 clobberWorld(); | 
 |                 makeHeapTopForNode(node); | 
 |             } else if (node->arrayMode().isOutOfBoundsSaneChain()) | 
 |                 setNonCellTypeForNode(node, SpecInt32Only | SpecOther); | 
 |             else | 
 |                 setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Double: | 
 |             if (node->arrayMode().isEffectfulOutOfBounds()) { | 
 |                 clobberWorld(); | 
 |                 makeHeapTopForNode(node); | 
 |             } else if (node->arrayMode().isInBoundsSaneChain()) | 
 |                 setNonCellTypeForNode(node, SpecBytecodeDouble); | 
 |             else if (node->arrayMode().isOutOfBoundsSaneChain()) { | 
 |                 if (!!(node->flags() & NodeBytecodeUsesAsOther)) | 
 |                     setNonCellTypeForNode(node, SpecBytecodeDouble | SpecOther); | 
 |                 else | 
 |                     setNonCellTypeForNode(node, SpecBytecodeDouble); | 
 |             } else | 
 |                 setNonCellTypeForNode(node, SpecDoubleReal); | 
 |             break; | 
 |         case Array::Contiguous: | 
 |         case Array::ArrayStorage: | 
 |         case Array::SlowPutArrayStorage: | 
 |             if (node->arrayMode().isEffectfulOutOfBounds()) | 
 |                 clobberWorld(); | 
 |             makeHeapTopForNode(node); | 
 |             break; | 
 |         case Array::Int8Array: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Int16Array: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Int32Array: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Uint8Array: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Uint8ClampedArray: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Uint16Array: | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         case Array::Uint32Array: | 
 |             if (node->shouldSpeculateInt32()) | 
 |                 setNonCellTypeForNode(node, SpecInt32Only); | 
 |             else if (node->shouldSpeculateInt52()) | 
 |                 setNonCellTypeForNode(node, SpecInt52Any); | 
 |             else | 
 |                 setNonCellTypeForNode(node, SpecAnyIntAsDouble); | 
 |             break; | 
 |         case Array::Float32Array: | 
 |             setNonCellTypeForNode(node, SpecFullDouble); | 
 |             break; | 
 |         case Array::Float64Array: | 
 |             setNonCellTypeForNode(node, SpecFullDouble); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case PutByValDirect: | 
 |     case PutByVal: | 
 |     case PutByValAlias: { | 
 |         switch (node->arrayMode().modeForPut().type()) { | 
 |         case Array::ForceExit: | 
 |             m_state.setIsValid(false); | 
 |             break; | 
 |         case Array::Generic: | 
 |             clobberWorld(); | 
 |             break; | 
 |         case Array::Int32: | 
 |             if (node->arrayMode().isOutOfBounds()) | 
 |                 clobberWorld(); | 
 |             break; | 
 |         case Array::Double: | 
 |             if (node->arrayMode().isOutOfBounds()) | 
 |                 clobberWorld(); | 
 |             break; | 
 |         case Array::Contiguous: | 
 |         case Array::ArrayStorage: | 
 |             if (node->arrayMode().isOutOfBounds()) | 
 |                 clobberWorld(); | 
 |             break; | 
 |         case Array::SlowPutArrayStorage: | 
 |             if (node->arrayMode().mayStoreToHole()) | 
 |                 clobberWorld(); | 
 |             break; | 
 |         default: | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArrayPush: | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |         break; | 
 |  | 
 |     case ArraySlice: { | 
 |         JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |  | 
 |         // FIXME: We could do better here if we prove that the | 
 |         // incoming value has only a single structure. | 
 |         RegisteredStructureSet structureSet; | 
 |         structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32))); | 
 |         structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous))); | 
 |         structureSet.add(m_graph.registerStructure(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble))); | 
 |  | 
 |         setForNode(node, structureSet); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ArrayIndexOf: { | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |              | 
 |     case ArrayPop: | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |          | 
 |     case GetMyArgumentByVal: | 
 |     case GetMyArgumentByValOutOfBounds: { | 
 |         JSValue index = forNode(node->child2()).m_value; | 
 |         InlineCallFrame* inlineCallFrame = node->child1()->origin.semantic.inlineCallFrame(); | 
 |  | 
 |         if (index && index.isUInt32()) { | 
 |             // This pretends to return TOP for accesses that are actually proven out-of-bounds because | 
 |             // that's the conservative thing to do. Otherwise we'd need to write more code to mark such | 
 |             // paths as unreachable, or to return undefined. We could implement that eventually. | 
 |  | 
 |             Checked<unsigned, RecordOverflow> argumentIndexChecked = index.asUInt32(); | 
 |             argumentIndexChecked += node->numberOfArgumentsToSkip(); | 
 |             unsigned argumentIndex; | 
 |             if (argumentIndexChecked.safeGet(argumentIndex) != CheckedState::DidOverflow) { | 
 |                 if (inlineCallFrame) { | 
 |                     if (argumentIndex < static_cast<unsigned>(inlineCallFrame->argumentCountIncludingThis - 1)) { | 
 |                         setForNode(node, m_state.operand( | 
 |                             virtualRegisterForArgumentIncludingThis(argumentIndex + 1) + inlineCallFrame->stackOffset)); | 
 |                         m_state.setShouldTryConstantFolding(true); | 
 |                         break; | 
 |                     } | 
 |                 } else { | 
 |                     if (argumentIndex < m_state.numberOfArguments() - 1) { | 
 |                         setForNode(node, m_state.argument(argumentIndex + 1)); | 
 |                         m_state.setShouldTryConstantFolding(true); | 
 |                         break; | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |          | 
 |         if (inlineCallFrame) { | 
 |             // We have a bound on the types even though it's random access. Take advantage of this. | 
 |              | 
 |             AbstractValue result; | 
 |             for (unsigned i = 1 + node->numberOfArgumentsToSkip(); i < inlineCallFrame->argumentCountIncludingThis; ++i) { | 
 |                 result.merge( | 
 |                     m_state.operand( | 
 |                         virtualRegisterForArgumentIncludingThis(i) + inlineCallFrame->stackOffset)); | 
 |             } | 
 |              | 
 |             if (node->op() == GetMyArgumentByValOutOfBounds) | 
 |                 result.merge(SpecOther); | 
 |              | 
 |             if (result.value()) | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |              | 
 |             setForNode(node, result); | 
 |             break; | 
 |         } | 
 |          | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |     } | 
 |              | 
 |     case RegExpExec: | 
 |     case RegExpExecNonGlobalOrSticky: | 
 |         if (node->op() == RegExpExec) { | 
 |             // Even if we've proven known input types as RegExpObject and String, | 
 |             // accessing lastIndex is effectful if it's a global regexp. | 
 |             clobberWorld(); | 
 |         } | 
 |  | 
 |         if (JSValue globalObjectValue = forNode(node->child1()).m_value) { | 
 |             if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(m_vm, globalObjectValue)) { | 
 |                 if (!globalObject->isHavingABadTime()) { | 
 |                     m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint()); | 
 |                     RegisteredStructureSet structureSet; | 
 |                     structureSet.add(m_graph.registerStructure(globalObject->regExpMatchesArrayStructure())); | 
 |                     setForNode(node, structureSet); | 
 |                     forNode(node).merge(SpecOther); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |         setTypeForNode(node, SpecOther | SpecArray); | 
 |         break; | 
 |  | 
 |     case RegExpTest: | 
 |         // Even if we've proven known input types as RegExpObject and String, | 
 |         // accessing lastIndex is effectful if it's a global regexp. | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |  | 
 |     case RegExpMatchFast: | 
 |         ASSERT(node->child2().useKind() == RegExpObjectUse); | 
 |         ASSERT(node->child3().useKind() == StringUse || node->child3().useKind() == KnownStringUse); | 
 |         setTypeForNode(node, SpecOther | SpecArray); | 
 |         break; | 
 |  | 
 |     case RegExpMatchFastGlobal: | 
 |         ASSERT(node->child2().useKind() == StringUse || node->child2().useKind() == KnownStringUse); | 
 |         setTypeForNode(node, SpecOther | SpecArray); | 
 |         break; | 
 |              | 
 |     case StringReplace: | 
 |     case StringReplaceRegExp: | 
 |         if (node->child1().useKind() == StringUse | 
 |             && node->child2().useKind() == RegExpObjectUse | 
 |             && node->child3().useKind() == StringUse) { | 
 |             // This doesn't clobber the world. It just reads and writes regexp state. | 
 |         } else | 
 |             clobberWorld(); | 
 |         setForNode(node, m_vm.stringStructure.get()); | 
 |         break; | 
 |  | 
 |     case Jump: | 
 |         break; | 
 |              | 
 |     case Branch: { | 
 |         Node* child = node->child1().node(); | 
 |         switch (booleanResult(node, forNode(child))) { | 
 |         case TriState::True: | 
 |             m_state.setBranchDirection(TakeTrue); | 
 |             break; | 
 |         case TriState::False: | 
 |             m_state.setBranchDirection(TakeFalse); | 
 |             break; | 
 |         case TriState::Indeterminate: | 
 |             // FIXME: The above handles the trivial cases of sparse conditional | 
 |             // constant propagation, but we can do better: | 
 |             // We can specialize the source variable's value on each direction of | 
 |             // the branch. | 
 |             m_state.setBranchDirection(TakeBoth); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case Switch: { | 
 |         // Nothing to do for now. | 
 |         // FIXME: Do sparse conditional things. | 
 |         break; | 
 |     } | 
 |  | 
 |     case EntrySwitch: | 
 |         break; | 
 |  | 
 |     case Return: | 
 |         m_state.setIsValid(false); | 
 |         break; | 
 |  | 
 |     case Throw: | 
 |     case ThrowStaticError: | 
 |     case TailCall: | 
 |     case DirectTailCall: | 
 |     case TailCallVarargs: | 
 |     case TailCallForwardVarargs: | 
 |         clobberWorld(); | 
 |         m_state.setIsValid(false); | 
 |         break; | 
 |          | 
 |     case ToPrimitive: { | 
 |         JSValue childConst = forNode(node->child1()).value(); | 
 |         if (childConst && childConst.isNumber()) { | 
 |             didFoldClobberWorld(); | 
 |             setConstant(node, childConst); | 
 |             break; | 
 |         } | 
 |          | 
 |         ASSERT(node->child1().useKind() == UntypedUse); | 
 |          | 
 |         if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol | SpecBigInt))) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             didFoldClobberWorld(); | 
 |             setForNode(node, forNode(node->child1())); | 
 |             break; | 
 |         } | 
 |          | 
 |         clobberWorld(); | 
 |          | 
 |         setTypeForNode(node, SpecHeapTop & ~SpecObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ToPropertyKey: { | 
 |         if (!(forNode(node->child1()).m_type & ~(SpecString | SpecSymbol))) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             didFoldClobberWorld(); | 
 |             setForNode(node, forNode(node->child1())); | 
 |             break; | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |  | 
 |         setTypeForNode(node, SpecString | SpecSymbol); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ToNumber: { | 
 |         JSValue childConst = forNode(node->child1()).value(); | 
 |         if (childConst && childConst.isNumber()) { | 
 |             didFoldClobberWorld(); | 
 |             setConstant(node, childConst); | 
 |             break; | 
 |         } | 
 |  | 
 |         ASSERT(node->child1().useKind() == UntypedUse); | 
 |  | 
 |         if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             didFoldClobberWorld(); | 
 |             setForNode(node, forNode(node->child1())); | 
 |             break; | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ToNumeric: { | 
 |         JSValue childConst = forNode(node->child1()).value(); | 
 |         if (childConst && (childConst.isNumber() || childConst.isBigInt())) { | 
 |             didFoldClobberWorld(); | 
 |             if (childConst.isCell()) | 
 |                 setConstant(node, *m_graph.freeze(childConst.asCell())); | 
 |             else | 
 |                 setConstant(node, childConst); | 
 |             break; | 
 |         } | 
 |  | 
 |         ASSERT(node->child1().useKind() == UntypedUse); | 
 |  | 
 |         if (!(forNode(node->child1()).m_type & ~(SpecBytecodeNumber | SpecBigInt))) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             didFoldClobberWorld(); | 
 |             setForNode(node, forNode(node->child1())); | 
 |             break; | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CallNumberConstructor: { | 
 |         JSValue childConst = forNode(node->child1()).value(); | 
 |         if (childConst) { | 
 |             if (childConst.isNumber()) { | 
 |                 if (node->child1().useKind() == UntypedUse) | 
 |                     didFoldClobberWorld(); | 
 |                 setConstant(node, childConst); | 
 |                 break; | 
 |             } | 
 | #if USE(BIGINT32) | 
 |             if (childConst.isBigInt32()) { | 
 |                 if (node->child1().useKind() == UntypedUse) | 
 |                     didFoldClobberWorld(); | 
 |                 setConstant(node, jsNumber(childConst.bigInt32AsInt32())); | 
 |                 break; | 
 |             } | 
 | #endif | 
 |         } | 
 |  | 
 |         ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == BigInt32Use); | 
 |  | 
 |         if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             if (node->child1().useKind() == UntypedUse) | 
 |                 didFoldClobberWorld(); | 
 |             setForNode(node, forNode(node->child1())); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (node->child1().useKind() == BigInt32Use) { | 
 |             setTypeForNode(node, SpecInt32Only); | 
 |             break; | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |         break; | 
 |     } | 
 |          | 
 |     case ToString: | 
 |     case CallStringConstructor: { | 
 |         switch (node->child1().useKind()) { | 
 |         case StringObjectUse: | 
 |         case StringOrStringObjectUse: | 
 |         case Int32Use: | 
 |         case Int52RepUse: | 
 |         case DoubleRepUse: | 
 |         case NotCellUse: | 
 |             break; | 
 |         case CellUse: | 
 |         case UntypedUse: | 
 |             clobberWorld(); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         setForNode(node, m_vm.stringStructure.get()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case NumberToStringWithRadix: { | 
 |         JSValue radixValue = forNode(node->child2()).m_value; | 
 |         if (radixValue && radixValue.isInt32()) { | 
 |             int32_t radix = radixValue.asInt32(); | 
 |             if (2 <= radix && radix <= 36) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 didFoldClobberWorld(); | 
 |                 setForNode(node, m_graph.m_vm.stringStructure.get()); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         clobberWorld(); | 
 |         setForNode(node, m_graph.m_vm.stringStructure.get()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case NumberToStringWithValidRadixConstant: { | 
 |         setForNode(node, m_graph.m_vm.stringStructure.get()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case NewStringObject: { | 
 |         ASSERT(node->structure()->classInfo() == StringObject::info()); | 
 |         setForNode(node, node->structure()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case NewSymbol: { | 
 |         setForNode(node, m_vm.symbolStructure.get()); | 
 |         break; | 
 |     } | 
 |              | 
 |     case NewArray: | 
 |         ASSERT(node->indexingMode() == node->indexingType()); // Copy on write arrays should only be created by NewArrayBuffer. | 
 |         setForNode(node, | 
 |             m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType())); | 
 |         break; | 
 |  | 
 |     case NewArrayWithSpread: | 
 |         if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { | 
 |             // We've compiled assuming we're not having a bad time, so to be consistent | 
 |             // with StructureRegisterationPhase we must say we produce an original array | 
 |             // allocation structure. | 
 | #if USE(JSVALUE64) | 
 |             BitVector* bitVector = node->bitVector(); | 
 |             if (node->numChildren() == 1 && bitVector->get(0)) { | 
 |                 Edge use = m_graph.varArgChild(node, 0); | 
 |                 if (use->op() == PhantomSpread) { | 
 |                     if (use->child1()->op() == PhantomNewArrayBuffer) { | 
 |                         auto* immutableButterfly = use->child1()->castOperand<JSImmutableButterfly*>(); | 
 |                         if (hasContiguous(immutableButterfly->indexingType())) { | 
 |                             m_state.setShouldTryConstantFolding(true); | 
 |                             setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous)); | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                 } else { | 
 |                     setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous)); | 
 |                     break; | 
 |                 } | 
 |             } | 
 | #endif | 
 |             setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->originalArrayStructureForIndexingType(ArrayWithContiguous)); | 
 |         } else { | 
 |             setForNode(node,  | 
 |                 m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous)); | 
 |         } | 
 |  | 
 |         break; | 
 |  | 
 |     case Spread: | 
 |         switch (node->child1()->op()) { | 
 |         case PhantomNewArrayBuffer: | 
 |         case PhantomCreateRest: | 
 |             break; | 
 |         default: | 
 |             if (!m_graph.canDoFastSpread(node, forNode(node->child1()))) | 
 |                 clobberWorld(); | 
 |             else | 
 |                 didFoldClobberWorld(); | 
 |             break; | 
 |         } | 
 |  | 
 |         setForNode(node, m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get()); | 
 |         break; | 
 |          | 
 |     case NewArrayBuffer: | 
 |         setForNode(node, | 
 |             m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingMode())); | 
 |         break; | 
 |  | 
 |     case NewArrayWithSize: | 
 |         setTypeForNode(node, SpecArray); | 
 |         break; | 
 |          | 
 |     case NewTypedArray: | 
 |         switch (node->child1().useKind()) { | 
 |         case Int32Use: | 
 |             break; | 
 |         case UntypedUse: | 
 |             clobberWorld(); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         setForNode(node,  | 
 |             m_graph.globalObjectFor(node->origin.semantic)->typedArrayStructureConcurrently( | 
 |                 node->typedArrayType())); | 
 |         break; | 
 |          | 
 |     case NewRegexp: | 
 |         setForNode(node, m_graph.globalObjectFor(node->origin.semantic)->regExpStructure()); | 
 |         break; | 
 |              | 
 |     case ToThis: { | 
 |         AbstractValue& source = forNode(node->child1()); | 
 |         AbstractValue& destination = forNode(node); | 
 |         ECMAMode ecmaMode = node->ecmaMode(); | 
 |  | 
 |         ToThisResult result = isToThisAnIdentity(m_vm, ecmaMode, source); | 
 |         switch (result) { | 
 |         case ToThisResult::Identity: | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             destination = source; | 
 |             break; | 
 |         case ToThisResult::Undefined: | 
 |             setConstant(node, jsUndefined()); | 
 |             break; | 
 |         case ToThisResult::GlobalThis: | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             destination.setType(m_graph, SpecObject); | 
 |             break; | 
 |         case ToThisResult::Dynamic: | 
 |             if (ecmaMode.isStrict()) | 
 |                 destination.makeHeapTop(); | 
 |             else { | 
 |                 destination = source; | 
 |                 destination.merge(SpecObject); | 
 |             } | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case CreateThis: { | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             if (auto* function = jsDynamicCast<JSFunction*>(m_vm, base)) { | 
 |                 if (FunctionRareData* rareData = function->rareData()) { | 
 |                     if (rareData->allocationProfileWatchpointSet().isStillValid()) { | 
 |                         if (Structure* structure = rareData->objectAllocationStructure()) { | 
 |                             m_graph.freeze(rareData); | 
 |                             m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet()); | 
 |                             m_state.setShouldTryConstantFolding(true); | 
 |                             didFoldClobberWorld(); | 
 |                             setForNode(node, structure); | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecFinalObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CreatePromise: { | 
 |         JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             if (base == (node->isInternalPromise() ? globalObject->internalPromiseConstructor() : globalObject->promiseConstructor())) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 didFoldClobberWorld(); | 
 |                 setForNode(node, node->isInternalPromise() ? globalObject->internalPromiseStructure() : globalObject->promiseStructure()); | 
 |                 break; | 
 |             } | 
 |             if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) { | 
 |                 if (FunctionRareData* rareData = function->rareData()) { | 
 |                     if (rareData->allocationProfileWatchpointSet().isStillValid()) { | 
 |                         Structure* structure = rareData->internalFunctionAllocationStructure(); | 
 |                         if (structure | 
 |                             && structure->classInfo() == (node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info()) | 
 |                             && structure->globalObject() == globalObject | 
 |                             && rareData->allocationProfileWatchpointSet().isStillValid()) { | 
 |                             m_graph.freeze(rareData); | 
 |                             m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet()); | 
 |                             m_state.setShouldTryConstantFolding(true); | 
 |                             didFoldClobberWorld(); | 
 |                             setForNode(node, structure); | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecPromiseObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CreateGenerator: | 
 |     case CreateAsyncGenerator: { | 
 |         auto tryToFold = [&] (const ClassInfo* classInfo) -> bool { | 
 |             JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |             if (JSValue base = forNode(node->child1()).m_value) { | 
 |                 if (auto* function = jsDynamicCast<JSFunction*>(m_graph.m_vm, base)) { | 
 |                     if (FunctionRareData* rareData = function->rareData()) { | 
 |                         if (rareData->allocationProfileWatchpointSet().isStillValid()) { | 
 |                             Structure* structure = rareData->internalFunctionAllocationStructure(); | 
 |                             if (structure | 
 |                                 && structure->classInfo() == classInfo | 
 |                                 && structure->globalObject() == globalObject | 
 |                                 && rareData->allocationProfileWatchpointSet().isStillValid()) { | 
 |                                 m_graph.freeze(rareData); | 
 |                                 m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet()); | 
 |                                 m_state.setShouldTryConstantFolding(true); | 
 |                                 didFoldClobberWorld(); | 
 |                                 setForNode(node, structure); | 
 |                                 return true; | 
 |                             } | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |             return false; | 
 |         }; | 
 |  | 
 |         bool found = false; | 
 |         switch (node->op()) { | 
 |         case CreateGenerator: | 
 |             found = tryToFold(JSGenerator::info()); | 
 |             break; | 
 |         case CreateAsyncGenerator: | 
 |             found = tryToFold(JSAsyncGenerator::info()); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         if (found) | 
 |             break; | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecObjectOther); | 
 |         break; | 
 |     } | 
 |  | 
 |     case NewGenerator: | 
 |     case NewAsyncGenerator:     | 
 |     case NewInternalFieldObject: | 
 |     case NewObject: | 
 |     case MaterializeNewInternalFieldObject: | 
 |         ASSERT(!!node->structure().get()); | 
 |         setForNode(node, node->structure()); | 
 |         break; | 
 |  | 
 |     case ObjectCreate: { | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic); | 
 |             Structure* structure = nullptr; | 
 |             if (base.isNull()) | 
 |                 structure = globalObject->nullPrototypeObjectStructure(); | 
 |             else if (base.isObject()) | 
 |                 structure = m_vm.structureCache.emptyObjectStructureConcurrently(globalObject, base.getObject(), JSFinalObject::defaultInlineCapacity()); | 
 |              | 
 |             if (structure) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 if (node->child1().useKind() == UntypedUse) | 
 |                     didFoldClobberWorld(); | 
 |                 setForNode(node, structure); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         if (node->child1().useKind() == UntypedUse) | 
 |             clobberWorld(); | 
 |         setTypeForNode(node, SpecFinalObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ObjectGetOwnPropertyNames: | 
 |     case ObjectKeys: { | 
 |         if (node->child1().useKind() == ObjectUse) { | 
 |             auto& structureSet = forNode(node->child1()).m_structure; | 
 |             if (structureSet.isFinite() && structureSet.size() == 1) { | 
 |                 RegisteredStructure structure = structureSet.onlyStructure(); | 
 |                 if (auto* rareData = structure->rareDataConcurrently()) { | 
 |                     if (!!rareData->cachedPropertyNamesConcurrently(node->op() == ObjectGetOwnPropertyNames ? CachedPropertyNamesKind::GetOwnPropertyNames : CachedPropertyNamesKind::Keys)) { | 
 |                         if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { | 
 |                             m_state.setShouldTryConstantFolding(true); | 
 |                             didFoldClobberWorld(); | 
 |                             setTypeForNode(node, SpecArray); | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecArray); | 
 |         break; | 
 |     } | 
 |  | 
 |     case ToObject: | 
 |     case CallObjectConstructor: { | 
 |         AbstractValue& source = forNode(node->child1()); | 
 |         AbstractValue& destination = forNode(node); | 
 |  | 
 |         if (!(source.m_type & ~SpecObject)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             if (node->op() == ToObject) | 
 |                 didFoldClobberWorld(); | 
 |             destination = source; | 
 |             break; | 
 |         } | 
 |  | 
 |         if (node->op() == ToObject) | 
 |             clobberWorld(); | 
 |         setTypeForNode(node, SpecObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PhantomNewObject: | 
 |     case PhantomNewFunction: | 
 |     case PhantomNewGeneratorFunction: | 
 |     case PhantomNewAsyncGeneratorFunction: | 
 |     case PhantomNewAsyncFunction: | 
 |     case PhantomCreateActivation: | 
 |     case PhantomDirectArguments: | 
 |     case PhantomClonedArguments: | 
 |     case PhantomCreateRest: | 
 |     case PhantomSpread: | 
 |     case PhantomNewArrayWithSpread: | 
 |     case PhantomNewArrayBuffer: | 
 |     case PhantomNewInternalFieldObject: | 
 |     case PhantomNewRegexp: | 
 |     case BottomValue: { | 
 |         clearForNode(node); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PutHint: | 
 |         break; | 
 |          | 
 |     case MaterializeNewObject: { | 
 |         setForNode(node, node->structureSet()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PushWithScope: | 
 |         // We don't use the more precise withScopeStructure() here because it is a LazyProperty and may not yet be allocated. | 
 |         setTypeForNode(node, SpecObjectOther); | 
 |         break; | 
 |  | 
 |     case CreateActivation: | 
 |     case MaterializeCreateActivation: | 
 |         setForNode(node,  | 
 |             m_codeBlock->globalObjectFor(node->origin.semantic)->activationStructure()); | 
 |         break; | 
 |          | 
 |     case CreateDirectArguments: | 
 |         setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->directArgumentsStructure()); | 
 |         break; | 
 |          | 
 |     case CreateScopedArguments: | 
 |         setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->scopedArgumentsStructure()); | 
 |         break; | 
 |          | 
 |     case CreateClonedArguments: | 
 |         if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) { | 
 |             setTypeForNode(node, SpecObject); | 
 |             break; | 
 |         } | 
 |         setForNode(node, m_codeBlock->globalObjectFor(node->origin.semantic)->clonedArgumentsStructure()); | 
 |         break; | 
 |  | 
 |     case CreateArgumentsButterfly: | 
 |         setForNode(node, m_vm.immutableButterflyStructures[arrayIndexFromIndexingType(CopyOnWriteArrayWithContiguous) - NumberOfIndexingShapes].get()); | 
 |         break; | 
 |  | 
 |     case NewGeneratorFunction: | 
 |         setForNode(node,  | 
 |             m_codeBlock->globalObjectFor(node->origin.semantic)->generatorFunctionStructure()); | 
 |         break; | 
 |  | 
 |     case NewAsyncGeneratorFunction: | 
 |         setForNode(node,  | 
 |             m_codeBlock->globalObjectFor(node->origin.semantic)->asyncGeneratorFunctionStructure()); | 
 |         break; | 
 |  | 
 |     case NewAsyncFunction: | 
 |         setForNode(node,  | 
 |             m_codeBlock->globalObjectFor(node->origin.semantic)->asyncFunctionStructure()); | 
 |         break; | 
 |  | 
 |     case NewFunction: { | 
 |         JSGlobalObject* globalObject = m_codeBlock->globalObjectFor(node->origin.semantic); | 
 |         Structure* structure = JSFunction::selectStructureForNewFuncExp(globalObject, node->castOperand<FunctionExecutable*>()); | 
 |         setForNode(node, structure); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetCallee: | 
 |         if (FunctionExecutable* executable = jsDynamicCast<FunctionExecutable*>(m_vm, m_codeBlock->ownerExecutable())) { | 
 |             if (JSFunction* function = executable->singleton().inferredValue()) { | 
 |                 m_graph.watchpoints().addLazily(executable); | 
 |                 setConstant(node, *m_graph.freeze(function)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setTypeForNode(node, SpecFunction | SpecObjectOther); | 
 |         break; | 
 |          | 
 |     case GetArgumentCountIncludingThis: | 
 |         setTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |  | 
 |     case SetCallee: | 
 |     case SetArgumentCountIncludingThis: | 
 |         break; | 
 |          | 
 |     case GetRestLength: | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |          | 
 |     case GetGetter: { | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             GetterSetter* getterSetter = jsDynamicCast<GetterSetter*>(m_vm, base); | 
 |             if (getterSetter && !getterSetter->isGetterNull()) { | 
 |                 setConstant(node, *m_graph.freeze(getterSetter->getterConcurrently())); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         setTypeForNode(node, SpecObject); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetSetter: { | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             GetterSetter* getterSetter = jsDynamicCast<GetterSetter*>(m_vm, base); | 
 |             if (getterSetter && !getterSetter->isSetterNull()) { | 
 |                 setConstant(node, *m_graph.freeze(getterSetter->setterConcurrently())); | 
 |                 break; | 
 |             } | 
 |         } | 
 |          | 
 |         setTypeForNode(node, SpecObject); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetScope: | 
 |         if (JSValue base = forNode(node->child1()).m_value) { | 
 |             if (JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, base)) { | 
 |                 setConstant(node, *m_graph.freeze(function->scope())); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setTypeForNode(node, SpecObjectOther); | 
 |         break; | 
 |  | 
 |     case SkipScope: { | 
 |         if (JSValue child = forNode(node->child1()).value()) { | 
 |             if (JSScope* scope = jsDynamicCast<JSScope*>(m_vm, child)) { | 
 |                 if (JSScope* nextScope = scope->next()) { | 
 |                     setConstant(node, *m_graph.freeze(JSValue(nextScope))); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |         setTypeForNode(node, SpecObjectOther); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetGlobalObject: { | 
 |         JSValue child = forNode(node->child1()).value(); | 
 |         if (child) { | 
 |             setConstant(node, *m_graph.freeze(JSValue(asObject(child)->globalObject(m_vm)))); | 
 |             break; | 
 |         } | 
 |  | 
 |         if (forNode(node->child1()).m_structure.isFinite()) { | 
 |             JSGlobalObject* globalObject = nullptr; | 
 |             bool ok = true; | 
 |             forNode(node->child1()).m_structure.forEach( | 
 |                 [&] (RegisteredStructure structure) { | 
 |                     if (!globalObject) | 
 |                         globalObject = structure->globalObject(); | 
 |                     else if (globalObject != structure->globalObject()) | 
 |                         ok = false; | 
 |                 }); | 
 |             if (globalObject && ok) { | 
 |                 setConstant(node, *m_graph.freeze(JSValue(globalObject))); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         setTypeForNode(node, SpecObjectOther); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetGlobalThis: { | 
 |         setTypeForNode(node, SpecObject); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetClosureVar: | 
 |         if (JSValue value = m_graph.tryGetConstantClosureVar(forNode(node->child1()), node->scopeOffset())) { | 
 |             setConstant(node, *m_graph.freeze(value)); | 
 |             break; | 
 |         } | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |              | 
 |     case PutClosureVar: | 
 |         break; | 
 |  | 
 |     case GetInternalField: | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |  | 
 |     case PutInternalField: | 
 |         break; | 
 |  | 
 |  | 
 |     case GetRegExpObjectLastIndex: | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case SetRegExpObjectLastIndex: | 
 |     case RecordRegExpCachedResult: | 
 |         break; | 
 |          | 
 |     case GetFromArguments: | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |          | 
 |     case PutToArguments: | 
 |         break; | 
 |  | 
 |     case GetArgument: | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case TryGetById: | 
 |         // FIXME: This should constant fold at least as well as the normal GetById case. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=156422 | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case GetPrivateNameById: | 
 |     case GetByIdDirect: | 
 |     case GetByIdDirectFlush: | 
 |     case GetById: | 
 |     case GetByIdFlush: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite() | 
 |             && (node->child1().useKind() == CellUse || !(value.m_type & ~SpecCell))) { | 
 |             UniquedStringImpl* uid = node->cacheableIdentifier().uid(); | 
 |             GetByStatus status = GetByStatus::computeFor(value.m_structure.toStructureSet(), uid); | 
 |             if (status.isSimple()) { | 
 |                 // Figure out what the result is going to be - is it TOP, a constant, or maybe | 
 |                 // something more subtle? | 
 |                 AbstractValue result; | 
 |                 for (unsigned i = status.numVariants(); i--;) { | 
 |                     // This thing won't give us a variant that involves prototypes. If it did, we'd | 
 |                     // have more work to do here. | 
 |                     DFG_ASSERT(m_graph, node, status[i].conditionSet().isEmpty()); | 
 |  | 
 |                     result.merge( | 
 |                         m_graph.inferredValueForProperty( | 
 |                             value, status[i].offset(), m_state.structureClobberState())); | 
 |                 } | 
 |              | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 didFoldClobberWorld(); | 
 |                 forNode(node) = result; | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetPrivateName: | 
 |     case GetByValWithThis: | 
 |     case GetByIdWithThis: | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |              | 
 |     case GetArrayLength: { | 
 |         JSArrayBufferView* view = m_graph.tryGetFoldableView( | 
 |             forNode(node->child1()).m_value, node->arrayMode()); | 
 |         if (view) { | 
 |             setConstant(node, jsNumber(view->length())); | 
 |             break; | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetVectorLength: { | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DeleteById: | 
 |     case DeleteByVal: { | 
 |         // FIXME: This could decide if the delete will be successful based on the set of structures that | 
 |         // we get from our base value. https://bugs.webkit.org/show_bug.cgi?id=156611 | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |          | 
 |     case CheckStructure: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |  | 
 |         const RegisteredStructureSet& set = node->structureSet(); | 
 |          | 
 |         // It's interesting that we could have proven that the object has a larger structure set | 
 |         // that includes the set we're testing. In that case we could make the structure check | 
 |         // more efficient. We currently don't. | 
 |          | 
 |         if (value.m_structure.isSubsetOf(set)) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |  | 
 |         SpeculatedType admittedTypes = SpecNone; | 
 |         switch (node->child1().useKind()) { | 
 |         case CellUse: | 
 |         case KnownCellUse: | 
 |             admittedTypes = SpecNone; | 
 |             break; | 
 |         case CellOrOtherUse: | 
 |             admittedTypes = SpecOther; | 
 |             break; | 
 |         default: | 
 |             DFG_CRASH(m_graph, node, "Bad use kind"); | 
 |             break; | 
 |         } | 
 |          | 
 |         filter(value, set, admittedTypes); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CheckStructureOrEmpty: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |  | 
 |         bool mayBeEmpty = value.m_type & SpecEmpty; | 
 |         if (!mayBeEmpty) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |  | 
 |         SpeculatedType admittedTypes = mayBeEmpty ? SpecEmpty : SpecNone; | 
 |         filter(value, node->structureSet(), admittedTypes); | 
 |         break; | 
 |     } | 
 |          | 
 |     case CheckStructureImmediate: { | 
 |         // FIXME: This currently can only reason about one structure at a time. | 
 |         // https://bugs.webkit.org/show_bug.cgi?id=136988 | 
 |          | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         const RegisteredStructureSet& set = node->structureSet(); | 
 |          | 
 |         if (value.value()) { | 
 |             if (Structure* structure = jsDynamicCast<Structure*>(m_vm, value.value())) { | 
 |                 if (set.contains(m_graph.registerStructure(structure))) { | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |             m_state.setIsValid(false); | 
 |             break; | 
 |         } | 
 |          | 
 |         if (m_phiChildren) { | 
 |             bool allGood = true; | 
 |             m_phiChildren->forAllTransitiveIncomingValues( | 
 |                 node, | 
 |                 [&] (Node* incoming) { | 
 |                     if (Structure* structure = incoming->dynamicCastConstant<Structure*>(m_vm)) { | 
 |                         if (set.contains(m_graph.registerStructure(structure))) | 
 |                             return; | 
 |                     } | 
 |                     allGood = false; | 
 |                 }); | 
 |             if (allGood) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 break; | 
 |             } | 
 |         } | 
 |              | 
 |         if (RegisteredStructure structure = set.onlyStructure()) { | 
 |             filterByValue(node->child1(), *m_graph.freeze(structure.get())); | 
 |             break; | 
 |         } | 
 |          | 
 |         // Aw shucks, we can't do anything! | 
 |         break; | 
 |     } | 
 |          | 
 |     case PutStructure: | 
 |         if (!forNode(node->child1()).m_structure.isClear()) { | 
 |             if (forNode(node->child1()).m_structure.onlyStructure() == node->transition()->next) { | 
 |                 didFoldClobberStructures(); | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |             } else { | 
 |                 observeTransition( | 
 |                     clobberLimit, node->transition()->previous, node->transition()->next); | 
 |                 forNode(node->child1()).changeStructure(m_graph, node->transition()->next); | 
 |             } | 
 |         } else { | 
 |             // We're going to exit before we get here, but for the sake of validation, we've folded our write to StructureID. | 
 |             didFoldClobberStructures(); | 
 |         } | 
 |         break; | 
 |     case GetButterfly: | 
 |     case AllocatePropertyStorage: | 
 |     case ReallocatePropertyStorage: | 
 |     case NukeStructureAndSetButterfly: | 
 |         // FIXME: We don't model the fact that the structureID is nuked, simply because currently | 
 |         // nobody would currently benefit from having that information. But it's a bug nonetheless. | 
 |         if (node->op() == NukeStructureAndSetButterfly) | 
 |             didFoldClobberStructures(); | 
 |         clearForNode(node); // The result is not a JS value. | 
 |         break; | 
 |     case CheckJSCast: { | 
 |         const ClassInfo* classInfo = node->classInfo(); | 
 |         JSValue constant = forNode(node->child1()).value(); | 
 |         if (constant) { | 
 |             if (constant.isCell() && constant.asCell()->inherits(m_vm, classInfo)) { | 
 |                 ASSERT(!classInfo->inheritsJSTypeRange || classInfo->inheritsJSTypeRange->contains(constant.asCell()->type())); | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 ASSERT(constant); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |  | 
 |         if (value.m_structure.isSubClassOf(classInfo)) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |  | 
 |         filterClassInfo(value, classInfo); | 
 |         break; | 
 |     } | 
 |     case CheckNotJSCast: { | 
 |         const ClassInfo* classInfo = node->classInfo(); | 
 |         JSValue constant = forNode(node->child1()).value(); | 
 |         if (constant) { | 
 |             if (constant.isCell() && !constant.asCell()->inherits(m_vm, classInfo)) { | 
 |                 ASSERT(!classInfo->inheritsJSTypeRange || !classInfo->inheritsJSTypeRange->contains(constant.asCell()->type())); | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 ASSERT(constant); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |  | 
 |         if (value.m_structure.isNotSubClassOf(classInfo)) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CallDOMGetter: { | 
 |         CallDOMGetterData* callDOMGetterData = node->callDOMGetterData(); | 
 |         DOMJIT::CallDOMGetterSnippet* snippet = callDOMGetterData->snippet; | 
 |         if (!snippet || snippet->effect.writes) | 
 |             clobberWorld(); | 
 |         if (callDOMGetterData->domJIT) | 
 |             setTypeForNode(node, callDOMGetterData->domJIT->resultType()); | 
 |         else | 
 |             makeBytecodeTopForNode(node); | 
 |         break; | 
 |     } | 
 |     case CallDOM: { | 
 |         const DOMJIT::Signature* signature = node->signature(); | 
 |         if (signature->effect.writes) | 
 |             clobberWorld(); | 
 |         setTypeForNode(node, signature->result); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CheckArrayOrEmpty: | 
 |     case CheckArray: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |  | 
 |         SpeculatedType admittedTypes = SpecNone; | 
 |         if (node->op() == CheckArrayOrEmpty) { | 
 |             bool mayBeEmpty = value.m_type & SpecEmpty; | 
 |             if (!mayBeEmpty) | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |             else | 
 |                 admittedTypes = SpecEmpty; | 
 |         } | 
 |  | 
 |         if (node->arrayMode().alreadyChecked(m_graph, node, value)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             break; | 
 |         } | 
 |  | 
 |         switch (node->arrayMode().type()) { | 
 |         case Array::String: | 
 |             filter(node->child1(), SpecString | admittedTypes); | 
 |             break; | 
 |         case Array::Int32: | 
 |         case Array::Double: | 
 |         case Array::Contiguous: | 
 |         case Array::Undecided: | 
 |         case Array::ArrayStorage: | 
 |         case Array::SlowPutArrayStorage: | 
 |             break; | 
 |         case Array::DirectArguments: | 
 |             filter(node->child1(), SpecDirectArguments | admittedTypes); | 
 |             break; | 
 |         case Array::ScopedArguments: | 
 |             filter(node->child1(), SpecScopedArguments | admittedTypes); | 
 |             break; | 
 |         case Array::Int8Array: | 
 |             filter(node->child1(), SpecInt8Array | admittedTypes); | 
 |             break; | 
 |         case Array::Int16Array: | 
 |             filter(node->child1(), SpecInt16Array | admittedTypes); | 
 |             break; | 
 |         case Array::Int32Array: | 
 |             filter(node->child1(), SpecInt32Array | admittedTypes); | 
 |             break; | 
 |         case Array::Uint8Array: | 
 |             filter(node->child1(), SpecUint8Array | admittedTypes); | 
 |             break; | 
 |         case Array::Uint8ClampedArray: | 
 |             filter(node->child1(), SpecUint8ClampedArray | admittedTypes); | 
 |             break; | 
 |         case Array::Uint16Array: | 
 |             filter(node->child1(), SpecUint16Array | admittedTypes); | 
 |             break; | 
 |         case Array::Uint32Array: | 
 |             filter(node->child1(), SpecUint32Array | admittedTypes); | 
 |             break; | 
 |         case Array::Float32Array: | 
 |             filter(node->child1(), SpecFloat32Array | admittedTypes); | 
 |             break; | 
 |         case Array::Float64Array: | 
 |             filter(node->child1(), SpecFloat64Array | admittedTypes); | 
 |             break; | 
 |         case Array::AnyTypedArray: | 
 |             filter(node->child1(), SpecTypedArrayView | admittedTypes); | 
 |             break; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             break; | 
 |         } | 
 |         filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering(), admittedTypes); | 
 |         break; | 
 |     } | 
 |  | 
 |     case Arrayify: { | 
 |         if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) { | 
 |             didFoldClobberStructures(); | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             break; | 
 |         } | 
 |         ASSERT(node->arrayMode().conversion() == Array::Convert); | 
 |         clobberStructures(); | 
 |         filterArrayModes(node->child1(), node->arrayMode().arrayModesThatPassFiltering()); | 
 |         break; | 
 |     } | 
 |     case ArrayifyToStructure: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isSubsetOf(RegisteredStructureSet(node->structure()))) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         clobberStructures(); | 
 |          | 
 |         // We have a bunch of options of how to express the abstract set at this point. Let set S | 
 |         // be the set of structures that the value had before clobbering and assume that all of | 
 |         // them are watchable. The new value should be the least expressible upper bound of the | 
 |         // intersection of "values that currently have structure = node->structure()" and "values | 
 |         // that have structure in S plus any structure transition-reachable from S". Assume that | 
 |         // node->structure() is not in S but it is transition-reachable from S. Then we would | 
 |         // like to say that the result is "values that have structure = node->structure() until | 
 |         // we invalidate", but there is no way to express this using the AbstractValue syntax. So | 
 |         // we must choose between: | 
 |         // | 
 |         // 1) "values that currently have structure = node->structure()". This is a valid | 
 |         //    superset of the value that we really want, and it's specific enough to satisfy the | 
 |         //    preconditions of the array access that this is guarding. It's also specific enough | 
 |         //    to allow relevant optimizations in the case that we didn't have a contradiction | 
 |         //    like in this example. Notice that in the abscence of any contradiction, this result | 
 |         //    is precise rather than being a conservative LUB. | 
 |         // | 
 |         // 2) "values that currently hava structure in S plus any structure transition-reachable | 
 |         //    from S". This is also a valid superset of the value that we really want, but it's | 
 |         //    not specific enough to satisfy the preconditions of the array access that this is | 
 |         //    guarding - so playing such shenanigans would preclude us from having assertions on | 
 |         //    the typing preconditions of any array accesses. This would also not be a desirable | 
 |         //    answer in the absence of a contradiction. | 
 |         // | 
 |         // Note that it's tempting to simply say that the resulting value is BOTTOM because of | 
 |         // the contradiction. That would be wrong, since we haven't hit an invalidation point, | 
 |         // yet. | 
 |         forNode(node->child1()).set(m_graph, node->structure()); | 
 |         break; | 
 |     } | 
 |     case GetIndexedPropertyStorage: { | 
 |         JSArrayBufferView* view = m_graph.tryGetFoldableView( | 
 |             forNode(node->child1()).m_value, node->arrayMode()); | 
 |         if (view) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         clearForNode(node); | 
 |         break; | 
 |     } | 
 |     case ConstantStoragePointer: { | 
 |         clearForNode(node); | 
 |         break;  | 
 |     } | 
 |          | 
 |     case GetTypedArrayByteOffset: { | 
 |         JSArrayBufferView* view = m_graph.tryGetFoldableView(forNode(node->child1()).m_value); | 
 |         if (view) { | 
 |             Optional<unsigned> byteOffset = view->byteOffsetConcurrently(); | 
 |             if (byteOffset) { | 
 |                 setConstant(node, jsNumber(*byteOffset)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetPrototypeOf: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) { | 
 |             bool canFold = !value.m_structure.isClear(); | 
 |             JSValue prototype; | 
 |             value.m_structure.forEach([&] (RegisteredStructure structure) { | 
 |                 if (structure->typeInfo().overridesGetPrototype()) { | 
 |                     canFold = false; | 
 |                     return; | 
 |                 } | 
 |  | 
 |                 if (structure->hasPolyProto()) { | 
 |                     canFold = false; | 
 |                     return; | 
 |                 } | 
 |                 if (!prototype) | 
 |                     prototype = structure->storedPrototype(); | 
 |                 else if (prototype != structure->storedPrototype()) | 
 |                     canFold = false; | 
 |             }); | 
 |  | 
 |             if (prototype && canFold) { | 
 |                 switch (node->child1().useKind()) { | 
 |                 case ArrayUse: | 
 |                 case FunctionUse: | 
 |                 case FinalObjectUse: | 
 |                     break; | 
 |                 default: | 
 |                     didFoldClobberWorld(); | 
 |                     break; | 
 |                 } | 
 |                 setConstant(node, *m_graph.freeze(prototype)); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         switch (node->child1().useKind()) { | 
 |         case ArrayUse: | 
 |         case FunctionUse: | 
 |         case FinalObjectUse: | 
 |             break; | 
 |         default: | 
 |             clobberWorld(); | 
 |             break; | 
 |         } | 
 |         setTypeForNode(node, SpecObject | SpecOther); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetByOffset: { | 
 |         StorageAccessData& data = node->storageAccessData(); | 
 |  | 
 |         // FIXME: The part of this that handles inferred property types relies on AI knowing the structure | 
 |         // right now. That's probably not optimal. In some cases, we may perform an optimization (usually | 
 |         // by something other than AI, maybe by CSE for example) that obscures AI's view of the structure | 
 |         // at the point where GetByOffset runs. Currently, when that happens, we'll have to rely entirely | 
 |         // on the type that ByteCodeParser was able to prove. | 
 |         AbstractValue value = m_graph.inferredValueForProperty( | 
 |             forNode(node->child2()), data.offset, m_state.structureClobberState()); | 
 |  | 
 |         // If we decide that there does not exist any value that this can return, then it's probably | 
 |         // because the compilation was already invalidated. | 
 |         if (value.isClear()) | 
 |             m_state.setIsValid(false); | 
 |  | 
 |         setForNode(node, value); | 
 |         if (value.m_value) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetGetterSetterByOffset: { | 
 |         StorageAccessData& data = node->storageAccessData(); | 
 |         AbstractValue base = forNode(node->child2()); | 
 |         JSValue result = m_graph.tryGetConstantProperty(base, data.offset); | 
 |         if (result && jsDynamicCast<GetterSetter*>(m_vm, result)) { | 
 |             setConstant(node, *m_graph.freeze(result)); | 
 |             break; | 
 |         } | 
 |          | 
 |         setForNode(node, m_vm.getterSetterStructure.get()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case MultiGetByOffset: { | 
 |         // This code will filter the base value in a manner that is possibly different (either more | 
 |         // or less precise) than the way it would be filtered if this was strength-reduced to a | 
 |         // CheckStructure. This is fine. It's legal for different passes over the code to prove | 
 |         // different things about the code, so long as all of them are sound. That even includes | 
 |         // one guy proving that code should never execute (due to a contradiction) and another guy | 
 |         // not finding that contradiction. If someone ever proved that there would be a | 
 |         // contradiction then there must always be a contradiction even if subsequent passes don't | 
 |         // realize it. This is the case here. | 
 |          | 
 |         // Ordinarily you have to be careful with calling setShouldTryConstantFolding() | 
 |         // because of the effect on compile times, but this node is FTL-only. | 
 |         m_state.setShouldTryConstantFolding(true); | 
 |          | 
 |         AbstractValue base = forNode(node->child1()); | 
 |         RegisteredStructureSet baseSet; | 
 |         AbstractValue result; | 
 |         for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) { | 
 |             RegisteredStructureSet set = getCase.set(); | 
 |             set.filter(base); | 
 |             if (set.isEmpty()) | 
 |                 continue; | 
 |             baseSet.merge(set); | 
 |  | 
 |             switch (getCase.method().kind()) { | 
 |             case GetByOffsetMethod::Constant: { | 
 |                 AbstractValue thisResult; | 
 |                 thisResult.set( | 
 |                     m_graph, | 
 |                     *getCase.method().constant(), | 
 |                     m_state.structureClobberState()); | 
 |                 result.merge(thisResult); | 
 |                 break; | 
 |             } | 
 |  | 
 |             default: { | 
 |                 result.makeHeapTop(); | 
 |                 break; | 
 |             } } | 
 |         } | 
 |          | 
 |         if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction) | 
 |             m_state.setIsValid(false); | 
 |          | 
 |         setForNode(node, result); | 
 |         break; | 
 |     } | 
 |              | 
 |     case PutByOffset: { | 
 |         break; | 
 |     } | 
 |          | 
 |     case MultiPutByOffset: { | 
 |         RegisteredStructureSet newSet; | 
 |         TransitionVector transitions; | 
 |          | 
 |         // Ordinarily you have to be careful with calling setShouldTryConstantFolding() | 
 |         // because of the effect on compile times, but this node is FTL-only. | 
 |         m_state.setShouldTryConstantFolding(true); | 
 |          | 
 |         AbstractValue base = forNode(node->child1()); | 
 |         AbstractValue originalValue = forNode(node->child2()); | 
 |         AbstractValue resultingValue; | 
 |          | 
 |         if (node->multiPutByOffsetData().writesStructures()) | 
 |             didFoldClobberStructures(); | 
 |              | 
 |         for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { | 
 |             const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i]; | 
 |             RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure()); | 
 |             thisSet.filter(base); | 
 |             if (thisSet.isEmpty()) | 
 |                 continue; | 
 |  | 
 |             AbstractValue thisValue = originalValue; | 
 |             resultingValue.merge(thisValue); | 
 |              | 
 |             if (variant.kind() == PutByIdVariant::Transition) { | 
 |                 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure()); | 
 |                 if (thisSet.onlyStructure() != newStructure) { | 
 |                     transitions.append( | 
 |                         Transition(m_graph.registerStructure(variant.oldStructureForTransition()), newStructure)); | 
 |                 } // else this is really a replace. | 
 |                 newSet.add(newStructure); | 
 |             } else { | 
 |                 ASSERT(variant.kind() == PutByIdVariant::Replace); | 
 |                 newSet.merge(thisSet); | 
 |             } | 
 |         } | 
 |          | 
 |         // We need to order AI executing these effects in the same order as they're executed | 
 |         // at runtime. This is critical when you have JS code like `o.f = o;`. We first | 
 |         // filter types on o, then transition o. Not the other way around. If we got | 
 |         // this ordering wrong, we could end up with the wrong type representing o. | 
 |         setForNode(node->child2(), resultingValue); | 
 |         if (!!originalValue && !resultingValue) | 
 |             m_state.setIsValid(false); | 
 |  | 
 |         observeTransitions(clobberLimit, transitions); | 
 |         if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction) | 
 |             m_state.setIsValid(false); | 
 |         break; | 
 |     } | 
 |  | 
 |     case MultiDeleteByOffset: { | 
 |         RegisteredStructureSet newSet; | 
 |         TransitionVector transitions; | 
 |  | 
 |         // Ordinarily you have to be careful with calling setShouldTryConstantFolding() | 
 |         // because of the effect on compile times, but this node is FTL-only. | 
 |         m_state.setShouldTryConstantFolding(true); | 
 |  | 
 |         AbstractValue base = forNode(node->child1()); | 
 |  | 
 |         if (node->multiDeleteByOffsetData().writesStructures()) | 
 |             didFoldClobberStructures(); | 
 |  | 
 |         for (unsigned i = node->multiDeleteByOffsetData().variants.size(); i--;) { | 
 |             const DeleteByIdVariant& variant = node->multiDeleteByOffsetData().variants[i]; | 
 |             RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure()); | 
 |             thisSet.filter(base); | 
 |             if (thisSet.isEmpty()) | 
 |                 continue; | 
 |  | 
 |             if (variant.newStructure()) { | 
 |                 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure()); | 
 |                 transitions.append( | 
 |                     Transition(m_graph.registerStructure(variant.oldStructure()), newStructure)); | 
 |                 newSet.add(newStructure); | 
 |             } else | 
 |                 newSet.merge(thisSet); | 
 |         } | 
 |  | 
 |         observeTransitions(clobberLimit, transitions); | 
 |         if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction) | 
 |             m_state.setIsValid(false); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |          | 
 |     case GetExecutable: { | 
 |         JSValue value = forNode(node->child1()).value(); | 
 |         if (value) { | 
 |             JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value); | 
 |             if (function) { | 
 |                 setConstant(node, *m_graph.freeze(function->executable())); | 
 |                 break; | 
 |             } | 
 |         } | 
 |         setTypeForNode(node, SpecCellOther); | 
 |         break; | 
 |     } | 
 |      | 
 |     case CheckIsConstant: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.value() == node->constant()->value() && (value.value() || value.m_type == SpecEmpty)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             break; | 
 |         } | 
 |         filterByValue(node->child1(), *node->constant()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case AssertNotEmpty: | 
 |     case CheckNotEmpty: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (!(value.m_type & SpecEmpty)) { | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |             break; | 
 |         } | 
 |          | 
 |         filter(value, ~SpecEmpty); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CheckIdent: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         UniquedStringImpl* uid = node->uidOperand(); | 
 |  | 
 |         JSValue childConstant = value.value(); | 
 |         if (childConstant) { | 
 |             if (childConstant.isString()) { | 
 |                 if (asString(childConstant)->tryGetValueImpl() == uid) { | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |                     break; | 
 |                 } | 
 |             } else if (childConstant.isSymbol()) { | 
 |                 if (&jsCast<Symbol*>(childConstant)->uid() == uid) { | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         if (node->child1().useKind() == StringIdentUse) | 
 |             filter(value, SpecStringIdent); | 
 |         else | 
 |             filter(value, SpecSymbol); | 
 |         break; | 
 |     } | 
 |  | 
 |     case AssertInBounds: | 
 |         break; | 
 |  | 
 |     case CheckInBounds: { | 
 |         JSValue left = forNode(node->child1()).value(); | 
 |         JSValue right = forNode(node->child2()).value(); | 
 |         if (left && right && left.isInt32() && right.isInt32() && static_cast<uint32_t>(left.asInt32()) < static_cast<uint32_t>(right.asInt32())) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |  | 
 |         // We claim we result in Int32. It's not really important what our result is (though we | 
 |         // don't want to claim we may result in the empty value), other nodes with data flow edges | 
 |         // to us just do that to maintain the invariant that they can't be hoisted higher than us. | 
 |         // So we just arbitrarily pick Int32. In some ways, StorageResult may be the more correct | 
 |         // thing to do here. We pick NodeResultJS because it makes converting this to an identity | 
 |         // easier. | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PutPrivateName: { | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PutPrivateNameById: | 
 |     case PutById: | 
 |     case PutByIdFlush: | 
 |     case PutByIdDirect: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite()) { | 
 |             bool isDirect = node->op() == PutByIdDirect || node->op() == PutPrivateNameById; | 
 |             auto privateFieldPutKind = node->op() == PutPrivateNameById ? node->privateFieldPutKind() : PrivateFieldPutKind::none(); | 
 |             PutByIdStatus status = PutByIdStatus::computeFor( | 
 |                 m_graph.globalObjectFor(node->origin.semantic), | 
 |                 value.m_structure.toStructureSet(), | 
 |                 node->cacheableIdentifier().uid(), | 
 |                 isDirect, privateFieldPutKind); | 
 |  | 
 |             bool allGood = true; | 
 |             if (status.isSimple()) { | 
 |                 RegisteredStructureSet newSet; | 
 |                 TransitionVector transitions; | 
 |                  | 
 |                 for (const PutByIdVariant& variant : status.variants()) { | 
 |                     for (const ObjectPropertyCondition& condition : variant.conditionSet()) { | 
 |                         if (!m_graph.watchCondition(condition)) { | 
 |                             allGood = false; | 
 |                             break; | 
 |                         } | 
 |                     } | 
 |  | 
 |                     if (!allGood) | 
 |                         break; | 
 |  | 
 |                     if (variant.kind() == PutByIdVariant::Transition) { | 
 |                         RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure()); | 
 |                         transitions.append( | 
 |                             Transition( | 
 |                                 m_graph.registerStructure(variant.oldStructureForTransition()), newStructure)); | 
 |                         newSet.add(newStructure); | 
 |                     } else { | 
 |                         ASSERT(variant.kind() == PutByIdVariant::Replace); | 
 |                         newSet.merge(*m_graph.addStructureSet(variant.oldStructure())); | 
 |                     } | 
 |                 } | 
 |  | 
 |                 if (status.numVariants() == 1 || m_graph.m_plan.isFTL()) | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |                  | 
 |                 if (allGood) { | 
 |                     didFoldClobberWorld(); | 
 |                     observeTransitions(clobberLimit, transitions); | 
 |                     if (forNode(node->child1()).changeStructure(m_graph, newSet) == Contradiction) | 
 |                         m_state.setIsValid(false); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |          | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |  | 
 |     case PutByValWithThis: | 
 |     case PutByIdWithThis: | 
 |         clobberWorld(); | 
 |         break; | 
 |  | 
 |     case PutGetterById: | 
 |     case PutSetterById: | 
 |     case PutGetterSetterById: | 
 |     case PutGetterByVal: | 
 |     case PutSetterByVal: { | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DefineDataProperty: | 
 |     case DefineAccessorProperty: | 
 |         clobberWorld(); | 
 |         break; | 
 |          | 
 |     case InById: { | 
 |         // FIXME: We can determine when the property definitely exists based on abstract | 
 |         // value information. | 
 |         clobberWorld(); | 
 |         filter(node->child1(), SpecObject); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |  | 
 |     case InByVal: { | 
 |         AbstractValue& property = forNode(node->child2()); | 
 |         if (JSValue constant = property.value()) { | 
 |             if (constant.isString()) { | 
 |                 JSString* string = asString(constant); | 
 |                 if (CacheableIdentifier::isCacheableIdentifierCell(string)) | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |             } | 
 |         } | 
 |  | 
 |         // FIXME: We can determine when the property definitely exists based on abstract | 
 |         // value information. | 
 |         clobberWorld(); | 
 |         filter(node->child1(), SpecObject); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |  | 
 |     case HasOwnProperty: { | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |              | 
 |     case GetEnumerableLength: { | 
 |         setNonCellTypeForNode(node, SpecInt32Only); | 
 |         break; | 
 |     } | 
 |     case HasEnumerableProperty: { | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |     case InStructureProperty: | 
 |     case HasOwnStructureProperty: | 
 |     case HasEnumerableStructureProperty: { | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |     case HasIndexedProperty: | 
 |     case HasEnumerableIndexedProperty: { | 
 |         ArrayMode mode = node->arrayMode(); | 
 |         switch (mode.type()) { | 
 |         case Array::Int32: | 
 |         case Array::Double: | 
 |         case Array::Contiguous: | 
 |         case Array::ArrayStorage: { | 
 |             if (mode.isInBounds()) | 
 |                 break; | 
 |             FALLTHROUGH; | 
 |         } | 
 |         default: { | 
 |             clobberWorld(); | 
 |             break; | 
 |         } | 
 |         } | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |     } | 
 |     case GetDirectPname: { | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |     } | 
 |     case GetPropertyEnumerator: { | 
 |         setTypeForNode(node, SpecCell); | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |     case GetEnumeratorStructurePname: { | 
 |         setTypeForNode(node, SpecString | SpecOther); | 
 |         break; | 
 |     } | 
 |     case GetEnumeratorGenericPname: { | 
 |         setTypeForNode(node, SpecString | SpecOther); | 
 |         break; | 
 |     } | 
 |     case ToIndexString: { | 
 |         setTypeForNode(node, SpecString); | 
 |         break; | 
 |     } | 
 |  | 
 |     case GetGlobalVar: | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case GetGlobalLexicalVariable: | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |  | 
 |     case GetDynamicVar: | 
 |         clobberWorld(); | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |  | 
 |     case PutDynamicVar: | 
 |         clobberWorld(); | 
 |         break; | 
 |  | 
 |     case ResolveScope: | 
 |         clobberWorld(); | 
 |         setTypeForNode(node, SpecObject); | 
 |         break; | 
 |  | 
 |     case ResolveScopeForHoistingFuncDeclInEval: | 
 |         clobberWorld(); | 
 |         makeBytecodeTopForNode(node); | 
 |         break; | 
 |  | 
 |     case PutGlobalVariable: | 
 |     case NotifyWrite: | 
 |         break; | 
 |  | 
 |     case OverridesHasInstance: | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |              | 
 |     case InstanceOf: | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |  | 
 |     case InstanceOfCustom: | 
 |         clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBoolean); | 
 |         break; | 
 |          | 
 |     case MatchStructure: { | 
 |         AbstractValue base = forNode(node->child1()); | 
 |         RegisteredStructureSet baseSet; | 
 |          | 
 |         BooleanLattice result = BooleanLattice::Bottom; | 
 |         for (MatchStructureVariant& variant : node->matchStructureData().variants) { | 
 |             RegisteredStructure structure = variant.structure; | 
 |             if (!base.contains(structure)) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 continue; | 
 |             } | 
 |              | 
 |             baseSet.add(structure); | 
 |             result = leastUpperBoundOfBooleanLattices( | 
 |                 result, variant.result ? BooleanLattice::True : BooleanLattice::False); | 
 |         } | 
 |          | 
 |         if (forNode(node->child1()).changeStructure(m_graph, baseSet) == Contradiction) | 
 |             m_state.setIsValid(false); | 
 |          | 
 |         switch (result) { | 
 |         case BooleanLattice::False: | 
 |             setConstant(node, jsBoolean(false)); | 
 |             break; | 
 |         case BooleanLattice::True: | 
 |             setConstant(node, jsBoolean(true)); | 
 |             break; | 
 |         default: | 
 |             setNonCellTypeForNode(node, SpecBoolean); | 
 |             break; | 
 |         } | 
 |         break; | 
 |     } | 
 |              | 
 |     case Phi: | 
 |         RELEASE_ASSERT(m_graph.m_form == SSA); | 
 |         setForNode(node, forNode(NodeFlowProjection(node, NodeFlowProjection::Shadow))); | 
 |         // The state of this node would have already been decided, but it may have become a | 
 |         // constant, in which case we'd like to know. | 
 |         if (forNode(node).m_value) | 
 |             m_state.setShouldTryConstantFolding(true); | 
 |         break; | 
 |          | 
 |     case Upsilon: { | 
 |         NodeFlowProjection shadow(node->phi(), NodeFlowProjection::Shadow); | 
 |         if (shadow.isStillValid()) { | 
 |             m_state.createValueForNode(shadow); | 
 |             setForNode(shadow, forNode(node->child1())); | 
 |         } | 
 |         break; | 
 |     } | 
 |          | 
 |     case Flush: | 
 |     case PhantomLocal: | 
 |         break; | 
 |              | 
 |     case Call: | 
 |     case TailCallInlinedCaller: | 
 |     case Construct: | 
 |     case CallVarargs: | 
 |     case CallForwardVarargs: | 
 |     case TailCallVarargsInlinedCaller: | 
 |     case ConstructVarargs: | 
 |     case ConstructForwardVarargs: | 
 |     case TailCallForwardVarargsInlinedCaller: | 
 |     case CallEval: | 
 |     case DirectCall: | 
 |     case DirectConstruct: | 
 |     case DirectTailCallInlinedCaller: | 
 |         clobberWorld(); | 
 |         makeHeapTopForNode(node); | 
 |         break; | 
 |  | 
 |     case ForceOSRExit: | 
 |     case CheckBadValue: | 
 |         m_state.setIsValid(false); | 
 |         break; | 
 |          | 
 |     case InvalidationPoint: | 
 |         m_state.setStructureClobberState(StructuresAreWatched); | 
 |         m_state.observeInvalidationPoint(); | 
 |         break; | 
 |  | 
 |     case CPUIntrinsic:  | 
 |         if (node->intrinsic() == CPURdtscIntrinsic) | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |         else | 
 |             setNonCellTypeForNode(node, SpecOther); | 
 |         break; | 
 |  | 
 |     case CheckTraps: | 
 |     case LogShadowChickenPrologue: | 
 |     case LogShadowChickenTail: | 
 |     case ProfileType: | 
 |     case ProfileControlFlow: | 
 |     case Phantom: | 
 |     case CountExecution: | 
 |     case CheckTierUpInLoop: | 
 |     case CheckTierUpAtReturn: | 
 |     case CheckDetached: | 
 |     case SuperSamplerBegin: | 
 |     case SuperSamplerEnd: | 
 |     case CheckTierUpAndOSREnter: | 
 |     case LoopHint: | 
 |     case ExitOK: | 
 |     case FilterCallLinkStatus: | 
 |     case FilterGetByStatus: | 
 |     case FilterPutByIdStatus: | 
 |     case FilterInByIdStatus: | 
 |     case FilterDeleteByStatus: | 
 |     case ClearCatchLocals: | 
 |         break; | 
 |  | 
 |     case CheckTypeInfoFlags: { | 
 |         const AbstractValue& abstractValue = forNode(node->child1()); | 
 |         unsigned bits = node->typeInfoOperand(); | 
 |         ASSERT(bits); | 
 |         if (bits == ImplementsDefaultHasInstance) { | 
 |             if (abstractValue.m_type == SpecFunctionWithDefaultHasInstance) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         if (JSValue value = abstractValue.value()) { | 
 |             if (value.isCell()) { | 
 |                 // This works because if we see a cell here, we know it's fully constructed | 
 |                 // and we can read its inline type info flags. These flags don't change over the | 
 |                 // object's lifetime. | 
 |                 if ((value.asCell()->inlineTypeFlags() & bits) == bits) { | 
 |                     m_state.setShouldTryConstantFolding(true); | 
 |                     break; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         if (abstractValue.m_structure.isFinite()) { | 
 |             bool ok = true; | 
 |             abstractValue.m_structure.forEach([&] (RegisteredStructure structure) { | 
 |                 ok &= (structure->typeInfo().inlineTypeFlags() & bits) == bits; | 
 |             }); | 
 |             if (ok) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         break; | 
 |     } | 
 |  | 
 |     case ParseInt: { | 
 |         AbstractValue value = forNode(node->child1()); | 
 |         if (value.m_type && !(value.m_type & ~SpecInt32Only)) { | 
 |             JSValue radix; | 
 |             if (!node->child2()) | 
 |                 radix = jsNumber(0); | 
 |             else | 
 |                 radix = forNode(node->child2()).m_value; | 
 |  | 
 |             if (radix.isNumber() | 
 |                 && (radix.asNumber() == 0 || radix.asNumber() == 10)) { | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |                 if (node->child1().useKind() == UntypedUse) | 
 |                     didFoldClobberWorld(); | 
 |                 setNonCellTypeForNode(node, SpecInt32Only); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         if (node->child1().useKind() == UntypedUse) | 
 |             clobberWorld(); | 
 |         setNonCellTypeForNode(node, SpecBytecodeNumber); | 
 |         break; | 
 |     } | 
 |  | 
 |     case CreateRest: | 
 |         if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) { | 
 |             // This means we're already having a bad time. | 
 |             clobberWorld(); | 
 |             setTypeForNode(node, SpecArray); | 
 |             break; | 
 |         } | 
 |         setForNode(node, | 
 |             m_graph.globalObjectFor(node->origin.semantic)->restParameterStructure()); | 
 |         break; | 
 |              | 
 |     case CheckVarargs: | 
 |     case Check: { | 
 |         // Simplify out checks that don't actually do checking. | 
 |         m_graph.doToChildren(node, [&] (Edge edge) { | 
 |             if (!edge) | 
 |                 return; | 
 |             if (edge.isProved() || edge.willNotHaveCheck()) | 
 |                 m_state.setShouldTryConstantFolding(true); | 
 |         }); | 
 |         break; | 
 |     } | 
 |  | 
 |     case SetFunctionName: { | 
 |         clobberWorld(); | 
 |         break; | 
 |     } | 
 |  | 
 |     case StoreBarrier: | 
 |     case FencedStoreBarrier: { | 
 |         filter(node->child1(), SpecCell); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DataViewGetInt: { | 
 |         DataViewData data = node->dataViewData(); | 
 |         if (data.byteSize < 4) | 
 |             setNonCellTypeForNode(node, SpecInt32Only); | 
 |         else { | 
 |             ASSERT(data.byteSize == 4); | 
 |             if (data.isSigned) | 
 |                 setNonCellTypeForNode(node, SpecInt32Only); | 
 |             else | 
 |                 setNonCellTypeForNode(node, SpecInt52Any); | 
 |         } | 
 |         break; | 
 |     } | 
 |  | 
 |     case DataViewGetFloat: { | 
 |         setNonCellTypeForNode(node, SpecFullDouble); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DateGetInt32OrNaN: { | 
 |         setNonCellTypeForNode(node, SpecInt32Only | SpecDoublePureNaN); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DateGetTime: { | 
 |         setNonCellTypeForNode(node, SpecFullDouble); | 
 |         break; | 
 |     } | 
 |  | 
 |     case DataViewSet: { | 
 |         break; | 
 |     } | 
 |          | 
 |     case Unreachable: | 
 |         // It may be that during a previous run of AI we proved that something was unreachable, but | 
 |         // during this run of AI we forget that it's unreachable. AI's proofs don't have to get | 
 |         // monotonically stronger over time. So, we don't assert that AI doesn't reach the | 
 |         // Unreachable. We have no choice but to take our past proof at face value. Otherwise we'll | 
 |         // crash whenever AI fails to be as powerful on run K as it was on run K-1. | 
 |         m_state.setIsValid(false); | 
 |         break; | 
 |          | 
 |     case LastNodeType: | 
 |     case ArithIMul: | 
 |     case FiatInt52: | 
 |         DFG_CRASH(m_graph, node, "Unexpected node type"); | 
 |         break; | 
 |     } | 
 |      | 
 |     return m_state.isValid(); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::filterICStatus(Node* node) | 
 | { | 
 |     switch (node->op()) { | 
 |     case FilterCallLinkStatus: | 
 |         if (JSValue value = forNode(node->child1()).m_value) | 
 |             node->callLinkStatus()->filter(m_vm, value); | 
 |         break; | 
 |          | 
 |     case FilterGetByStatus: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite()) | 
 |             node->getByStatus()->filter(value.m_structure.toStructureSet()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case FilterInByIdStatus: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite()) | 
 |             node->inByIdStatus()->filter(value.m_structure.toStructureSet()); | 
 |         break; | 
 |     } | 
 |          | 
 |     case FilterPutByIdStatus: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite()) | 
 |             node->putByIdStatus()->filter(value.m_structure.toStructureSet()); | 
 |         break; | 
 |     } | 
 |  | 
 |     case FilterDeleteByStatus: { | 
 |         AbstractValue& value = forNode(node->child1()); | 
 |         if (value.m_structure.isFinite()) | 
 |             node->deleteByStatus()->filter(value.m_structure.toStructureSet()); | 
 |         break; | 
 |     } | 
 |  | 
 |     default: | 
 |         RELEASE_ASSERT_NOT_REACHED(); | 
 |         break; | 
 |     } | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBlock) | 
 | { | 
 |     return executeEffects(indexInBlock, m_state.block()->at(indexInBlock)); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock) | 
 | { | 
 |     Node* node = m_state.block()->at(indexInBlock); | 
 |  | 
 |     startExecuting(); | 
 |     executeEdges(node); | 
 |     return executeEffects(indexInBlock, node); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | bool AbstractInterpreter<AbstractStateType>::execute(Node* node) | 
 | { | 
 |     startExecuting(); | 
 |     executeEdges(node); | 
 |     return executeEffects(UINT_MAX, node); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::clobberWorld() | 
 | { | 
 |     clobberStructures(); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::didFoldClobberWorld() | 
 | { | 
 |     didFoldClobberStructures(); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | template<typename Functor> | 
 | void AbstractInterpreter<AbstractStateType>::forAllValues( | 
 |     unsigned clobberLimit, Functor& functor) | 
 | { | 
 |     if (clobberLimit >= m_state.block()->size()) | 
 |         clobberLimit = m_state.block()->size(); | 
 |     else | 
 |         clobberLimit++; | 
 |     ASSERT(clobberLimit <= m_state.block()->size()); | 
 |     for (size_t i = clobberLimit; i--;) { | 
 |         NodeFlowProjection::forEach( | 
 |             m_state.block()->at(i), | 
 |             [&] (NodeFlowProjection nodeProjection) { | 
 |                 functor(forNode(nodeProjection)); | 
 |             }); | 
 |     } | 
 |     if (m_graph.m_form == SSA) { | 
 |         for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) { | 
 |             if (node.isStillValid()) | 
 |                 functor(forNode(node)); | 
 |         } | 
 |     } | 
 |     for (size_t i = m_state.size(); i--;) | 
 |         functor(m_state.atIndex(i)); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::clobberStructures() | 
 | { | 
 |     m_state.clobberStructures(); | 
 |     m_state.mergeClobberState(AbstractInterpreterClobberState::ClobberedStructures); | 
 |     m_state.setStructureClobberState(StructuresAreClobbered); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::didFoldClobberStructures() | 
 | { | 
 |     m_state.mergeClobberState(AbstractInterpreterClobberState::FoldedClobber); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::observeTransition( | 
 |     unsigned clobberLimit, RegisteredStructure from, RegisteredStructure to) | 
 | { | 
 |     // Stop performing precise structure transition tracking. | 
 |     // Precise structure transition tracking shows quadratic complexity for # of nodes in a basic block. | 
 |     // If it is too large, we conservatively clobber all the structures. | 
 |     if (m_state.block()->size() > Options::maxDFGNodesInBasicBlockForPreciseAnalysis()) { | 
 |         clobberStructures(); | 
 |         return; | 
 |     } | 
 |  | 
 |     AbstractValue::TransitionObserver transitionObserver(from, to); | 
 |     forAllValues(clobberLimit, transitionObserver); | 
 |      | 
 |     ASSERT(!from->dfgShouldWatch()); // We don't need to claim to be in a clobbered state because 'from' was never watchable (during the time we were compiling), hence no constants ever introduced into the DFG IR that ever had a watchable structure would ever have the same structure as from. | 
 |      | 
 |     m_state.mergeClobberState(AbstractInterpreterClobberState::ObservedTransitions); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::observeTransitions( | 
 |     unsigned clobberLimit, const TransitionVector& vector) | 
 | { | 
 |     if (vector.isEmpty()) | 
 |         return; | 
 |      | 
 |     // Stop performing precise structure transition tracking. | 
 |     // Precise structure transition tracking shows quadratic complexity for # of nodes in a basic block. | 
 |     // If it is too large, we conservatively clobber all the structures. | 
 |     if (m_state.block()->size() > Options::maxDFGNodesInBasicBlockForPreciseAnalysis()) { | 
 |         clobberStructures(); | 
 |         return; | 
 |     } | 
 |  | 
 |     AbstractValue::TransitionsObserver transitionsObserver(vector); | 
 |     forAllValues(clobberLimit, transitionsObserver); | 
 |      | 
 |     if (ASSERT_ENABLED) { | 
 |         // We don't need to claim to be in a clobbered state because none of the Transition::previous structures are watchable. | 
 |         for (unsigned i = vector.size(); i--;) | 
 |             ASSERT(!vector[i].previous->dfgShouldWatch()); | 
 |     } | 
 |  | 
 |     m_state.mergeClobberState(AbstractInterpreterClobberState::ObservedTransitions); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) const | 
 | { | 
 |     const_cast<AbstractInterpreter<AbstractStateType>*>(this)->dump(out); | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out) | 
 | { | 
 |     CommaPrinter comma(" "); | 
 |     HashSet<NodeFlowProjection> seen; | 
 |     if (m_graph.m_form == SSA) { | 
 |         for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) { | 
 |             seen.add(node); | 
 |             AbstractValue& value = forNode(node); | 
 |             if (value.isClear()) | 
 |                 continue; | 
 |             out.print(comma, node, ":", value); | 
 |         } | 
 |     } | 
 |     for (size_t i = 0; i < m_state.block()->size(); ++i) { | 
 |         NodeFlowProjection::forEach( | 
 |             m_state.block()->at(i), [&] (NodeFlowProjection nodeProjection) { | 
 |                 seen.add(nodeProjection); | 
 |                 AbstractValue& value = forNode(nodeProjection); | 
 |                 if (value.isClear()) | 
 |                     return; | 
 |                 out.print(comma, nodeProjection, ":", value); | 
 |             }); | 
 |     } | 
 |     if (m_graph.m_form == SSA) { | 
 |         for (NodeFlowProjection node : m_state.block()->ssa->liveAtTail) { | 
 |             if (seen.contains(node)) | 
 |                 continue; | 
 |             AbstractValue& value = forNode(node); | 
 |             if (value.isClear()) | 
 |                 continue; | 
 |             out.print(comma, node, ":", value); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | FiltrationResult AbstractInterpreter<AbstractStateType>::filter( | 
 |     AbstractValue& value, const RegisteredStructureSet& set, SpeculatedType admittedTypes) | 
 | { | 
 |     if (value.filter(m_graph, set, admittedTypes) == FiltrationOK) | 
 |         return FiltrationOK; | 
 |     m_state.setIsValid(false); | 
 |     return Contradiction; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | FiltrationResult AbstractInterpreter<AbstractStateType>::filterArrayModes( | 
 |     AbstractValue& value, ArrayModes arrayModes, SpeculatedType admittedTypes) | 
 | { | 
 |     if (value.filterArrayModes(arrayModes, admittedTypes) == FiltrationOK) | 
 |         return FiltrationOK; | 
 |     m_state.setIsValid(false); | 
 |     return Contradiction; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | FiltrationResult AbstractInterpreter<AbstractStateType>::filter( | 
 |     AbstractValue& value, SpeculatedType type) | 
 | { | 
 |     if (value.filter(type) == FiltrationOK) | 
 |         return FiltrationOK; | 
 |     m_state.setIsValid(false); | 
 |     return Contradiction; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | FiltrationResult AbstractInterpreter<AbstractStateType>::filterByValue( | 
 |     AbstractValue& abstractValue, FrozenValue concreteValue) | 
 | { | 
 |     if (abstractValue.filterByValue(concreteValue) == FiltrationOK) | 
 |         return FiltrationOK; | 
 |     m_state.setIsValid(false); | 
 |     return Contradiction; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | FiltrationResult AbstractInterpreter<AbstractStateType>::filterClassInfo( | 
 |     AbstractValue& value, const ClassInfo* classInfo) | 
 | { | 
 |     if (value.filterClassInfo(m_graph, classInfo) == FiltrationOK) | 
 |         return FiltrationOK; | 
 |     m_state.setIsValid(false); | 
 |     return Contradiction; | 
 | } | 
 |  | 
 | template<typename AbstractStateType> | 
 | void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double)) | 
 | { | 
 |     JSValue child = forNode(node->child1()).value(); | 
 |     if (Optional<double> number = child.toNumberFromPrimitive()) { | 
 |         if (node->child1().useKind() != DoubleRepUse) | 
 |             didFoldClobberWorld(); | 
 |         setConstant(node, jsDoubleNumber(equivalentFunction(*number))); | 
 |         return; | 
 |     } | 
 |     SpeculatedType type; | 
 |     if (node->child1().useKind() == DoubleRepUse) | 
 |         type = typeOfDoubleUnaryOp(forNode(node->child1()).m_type); | 
 |     else { | 
 |         clobberWorld(); | 
 |         type = SpecBytecodeNumber; | 
 |     } | 
 |     setNonCellTypeForNode(node, type); | 
 | } | 
 |  | 
 | } } // namespace JSC::DFG | 
 |  | 
 | #endif // ENABLE(DFG_JIT) |