/* * Copyright (C) 2011 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. */ #ifndef DFGNode_h #define DFGNode_h // Emit various logging information for debugging, including dumping the dataflow graphs. #define DFG_DEBUG_VERBOSE 0 // Enable generation of dynamic checks into the instruction stream. #define DFG_JIT_ASSERT 0 // Consistency check contents compiler data structures. #define DFG_CONSISTENCY_CHECK 0 // Emit a breakpoint into the head of every generated function, to aid debugging in GDB. #define DFG_JIT_BREAK_ON_EVERY_FUNCTION 0 // Emit a breakpoint into the head of every generated node, to aid debugging in GDB. #define DFG_JIT_BREAK_ON_EVERY_BLOCK 0 // Emit a breakpoint into the head of every generated node, to aid debugging in GDB. #define DFG_JIT_BREAK_ON_EVERY_NODE 0 // Disable the DFG JIT without having to touch Platform.h! #define DFG_DEBUG_LOCAL_DISBALE 0 // Generate stats on how successful we were in making use of the DFG jit, and remaining on the hot path. #define DFG_SUCCESS_STATS 0 #if ENABLE(DFG_JIT) #include <wtf/Vector.h> namespace JSC { namespace DFG { // Type for a virtual register number (spill location). // Using an enum to make this type-checked at compile time, to avert programmer errors. enum VirtualRegister { InvalidVirtualRegister = -1 }; COMPILE_ASSERT(sizeof(VirtualRegister) == sizeof(int), VirtualRegister_is_32bit); // Type for a reference to another node in the graph. typedef uint32_t NodeIndex; static const NodeIndex NoNode = UINT_MAX; // Information used to map back from an exception to any handler/source information. // (Presently implemented as a bytecode index). typedef uint32_t ExceptionInfo; // Entries in the NodeType enum (below) are composed of an id, a result type (possibly none) // and some additional informative flags (must generate, is constant, etc). #define NodeIdMask 0xFFF #define NodeResultMask 0xF000 #define NodeMustGenerate 0x10000 // set on nodes that have side effects, and may not trivially be removed by DCE. #define NodeIsConstant 0x20000 #define NodeIsJump 0x40000 #define NodeIsBranch 0x80000 // These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result. #define NodeResultJS 0x1000 #define NodeResultDouble 0x2000 #define NodeResultInt32 0x3000 // This macro defines a set of information about all known node types, used to populate NodeId, NodeType below. #define FOR_EACH_DFG_OP(macro) \ /* Nodes for constants. */\ macro(JSConstant, NodeResultJS | NodeIsConstant) \ macro(Int32Constant, NodeResultJS | NodeIsConstant) \ macro(DoubleConstant, NodeResultJS | NodeIsConstant) \ macro(ConvertThis, NodeResultJS) \ \ /* Nodes for local variable access. */\ macro(GetLocal, NodeResultJS) \ macro(SetLocal, NodeMustGenerate) \ \ /* Nodes for bitwise operations. */\ macro(BitAnd, NodeResultInt32) \ macro(BitOr, NodeResultInt32) \ macro(BitXor, NodeResultInt32) \ macro(BitLShift, NodeResultInt32) \ macro(BitRShift, NodeResultInt32) \ macro(BitURShift, NodeResultInt32) \ /* Bitwise operators call ToInt32 on their operands. */\ macro(NumberToInt32, NodeResultInt32) \ macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \ /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\ macro(UInt32ToNumber, NodeResultDouble) \ \ /* Nodes for arithmetic operations. */\ macro(ArithAdd, NodeResultDouble) \ macro(ArithSub, NodeResultDouble) \ macro(ArithMul, NodeResultDouble) \ macro(ArithDiv, NodeResultDouble) \ macro(ArithMod, NodeResultDouble) \ /* Arithmetic operators call ToNumber on their operands. */\ macro(Int32ToNumber, NodeResultDouble) \ macro(ValueToNumber, NodeResultDouble | NodeMustGenerate) \ \ /* Add of values may either be arithmetic, or result in string concatenation. */\ macro(ValueAdd, NodeResultJS | NodeMustGenerate) \ \ /* Property access. */\ /* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\ /* Since a put to 'length' may invalidate optimizations here, */\ /* this must be the directly subsequent property put. */\ macro(GetByVal, NodeResultJS | NodeMustGenerate) \ macro(PutByVal, NodeMustGenerate) \ macro(PutByValAlias, NodeMustGenerate) \ macro(GetById, NodeResultJS | NodeMustGenerate) \ macro(PutById, NodeMustGenerate) \ macro(PutByIdDirect, NodeMustGenerate) \ macro(GetGlobalVar, NodeResultJS | NodeMustGenerate) \ macro(PutGlobalVar, NodeMustGenerate) \ \ /* Nodes for comparison operations. */\ macro(CompareLess, NodeResultJS | NodeMustGenerate) \ macro(CompareLessEq, NodeResultJS | NodeMustGenerate) \ macro(CompareEq, NodeResultJS | NodeMustGenerate) \ macro(CompareStrictEq, NodeResultJS) \ \ /* Nodes for misc operations. */\ macro(LogicalNot, NodeResultJS) \ \ /* Block terminals. */\ macro(Jump, NodeMustGenerate | NodeIsJump) \ macro(Branch, NodeMustGenerate | NodeIsBranch) \ macro(Return, NodeMustGenerate) // This enum generates a monotonically increasing id for all Node types, // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask). enum NodeId { #define DFG_OP_ENUM(opcode, flags) opcode##_id, FOR_EACH_DFG_OP(DFG_OP_ENUM) #undef DFG_OP_ENUM }; // Entries in this enum describe all Node types. // The enum value contains a monotonically increasing id, a result type, and additional flags. enum NodeType { #define DFG_OP_ENUM(opcode, flags) opcode = opcode##_id | (flags), FOR_EACH_DFG_OP(DFG_OP_ENUM) #undef DFG_OP_ENUM }; // This type used in passing an immediate argument to Node constructor; // distinguishes an immediate value (typically an index into a CodeBlock data structure - // a constant index, argument, or identifier) from a NodeIndex. struct OpInfo { explicit OpInfo(unsigned value) : m_value(value) {} unsigned m_value; }; // === Node === // // Node represents a single operation in the data flow graph. struct Node { // Construct a node with up to 3 children, no immediate value. Node(NodeType op, ExceptionInfo exceptionInfo, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) : op(op) , exceptionInfo(exceptionInfo) , child1(child1) , child2(child2) , child3(child3) , virtualRegister(InvalidVirtualRegister) , refCount(0) { } // Construct a node with up to 3 children and an immediate value. Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) : op(op) , exceptionInfo(exceptionInfo) , child1(child1) , child2(child2) , child3(child3) , virtualRegister(InvalidVirtualRegister) , refCount(0) , m_opInfo(imm.m_value) { } // Construct a node with up to 3 children and two immediate values. Node(NodeType op, ExceptionInfo exceptionInfo, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) : op(op) , exceptionInfo(exceptionInfo) , child1(child1) , child2(child2) , child3(child3) , virtualRegister(InvalidVirtualRegister) , refCount(0) , m_opInfo(imm1.m_value) { m_constantValue.opInfo2 = imm2.m_value; } bool mustGenerate() { return op & NodeMustGenerate; } bool isConstant() { return op & NodeIsConstant; } unsigned constantNumber() { ASSERT(isConstant()); return m_opInfo; } bool hasLocal() { return op == GetLocal || op == SetLocal; } VirtualRegister local() { ASSERT(hasLocal()); return (VirtualRegister)m_opInfo; } bool hasIdentifier() { return op == GetById || op == PutById || op == PutByIdDirect; } unsigned identifierNumber() { ASSERT(hasIdentifier()); return m_opInfo; } bool hasVarNumber() { return op == GetGlobalVar || op == PutGlobalVar; } unsigned varNumber() { ASSERT(hasVarNumber()); return m_opInfo; } bool hasInt32Result() { return (op & NodeResultMask) == NodeResultInt32; } bool hasDoubleResult() { return (op & NodeResultMask) == NodeResultDouble; } bool hasJSResult() { return (op & NodeResultMask) == NodeResultJS; } // Check for integers or doubles. bool hasNumericResult() { // This check will need updating if more result types are added. ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult()); return !hasJSResult(); } int32_t int32Constant() { ASSERT(op == Int32Constant); return m_constantValue.asInt32; } void setInt32Constant(int32_t value) { ASSERT(op == Int32Constant); m_constantValue.asInt32 = value; } double numericConstant() { ASSERT(op == DoubleConstant); return m_constantValue.asDouble; } void setDoubleConstant(double value) { ASSERT(op == DoubleConstant); m_constantValue.asDouble = value; } bool isJump() { return op & NodeIsJump; } bool isBranch() { return op & NodeIsBranch; } unsigned takenBytecodeOffset() { ASSERT(isBranch() || isJump()); return m_opInfo; } unsigned notTakenBytecodeOffset() { ASSERT(isBranch()); return m_constantValue.opInfo2; } // This enum value describes the type of the node. NodeType op; // Used to look up exception handling information (currently implemented as a bytecode index). ExceptionInfo exceptionInfo; // References to up to 3 children (0 for no child). NodeIndex child1, child2, child3; // The virtual register number (spill location) associated with this . VirtualRegister virtualRegister; // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects). unsigned refCount; private: // An immediate value, accesses type-checked via accessors above. unsigned m_opInfo; // The value of an int32/double constant. union { int32_t asInt32; double asDouble; unsigned opInfo2; } m_constantValue; }; } } // namespace JSC::DFG #endif #endif