| /* | 
 |  * Copyright (C) 2011-2021 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 "B3SparseCollection.h" | 
 | #include "BasicBlockLocation.h" | 
 | #include "CheckPrivateBrandVariant.h" | 
 | #include "CodeBlock.h" | 
 | #include "DFGAdjacencyList.h" | 
 | #include "DFGArithMode.h" | 
 | #include "DFGArrayMode.h" | 
 | #include "DFGCommon.h" | 
 | #include "DFGEpoch.h" | 
 | #include "DFGLazyJSValue.h" | 
 | #include "DFGMultiGetByOffsetData.h" | 
 | #include "DFGNodeFlags.h" | 
 | #include "DFGNodeOrigin.h" | 
 | #include "DFGNodeType.h" | 
 | #include "DFGObjectMaterializationData.h" | 
 | #include "DFGOpInfo.h" | 
 | #include "DFGRegisteredStructure.h" | 
 | #include "DFGRegisteredStructureSet.h" | 
 | #include "DFGTransition.h" | 
 | #include "DFGUseKind.h" | 
 | #include "DFGVariableAccessData.h" | 
 | #include "DOMJITSignature.h" | 
 | #include "DeleteByVariant.h" | 
 | #include "GetByVariant.h" | 
 | #include "JSCJSValue.h" | 
 | #include "JSPropertyNameEnumerator.h" | 
 | #include "Operands.h" | 
 | #include "PrivateFieldPutKind.h" | 
 | #include "PutByVariant.h" | 
 | #include "SetPrivateBrandVariant.h" | 
 | #include "SpeculatedType.h" | 
 | #include "TypeLocation.h" | 
 | #include "ValueProfile.h" | 
 | #include <type_traits> | 
 | #include <wtf/FastMalloc.h> | 
 | #include <wtf/ListDump.h> | 
 | #include <wtf/LoggingHashSet.h> | 
 |  | 
 | namespace JSC { | 
 |  | 
 | namespace DOMJIT { | 
 | class GetterSetter; | 
 | class CallDOMGetterSnippet; | 
 | class Signature; | 
 | } | 
 |  | 
 | namespace Profiler { | 
 | class ExecutionCounter; | 
 | } | 
 |  | 
 | class Snippet; | 
 |  | 
 | namespace DFG { | 
 |  | 
 | class Graph; | 
 | class PromotedLocationDescriptor; | 
 | struct BasicBlock; | 
 |  | 
 | struct StorageAccessData { | 
 |     PropertyOffset offset; | 
 |     unsigned identifierNumber; | 
 | }; | 
 |  | 
 | struct MultiPutByOffsetData { | 
 |     unsigned identifierNumber; | 
 |     Vector<PutByVariant, 2> variants; | 
 |      | 
 |     bool writesStructures() const; | 
 |     bool reallocatesStorage() const; | 
 | }; | 
 |  | 
 | struct MultiDeleteByOffsetData { | 
 |     unsigned identifierNumber; | 
 |     Vector<DeleteByVariant, 2> variants; | 
 |  | 
 |     bool writesStructures() const; | 
 |     bool allVariantsStoreEmpty() const; | 
 | }; | 
 |  | 
 | struct MatchStructureVariant { | 
 |     RegisteredStructure structure; | 
 |     bool result; | 
 | }; | 
 |  | 
 | struct MatchStructureData { | 
 |     Vector<MatchStructureVariant, 2> variants; | 
 | }; | 
 |  | 
 | struct NewArrayBufferData { | 
 |     union { | 
 |         struct { | 
 |             unsigned vectorLengthHint; | 
 |             unsigned indexingMode; | 
 |         }; | 
 |         uint64_t asQuadWord; | 
 |     }; | 
 | }; | 
 | static_assert(sizeof(IndexingType) <= sizeof(unsigned), ""); | 
 | static_assert(sizeof(NewArrayBufferData) == sizeof(uint64_t), ""); | 
 |  | 
 | struct DataViewData { | 
 |     union { | 
 |         struct { | 
 |             uint8_t byteSize; | 
 |             bool isSigned; | 
 |             bool isFloatingPoint; // Used for the DataViewSet node. | 
 |             TriState isLittleEndian; | 
 |         }; | 
 |         uint64_t asQuadWord; | 
 |     }; | 
 | }; | 
 | static_assert(sizeof(DataViewData) == sizeof(uint64_t), ""); | 
 |  | 
 | struct BranchTarget { | 
 |     BranchTarget() | 
 |         : block(nullptr) | 
 |         , count(PNaN) | 
 |     { | 
 |     } | 
 |      | 
 |     explicit BranchTarget(BasicBlock* block) | 
 |         : block(block) | 
 |         , count(PNaN) | 
 |     { | 
 |     } | 
 |      | 
 |     void setBytecodeIndex(unsigned bytecodeIndex) | 
 |     { | 
 |         block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(bytecodeIndex)); | 
 |     } | 
 |     unsigned bytecodeIndex() const { return bitwise_cast<uintptr_t>(block); } | 
 |      | 
 |     void dump(PrintStream&) const; | 
 |      | 
 |     BasicBlock* block; | 
 |     float count; | 
 | }; | 
 |  | 
 | struct BranchData { | 
 |     static BranchData withBytecodeIndices( | 
 |         unsigned takenBytecodeIndex, unsigned notTakenBytecodeIndex) | 
 |     { | 
 |         BranchData result; | 
 |         result.taken.block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(takenBytecodeIndex)); | 
 |         result.notTaken.block = bitwise_cast<BasicBlock*>(static_cast<uintptr_t>(notTakenBytecodeIndex)); | 
 |         return result; | 
 |     } | 
 |      | 
 |     unsigned takenBytecodeIndex() const { return taken.bytecodeIndex(); } | 
 |     unsigned notTakenBytecodeIndex() const { return notTaken.bytecodeIndex(); } | 
 |      | 
 |     BasicBlock*& forCondition(bool condition) | 
 |     { | 
 |         if (condition) | 
 |             return taken.block; | 
 |         return notTaken.block; | 
 |     } | 
 |      | 
 |     BranchTarget taken; | 
 |     BranchTarget notTaken; | 
 | }; | 
 |  | 
 | // The SwitchData and associated data structures duplicate the information in | 
 | // JumpTable. The DFG may ultimately end up using the JumpTable, though it may | 
 | // instead decide to do something different - this is entirely up to the DFG. | 
 | // These data structures give the DFG a higher-level semantic description of | 
 | // what is going on, which will allow it to make the right decision. | 
 | // | 
 | // Note that there will never be multiple SwitchCases in SwitchData::cases that | 
 | // have the same SwitchCase::value, since the bytecode's JumpTables never have | 
 | // duplicates - since the JumpTable maps a value to a target. It's a | 
 | // one-to-many mapping. So we may have duplicate targets, but never duplicate | 
 | // values. | 
 | struct SwitchCase { | 
 |     SwitchCase() | 
 |     { | 
 |     } | 
 |      | 
 |     SwitchCase(LazyJSValue value, BasicBlock* target) | 
 |         : value(value) | 
 |         , target(target) | 
 |     { | 
 |     } | 
 |      | 
 |     static SwitchCase withBytecodeIndex(LazyJSValue value, unsigned bytecodeIndex) | 
 |     { | 
 |         SwitchCase result; | 
 |         result.value = value; | 
 |         result.target.setBytecodeIndex(bytecodeIndex); | 
 |         return result; | 
 |     } | 
 |      | 
 |     LazyJSValue value; | 
 |     BranchTarget target; | 
 | }; | 
 |  | 
 | struct SwitchData { | 
 |     // Initializes most fields to obviously invalid values. Anyone | 
 |     // constructing this should make sure to initialize everything they | 
 |     // care about manually. | 
 |     SwitchData() | 
 |         : switchTableIndex(UINT_MAX) | 
 |         , kind(static_cast<SwitchKind>(-1)) | 
 |         , didUseJumpTable(false) | 
 |     { | 
 |     } | 
 |      | 
 |     Vector<SwitchCase> cases; | 
 |     BranchTarget fallThrough; | 
 |     size_t switchTableIndex; | 
 |     SwitchKind kind; | 
 |     bool didUseJumpTable; | 
 | }; | 
 |  | 
 | struct EntrySwitchData { | 
 |     Vector<BasicBlock*> cases; | 
 | }; | 
 |  | 
 | struct CallVarargsData { | 
 |     int firstVarArgOffset; | 
 | }; | 
 |  | 
 | struct LoadVarargsData { | 
 |     VirtualRegister start; // Local for the first element. This is the first actual argument, not this. | 
 |     VirtualRegister count; // Local for the count. | 
 |     VirtualRegister machineStart; | 
 |     VirtualRegister machineCount; | 
 |     unsigned offset; // Which array element to start with. Usually this is 0. | 
 |     unsigned mandatoryMinimum; // The number of elements on the stack that must be initialized; if the array is too short then the missing elements must get undefined. Does not include "this". | 
 |     unsigned limit; // Maximum number of elements to load. Includes "this". | 
 | }; | 
 |  | 
 | struct StackAccessData { | 
 |     StackAccessData() | 
 |         : format(DeadFlush) | 
 |     { | 
 |     } | 
 |      | 
 |     StackAccessData(Operand operand, FlushFormat format) | 
 |         : operand(operand) | 
 |         , format(format) | 
 |     { | 
 |     } | 
 |      | 
 |     Operand operand; | 
 |     VirtualRegister machineLocal; | 
 |     FlushFormat format; | 
 |      | 
 |     FlushedAt flushedAt() { return FlushedAt(format, machineLocal); } | 
 | }; | 
 |  | 
 | struct CallDOMGetterData { | 
 |     FunctionPtr<CustomAccessorPtrTag> customAccessorGetter; | 
 |     const DOMJIT::GetterSetter* domJIT { nullptr }; | 
 |     DOMJIT::CallDOMGetterSnippet* snippet { nullptr }; | 
 |     unsigned identifierNumber { 0 }; | 
 |     const ClassInfo* requiredClassInfo { nullptr }; | 
 | }; | 
 |  | 
 | enum class BucketOwnerType : uint32_t { | 
 |     Map, | 
 |     Set | 
 | }; | 
 |  | 
 | // === Node === | 
 | // | 
 | // Node represents a single operation in the data flow graph. | 
 | DECLARE_ALLOCATOR_WITH_HEAP_IDENTIFIER(DFGNode); | 
 | struct Node { | 
 |     WTF_MAKE_STRUCT_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(DFGNode); | 
 | public: | 
 |     static const char HashSetTemplateInstantiationString[]; | 
 |      | 
 |     enum VarArgTag { VarArg }; | 
 |      | 
 |     Node() { } | 
 |      | 
 |     Node(NodeType op, NodeOrigin nodeOrigin, const AdjacencyList& children) | 
 |         : origin(nodeOrigin) | 
 |         , children(children) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |     } | 
 |      | 
 |     // Construct a node with up to 3 children, no immediate value. | 
 |     Node(NodeType op, NodeOrigin nodeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Fixed, child1, child2, child3) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |     } | 
 |  | 
 |     // Construct a node with up to 3 children, no immediate value. | 
 |     Node(NodeFlags result, NodeType op, NodeOrigin nodeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Fixed, child1, child2, child3) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         setResult(result); | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |     } | 
 |  | 
 |     // Construct a node with up to 3 children and an immediate value. | 
 |     Node(NodeType op, NodeOrigin nodeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Fixed, child1, child2, child3) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , m_opInfo(imm.m_value) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |     } | 
 |  | 
 |     // Construct a node with up to 3 children and an immediate value. | 
 |     Node(NodeFlags result, NodeType op, NodeOrigin nodeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Fixed, child1, child2, child3) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , m_opInfo(imm.m_value) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         setResult(result); | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |     } | 
 |  | 
 |     // Construct a node with up to 3 children and two immediate values. | 
 |     Node(NodeType op, NodeOrigin nodeOrigin, OpInfo imm1, OpInfo imm2, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Fixed, child1, child2, child3) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , m_opInfo(imm1.m_value) | 
 |         , m_opInfo2(imm2.m_value) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |     } | 
 |      | 
 |     // Construct a node with a variable number of children and two immediate values. | 
 |     Node(VarArgTag, NodeType op, NodeOrigin nodeOrigin, OpInfo imm1, OpInfo imm2, unsigned firstChild, unsigned numChildren) | 
 |         : origin(nodeOrigin) | 
 |         , children(AdjacencyList::Variable, firstChild, numChildren) | 
 |         , m_virtualRegister(VirtualRegister()) | 
 |         , m_refCount(1) | 
 |         , m_prediction(SpecNone) | 
 |         , m_opInfo(imm1.m_value) | 
 |         , m_opInfo2(imm2.m_value) | 
 |         , owner(nullptr) | 
 |     { | 
 |         m_misc.replacement = nullptr; | 
 |         setOpAndDefaultFlags(op); | 
 |         ASSERT(m_flags & NodeHasVarArgs); | 
 |     } | 
 |      | 
 |     NodeType op() const { return static_cast<NodeType>(m_op); } | 
 |     NodeFlags flags() const { return m_flags; } | 
 |  | 
 |     unsigned index() const { return m_index; } | 
 |      | 
 |     void setOp(NodeType op) | 
 |     { | 
 |         m_op = op; | 
 |     } | 
 |      | 
 |     void setFlags(NodeFlags flags) | 
 |     { | 
 |         m_flags = flags; | 
 |     } | 
 |      | 
 |     bool mergeFlags(NodeFlags flags) | 
 |     { | 
 |         NodeFlags newFlags = m_flags | flags; | 
 |         if (newFlags == m_flags) | 
 |             return false; | 
 |         m_flags = newFlags; | 
 |         return true; | 
 |     } | 
 |      | 
 |     bool filterFlags(NodeFlags flags) | 
 |     { | 
 |         NodeFlags newFlags = m_flags & flags; | 
 |         if (newFlags == m_flags) | 
 |             return false; | 
 |         m_flags = newFlags; | 
 |         return true; | 
 |     } | 
 |      | 
 |     bool clearFlags(NodeFlags flags) | 
 |     { | 
 |         return filterFlags(~flags); | 
 |     } | 
 |      | 
 |     void setResult(NodeFlags result) | 
 |     { | 
 |         ASSERT(!(result & ~NodeResultMask)); | 
 |         clearFlags(NodeResultMask); | 
 |         mergeFlags(result); | 
 |     } | 
 |      | 
 |     NodeFlags result() const | 
 |     { | 
 |         return flags() & NodeResultMask; | 
 |     } | 
 |      | 
 |     void setOpAndDefaultFlags(NodeType op) | 
 |     { | 
 |         m_op = op; | 
 |         m_flags = defaultFlags(op); | 
 |     } | 
 |  | 
 |     void remove(Graph&); | 
 |     void removeWithoutChecks(); | 
 |  | 
 |     void convertToCheckStructure(RegisteredStructureSet* set) | 
 |     { | 
 |         setOpAndDefaultFlags(CheckStructure); | 
 |         m_opInfo = set; | 
 |     } | 
 |  | 
 |     void convertToCheckStructureOrEmpty(RegisteredStructureSet* set) | 
 |     { | 
 |         if (SpecCellCheck & SpecEmpty) | 
 |             setOpAndDefaultFlags(CheckStructureOrEmpty); | 
 |         else | 
 |             setOpAndDefaultFlags(CheckStructure); | 
 |         m_opInfo = set; | 
 |     } | 
 |  | 
 |     void convertCheckStructureOrEmptyToCheckStructure() | 
 |     { | 
 |         ASSERT(op() == CheckStructureOrEmpty); | 
 |         setOpAndDefaultFlags(CheckStructure); | 
 |     } | 
 |  | 
 |     void convertToCheckStructureImmediate(Node* structure) | 
 |     { | 
 |         ASSERT(op() == CheckStructure || op() == CheckStructureOrEmpty); | 
 |         m_op = CheckStructureImmediate; | 
 |         children.setChild1(Edge(structure, CellUse)); | 
 |     } | 
 |  | 
 |     void convertCheckArrayOrEmptyToCheckArray() | 
 |     { | 
 |         ASSERT(op() == CheckArrayOrEmpty); | 
 |         setOpAndDefaultFlags(CheckArray); | 
 |     } | 
 |      | 
 |     void replaceWith(Graph&, Node* other); | 
 |     void replaceWithWithoutChecks(Node* other); | 
 |  | 
 |     void convertToIdentity(); | 
 |     void convertToIdentityOn(Node*); | 
 |  | 
 |     bool mustGenerate() const | 
 |     { | 
 |         return m_flags & NodeMustGenerate; | 
 |     } | 
 |  | 
 |     bool hasVarArgs() const | 
 |     { | 
 |         return m_flags & NodeHasVarArgs; | 
 |     } | 
 |      | 
 |     bool isConstant() | 
 |     { | 
 |         switch (op()) { | 
 |         case JSConstant: | 
 |         case DoubleConstant: | 
 |         case Int52Constant: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     bool hasConstant() | 
 |     { | 
 |         switch (op()) { | 
 |         case CheckIsConstant: | 
 |         case JSConstant: | 
 |         case DoubleConstant: | 
 |         case Int52Constant: | 
 |             return true; | 
 |              | 
 |         case PhantomDirectArguments: | 
 |         case PhantomClonedArguments: | 
 |             // These pretend to be the empty value constant for the benefit of the DFG backend, which | 
 |             // otherwise wouldn't take kindly to a node that doesn't compute a value. | 
 |             return true; | 
 |              | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     FrozenValue* constant() | 
 |     { | 
 |         ASSERT(hasConstant()); | 
 |          | 
 |         if (op() == PhantomDirectArguments || op() == PhantomClonedArguments) { | 
 |             // These pretend to be the empty value constant for the benefit of the DFG backend, which | 
 |             // otherwise wouldn't take kindly to a node that doesn't compute a value. | 
 |             return FrozenValue::emptySingleton(); | 
 |         } | 
 |          | 
 |         return m_opInfo.as<FrozenValue*>(); | 
 |     } | 
 |      | 
 |     // Don't call this directly - use Graph::convertToConstant() instead! | 
 |     void convertToConstant(FrozenValue* value) | 
 |     { | 
 |         if (hasDoubleResult()) | 
 |             m_op = DoubleConstant; | 
 |         else if (hasInt52Result()) | 
 |             m_op = Int52Constant; | 
 |         else | 
 |             m_op = JSConstant; | 
 |         m_flags &= ~(NodeMustGenerate | NodeHasVarArgs); | 
 |         m_opInfo = value; | 
 |         children.reset(); | 
 |     } | 
 |  | 
 |     void convertToLazyJSConstant(Graph&, LazyJSValue); | 
 |      | 
 |     void convertToConstantStoragePointer(void* pointer) | 
 |     { | 
 |         ASSERT(op() == GetIndexedPropertyStorage); | 
 |         m_op = ConstantStoragePointer; | 
 |         m_opInfo = pointer; | 
 |         children.reset(); | 
 |     } | 
 |      | 
 |     void convertToPutStack(StackAccessData* data) | 
 |     { | 
 |         m_op = PutStack; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = data; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |      | 
 |     void convertToGetStack(StackAccessData* data) | 
 |     { | 
 |         m_op = GetStack; | 
 |         m_flags &= ~NodeMustGenerate; | 
 |         m_opInfo = data; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children.reset(); | 
 |     } | 
 |      | 
 |     void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base) | 
 |     { | 
 |         ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == GetByIdDirect || m_op == GetByIdDirectFlush || m_op == GetPrivateNameById || m_op == MultiGetByOffset); | 
 |         m_opInfo = &data; | 
 |         children.setChild1(storage); | 
 |         children.setChild2(base); | 
 |         m_op = GetByOffset; | 
 |         m_flags &= ~NodeMustGenerate; | 
 |     } | 
 |      | 
 |     void convertToMultiGetByOffset(MultiGetByOffsetData* data) | 
 |     { | 
 |         RELEASE_ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == GetByIdDirect || m_op == GetByIdDirectFlush || m_op == GetPrivateNameById); | 
 |         m_opInfo = data; | 
 |         child1().setUseKind(CellUse); | 
 |         m_op = MultiGetByOffset; | 
 |         RELEASE_ASSERT(m_flags & NodeMustGenerate); | 
 |     } | 
 |      | 
 |     void convertToPutByOffset(StorageAccessData& data, Edge storage, Edge base) | 
 |     { | 
 |         ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush || m_op == MultiPutByOffset || m_op == PutPrivateNameById); | 
 |         m_opInfo = &data; | 
 |         children.setChild3(children.child2()); | 
 |         children.setChild2(base); | 
 |         children.setChild1(storage); | 
 |         m_op = PutByOffset; | 
 |     } | 
 |      | 
 |     void convertToMultiPutByOffset(MultiPutByOffsetData* data) | 
 |     { | 
 |         ASSERT(m_op == PutById || m_op == PutByIdDirect || m_op == PutByIdFlush || m_op == PutPrivateNameById); | 
 |         m_opInfo = data; | 
 |         m_op = MultiPutByOffset; | 
 |     } | 
 |      | 
 |     void convertToPhantomNewObject() | 
 |     { | 
 |         ASSERT(m_op == NewObject); | 
 |         m_op = PhantomNewObject; | 
 |         m_flags &= ~NodeHasVarArgs; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewFunction() | 
 |     { | 
 |         ASSERT(m_op == NewFunction || m_op == NewGeneratorFunction || m_op == NewAsyncFunction || m_op == NewAsyncGeneratorFunction); | 
 |         m_op = PhantomNewFunction; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewGeneratorFunction() | 
 |     { | 
 |         ASSERT(m_op == NewGeneratorFunction); | 
 |         m_op = PhantomNewGeneratorFunction; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewInternalFieldObject() | 
 |     { | 
 |         ASSERT(m_op == NewInternalFieldObject); | 
 |         m_op = PhantomNewInternalFieldObject; | 
 |         m_flags &= ~NodeHasVarArgs; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewAsyncFunction() | 
 |     { | 
 |         ASSERT(m_op == NewAsyncFunction); | 
 |         m_op = PhantomNewAsyncFunction; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewAsyncGeneratorFunction() | 
 |     { | 
 |         ASSERT(m_op == NewAsyncGeneratorFunction); | 
 |         m_op = PhantomNewAsyncGeneratorFunction; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |      | 
 |     void convertToPhantomCreateActivation() | 
 |     { | 
 |         ASSERT(m_op == CreateActivation); | 
 |         m_op = PhantomCreateActivation; | 
 |         m_flags &= ~NodeHasVarArgs; | 
 |         m_flags |= NodeMustGenerate; | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertToPhantomNewRegexp() | 
 |     { | 
 |         ASSERT(m_op == NewRegexp); | 
 |         setOpAndDefaultFlags(PhantomNewRegexp); | 
 |         m_opInfo = OpInfoWrapper(); | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |         children = AdjacencyList(); | 
 |     } | 
 |  | 
 |     void convertPhantomToPhantomLocal() | 
 |     { | 
 |         ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgumentDefinitely)); | 
 |         m_op = PhantomLocal; | 
 |         m_opInfo = child1()->m_opInfo; // Copy the variableAccessData. | 
 |         children.setChild1(Edge()); | 
 |     } | 
 |      | 
 |     void convertFlushToPhantomLocal() | 
 |     { | 
 |         ASSERT(m_op == Flush); | 
 |         m_op = PhantomLocal; | 
 |         children = AdjacencyList(); | 
 |     } | 
 |      | 
 |     void convertToToString() | 
 |     { | 
 |         ASSERT(m_op == ToPrimitive || m_op == StringValueOf || m_op == ToPropertyKey); | 
 |         m_op = ToString; | 
 |     } | 
 |  | 
 |     void convertToArithNegate() | 
 |     { | 
 |         ASSERT(m_op == ArithAbs && child1().useKind() == Int32Use); | 
 |         m_op = ArithNegate; | 
 |     } | 
 |  | 
 |     void convertToCompareEqPtr(FrozenValue* cell, Edge node) | 
 |     { | 
 |         ASSERT(m_op == CompareStrictEq || m_op == SameValue); | 
 |         setOpAndDefaultFlags(CompareEqPtr); | 
 |         children.setChild1(node); | 
 |         children.setChild2(Edge()); | 
 |         m_opInfo = cell; | 
 |     } | 
 |  | 
 |     void convertToNumberToStringWithValidRadixConstant(int32_t radix) | 
 |     { | 
 |         ASSERT(m_op == NumberToStringWithRadix); | 
 |         ASSERT(2 <= radix && radix <= 36); | 
 |         setOpAndDefaultFlags(NumberToStringWithValidRadixConstant); | 
 |         children.setChild2(Edge()); | 
 |         m_opInfo = radix; | 
 |     } | 
 |  | 
 |     void convertToGetGlobalThis() | 
 |     { | 
 |         ASSERT(m_op == ToThis); | 
 |         setOpAndDefaultFlags(GetGlobalThis); | 
 |         children.setChild1(Edge()); | 
 |     } | 
 |  | 
 |     void convertToCallObjectConstructor(FrozenValue* globalObject) | 
 |     { | 
 |         ASSERT(m_op == ToObject); | 
 |         setOpAndDefaultFlags(CallObjectConstructor); | 
 |         m_opInfo = globalObject; | 
 |     } | 
 |  | 
 |     void convertToNewStringObject(RegisteredStructure structure) | 
 |     { | 
 |         ASSERT(m_op == CallObjectConstructor || m_op == ToObject); | 
 |         setOpAndDefaultFlags(NewStringObject); | 
 |         m_opInfo = structure; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |  | 
 |     void convertToNewObject(RegisteredStructure structure) | 
 |     { | 
 |         ASSERT(m_op == CallObjectConstructor || m_op == CreateThis || m_op == ObjectCreate); | 
 |         setOpAndDefaultFlags(NewObject); | 
 |         children.reset(); | 
 |         m_opInfo = structure; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |  | 
 |     void convertToNewInternalFieldObject(RegisteredStructure structure) | 
 |     { | 
 |         ASSERT(m_op == CreatePromise); | 
 |         setOpAndDefaultFlags(NewInternalFieldObject); | 
 |         children.reset(); | 
 |         m_opInfo = structure; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |  | 
 |     void convertToNewInternalFieldObjectWithInlineFields(NodeType newOp, RegisteredStructure structure) | 
 |     { | 
 |         ASSERT(m_op == CreateAsyncGenerator || m_op == CreateGenerator); | 
 |         setOpAndDefaultFlags(newOp); | 
 |         children.reset(); | 
 |         m_opInfo = structure; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |  | 
 |     void convertToNewArrayBuffer(FrozenValue* immutableButterfly); | 
 |      | 
 |     void convertToDirectCall(FrozenValue*); | 
 |  | 
 |     void convertToCallDOM(Graph&); | 
 |  | 
 |     void convertToRegExpExecNonGlobalOrStickyWithoutChecks(FrozenValue* regExp); | 
 |     void convertToRegExpMatchFastGlobalWithoutChecks(FrozenValue* regExp); | 
 |     void convertToRegExpTestInline(FrozenValue* globalObject, FrozenValue* regExp); | 
 |  | 
 |     void convertToSetRegExpObjectLastIndex() | 
 |     { | 
 |         setOp(SetRegExpObjectLastIndex); | 
 |         m_opInfo = false; | 
 |     } | 
 |  | 
 |     void convertToInById(CacheableIdentifier identifier) | 
 |     { | 
 |         ASSERT(m_op == InByVal); | 
 |         setOpAndDefaultFlags(InById); | 
 |         children.setChild2(Edge()); | 
 |         m_opInfo = identifier; | 
 |         m_opInfo2 = OpInfoWrapper(); | 
 |     } | 
 |      | 
 |     JSValue asJSValue() | 
 |     { | 
 |         return constant()->value(); | 
 |     } | 
 |       | 
 |     bool isInt32Constant() | 
 |     { | 
 |         return isConstant() && constant()->value().isInt32(); | 
 |     } | 
 |       | 
 |     int32_t asInt32() | 
 |     { | 
 |         return asJSValue().asInt32(); | 
 |     } | 
 |       | 
 |     uint32_t asUInt32() | 
 |     { | 
 |         return asInt32(); | 
 |     } | 
 |       | 
 |     bool isDoubleConstant() | 
 |     { | 
 |         return isConstant() && constant()->value().isDouble(); | 
 |     } | 
 |       | 
 |     bool isNumberConstant() | 
 |     { | 
 |         return isConstant() && constant()->value().isNumber(); | 
 |     } | 
 |      | 
 |     double asNumber() | 
 |     { | 
 |         return asJSValue().asNumber(); | 
 |     } | 
 |       | 
 |     bool isAnyIntConstant() | 
 |     { | 
 |         return isConstant() && constant()->value().isAnyInt(); | 
 |     } | 
 |       | 
 |     int64_t asAnyInt() | 
 |     { | 
 |         return asJSValue().asAnyInt(); | 
 |     } | 
 |       | 
 |     bool isBooleanConstant() | 
 |     { | 
 |         return isConstant() && constant()->value().isBoolean(); | 
 |     } | 
 |       | 
 |     bool asBoolean() | 
 |     { | 
 |         return constant()->value().asBoolean(); | 
 |     } | 
 |  | 
 |     bool isUndefinedOrNullConstant() | 
 |     { | 
 |         return isConstant() && constant()->value().isUndefinedOrNull(); | 
 |     } | 
 |  | 
 |     bool isCellConstant() | 
 |     { | 
 |         return isConstant() && constant()->value() && constant()->value().isCell(); | 
 |     } | 
 |       | 
 |     JSCell* asCell() | 
 |     { | 
 |         return constant()->value().asCell(); | 
 |     } | 
 |       | 
 |     template<typename T> | 
 |     T dynamicCastConstant(VM& vm) | 
 |     { | 
 |         if (!isCellConstant()) | 
 |             return nullptr; | 
 |         return jsDynamicCast<T>(vm, asCell()); | 
 |     } | 
 |      | 
 |     bool hasLazyJSValue() | 
 |     { | 
 |         return op() == LazyJSConstant; | 
 |     } | 
 |  | 
 |     LazyJSValue lazyJSValue() | 
 |     { | 
 |         ASSERT(hasLazyJSValue()); | 
 |         return *m_opInfo.as<LazyJSValue*>(); | 
 |     } | 
 |  | 
 |     String tryGetString(Graph&); | 
 |  | 
 |     JSValue initializationValueForActivation() const | 
 |     { | 
 |         ASSERT(op() == CreateActivation); | 
 |         return m_opInfo2.as<FrozenValue*>()->value(); | 
 |     } | 
 |  | 
 |     bool hasArgumentsChild() | 
 |     { | 
 |         switch (op()) { | 
 |         case GetMyArgumentByVal: | 
 |         case GetMyArgumentByValOutOfBounds: | 
 |         case VarargsLength: | 
 |         case LoadVarargs: | 
 |         case ForwardVarargs: | 
 |         case CallVarargs: | 
 |         case CallForwardVarargs: | 
 |         case ConstructVarargs: | 
 |         case ConstructForwardVarargs: | 
 |         case TailCallVarargs: | 
 |         case TailCallForwardVarargs: | 
 |         case TailCallVarargsInlinedCaller: | 
 |         case TailCallForwardVarargsInlinedCaller: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     Edge& argumentsChild() | 
 |     { | 
 |         switch (op()) { | 
 |         case GetMyArgumentByVal: | 
 |         case GetMyArgumentByValOutOfBounds: | 
 |         case VarargsLength: | 
 |             return child1(); | 
 |         case LoadVarargs: | 
 |         case ForwardVarargs: | 
 |             return child2(); | 
 |         case CallVarargs: | 
 |         case CallForwardVarargs: | 
 |         case ConstructVarargs: | 
 |         case ConstructForwardVarargs: | 
 |         case TailCallVarargs: | 
 |         case TailCallForwardVarargs: | 
 |         case TailCallVarargsInlinedCaller: | 
 |         case TailCallForwardVarargsInlinedCaller: | 
 |             return child3(); | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             return child1(); | 
 |         } | 
 |     } | 
 |  | 
 |     bool containsMovHint() | 
 |     { | 
 |         switch (op()) { | 
 |         case MovHint: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     bool hasVariableAccessData(Graph&); | 
 |     bool accessesStack(Graph& graph) | 
 |     { | 
 |         return hasVariableAccessData(graph); | 
 |     } | 
 |      | 
 |     // This is useful for debugging code, where a node that should have a variable | 
 |     // access data doesn't have one because it hasn't been initialized yet. | 
 |     VariableAccessData* tryGetVariableAccessData() | 
 |     { | 
 |         VariableAccessData* result = m_opInfo.as<VariableAccessData*>(); | 
 |         if (!result) | 
 |             return nullptr; | 
 |         return result->find(); | 
 |     } | 
 |      | 
 |     VariableAccessData* variableAccessData() | 
 |     { | 
 |         return m_opInfo.as<VariableAccessData*>()->find(); | 
 |     } | 
 |      | 
 |     Operand operand() | 
 |     { | 
 |         return variableAccessData()->operand(); | 
 |     } | 
 |      | 
 |     VirtualRegister machineLocal() | 
 |     { | 
 |         return variableAccessData()->machineLocal(); | 
 |     } | 
 |      | 
 |     bool hasUnlinkedOperand() | 
 |     { | 
 |         switch (op()) { | 
 |         case ExtractOSREntryLocal: | 
 |         case MovHint: | 
 |         case KillStack: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     Operand unlinkedOperand() | 
 |     { | 
 |         ASSERT(hasUnlinkedOperand()); | 
 |         return Operand::fromBits(m_opInfo.as<uint64_t>()); | 
 |     } | 
 |      | 
 |     bool hasStackAccessData() | 
 |     { | 
 |         switch (op()) { | 
 |         case PutStack: | 
 |         case GetStack: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     StackAccessData* stackAccessData() | 
 |     { | 
 |         ASSERT(hasStackAccessData()); | 
 |         return m_opInfo.as<StackAccessData*>(); | 
 |     } | 
 |  | 
 |     unsigned argumentCountIncludingThis() | 
 |     { | 
 |         ASSERT(op() == SetArgumentCountIncludingThis); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |      | 
 |     bool hasPhi() | 
 |     { | 
 |         return op() == Upsilon; | 
 |     } | 
 |      | 
 |     Node* phi() | 
 |     { | 
 |         ASSERT(hasPhi()); | 
 |         return m_opInfo.as<Node*>(); | 
 |     } | 
 |  | 
 |     bool isStoreBarrier() | 
 |     { | 
 |         return op() == StoreBarrier || op() == FencedStoreBarrier; | 
 |     } | 
 |  | 
 |     bool hasCacheableIdentifier() | 
 |     { | 
 |         switch (op()) { | 
 |         case TryGetById: | 
 |         case GetById: | 
 |         case GetByIdFlush: | 
 |         case GetByIdWithThis: | 
 |         case GetByIdDirect: | 
 |         case GetByIdDirectFlush: | 
 |         case GetPrivateNameById: | 
 |         case DeleteById: | 
 |         case InById: | 
 |         case PutById: | 
 |         case PutByIdFlush: | 
 |         case PutByIdDirect: | 
 |         case PutByIdWithThis: | 
 |         case PutPrivateNameById: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     CacheableIdentifier cacheableIdentifier() | 
 |     { | 
 |         ASSERT(hasCacheableIdentifier()); | 
 |         return CacheableIdentifier::createFromRawBits(m_opInfo.as<uintptr_t>()); | 
 |     } | 
 |  | 
 |     bool hasIdentifier() | 
 |     { | 
 |         switch (op()) { | 
 |         case PutGetterById: | 
 |         case PutSetterById: | 
 |         case PutGetterSetterById: | 
 |         case GetDynamicVar: | 
 |         case PutDynamicVar: | 
 |         case ResolveScopeForHoistingFuncDeclInEval: | 
 |         case ResolveScope: | 
 |         case ToObject: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     unsigned identifierNumber() | 
 |     { | 
 |         ASSERT(hasIdentifier()); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     bool hasGetPutInfo() | 
 |     { | 
 |         switch (op()) { | 
 |         case GetDynamicVar: | 
 |         case PutDynamicVar: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     unsigned getPutInfo() | 
 |     { | 
 |         ASSERT(hasGetPutInfo()); | 
 |         return static_cast<unsigned>(m_opInfo.as<uint64_t>() >> 32); | 
 |     } | 
 |  | 
 |     bool hasAccessorAttributes() | 
 |     { | 
 |         switch (op()) { | 
 |         case PutGetterById: | 
 |         case PutSetterById: | 
 |         case PutGetterSetterById: | 
 |         case PutGetterByVal: | 
 |         case PutSetterByVal: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     int32_t accessorAttributes() | 
 |     { | 
 |         ASSERT(hasAccessorAttributes()); | 
 |         switch (op()) { | 
 |         case PutGetterById: | 
 |         case PutSetterById: | 
 |         case PutGetterSetterById: | 
 |             return m_opInfo2.as<int32_t>(); | 
 |         case PutGetterByVal: | 
 |         case PutSetterByVal: | 
 |             return m_opInfo.as<int32_t>(); | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             return 0; | 
 |         } | 
 |     } | 
 |      | 
 |     bool hasPromotedLocationDescriptor() | 
 |     { | 
 |         return op() == PutHint; | 
 |     } | 
 |      | 
 |     PromotedLocationDescriptor promotedLocationDescriptor(); | 
 |      | 
 |     // This corrects the arithmetic node flags, so that irrelevant bits are | 
 |     // ignored. In particular, anything other than ArithMul or ValueMul does not need | 
 |     // to know if it can speculate on negative zero. | 
 |     NodeFlags arithNodeFlags() | 
 |     { | 
 |         NodeFlags result = m_flags & NodeArithFlagsMask; | 
 |         if (op() == ArithMul || op() == ArithDiv || op() == ValueDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate || op() == ValueMul || op() == ValueDiv) | 
 |             return result; | 
 |         return result & ~NodeBytecodeNeedsNegZero; | 
 |     } | 
 |  | 
 |     bool mayHaveNonIntResult() | 
 |     { | 
 |         return m_flags & NodeMayHaveNonIntResult; | 
 |     } | 
 |      | 
 |     bool mayHaveDoubleResult() | 
 |     { | 
 |         return m_flags & NodeMayHaveDoubleResult; | 
 |     } | 
 |      | 
 |     bool mayHaveNonNumericResult() | 
 |     { | 
 |         return m_flags & NodeMayHaveNonNumericResult; | 
 |     } | 
 |  | 
 |     bool mayHaveBigInt32Result() | 
 |     { | 
 |         return m_flags & NodeMayHaveBigInt32Result; | 
 |     } | 
 |  | 
 |     bool mayHaveHeapBigIntResult() | 
 |     { | 
 |         return m_flags & NodeMayHaveHeapBigIntResult; | 
 |     } | 
 |  | 
 |     bool mayHaveBigIntResult() | 
 |     { | 
 |         return mayHaveBigInt32Result() || mayHaveHeapBigIntResult(); | 
 |     } | 
 |  | 
 |     bool hasNewArrayBufferData() | 
 |     { | 
 |         return op() == NewArrayBuffer || op() == PhantomNewArrayBuffer; | 
 |     } | 
 |      | 
 |     NewArrayBufferData newArrayBufferData() | 
 |     { | 
 |         ASSERT(hasNewArrayBufferData()); | 
 |         return m_opInfo2.asNewArrayBufferData(); | 
 |     } | 
 |  | 
 |     unsigned hasVectorLengthHint() | 
 |     { | 
 |         switch (op()) { | 
 |         case NewArray: | 
 |         case NewArrayBuffer: | 
 |         case PhantomNewArrayBuffer: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     unsigned vectorLengthHint() | 
 |     { | 
 |         ASSERT(hasVectorLengthHint()); | 
 |         if (op() == NewArray) | 
 |             return m_opInfo2.as<unsigned>(); | 
 |         return newArrayBufferData().vectorLengthHint; | 
 |     } | 
 |      | 
 |     bool hasIndexingType() | 
 |     { | 
 |         switch (op()) { | 
 |         case NewArray: | 
 |         case NewArrayWithSize: | 
 |         case NewArrayBuffer: | 
 |         case PhantomNewArrayBuffer: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     BitVector* bitVector() | 
 |     { | 
 |         ASSERT(op() == NewArrayWithSpread || op() == PhantomNewArrayWithSpread); | 
 |         return m_opInfo.as<BitVector*>(); | 
 |     } | 
 |  | 
 |     // Return the indexing type that an array allocation *wants* to use. It may end up using a different | 
 |     // type if we're having a bad time. You can determine the actual indexing type by asking the global | 
 |     // object: | 
 |     // | 
 |     //     m_graph.globalObjectFor(node->origin.semantic)->arrayStructureForIndexingTypeDuringAllocation(node->indexingType()) | 
 |     // | 
 |     // This will give you a Structure*, and that will have some indexing type that may be different from | 
 |     // the this one. | 
 |     IndexingType indexingType() | 
 |     { | 
 |         ASSERT(hasIndexingType()); | 
 |         if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer) | 
 |             return static_cast<IndexingType>(newArrayBufferData().indexingMode) & IndexingTypeMask; | 
 |         return static_cast<IndexingType>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |  | 
 |     IndexingType indexingMode() | 
 |     { | 
 |         ASSERT(hasIndexingType()); | 
 |         if (op() == NewArrayBuffer || op() == PhantomNewArrayBuffer) | 
 |             return static_cast<IndexingType>(newArrayBufferData().indexingMode); | 
 |         return static_cast<IndexingType>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |      | 
 |     bool hasTypedArrayType() | 
 |     { | 
 |         switch (op()) { | 
 |         case NewTypedArray: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     TypedArrayType typedArrayType() | 
 |     { | 
 |         ASSERT(hasTypedArrayType()); | 
 |         TypedArrayType result = static_cast<TypedArrayType>(m_opInfo.as<uint32_t>()); | 
 |         ASSERT(isTypedView(result)); | 
 |         return result; | 
 |     } | 
 |      | 
 |     bool hasInlineCapacity() | 
 |     { | 
 |         return op() == CreateThis; | 
 |     } | 
 |  | 
 |     unsigned inlineCapacity() | 
 |     { | 
 |         ASSERT(hasInlineCapacity()); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     bool hasIsInternalPromise() | 
 |     { | 
 |         return op() == CreatePromise; | 
 |     } | 
 |  | 
 |     bool isInternalPromise() | 
 |     { | 
 |         ASSERT(hasIsInternalPromise()); | 
 |         return m_opInfo2.as<bool>(); | 
 |     } | 
 |  | 
 |     void setIndexingType(IndexingType indexingType) | 
 |     { | 
 |         ASSERT(hasIndexingType()); | 
 |         m_opInfo = indexingType; | 
 |     } | 
 |      | 
 |     bool hasScopeOffset() | 
 |     { | 
 |         return op() == GetClosureVar || op() == PutClosureVar; | 
 |     } | 
 |  | 
 |     ScopeOffset scopeOffset() | 
 |     { | 
 |         ASSERT(hasScopeOffset()); | 
 |         return ScopeOffset(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |  | 
 |     unsigned hasInternalFieldIndex() | 
 |     { | 
 |         return op() == GetInternalField || op() == PutInternalField; | 
 |     } | 
 |  | 
 |     unsigned internalFieldIndex() | 
 |     { | 
 |         ASSERT(hasInternalFieldIndex()); | 
 |         return m_opInfo.as<uint32_t>(); | 
 |     } | 
 |      | 
 |     bool hasDirectArgumentsOffset() | 
 |     { | 
 |         return op() == GetFromArguments || op() == PutToArguments; | 
 |     } | 
 |      | 
 |     DirectArgumentsOffset capturedArgumentsOffset() | 
 |     { | 
 |         ASSERT(hasDirectArgumentsOffset()); | 
 |         return DirectArgumentsOffset(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |      | 
 |     bool hasRegisterPointer() | 
 |     { | 
 |         return op() == GetGlobalVar || op() == GetGlobalLexicalVariable || op() == PutGlobalVariable; | 
 |     } | 
 |      | 
 |     WriteBarrier<Unknown>* variablePointer() | 
 |     { | 
 |         return m_opInfo.as<WriteBarrier<Unknown>*>(); | 
 |     } | 
 |      | 
 |     bool hasCallVarargsData() | 
 |     { | 
 |         switch (op()) { | 
 |         case CallVarargs: | 
 |         case CallForwardVarargs: | 
 |         case TailCallVarargs: | 
 |         case TailCallForwardVarargs: | 
 |         case TailCallVarargsInlinedCaller: | 
 |         case TailCallForwardVarargsInlinedCaller: | 
 |         case ConstructVarargs: | 
 |         case ConstructForwardVarargs: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     CallVarargsData* callVarargsData() | 
 |     { | 
 |         ASSERT(hasCallVarargsData()); | 
 |         return m_opInfo.as<CallVarargsData*>(); | 
 |     } | 
 |      | 
 |     bool hasLoadVarargsData() | 
 |     { | 
 |         return op() == LoadVarargs || op() == ForwardVarargs || op() == VarargsLength; | 
 |     } | 
 |      | 
 |     LoadVarargsData* loadVarargsData() | 
 |     { | 
 |         ASSERT(hasLoadVarargsData()); | 
 |         return m_opInfo.as<LoadVarargsData*>(); | 
 |     } | 
 |  | 
 |     InlineCallFrame* argumentsInlineCallFrame() | 
 |     { | 
 |         ASSERT(op() == GetArgumentCountIncludingThis); | 
 |         return m_opInfo.as<InlineCallFrame*>(); | 
 |     } | 
 |  | 
 |     bool hasQueriedType() | 
 |     { | 
 |         return op() == IsCellWithType; | 
 |     } | 
 |  | 
 |     JSType queriedType() | 
 |     { | 
 |         static_assert(std::is_same<uint8_t, std::underlying_type<JSType>::type>::value, "Ensure that uint8_t is the underlying type for JSType."); | 
 |         return static_cast<JSType>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |  | 
 |     bool hasSpeculatedTypeForQuery() | 
 |     { | 
 |         return op() == IsCellWithType; | 
 |     } | 
 |  | 
 |     std::optional<SpeculatedType> speculatedTypeForQuery() | 
 |     { | 
 |         return speculationFromJSType(queriedType()); | 
 |     } | 
 |      | 
 |     bool hasResult() | 
 |     { | 
 |         return !!result(); | 
 |     } | 
 |      | 
 |     bool hasInt32Result() | 
 |     { | 
 |         return result() == NodeResultInt32; | 
 |     } | 
 |  | 
 |     bool hasInt52Result() | 
 |     { | 
 |         return result() == NodeResultInt52; | 
 |     } | 
 |      | 
 |     bool hasNumberResult() | 
 |     { | 
 |         return result() == NodeResultNumber; | 
 |     } | 
 |  | 
 |     bool hasNumberOrAnyIntResult() | 
 |     { | 
 |         return hasNumberResult() || hasInt32Result() || hasInt52Result(); | 
 |     } | 
 |      | 
 |     bool hasNumericResult() | 
 |     { | 
 |         switch (op()) { | 
 |         case ValueSub: | 
 |         case ValueMul: | 
 |         case ValueBitAnd: | 
 |         case ValueBitOr: | 
 |         case ValueBitXor: | 
 |         case ValueBitNot: | 
 |         case ValueBitLShift: | 
 |         case ValueBitRShift: | 
 |         case ValueNegate: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool hasDoubleResult() | 
 |     { | 
 |         return result() == NodeResultDouble; | 
 |     } | 
 |      | 
 |     bool hasJSResult() | 
 |     { | 
 |         return result() == NodeResultJS; | 
 |     } | 
 |      | 
 |     bool hasBooleanResult() | 
 |     { | 
 |         return result() == NodeResultBoolean; | 
 |     } | 
 |  | 
 |     bool hasStorageResult() | 
 |     { | 
 |         return result() == NodeResultStorage; | 
 |     } | 
 |      | 
 |     UseKind defaultUseKind() | 
 |     { | 
 |         return useKindForResult(result()); | 
 |     } | 
 |      | 
 |     Edge defaultEdge() | 
 |     { | 
 |         return Edge(this, defaultUseKind()); | 
 |     } | 
 |  | 
 |     bool isJump() | 
 |     { | 
 |         return op() == Jump; | 
 |     } | 
 |  | 
 |     bool isBranch() | 
 |     { | 
 |         return op() == Branch; | 
 |     } | 
 |      | 
 |     bool isSwitch() const | 
 |     { | 
 |         return op() == Switch; | 
 |     } | 
 |  | 
 |     bool isEntrySwitch() const | 
 |     { | 
 |         return op() == EntrySwitch; | 
 |     } | 
 |  | 
 |     bool isTerminal() | 
 |     { | 
 |         switch (op()) { | 
 |         case Jump: | 
 |         case Branch: | 
 |         case Switch: | 
 |         case EntrySwitch: | 
 |         case Return: | 
 |         case TailCall: | 
 |         case DirectTailCall: | 
 |         case TailCallVarargs: | 
 |         case TailCallForwardVarargs: | 
 |         case Unreachable: | 
 |         case Throw: | 
 |         case ThrowStaticError: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool isFunctionTerminal() | 
 |     { | 
 |         if (isTerminal() && !numSuccessors()) | 
 |             return true; | 
 |  | 
 |         return false; | 
 |     } | 
 |  | 
 |     // As is described in DFGNodeType.h's ForceOSRExit, this is a pseudo-terminal. | 
 |     // It means that execution should fall out of DFG at this point, but execution | 
 |     // does continue in the basic block - just in a different compiler. | 
 |     // FIXME: This is used for lightweight reachability decision. But this should | 
 |     // be replaced with AI-based reachability ideally. | 
 |     bool isPseudoTerminal() | 
 |     { | 
 |         switch (op()) { | 
 |         case ForceOSRExit: | 
 |         case CheckBadValue: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     unsigned targetBytecodeOffsetDuringParsing() | 
 |     { | 
 |         ASSERT(isJump()); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     BasicBlock*& targetBlock() | 
 |     { | 
 |         ASSERT(isJump()); | 
 |         return *bitwise_cast<BasicBlock**>(&m_opInfo.u.pointer); | 
 |     } | 
 |      | 
 |     BranchData* branchData() | 
 |     { | 
 |         ASSERT(isBranch()); | 
 |         return m_opInfo.as<BranchData*>(); | 
 |     } | 
 |      | 
 |     SwitchData* switchData() | 
 |     { | 
 |         ASSERT(isSwitch()); | 
 |         return m_opInfo.as<SwitchData*>(); | 
 |     } | 
 |  | 
 |     EntrySwitchData* entrySwitchData() | 
 |     { | 
 |         ASSERT(isEntrySwitch()); | 
 |         return m_opInfo.as<EntrySwitchData*>(); | 
 |     } | 
 |  | 
 |     bool hasIntrinsic() | 
 |     { | 
 |         switch (op()) { | 
 |         case CPUIntrinsic: | 
 |         case DateGetTime: | 
 |         case DateGetInt32OrNaN: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     Intrinsic intrinsic() | 
 |     { | 
 |         ASSERT(hasIntrinsic()); | 
 |         return m_opInfo.as<Intrinsic>(); | 
 |     } | 
 |      | 
 |     unsigned numSuccessors() | 
 |     { | 
 |         switch (op()) { | 
 |         case Jump: | 
 |             return 1; | 
 |         case Branch: | 
 |             return 2; | 
 |         case Switch: | 
 |             return switchData()->cases.size() + 1; | 
 |         case EntrySwitch: | 
 |             return entrySwitchData()->cases.size(); | 
 |         default: | 
 |             return 0; | 
 |         } | 
 |     } | 
 |      | 
 |     BasicBlock*& successor(unsigned index) | 
 |     { | 
 |         if (isSwitch()) { | 
 |             if (index < switchData()->cases.size()) | 
 |                 return switchData()->cases[index].target.block; | 
 |             RELEASE_ASSERT(index == switchData()->cases.size()); | 
 |             return switchData()->fallThrough.block; | 
 |         } else if (isEntrySwitch()) | 
 |             return entrySwitchData()->cases[index]; | 
 |  | 
 |         switch (index) { | 
 |         case 0: | 
 |             if (isJump()) | 
 |                 return targetBlock(); | 
 |             return branchData()->taken.block; | 
 |         case 1: | 
 |             return branchData()->notTaken.block; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             return targetBlock(); | 
 |         } | 
 |     } | 
 |      | 
 |     class SuccessorsIterable { | 
 |     public: | 
 |         SuccessorsIterable() | 
 |             : m_terminal(nullptr) | 
 |         { | 
 |         } | 
 |          | 
 |         SuccessorsIterable(Node* terminal) | 
 |             : m_terminal(terminal) | 
 |         { | 
 |         } | 
 |          | 
 |         class iterator { | 
 |         public: | 
 |             iterator() | 
 |                 : m_terminal(nullptr) | 
 |                 , m_index(UINT_MAX) | 
 |             { | 
 |             } | 
 |              | 
 |             iterator(Node* terminal, unsigned index) | 
 |                 : m_terminal(terminal) | 
 |                 , m_index(index) | 
 |             { | 
 |             } | 
 |              | 
 |             BasicBlock* operator*() | 
 |             { | 
 |                 return m_terminal->successor(m_index); | 
 |             } | 
 |              | 
 |             iterator& operator++() | 
 |             { | 
 |                 m_index++; | 
 |                 return *this; | 
 |             } | 
 |              | 
 |             bool operator==(const iterator& other) const | 
 |             { | 
 |                 return m_index == other.m_index; | 
 |             } | 
 |              | 
 |             bool operator!=(const iterator& other) const | 
 |             { | 
 |                 return !(*this == other); | 
 |             } | 
 |         private: | 
 |             Node* m_terminal; | 
 |             unsigned m_index; | 
 |         }; | 
 |          | 
 |         iterator begin() | 
 |         { | 
 |             return iterator(m_terminal, 0); | 
 |         } | 
 |          | 
 |         iterator end() | 
 |         { | 
 |             return iterator(m_terminal, m_terminal->numSuccessors()); | 
 |         } | 
 |  | 
 |         size_t size() const { return m_terminal->numSuccessors(); } | 
 |         BasicBlock* at(size_t index) const { return m_terminal->successor(index); } | 
 |         BasicBlock* operator[](size_t index) const { return at(index); } | 
 |          | 
 |     private: | 
 |         Node* m_terminal; | 
 |     }; | 
 |      | 
 |     SuccessorsIterable successors() | 
 |     { | 
 |         return SuccessorsIterable(this); | 
 |     } | 
 |      | 
 |     BasicBlock*& successorForCondition(bool condition) | 
 |     { | 
 |         return branchData()->forCondition(condition); | 
 |     } | 
 |      | 
 |     bool hasHeapPrediction() | 
 |     { | 
 |         switch (op()) { | 
 |         case ArithAbs: | 
 |         case ArithRound: | 
 |         case ArithFloor: | 
 |         case ArithCeil: | 
 |         case ArithTrunc: | 
 |         case GetById: | 
 |         case GetByIdFlush: | 
 |         case GetByIdWithThis: | 
 |         case GetByIdDirect: | 
 |         case GetByIdDirectFlush: | 
 |         case GetPrototypeOf: | 
 |         case TryGetById: | 
 |         case EnumeratorGetByVal: | 
 |         case GetByVal: | 
 |         case GetByValWithThis: | 
 |         case GetPrivateName: | 
 |         case GetPrivateNameById: | 
 |         case Call: | 
 |         case DirectCall: | 
 |         case TailCallInlinedCaller: | 
 |         case DirectTailCallInlinedCaller: | 
 |         case Construct: | 
 |         case DirectConstruct: | 
 |         case CallVarargs: | 
 |         case CallEval: | 
 |         case TailCallVarargsInlinedCaller: | 
 |         case ConstructVarargs: | 
 |         case CallForwardVarargs: | 
 |         case TailCallForwardVarargsInlinedCaller: | 
 |         case GetByOffset: | 
 |         case MultiGetByOffset: | 
 |         case GetClosureVar: | 
 |         case GetInternalField: | 
 |         case GetFromArguments: | 
 |         case GetArgument: | 
 |         case ArrayPop: | 
 |         case ArrayPush: | 
 |         case RegExpExec: | 
 |         case RegExpExecNonGlobalOrSticky: | 
 |         case RegExpTest: | 
 |         case RegExpTestInline: | 
 |         case RegExpMatchFast: | 
 |         case RegExpMatchFastGlobal: | 
 |         case GetGlobalVar: | 
 |         case GetGlobalLexicalVariable: | 
 |         case StringReplace: | 
 |         case StringReplaceRegExp: | 
 |         case ToNumber: | 
 |         case ToNumeric: | 
 |         case ToObject: | 
 |         case CallNumberConstructor: | 
 |         case ValueBitAnd: | 
 |         case ValueBitOr: | 
 |         case ValueBitXor: | 
 |         case ValueBitNot: | 
 |         case ValueBitLShift: | 
 |         case ValueBitRShift: | 
 |         case CallObjectConstructor: | 
 |         case LoadKeyFromMapBucket: | 
 |         case LoadValueFromMapBucket: | 
 |         case CallDOMGetter: | 
 |         case CallDOM: | 
 |         case ParseInt: | 
 |         case AtomicsAdd: | 
 |         case AtomicsAnd: | 
 |         case AtomicsCompareExchange: | 
 |         case AtomicsExchange: | 
 |         case AtomicsLoad: | 
 |         case AtomicsOr: | 
 |         case AtomicsStore: | 
 |         case AtomicsSub: | 
 |         case AtomicsXor: | 
 |         case GetDynamicVar: | 
 |         case ExtractValueFromWeakMapGet: | 
 |         case ToThis: | 
 |         case DataViewGetInt: | 
 |         case DataViewGetFloat: | 
 |         case DateGetInt32OrNaN: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     SpeculatedType getHeapPrediction() | 
 |     { | 
 |         ASSERT(hasHeapPrediction()); | 
 |         return m_opInfo2.as<SpeculatedType>(); | 
 |     } | 
 |  | 
 |     void setHeapPrediction(SpeculatedType prediction) | 
 |     { | 
 |         ASSERT(hasHeapPrediction()); | 
 |         m_opInfo2 = prediction; | 
 |     } | 
 |  | 
 |     SpeculatedType getForcedPrediction() | 
 |     { | 
 |         ASSERT(op() == IdentityWithProfile); | 
 |         return m_opInfo.as<SpeculatedType>(); | 
 |     } | 
 |  | 
 |     uint32_t catchOSREntryIndex() const | 
 |     { | 
 |         ASSERT(op() == ExtractCatchLocal); | 
 |         return m_opInfo.as<uint32_t>(); | 
 |     } | 
 |  | 
 |     SpeculatedType catchLocalPrediction() | 
 |     { | 
 |         ASSERT(op() == ExtractCatchLocal); | 
 |         return m_opInfo2.as<SpeculatedType>(); | 
 |     } | 
 |      | 
 |     bool hasCellOperand() | 
 |     { | 
 |         switch (op()) { | 
 |         case CheckIsConstant: | 
 |             return isCell(child1().useKind()); | 
 |         case OverridesHasInstance: | 
 |         case NewFunction: | 
 |         case NewGeneratorFunction: | 
 |         case NewAsyncFunction: | 
 |         case NewAsyncGeneratorFunction: | 
 |         case CreateActivation: | 
 |         case MaterializeCreateActivation: | 
 |         case NewRegexp: | 
 |         case NewArrayBuffer: | 
 |         case PhantomNewArrayBuffer: | 
 |         case CompareEqPtr: | 
 |         case CallObjectConstructor: | 
 |         case DirectCall: | 
 |         case DirectTailCall: | 
 |         case DirectConstruct: | 
 |         case DirectTailCallInlinedCaller: | 
 |         case RegExpExecNonGlobalOrSticky: | 
 |         case RegExpMatchFastGlobal: | 
 |         case RegExpTestInline: | 
 |             return true; | 
 |  | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool hasCellOperand2() | 
 |     { | 
 |         switch (op()) { | 
 |         case RegExpTestInline: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     FrozenValue* cellOperand() | 
 |     { | 
 |         ASSERT(hasCellOperand()); | 
 |         return m_opInfo.as<FrozenValue*>(); | 
 |     } | 
 |  | 
 |     FrozenValue* cellOperand2() | 
 |     { | 
 |         ASSERT(hasCellOperand2()); | 
 |         return m_opInfo2.as<FrozenValue*>(); | 
 |     } | 
 |  | 
 |     template<typename T> | 
 |     T castOperand() | 
 |     { | 
 |         return cellOperand()->cast<T>(); | 
 |     } | 
 |      | 
 |     void setCellOperand(FrozenValue* value) | 
 |     { | 
 |         ASSERT(hasCellOperand()); | 
 |         m_opInfo = value; | 
 |     } | 
 |      | 
 |     bool hasWatchpointSet() | 
 |     { | 
 |         return op() == NotifyWrite; | 
 |     } | 
 |      | 
 |     WatchpointSet* watchpointSet() | 
 |     { | 
 |         ASSERT(hasWatchpointSet()); | 
 |         return m_opInfo.as<WatchpointSet*>(); | 
 |     } | 
 |      | 
 |     bool hasStoragePointer() | 
 |     { | 
 |         return op() == ConstantStoragePointer; | 
 |     } | 
 |      | 
 |     void* storagePointer() | 
 |     { | 
 |         ASSERT(hasStoragePointer()); | 
 |         return m_opInfo.as<void*>(); | 
 |     } | 
 |  | 
 |     bool hasStorageChild() const | 
 |     { | 
 |         switch (op()) { | 
 |         case StringCharAt: | 
 |         case StringCharCodeAt: | 
 |         case StringCodePointAt: | 
 |         case EnumeratorGetByVal: | 
 |         case GetByVal: | 
 |         case PutByValDirect: | 
 |         case PutByVal: | 
 |         case PutByValAlias: | 
 |         case AtomicsAdd: | 
 |         case AtomicsAnd: | 
 |         case AtomicsCompareExchange: | 
 |         case AtomicsExchange: | 
 |         case AtomicsLoad: | 
 |         case AtomicsOr: | 
 |         case AtomicsStore: | 
 |         case AtomicsSub: | 
 |         case AtomicsXor: | 
 |         case ArrayPush: | 
 |         case ArrayPop: | 
 |         case GetArrayLength: | 
 |         case GetTypedArrayLengthAsInt52: | 
 |         case HasIndexedProperty: | 
 |         case EnumeratorNextUpdateIndexAndMode: | 
 |         case ArrayIndexOf: | 
 |             return true; | 
 |         default: | 
 |             break; | 
 |         } | 
 |         return false; | 
 |     } | 
 |  | 
 |     unsigned storageChildIndex() | 
 |     { | 
 |         ASSERT(hasStorageChild()); | 
 |         switch (op()) { | 
 |         case StringCharAt: | 
 |         case StringCharCodeAt: | 
 |         case StringCodePointAt: | 
 |         case EnumeratorGetByVal: | 
 |         case GetByVal: | 
 |             return 2; | 
 |         case PutByValDirect: | 
 |         case PutByVal: | 
 |         case PutByValAlias: | 
 |             return 3; | 
 |         case AtomicsAdd: | 
 |         case AtomicsAnd: | 
 |         case AtomicsCompareExchange: | 
 |         case AtomicsExchange: | 
 |         case AtomicsLoad: | 
 |         case AtomicsOr: | 
 |         case AtomicsStore: | 
 |         case AtomicsSub: | 
 |         case AtomicsXor: | 
 |             return 2 + numExtraAtomicsArgs(op()); | 
 |         case ArrayPush: | 
 |             return 0; | 
 |  | 
 |         case ArrayPop: | 
 |         case GetArrayLength: | 
 |         case GetTypedArrayLengthAsInt52: | 
 |             return 2; | 
 |  | 
 |         case HasIndexedProperty: | 
 |             return 2; | 
 |  | 
 |         case EnumeratorNextUpdateIndexAndMode: | 
 |             return 4; | 
 |  | 
 |         default: | 
 |             // FIXME: Add ArrayIndexOf but it does non-trivial things to determine storage edge. | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |         } | 
 |     } | 
 |  | 
 |     bool hasUidOperand() | 
 |     { | 
 |         return op() == CheckIdent; | 
 |     } | 
 |  | 
 |     UniquedStringImpl* uidOperand() | 
 |     { | 
 |         ASSERT(hasUidOperand()); | 
 |         return m_opInfo.as<UniquedStringImpl*>(); | 
 |     } | 
 |  | 
 |     bool hasTypeInfoOperand() | 
 |     { | 
 |         return op() == CheckTypeInfoFlags; | 
 |     } | 
 |  | 
 |     unsigned typeInfoOperand() | 
 |     { | 
 |         ASSERT(hasTypeInfoOperand() && m_opInfo.as<uint32_t>() <= static_cast<uint32_t>(UCHAR_MAX)); | 
 |         return m_opInfo.as<uint32_t>(); | 
 |     } | 
 |  | 
 |     bool hasTransition() | 
 |     { | 
 |         switch (op()) { | 
 |         case PutStructure: | 
 |         case AllocatePropertyStorage: | 
 |         case ReallocatePropertyStorage: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     Transition* transition() | 
 |     { | 
 |         ASSERT(hasTransition()); | 
 |         return m_opInfo.as<Transition*>(); | 
 |     } | 
 |      | 
 |     bool hasStructureSet() | 
 |     { | 
 |         switch (op()) { | 
 |         case CheckStructure: | 
 |         case CheckStructureOrEmpty: | 
 |         case CheckStructureImmediate: | 
 |         case MaterializeNewObject: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     const RegisteredStructureSet& structureSet() | 
 |     { | 
 |         ASSERT(hasStructureSet()); | 
 |         return *m_opInfo.as<RegisteredStructureSet*>(); | 
 |     } | 
 |      | 
 |     bool hasStructure() | 
 |     { | 
 |         switch (op()) { | 
 |         case ArrayifyToStructure: | 
 |         case MaterializeNewInternalFieldObject: | 
 |         case NewObject: | 
 |         case NewGenerator: | 
 |         case NewAsyncGenerator: | 
 |         case NewInternalFieldObject: | 
 |         case NewStringObject: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     RegisteredStructure structure() | 
 |     { | 
 |         ASSERT(hasStructure()); | 
 |         return m_opInfo.asRegisteredStructure(); | 
 |     } | 
 |      | 
 |     bool hasStorageAccessData() | 
 |     { | 
 |         switch (op()) { | 
 |         case GetByOffset: | 
 |         case PutByOffset: | 
 |         case GetGetterSetterByOffset: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     StorageAccessData& storageAccessData() | 
 |     { | 
 |         ASSERT(hasStorageAccessData()); | 
 |         return *m_opInfo.as<StorageAccessData*>(); | 
 |     } | 
 |      | 
 |     bool hasMultiGetByOffsetData() | 
 |     { | 
 |         return op() == MultiGetByOffset; | 
 |     } | 
 |      | 
 |     MultiGetByOffsetData& multiGetByOffsetData() | 
 |     { | 
 |         ASSERT(hasMultiGetByOffsetData()); | 
 |         return *m_opInfo.as<MultiGetByOffsetData*>(); | 
 |     } | 
 |      | 
 |     bool hasMultiPutByOffsetData() | 
 |     { | 
 |         return op() == MultiPutByOffset; | 
 |     } | 
 |      | 
 |     MultiPutByOffsetData& multiPutByOffsetData() | 
 |     { | 
 |         ASSERT(hasMultiPutByOffsetData()); | 
 |         return *m_opInfo.as<MultiPutByOffsetData*>(); | 
 |     } | 
 |  | 
 |     bool hasMultiDeleteByOffsetData() | 
 |     { | 
 |         return op() == MultiDeleteByOffset; | 
 |     } | 
 |  | 
 |     MultiDeleteByOffsetData& multiDeleteByOffsetData() | 
 |     { | 
 |         ASSERT(hasMultiDeleteByOffsetData()); | 
 |         return *m_opInfo.as<MultiDeleteByOffsetData*>(); | 
 |     } | 
 |      | 
 |     bool hasMatchStructureData() | 
 |     { | 
 |         return op() == MatchStructure; | 
 |     } | 
 |      | 
 |     MatchStructureData& matchStructureData() | 
 |     { | 
 |         ASSERT(hasMatchStructureData()); | 
 |         return *m_opInfo.as<MatchStructureData*>(); | 
 |     } | 
 |      | 
 |     bool hasObjectMaterializationData() | 
 |     { | 
 |         switch (op()) { | 
 |         case MaterializeNewObject: | 
 |         case MaterializeNewInternalFieldObject: | 
 |         case MaterializeCreateActivation: | 
 |             return true; | 
 |  | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     ObjectMaterializationData& objectMaterializationData() | 
 |     { | 
 |         ASSERT(hasObjectMaterializationData()); | 
 |         return *m_opInfo2.as<ObjectMaterializationData*>(); | 
 |     } | 
 |  | 
 |     bool isObjectAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case NewObject: | 
 |         case MaterializeNewObject: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     bool isPhantomObjectAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case PhantomNewObject: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     bool isActivationAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case CreateActivation: | 
 |         case MaterializeCreateActivation: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool isPhantomActivationAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case PhantomCreateActivation: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool isFunctionAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case NewFunction: | 
 |         case NewGeneratorFunction: | 
 |         case NewAsyncGeneratorFunction: | 
 |         case NewAsyncFunction: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool isPhantomFunctionAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case PhantomNewFunction: | 
 |         case PhantomNewGeneratorFunction: | 
 |         case PhantomNewAsyncFunction: | 
 |         case PhantomNewAsyncGeneratorFunction: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     bool isPhantomAllocation() | 
 |     { | 
 |         switch (op()) { | 
 |         case PhantomNewObject: | 
 |         case PhantomDirectArguments: | 
 |         case PhantomCreateRest: | 
 |         case PhantomSpread: | 
 |         case PhantomNewArrayWithSpread: | 
 |         case PhantomNewArrayBuffer: | 
 |         case PhantomClonedArguments: | 
 |         case PhantomNewFunction: | 
 |         case PhantomNewGeneratorFunction: | 
 |         case PhantomNewAsyncFunction: | 
 |         case PhantomNewAsyncGeneratorFunction: | 
 |         case PhantomNewInternalFieldObject: | 
 |         case PhantomCreateActivation: | 
 |         case PhantomNewRegexp: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     bool hasArrayMode() | 
 |     { | 
 |         switch (op()) { | 
 |         case GetIndexedPropertyStorage: | 
 |         case GetArrayLength: | 
 |         case GetTypedArrayLengthAsInt52: | 
 |         case GetVectorLength: | 
 |         case InByVal: | 
 |         case PutByValDirect: | 
 |         case PutByVal: | 
 |         case PutByValAlias: | 
 |         case GetByVal: | 
 |         case EnumeratorNextUpdateIndexAndMode: | 
 |         case EnumeratorGetByVal: | 
 |         case EnumeratorInByVal: | 
 |         case EnumeratorHasOwnProperty: | 
 |         case StringCharAt: | 
 |         case StringCharCodeAt: | 
 |         case StringCodePointAt: | 
 |         case CheckArray: | 
 |         case CheckArrayOrEmpty: | 
 |         case Arrayify: | 
 |         case ArrayifyToStructure: | 
 |         case ArrayPush: | 
 |         case ArrayPop: | 
 |         case ArrayIndexOf: | 
 |         case HasIndexedProperty: | 
 |         case AtomicsAdd: | 
 |         case AtomicsAnd: | 
 |         case AtomicsCompareExchange: | 
 |         case AtomicsExchange: | 
 |         case AtomicsLoad: | 
 |         case AtomicsOr: | 
 |         case AtomicsStore: | 
 |         case AtomicsSub: | 
 |         case AtomicsXor: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |      | 
 |     ArrayMode arrayMode() | 
 |     { | 
 |         ASSERT(hasArrayMode()); | 
 |         if (op() == ArrayifyToStructure) | 
 |             return ArrayMode::fromWord(m_opInfo2.as<uint32_t>()); | 
 |         return ArrayMode::fromWord(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |      | 
 |     bool setArrayMode(ArrayMode arrayMode) | 
 |     { | 
 |         ASSERT(hasArrayMode()); | 
 |         if (this->arrayMode() == arrayMode) | 
 |             return false; | 
 |         m_opInfo = arrayMode.asWord(); | 
 |         return true; | 
 |     } | 
 |  | 
 |     bool hasECMAMode() | 
 |     { | 
 |         switch (op()) { | 
 |         case CallEval: | 
 |         case DeleteById: | 
 |         case DeleteByVal: | 
 |         case PutById: | 
 |         case PutByIdDirect: | 
 |         case PutByIdFlush: | 
 |         case PutByIdWithThis: | 
 |         case PutByVal: | 
 |         case PutByValAlias: | 
 |         case PutByValDirect: | 
 |         case PutByValWithThis: | 
 |         case PutDynamicVar: | 
 |         case ToThis: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     ECMAMode ecmaMode() | 
 |     { | 
 |         ASSERT(hasECMAMode()); | 
 |         switch (op()) { | 
 |         case CallEval: | 
 |         case DeleteByVal: | 
 |         case PutByValWithThis: | 
 |         case ToThis: | 
 |             return ECMAMode::fromByte(m_opInfo.as<uint8_t>()); | 
 |         case DeleteById: | 
 |         case PutById: | 
 |         case PutByIdDirect: | 
 |         case PutByIdFlush: | 
 |         case PutByIdWithThis: | 
 |         case PutByVal: | 
 |         case PutByValAlias: | 
 |         case PutByValDirect: | 
 |         case PutDynamicVar: | 
 |             return ECMAMode::fromByte(m_opInfo2.as<uint8_t>()); | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             return ECMAMode::strict(); | 
 |         } | 
 |     } | 
 |      | 
 |     bool hasPrivateFieldPutKind() | 
 |     { | 
 |         if (op() == PutPrivateName || op() == PutPrivateNameById) | 
 |             return true; | 
 |         return false; | 
 |     } | 
 |  | 
 |     PrivateFieldPutKind privateFieldPutKind() | 
 |     { | 
 |         ASSERT(hasPrivateFieldPutKind()); | 
 |         return PrivateFieldPutKind::fromByte(m_opInfo2.as<uint8_t>()); | 
 |     } | 
 |  | 
 |     bool hasArithMode() | 
 |     { | 
 |         switch (op()) { | 
 |         case ArithAbs: | 
 |         case ArithAdd: | 
 |         case ArithSub: | 
 |         case ArithNegate: | 
 |         case ArithMul: | 
 |         case ArithDiv: | 
 |         case ArithMod: | 
 |         case UInt32ToNumber: | 
 |         case DoubleAsInt32: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     Arith::Mode arithMode() | 
 |     { | 
 |         ASSERT(hasArithMode()); | 
 |         return static_cast<Arith::Mode>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |      | 
 |     void setArithMode(Arith::Mode mode) | 
 |     { | 
 |         m_opInfo = mode; | 
 |     } | 
 |  | 
 |     bool hasArithRoundingMode() | 
 |     { | 
 |         return op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc; | 
 |     } | 
 |  | 
 |     Arith::RoundingMode arithRoundingMode() | 
 |     { | 
 |         ASSERT(hasArithRoundingMode()); | 
 |         return static_cast<Arith::RoundingMode>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |  | 
 |     void setArithRoundingMode(Arith::RoundingMode mode) | 
 |     { | 
 |         ASSERT(hasArithRoundingMode()); | 
 |         m_opInfo = static_cast<uint32_t>(mode); | 
 |     } | 
 |  | 
 |     bool hasArithUnaryType() | 
 |     { | 
 |         return op() == ArithUnary; | 
 |     } | 
 |  | 
 |     Arith::UnaryType arithUnaryType() | 
 |     { | 
 |         ASSERT(hasArithUnaryType()); | 
 |         return static_cast<Arith::UnaryType>(m_opInfo.as<uint32_t>()); | 
 |     } | 
 |      | 
 |     bool hasVirtualRegister() | 
 |     { | 
 |         return m_virtualRegister.isValid(); | 
 |     } | 
 |  | 
 |     VirtualRegister virtualRegister() | 
 |     { | 
 |         ASSERT(hasResult()); | 
 |         ASSERT(m_virtualRegister.isValid()); | 
 |         return m_virtualRegister; | 
 |     } | 
 |      | 
 |     void setVirtualRegister(VirtualRegister virtualRegister) | 
 |     { | 
 |         ASSERT(hasResult()); | 
 |         ASSERT(!m_virtualRegister.isValid()); | 
 |         m_virtualRegister = virtualRegister; | 
 |     } | 
 |      | 
 |     bool hasExecutionCounter() | 
 |     { | 
 |         return op() == CountExecution; | 
 |     } | 
 |      | 
 |     Profiler::ExecutionCounter* executionCounter() | 
 |     { | 
 |         return m_opInfo.as<Profiler::ExecutionCounter*>(); | 
 |     } | 
 |  | 
 |     unsigned entrypointIndex() | 
 |     { | 
 |         ASSERT(op() == InitializeEntrypointArguments); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     DataViewData dataViewData() | 
 |     { | 
 |         ASSERT(op() == DataViewGetInt || op() == DataViewGetFloat || op() == DataViewSet); | 
 |         return bitwise_cast<DataViewData>(m_opInfo.as<uint64_t>()); | 
 |     } | 
 |  | 
 |     bool shouldGenerate() | 
 |     { | 
 |         return m_refCount; | 
 |     } | 
 |      | 
 |     // Return true if the execution of this Node does not affect our ability to OSR to the FTL. | 
 |     // FIXME: Isn't this just like checking if the node has effects? | 
 |     bool isSemanticallySkippable() | 
 |     { | 
 |         return op() == CountExecution || op() == InvalidationPoint; | 
 |     } | 
 |  | 
 |     unsigned refCount() | 
 |     { | 
 |         return m_refCount; | 
 |     } | 
 |  | 
 |     unsigned postfixRef() | 
 |     { | 
 |         return m_refCount++; | 
 |     } | 
 |  | 
 |     unsigned adjustedRefCount() | 
 |     { | 
 |         return mustGenerate() ? m_refCount - 1 : m_refCount; | 
 |     } | 
 |      | 
 |     void setRefCount(unsigned refCount) | 
 |     { | 
 |         m_refCount = refCount; | 
 |     } | 
 |      | 
 |     Edge& child1() | 
 |     { | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |         return children.child1(); | 
 |     } | 
 |      | 
 |     // This is useful if you want to do a fast check on the first child | 
 |     // before also doing a check on the opcode. Use this with care and | 
 |     // avoid it if possible. | 
 |     Edge child1Unchecked() | 
 |     { | 
 |         return children.child1Unchecked(); | 
 |     } | 
 |  | 
 |     Edge& child2() | 
 |     { | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |         return children.child2(); | 
 |     } | 
 |  | 
 |     Edge& child3() | 
 |     { | 
 |         ASSERT(!(m_flags & NodeHasVarArgs)); | 
 |         return children.child3(); | 
 |     } | 
 |      | 
 |     unsigned firstChild() | 
 |     { | 
 |         ASSERT(m_flags & NodeHasVarArgs); | 
 |         return children.firstChild(); | 
 |     } | 
 |      | 
 |     unsigned numChildren() | 
 |     { | 
 |         ASSERT(m_flags & NodeHasVarArgs); | 
 |         return children.numChildren(); | 
 |     } | 
 |      | 
 |     UseKind binaryUseKind() | 
 |     { | 
 |         ASSERT(child1().useKind() == child2().useKind()); | 
 |         return child1().useKind(); | 
 |     } | 
 |      | 
 |     bool isBinaryUseKind(UseKind left, UseKind right) | 
 |     { | 
 |         return child1().useKind() == left && child2().useKind() == right; | 
 |     } | 
 |      | 
 |     bool isBinaryUseKind(UseKind useKind) | 
 |     { | 
 |         return isBinaryUseKind(useKind, useKind); | 
 |     } | 
 |      | 
 |     Edge childFor(UseKind useKind) | 
 |     { | 
 |         if (child1().useKind() == useKind) | 
 |             return child1(); | 
 |         if (child2().useKind() == useKind) | 
 |             return child2(); | 
 |         if (child3().useKind() == useKind) | 
 |             return child3(); | 
 |         return Edge(); | 
 |     } | 
 |      | 
 |     SpeculatedType prediction() | 
 |     { | 
 |         return m_prediction; | 
 |     } | 
 |      | 
 |     bool predict(SpeculatedType prediction) | 
 |     { | 
 |         return mergeSpeculation(m_prediction, prediction); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32() | 
 |     { | 
 |         return isInt32Speculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNotInt32() | 
 |     { | 
 |         return isNotInt32Speculation(prediction()); | 
 |     } | 
 |      | 
 |     bool sawBooleans() | 
 |     { | 
 |         return !!(prediction() & SpecBoolean); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32OrBoolean() | 
 |     { | 
 |         return isInt32OrBooleanSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32ForArithmetic() | 
 |     { | 
 |         return isInt32SpeculationForArithmetic(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32OrBooleanForArithmetic() | 
 |     { | 
 |         return isInt32OrBooleanSpeculationForArithmetic(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32OrBooleanExpectingDefined() | 
 |     { | 
 |         return isInt32OrBooleanSpeculationExpectingDefined(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt52() | 
 |     { | 
 |         // We have to include SpecInt32Only here for two reasons: | 
 |         // 1. We diligently write code that first checks if we should speculate Int32. | 
 |         // For example: | 
 |         // if (shouldSpeculateInt32()) ...  | 
 |         // else if (shouldSpeculateInt52()) ... | 
 |         // This means we it's totally valid to speculate Int52 when we're dealing | 
 |         // with a type that's the union of Int32 and Int52. | 
 |         // | 
 |         // It would be a performance mistake to not include Int32 here because we obviously | 
 |         // have variables that are the union of Int32 and Int52 values, and it's better | 
 |         // to speculate Int52 than double in that situation. | 
 |         // | 
 |         // 2. We also write code where we ask if the inputs can be Int52, like if | 
 |         // we know via profiling that an Add overflows, we may not emit an Int32 add. | 
 |         // However, we only emit such an add if both inputs can be Int52, and Int32 | 
 |         // can trivially become Int52. | 
 |         // | 
 |         return enableInt52() && isInt32OrInt52Speculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateDouble() | 
 |     { | 
 |         return isDoubleSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateDoubleReal() | 
 |     { | 
 |         return isDoubleRealSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateNumber() | 
 |     { | 
 |         return isFullNumberSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateNumberOrBoolean() | 
 |     { | 
 |         return isFullNumberOrBooleanSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateNumberOrBooleanExpectingDefined() | 
 |     { | 
 |         return isFullNumberOrBooleanSpeculationExpectingDefined(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateBoolean() | 
 |     { | 
 |         return isBooleanSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNotBoolean() | 
 |     { | 
 |         return isNotBooleanSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateOther() | 
 |     { | 
 |         return isOtherSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateMisc() | 
 |     { | 
 |         return isMiscSpeculation(prediction()); | 
 |     } | 
 |     | 
 |     bool shouldSpeculateStringIdent() | 
 |     { | 
 |         return isStringIdentSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateNotStringVar() | 
 |     { | 
 |         return isNotStringVarSpeculation(prediction()); | 
 |     } | 
 |   | 
 |     bool shouldSpeculateString() | 
 |     { | 
 |         return isStringSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNotString() | 
 |     { | 
 |         return isNotStringSpeculation(prediction()); | 
 |     } | 
 |   | 
 |     bool shouldSpeculateStringOrOther() | 
 |     { | 
 |         return isStringOrOtherSpeculation(prediction()); | 
 |     } | 
 |   | 
 |     bool shouldSpeculateStringObject() | 
 |     { | 
 |         return isStringObjectSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateStringOrStringObject() | 
 |     { | 
 |         return isStringOrStringObjectSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateRegExpObject() | 
 |     { | 
 |         return isRegExpObjectSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateSymbol() | 
 |     { | 
 |         return isSymbolSpeculation(prediction()); | 
 |     } | 
 |  | 
 | #if USE(BIGINT32) | 
 |     bool shouldSpeculateBigInt32() | 
 |     { | 
 |         return isBigInt32Speculation(prediction()); | 
 |     } | 
 | #endif | 
 |  | 
 |     bool shouldSpeculateHeapBigInt() | 
 |     { | 
 |         return isHeapBigIntSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateBigInt() | 
 |     { | 
 |         return isBigIntSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateFinalObject() | 
 |     { | 
 |         return isFinalObjectSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateFinalObjectOrOther() | 
 |     { | 
 |         return isFinalObjectOrOtherSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateArray() | 
 |     { | 
 |         return isArraySpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateFunction() | 
 |     { | 
 |         return isFunctionSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateProxyObject() | 
 |     { | 
 |         return isProxyObjectSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateDerivedArray() | 
 |     { | 
 |         return isDerivedArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateDirectArguments() | 
 |     { | 
 |         return isDirectArgumentsSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateScopedArguments() | 
 |     { | 
 |         return isScopedArgumentsSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt8Array() | 
 |     { | 
 |         return isInt8ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt16Array() | 
 |     { | 
 |         return isInt16ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateInt32Array() | 
 |     { | 
 |         return isInt32ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateUint8Array() | 
 |     { | 
 |         return isUint8ArraySpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateUint8ClampedArray() | 
 |     { | 
 |         return isUint8ClampedArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateUint16Array() | 
 |     { | 
 |         return isUint16ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateUint32Array() | 
 |     { | 
 |         return isUint32ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateFloat32Array() | 
 |     { | 
 |         return isFloat32ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateFloat64Array() | 
 |     { | 
 |         return isFloat64ArraySpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateArrayOrOther() | 
 |     { | 
 |         return isArrayOrOtherSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateObject() | 
 |     { | 
 |         return isObjectSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateObjectOrOther() | 
 |     { | 
 |         return isObjectOrOtherSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateCell() | 
 |     { | 
 |         return isCellSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateCellOrOther() | 
 |     { | 
 |         return isCellOrOtherSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateNotCell() | 
 |     { | 
 |         return isNotCellSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNotCellNorBigInt() | 
 |     { | 
 |         return isNotCellNorBigIntSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNotDouble() | 
 |     { | 
 |         return isNotDoubleSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNeitherDoubleNorHeapBigIntNorString() | 
 |     { | 
 |         return isNeitherDoubleNorHeapBigIntNorStringSpeculation(prediction()); | 
 |     } | 
 |  | 
 |     bool shouldSpeculateNeitherDoubleNorHeapBigInt() | 
 |     { | 
 |         return isNeitherDoubleNorHeapBigIntSpeculation(prediction()); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateUntypedForArithmetic() | 
 |     { | 
 |         return isUntypedSpeculationForArithmetic(prediction()); | 
 |     } | 
 |  | 
 |     static bool shouldSpeculateUntypedForArithmetic(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateUntypedForArithmetic() || op2->shouldSpeculateUntypedForArithmetic(); | 
 |     } | 
 |      | 
 |     bool shouldSpeculateUntypedForBitOps() | 
 |     { | 
 |         return isUntypedSpeculationForBitOps(prediction()); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateUntypedForBitOps(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateUntypedForBitOps() || op2->shouldSpeculateUntypedForBitOps(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateBoolean(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateInt32(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateInt32() && op2->shouldSpeculateInt32(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateInt32OrBoolean(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateInt32OrBoolean() | 
 |             && op2->shouldSpeculateInt32OrBoolean(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateInt32OrBooleanForArithmetic(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateInt32OrBooleanForArithmetic() | 
 |             && op2->shouldSpeculateInt32OrBooleanForArithmetic(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateInt32OrBooleanExpectingDefined(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateInt32OrBooleanExpectingDefined() | 
 |             && op2->shouldSpeculateInt32OrBooleanExpectingDefined(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateInt52(Node* op1, Node* op2) | 
 |     { | 
 |         return enableInt52() && op1->shouldSpeculateInt52() && op2->shouldSpeculateInt52(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateNumber(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateNumber() && op2->shouldSpeculateNumber(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateNumberOrBoolean(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateNumberOrBoolean() | 
 |             && op2->shouldSpeculateNumberOrBoolean(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateNumberOrBooleanExpectingDefined(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateNumberOrBooleanExpectingDefined() | 
 |             && op2->shouldSpeculateNumberOrBooleanExpectingDefined(); | 
 |     } | 
 |  | 
 |     static bool shouldSpeculateSymbol(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateSymbol() && op2->shouldSpeculateSymbol(); | 
 |     } | 
 |      | 
 |     static bool shouldSpeculateBigInt(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateBigInt() && op2->shouldSpeculateBigInt(); | 
 |     } | 
 |  | 
 | #if USE(BIGINT32) | 
 |     static bool shouldSpeculateBigInt32(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateBigInt32() && op2->shouldSpeculateBigInt32(); | 
 |     } | 
 | #endif | 
 |  | 
 |     static bool shouldSpeculateHeapBigInt(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateHeapBigInt() && op2->shouldSpeculateHeapBigInt(); | 
 |     } | 
 |  | 
 |     static bool shouldSpeculateFinalObject(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject(); | 
 |     } | 
 |  | 
 |     static bool shouldSpeculateArray(Node* op1, Node* op2) | 
 |     { | 
 |         return op1->shouldSpeculateArray() && op2->shouldSpeculateArray(); | 
 |     } | 
 |      | 
 |     bool canSpeculateInt32(RareCaseProfilingSource source) | 
 |     { | 
 |         return nodeCanSpeculateInt32(arithNodeFlags(), source); | 
 |     } | 
 |      | 
 |     bool canSpeculateInt52(RareCaseProfilingSource source) | 
 |     { | 
 |         return nodeCanSpeculateInt52(arithNodeFlags(), source); | 
 |     } | 
 |  | 
 |     bool canSpeculateBigInt32(RareCaseProfilingSource source) | 
 |     { | 
 |         return nodeCanSpeculateBigInt32(arithNodeFlags(), source); | 
 |     } | 
 |      | 
 |     RareCaseProfilingSource sourceFor(PredictionPass pass) | 
 |     { | 
 |         if (pass == PrimaryPass || child1()->sawBooleans() || (child2() && child2()->sawBooleans())) | 
 |             return DFGRareCase; | 
 |         return AllRareCases; | 
 |     } | 
 |      | 
 |     bool canSpeculateInt32(PredictionPass pass) | 
 |     { | 
 |         return canSpeculateInt32(sourceFor(pass)); | 
 |     } | 
 |      | 
 |     bool canSpeculateInt52(PredictionPass pass) | 
 |     { | 
 |         return canSpeculateInt52(sourceFor(pass)); | 
 |     } | 
 |  | 
 |     bool canSpeculateBigInt32(PredictionPass pass) | 
 |     { | 
 |         return canSpeculateBigInt32(sourceFor(pass)); | 
 |     } | 
 |  | 
 |     bool hasTypeLocation() | 
 |     { | 
 |         return op() == ProfileType; | 
 |     } | 
 |  | 
 |     TypeLocation* typeLocation() | 
 |     { | 
 |         ASSERT(hasTypeLocation()); | 
 |         return m_opInfo.as<TypeLocation*>(); | 
 |     } | 
 |  | 
 |     bool hasBasicBlockLocation() | 
 |     { | 
 |         return op() == ProfileControlFlow; | 
 |     } | 
 |  | 
 |     BasicBlockLocation* basicBlockLocation() | 
 |     { | 
 |         ASSERT(hasBasicBlockLocation()); | 
 |         return m_opInfo.as<BasicBlockLocation*>(); | 
 |     } | 
 |  | 
 |     bool hasCallDOMGetterData() const | 
 |     { | 
 |         return op() == CallDOMGetter; | 
 |     } | 
 |  | 
 |     CallDOMGetterData* callDOMGetterData() | 
 |     { | 
 |         ASSERT(hasCallDOMGetterData()); | 
 |         return m_opInfo.as<CallDOMGetterData*>(); | 
 |     } | 
 |  | 
 |     bool hasClassInfo() const | 
 |     { | 
 |         return op() == CheckJSCast || op() == CheckNotJSCast; | 
 |     } | 
 |  | 
 |     const ClassInfo* classInfo() | 
 |     { | 
 |         ASSERT(hasClassInfo()); | 
 |         return m_opInfo.as<const ClassInfo*>(); | 
 |     } | 
 |  | 
 |     bool hasSignature() const | 
 |     { | 
 |         // Note that this does not include TailCall node types intentionally. | 
 |         // CallDOM node types are always converted from Call. | 
 |         return op() == Call || op() == CallDOM; | 
 |     } | 
 |  | 
 |     const DOMJIT::Signature* signature() | 
 |     { | 
 |         return m_opInfo.as<const DOMJIT::Signature*>(); | 
 |     } | 
 |  | 
 |     const ClassInfo* requiredDOMJITClassInfo() | 
 |     { | 
 |         switch (op()) { | 
 |         case CallDOMGetter: | 
 |             return callDOMGetterData()->requiredClassInfo; | 
 |         case CallDOM: | 
 |             return signature()->classInfo; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |         } | 
 |         return nullptr; | 
 |     } | 
 |  | 
 |     Node* replacement() const | 
 |     { | 
 |         return m_misc.replacement; | 
 |     } | 
 |      | 
 |     void setReplacement(Node* replacement) | 
 |     { | 
 |         m_misc.replacement = replacement; | 
 |     } | 
 |      | 
 |     Epoch epoch() const | 
 |     { | 
 |         return Epoch::fromUnsigned(m_misc.epoch); | 
 |     } | 
 |      | 
 |     void setEpoch(Epoch epoch) | 
 |     { | 
 |         m_misc.epoch = epoch.toUnsigned(); | 
 |     } | 
 |      | 
 |     bool hasNumberOfArgumentsToSkip() | 
 |     { | 
 |         return op() == CreateRest || op() == PhantomCreateRest || op() == GetRestLength || op() == GetMyArgumentByVal || op() == GetMyArgumentByValOutOfBounds; | 
 |     } | 
 |  | 
 |     unsigned numberOfArgumentsToSkip() | 
 |     { | 
 |         ASSERT(hasNumberOfArgumentsToSkip()); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     bool hasArgumentIndex() | 
 |     { | 
 |         return op() == GetArgument; | 
 |     } | 
 |  | 
 |     unsigned argumentIndex() | 
 |     { | 
 |         ASSERT(hasArgumentIndex()); | 
 |         return m_opInfo.as<unsigned>(); | 
 |     } | 
 |  | 
 |     bool hasBucketOwnerType() | 
 |     { | 
 |         return op() == GetMapBucketNext || op() == LoadKeyFromMapBucket || op() == LoadValueFromMapBucket; | 
 |     } | 
 |  | 
 |     BucketOwnerType bucketOwnerType() | 
 |     { | 
 |         ASSERT(hasBucketOwnerType()); | 
 |         return m_opInfo.as<BucketOwnerType>(); | 
 |     } | 
 |  | 
 |     bool hasValidRadixConstant() | 
 |     { | 
 |         return op() == NumberToStringWithValidRadixConstant; | 
 |     } | 
 |  | 
 |     int32_t validRadixConstant() | 
 |     { | 
 |         ASSERT(hasValidRadixConstant()); | 
 |         return m_opInfo.as<int32_t>(); | 
 |     } | 
 |  | 
 |     bool hasIgnoreLastIndexIsWritable() | 
 |     { | 
 |         return op() == SetRegExpObjectLastIndex; | 
 |     } | 
 |  | 
 |     bool ignoreLastIndexIsWritable() | 
 |     { | 
 |         ASSERT(hasIgnoreLastIndexIsWritable()); | 
 |         return m_opInfo.as<uint32_t>(); | 
 |     } | 
 |  | 
 |     uint32_t errorType() | 
 |     { | 
 |         ASSERT(op() == ThrowStaticError); | 
 |         return m_opInfo.as<uint32_t>(); | 
 |     } | 
 |      | 
 |     bool hasCallLinkStatus() | 
 |     { | 
 |         return op() == FilterCallLinkStatus; | 
 |     } | 
 |      | 
 |     CallLinkStatus* callLinkStatus() | 
 |     { | 
 |         ASSERT(hasCallLinkStatus()); | 
 |         return m_opInfo.as<CallLinkStatus*>(); | 
 |     } | 
 |      | 
 |     bool hasGetByStatus() | 
 |     { | 
 |         return op() == FilterGetByStatus; | 
 |     } | 
 |      | 
 |     GetByStatus* getByStatus() | 
 |     { | 
 |         ASSERT(hasGetByStatus()); | 
 |         return m_opInfo.as<GetByStatus*>(); | 
 |     } | 
 |      | 
 |     bool hasInByStatus() | 
 |     { | 
 |         return op() == FilterInByStatus; | 
 |     } | 
 |      | 
 |     InByStatus* inByStatus() | 
 |     { | 
 |         ASSERT(hasInByStatus()); | 
 |         return m_opInfo.as<InByStatus*>(); | 
 |     } | 
 |      | 
 |     bool hasPutByStatus() | 
 |     { | 
 |         return op() == FilterPutByStatus; | 
 |     } | 
 |      | 
 |     PutByStatus* putByStatus() | 
 |     { | 
 |         ASSERT(hasPutByStatus()); | 
 |         return m_opInfo.as<PutByStatus*>(); | 
 |     } | 
 |  | 
 |     bool hasDeleteByStatus() | 
 |     { | 
 |         return op() == FilterDeleteByStatus; | 
 |     } | 
 |  | 
 |     DeleteByStatus* deleteByStatus() | 
 |     { | 
 |         ASSERT(hasDeleteByStatus()); | 
 |         return m_opInfo.as<DeleteByStatus*>(); | 
 |     } | 
 |  | 
 |     bool hasCheckPrivateBrandStatus() | 
 |     { | 
 |         return op() == FilterCheckPrivateBrandStatus; | 
 |     } | 
 |  | 
 |     CheckPrivateBrandStatus* checkPrivateBrandStatus() | 
 |     { | 
 |         ASSERT(hasCheckPrivateBrandStatus()); | 
 |         return m_opInfo.as<CheckPrivateBrandStatus*>(); | 
 |     } | 
 |  | 
 |     bool hasSetPrivateBrandStatus() | 
 |     { | 
 |         return op() == FilterSetPrivateBrandStatus; | 
 |     } | 
 |  | 
 |     SetPrivateBrandStatus* setPrivateBrandStatus() | 
 |     { | 
 |         ASSERT(hasSetPrivateBrandStatus()); | 
 |         return m_opInfo.as<SetPrivateBrandStatus*>(); | 
 |     } | 
 |  | 
 |     bool hasEnumeratorMetadata() const | 
 |     { | 
 |         switch (op()) { | 
 |         case EnumeratorNextUpdateIndexAndMode: | 
 |         case EnumeratorNextUpdatePropertyName: | 
 |         case EnumeratorHasOwnProperty: | 
 |         case EnumeratorInByVal: | 
 |             return true; | 
 |         default: | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     OptionSet<JSPropertyNameEnumerator::Flag> enumeratorMetadata() | 
 |     { | 
 |         ASSERT(hasEnumeratorMetadata()); | 
 |         return OptionSet<JSPropertyNameEnumerator::Flag>::fromRaw(m_opInfo2.as<unsigned>()); | 
 |     } | 
 |  | 
 |     void dumpChildren(PrintStream& out) | 
 |     { | 
 |         if (!child1()) | 
 |             return; | 
 |         out.printf("@%u", child1()->index()); | 
 |         if (!child2()) | 
 |             return; | 
 |         out.printf(", @%u", child2()->index()); | 
 |         if (!child3()) | 
 |             return; | 
 |         out.printf(", @%u", child3()->index()); | 
 |     } | 
 |  | 
 |     NodeOrigin origin; | 
 |  | 
 |     // References to up to 3 children, or links to a variable length set of children. | 
 |     AdjacencyList children; | 
 |  | 
 | private: | 
 |     friend class B3::SparseCollection<Node>; | 
 |  | 
 |     unsigned m_index { std::numeric_limits<unsigned>::max() }; | 
 |     unsigned m_op : 10; // real type is NodeType | 
 |     unsigned m_flags : 21; | 
 |     // The virtual register number (spill location) associated with this . | 
 |     VirtualRegister m_virtualRegister; | 
 |     // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects). | 
 |     unsigned m_refCount; | 
 |     // The prediction ascribed to this node after propagation. | 
 |     SpeculatedType m_prediction { SpecNone }; | 
 |     // Immediate values, accesses type-checked via accessors above. | 
 |     struct OpInfoWrapper { | 
 |         OpInfoWrapper() | 
 |         { | 
 |             u.int64 = 0; | 
 |         } | 
 |         OpInfoWrapper(uint32_t intValue) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.int32 = intValue; | 
 |         } | 
 |         OpInfoWrapper(uint64_t intValue) | 
 |         { | 
 |             u.int64 = intValue; | 
 |         } | 
 |         OpInfoWrapper(void* pointer) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = pointer; | 
 |         } | 
 |         OpInfoWrapper(const void* constPointer) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.constPointer = constPointer; | 
 |         } | 
 |         OpInfoWrapper(RegisteredStructure structure) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = bitwise_cast<void*>(structure); | 
 |         } | 
 |         OpInfoWrapper(CacheableIdentifier identifier) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = bitwise_cast<void*>(identifier.rawBits()); | 
 |         } | 
 |         OpInfoWrapper& operator=(uint32_t int32) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.int32 = int32; | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(int32_t int32) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.int32 = int32; | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(uint64_t int64) | 
 |         { | 
 |             u.int64 = int64; | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(void* pointer) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = pointer; | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(const void* constPointer) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.constPointer = constPointer; | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(RegisteredStructure structure) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = bitwise_cast<void*>(structure); | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(CacheableIdentifier identifier) | 
 |         { | 
 |             u.int64 = 0; | 
 |             u.pointer = bitwise_cast<void*>(identifier.rawBits()); | 
 |             return *this; | 
 |         } | 
 |         OpInfoWrapper& operator=(NewArrayBufferData newArrayBufferData) | 
 |         { | 
 |             u.int64 = bitwise_cast<uint64_t>(newArrayBufferData); | 
 |             return *this; | 
 |         } | 
 |         template <typename T> | 
 |         ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type | 
 |         { | 
 |             return static_cast<T>(u.pointer); | 
 |         } | 
 |         template <typename T> | 
 |         ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && std::is_const<typename std::remove_pointer<T>::type>::value, T>::type | 
 |         { | 
 |             return static_cast<T>(u.constPointer); | 
 |         } | 
 |         template <typename T> | 
 |         ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) <= 4, T>::type | 
 |         { | 
 |             return static_cast<T>(u.int32); | 
 |         } | 
 |         template <typename T> | 
 |         ALWAYS_INLINE auto as() const -> typename std::enable_if<(std::is_integral<T>::value || std::is_enum<T>::value) && sizeof(T) == 8, T>::type | 
 |         { | 
 |             return static_cast<T>(u.int64); | 
 |         } | 
 |         ALWAYS_INLINE RegisteredStructure asRegisteredStructure() const | 
 |         { | 
 |             return bitwise_cast<RegisteredStructure>(u.pointer); | 
 |         } | 
 |         ALWAYS_INLINE NewArrayBufferData asNewArrayBufferData() const | 
 |         { | 
 |             return bitwise_cast<NewArrayBufferData>(u.int64); | 
 |         } | 
 |  | 
 |         union { | 
 |             uint32_t int32; | 
 |             uint64_t int64; | 
 |             void* pointer; | 
 |             const void* constPointer; | 
 |         } u; | 
 |     }; | 
 |     OpInfoWrapper m_opInfo; | 
 |     OpInfoWrapper m_opInfo2; | 
 |  | 
 |     // Miscellaneous data that is usually meaningless, but can hold some analysis results | 
 |     // if you ask right. For example, if you do Graph::initializeNodeOwners(), Node::owner | 
 |     // will tell you which basic block a node belongs to. You cannot rely on this persisting | 
 |     // across transformations unless you do the maintenance work yourself. Other phases use | 
 |     // Node::replacement, but they do so manually: first you do Graph::clearReplacements() | 
 |     // and then you set, and use, replacement's yourself. Same thing for epoch. | 
 |     // | 
 |     // Bottom line: don't use these fields unless you initialize them yourself, or by | 
 |     // calling some appropriate methods that initialize them the way you want. Otherwise, | 
 |     // these fields are meaningless. | 
 | private: | 
 |     union { | 
 |         Node* replacement; | 
 |         unsigned epoch; | 
 |     } m_misc; | 
 | public: | 
 |     BasicBlock* owner; | 
 | }; | 
 |  | 
 | // Uncomment this to log NodeSet operations. | 
 | // typedef LoggingHashSet<Node::HashSetTemplateInstantiationString, Node*> NodeSet; | 
 | typedef HashSet<Node*> NodeSet; | 
 |  | 
 | struct NodeComparator { | 
 |     template<typename NodePtrType> | 
 |     bool operator()(NodePtrType a, NodePtrType b) const | 
 |     { | 
 |         return a->index() < b->index(); | 
 |     } | 
 | }; | 
 |  | 
 | template<typename T> | 
 | CString nodeListDump(const T& nodeList) | 
 | { | 
 |     return sortedListDump(nodeList, NodeComparator()); | 
 | } | 
 |  | 
 | template<typename T> | 
 | CString nodeMapDump(const T& nodeMap, DumpContext* context = nullptr) | 
 | { | 
 |     Vector<typename T::KeyType> keys; | 
 |     for ( | 
 |         typename T::const_iterator iter = nodeMap.begin(); | 
 |         iter != nodeMap.end(); ++iter) | 
 |         keys.append(iter->key); | 
 |     std::sort(keys.begin(), keys.end(), NodeComparator()); | 
 |     StringPrintStream out; | 
 |     CommaPrinter comma; | 
 |     for(unsigned i = 0; i < keys.size(); ++i) | 
 |         out.print(comma, keys[i], "=>", inContext(nodeMap.get(keys[i]), context)); | 
 |     return out.toCString(); | 
 | } | 
 |  | 
 | template<typename T> | 
 | CString nodeValuePairListDump(const T& nodeValuePairList, DumpContext* context = nullptr) | 
 | { | 
 |     using V = typename T::ValueType; | 
 |     T sortedList = nodeValuePairList; | 
 |     std::sort(sortedList.begin(), sortedList.end(), [](const V& a, const V& b) { | 
 |         return NodeComparator()(a.node, b.node); | 
 |     }); | 
 |  | 
 |     StringPrintStream out; | 
 |     CommaPrinter comma; | 
 |     for (const auto& pair : sortedList) | 
 |         out.print(comma, pair.node, "=>", inContext(pair.value, context)); | 
 |     return out.toCString(); | 
 | } | 
 |  | 
 | } } // namespace JSC::DFG | 
 |  | 
 | namespace WTF { | 
 |  | 
 | void printInternal(PrintStream&, JSC::DFG::SwitchKind); | 
 | void printInternal(PrintStream&, JSC::DFG::Node*); | 
 |  | 
 | inline JSC::DFG::Node* inContext(JSC::DFG::Node* node, JSC::DumpContext*) { return node; } | 
 |  | 
 | template<> | 
 | struct LoggingHashKeyTraits<JSC::DFG::Node*> { | 
 |     static void print(PrintStream& out, JSC::DFG::Node* key) | 
 |     { | 
 |         out.print("bitwise_cast<::JSC::DFG::Node*>(", RawPointer(key), "lu)"); | 
 |     } | 
 | }; | 
 |  | 
 | } // namespace WTF | 
 |  | 
 | using WTF::inContext; | 
 |  | 
 | #endif |