diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGNode.h')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGNode.h | 311 |
1 files changed, 226 insertions, 85 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index 5f7890a96..f45d3fa68 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,13 +32,15 @@ #include "CodeBlock.h" #include "CodeOrigin.h" +#include "DFGAbstractValue.h" #include "DFGAdjacencyList.h" #include "DFGArrayMode.h" #include "DFGCommon.h" #include "DFGNodeFlags.h" #include "DFGNodeType.h" #include "DFGVariableAccessData.h" -#include "JSValue.h" +#include "JSCJSValueInlines.h" +#include "JSCJSValue.h" #include "Operands.h" #include "SpeculatedType.h" #include "StructureSet.h" @@ -67,7 +69,7 @@ struct NewArrayBufferData { // 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. +// a constant index, argument, or identifier) from a Node*. struct OpInfo { explicit OpInfo(int32_t value) : m_value(static_cast<uintptr_t>(value)) { } explicit OpInfo(uint32_t value) : m_value(static_cast<uintptr_t>(value)) { } @@ -86,12 +88,22 @@ struct Node { Node() { } + Node(NodeType op, CodeOrigin codeOrigin, const AdjacencyList& children) + : codeOrigin(codeOrigin) + , children(children) + , m_virtualRegister(InvalidVirtualRegister) + , m_refCount(1) + , m_prediction(SpecNone) + { + setOpAndDefaultFlags(op); + } + // Construct a node with up to 3 children, no immediate value. - Node(NodeType op, CodeOrigin codeOrigin, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) + Node(NodeType op, CodeOrigin codeOrigin, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) : codeOrigin(codeOrigin) , children(AdjacencyList::Fixed, child1, child2, child3) , m_virtualRegister(InvalidVirtualRegister) - , m_refCount(0) + , m_refCount(1) , m_prediction(SpecNone) { setOpAndDefaultFlags(op); @@ -99,11 +111,11 @@ struct Node { } // Construct a node with up to 3 children and an immediate value. - Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) + Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) : codeOrigin(codeOrigin) , children(AdjacencyList::Fixed, child1, child2, child3) , m_virtualRegister(InvalidVirtualRegister) - , m_refCount(0) + , m_refCount(1) , m_opInfo(imm.m_value) , m_prediction(SpecNone) { @@ -112,11 +124,11 @@ struct Node { } // Construct a node with up to 3 children and two immediate values. - Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, NodeIndex child1 = NoNode, NodeIndex child2 = NoNode, NodeIndex child3 = NoNode) + Node(NodeType op, CodeOrigin codeOrigin, OpInfo imm1, OpInfo imm2, Edge child1 = Edge(), Edge child2 = Edge(), Edge child3 = Edge()) : codeOrigin(codeOrigin) , children(AdjacencyList::Fixed, child1, child2, child3) , m_virtualRegister(InvalidVirtualRegister) - , m_refCount(0) + , m_refCount(1) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) , m_prediction(SpecNone) @@ -130,7 +142,7 @@ struct Node { : codeOrigin(codeOrigin) , children(AdjacencyList::Variable, firstChild, numChildren) , m_virtualRegister(InvalidVirtualRegister) - , m_refCount(0) + , m_refCount(1) , m_opInfo(imm1.m_value) , m_opInfo2(safeCast<unsigned>(imm2.m_value)) , m_prediction(SpecNone) @@ -142,6 +154,9 @@ struct Node { NodeType op() const { return static_cast<NodeType>(m_op); } NodeFlags flags() const { return m_flags; } + // This is not a fast method. + unsigned index() const; + void setOp(NodeType op) { m_op = op; @@ -183,6 +198,35 @@ struct Node { m_flags = defaultFlags(op); } + void setOpAndDefaultNonExitFlags(NodeType op) + { + ASSERT(!(m_flags & NodeHasVarArgs)); + setOpAndDefaultNonExitFlagsUnchecked(op); + } + + void setOpAndDefaultNonExitFlagsUnchecked(NodeType op) + { + m_op = op; + m_flags = (defaultFlags(op) & ~NodeExitsForward) | (m_flags & NodeExitsForward); + } + + void convertToPhantom() + { + setOpAndDefaultNonExitFlags(Phantom); + } + + void convertToPhantomUnchecked() + { + setOpAndDefaultNonExitFlagsUnchecked(Phantom); + } + + void convertToIdentity() + { + RELEASE_ASSERT(child1()); + RELEASE_ASSERT(!child2()); + setOpAndDefaultNonExitFlags(Identity); + } + bool mustGenerate() { return m_flags & NodeMustGenerate; @@ -211,6 +255,16 @@ struct Node { return op() == WeakJSConstant; } + bool isStronglyProvedConstantIn(InlineCallFrame* inlineCallFrame) + { + return isConstant() && codeOrigin.inlineCallFrame == inlineCallFrame; + } + + bool isStronglyProvedConstantIn(const CodeOrigin& codeOrigin) + { + return isStronglyProvedConstantIn(codeOrigin.inlineCallFrame); + } + bool isPhantomArguments() { return op() == PhantomArguments; @@ -237,18 +291,22 @@ struct Node { void convertToConstant(unsigned constantNumber) { m_op = JSConstant; - if (m_flags & NodeMustGenerate) - m_refCount--; m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); m_opInfo = constantNumber; children.reset(); } + void convertToWeakConstant(JSCell* cell) + { + m_op = WeakJSConstant; + m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); + m_opInfo = bitwise_cast<uintptr_t>(cell); + children.reset(); + } + void convertToGetLocalUnlinked(VirtualRegister local) { m_op = GetLocalUnlinked; - if (m_flags & NodeMustGenerate) - m_refCount--; m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld); m_opInfo = local; children.reset(); @@ -269,26 +327,48 @@ struct Node { convertToStructureTransitionWatchpoint(structureSet().singletonStructure()); } - void convertToGetByOffset(unsigned storageAccessDataIndex, NodeIndex storage) + void convertToGetByOffset(unsigned storageAccessDataIndex, Edge storage) { ASSERT(m_op == GetById || m_op == GetByIdFlush); m_opInfo = storageAccessDataIndex; - children.setChild1(Edge(storage)); + children.setChild1(storage); m_op = GetByOffset; m_flags &= ~NodeClobbersWorld; } - void convertToPutByOffset(unsigned storageAccessDataIndex, NodeIndex storage) + void convertToPutByOffset(unsigned storageAccessDataIndex, Edge storage) { ASSERT(m_op == PutById || m_op == PutByIdDirect); m_opInfo = storageAccessDataIndex; children.setChild3(children.child2()); children.setChild2(children.child1()); - children.setChild1(Edge(storage)); + children.setChild1(storage); m_op = PutByOffset; m_flags &= ~NodeClobbersWorld; } + void convertToPhantomLocal() + { + ASSERT(m_op == Phantom && (child1()->op() == Phi || child1()->op() == SetLocal || child1()->op() == SetArgument)); + m_op = PhantomLocal; + m_opInfo = child1()->m_opInfo; // Copy the variableAccessData. + children.setChild1(Edge()); + } + + void convertToGetLocal(VariableAccessData* variable, Node* phi) + { + ASSERT(m_op == GetLocalUnlinked); + m_op = GetLocal; + m_opInfo = bitwise_cast<uintptr_t>(variable); + children.setChild1(Edge(phi)); + } + + void convertToToString() + { + ASSERT(m_op == ToPrimitive); + m_op = ToString; + } + JSCell* weakConstant() { ASSERT(op() == WeakJSConstant); @@ -305,7 +385,7 @@ struct Node { case PhantomArguments: return JSValue(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return JSValue(); // Have to return something in release mode. } } @@ -335,14 +415,31 @@ struct Node { return isConstant() && valueOfJSConstant(codeBlock).isBoolean(); } + bool containsMovHint() + { + switch (op()) { + case SetLocal: + case MovHint: + case MovHintAndCheck: + case ZombieHint: + return true; + default: + return false; + } + } + bool hasVariableAccessData() { switch (op()) { case GetLocal: case SetLocal: + case MovHint: + case MovHintAndCheck: + case ZombieHint: case Phi: case SetArgument: case Flush: + case PhantomLocal: return true; default: return false; @@ -427,8 +524,8 @@ struct Node { // to know if it can speculate on negative zero. NodeFlags arithNodeFlags() { - NodeFlags result = m_flags; - if (op() == ArithMul || op() == ArithDiv || op() == ArithMod) + NodeFlags result = m_flags & NodeArithFlagsMask; + if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == DoubleAsInt32) return result; return result & ~NodeNeedsNegZero; } @@ -474,6 +571,17 @@ struct Node { return m_opInfo; } + bool hasInlineCapacity() + { + return op() == CreateThis; + } + + unsigned inlineCapacity() + { + ASSERT(hasInlineCapacity()); + return m_opInfo; + } + void setIndexingType(IndexingType indexingType) { ASSERT(hasIndexingType()); @@ -523,23 +631,6 @@ struct Node { return bitwise_cast<WriteBarrier<Unknown>*>(m_opInfo); } - bool hasScopeChainDepth() - { - return op() == GetScope; - } - - unsigned scopeChainDepth() - { - ASSERT(hasScopeChainDepth()); - return m_opInfo; - } - - Edge scope() - { - ASSERT(op() == GetScopeRegisters); - return child1(); - } - bool hasResult() { return m_flags & NodeResultMask; @@ -650,7 +741,7 @@ struct Node { case 1: return notTakenBlockIndex(); default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); return NoBlock; } } @@ -705,7 +796,7 @@ struct Node { { switch (op()) { case CheckFunction: - case InheritorIDWatchpoint: + case AllocationProfileWatchpoint: return true; default: return false; @@ -719,6 +810,16 @@ struct Node { ASSERT(JSValue(result).isFunction()); return result; } + + bool hasExecutable() + { + return op() == CheckExecutable; + } + + ExecutableBase* executable() + { + return jsCast<ExecutableBase*>(reinterpret_cast<JSCell*>(m_opInfo)); + } bool hasStructureTransitionData() { @@ -763,6 +864,7 @@ struct Node { case ForwardStructureTransitionWatchpoint: case ArrayifyToStructure: case NewObject: + case NewStringObject: return true; default: return false; @@ -876,6 +978,16 @@ struct Node { ASSERT(hasArgumentPositionStart()); return m_opInfo; } + + bool hasExecutionCounter() + { + return op() == CountExecution; + } + + Profiler::ExecutionCounter* executionCounter() + { + return bitwise_cast<Profiler::ExecutionCounter*>(m_opInfo); + } bool shouldGenerate() { @@ -886,15 +998,20 @@ struct Node { { switch (op()) { case SetLocal: + case MovHint: + case ZombieHint: + case MovHintAndCheck: case Int32ToDouble: + case ForwardInt32ToDouble: case ValueToInt32: case UInt32ToNumber: case DoubleAsInt32: case PhantomArguments: return true; - case Phantom: case Nop: return false; + case Phantom: + return child1().useKindUnchecked() != UntypedUse || child2().useKindUnchecked() != UntypedUse || child3().useKindUnchecked() != UntypedUse; default: return shouldGenerate(); } @@ -905,10 +1022,9 @@ struct Node { return m_refCount; } - // returns true when ref count passes from 0 to 1. - bool ref() + unsigned postfixRef() { - return !m_refCount++; + return m_refCount++; } unsigned adjustedRefCount() @@ -921,16 +1037,7 @@ struct Node { m_refCount = refCount; } - // Derefs the node and returns true if the ref count reached zero. - // In general you don't want to use this directly; use Graph::deref - // instead. - bool deref() - { - ASSERT(m_refCount); - return !--m_refCount; - } - - Edge child1() + Edge& child1() { ASSERT(!(m_flags & NodeHasVarArgs)); return children.child1(); @@ -944,13 +1051,13 @@ struct Node { return children.child1Unchecked(); } - Edge child2() + Edge& child2() { ASSERT(!(m_flags & NodeHasVarArgs)); return children.child2(); } - Edge child3() + Edge& child3() { ASSERT(!(m_flags & NodeHasVarArgs)); return children.child3(); @@ -968,6 +1075,17 @@ struct Node { return children.numChildren(); } + UseKind binaryUseKind() + { + ASSERT(child1().useKind() == child2().useKind()); + return child1().useKind(); + } + + bool isBinaryUseKind(UseKind useKind) + { + return child1().useKind() == useKind && child2().useKind() == useKind; + } + SpeculatedType prediction() { return m_prediction; @@ -1023,21 +1141,21 @@ struct Node { return isStringSpeculation(prediction()); } - bool shouldSpeculateFinalObject() + bool shouldSpeculateStringObject() { - return isFinalObjectSpeculation(prediction()); + return isStringObjectSpeculation(prediction()); } - bool shouldSpeculateNonStringCell() + bool shouldSpeculateStringOrStringObject() { - return isNonStringCellSpeculation(prediction()); + return isStringOrStringObjectSpeculation(prediction()); } - - bool shouldSpeculateNonStringCellOrOther() + + bool shouldSpeculateFinalObject() { - return isNonStringCellOrOtherSpeculation(prediction()); + return isFinalObjectSpeculation(prediction()); } - + bool shouldSpeculateFinalObjectOrOther() { return isFinalObjectOrOtherSpeculation(prediction()); @@ -1108,49 +1226,59 @@ struct Node { return isObjectSpeculation(prediction()); } + bool shouldSpeculateObjectOrOther() + { + return isObjectOrOtherSpeculation(prediction()); + } + bool shouldSpeculateCell() { return isCellSpeculation(prediction()); } - static bool shouldSpeculateInteger(Node& op1, Node& op2) + static bool shouldSpeculateBoolean(Node* op1, Node* op2) + { + return op1->shouldSpeculateBoolean() && op2->shouldSpeculateBoolean(); + } + + static bool shouldSpeculateInteger(Node* op1, Node* op2) { - return op1.shouldSpeculateInteger() && op2.shouldSpeculateInteger(); + return op1->shouldSpeculateInteger() && op2->shouldSpeculateInteger(); } - static bool shouldSpeculateIntegerForArithmetic(Node& op1, Node& op2) + static bool shouldSpeculateIntegerForArithmetic(Node* op1, Node* op2) { - return op1.shouldSpeculateIntegerForArithmetic() && op2.shouldSpeculateIntegerForArithmetic(); + return op1->shouldSpeculateIntegerForArithmetic() && op2->shouldSpeculateIntegerForArithmetic(); } - static bool shouldSpeculateIntegerExpectingDefined(Node& op1, Node& op2) + static bool shouldSpeculateIntegerExpectingDefined(Node* op1, Node* op2) { - return op1.shouldSpeculateIntegerExpectingDefined() && op2.shouldSpeculateIntegerExpectingDefined(); + return op1->shouldSpeculateIntegerExpectingDefined() && op2->shouldSpeculateIntegerExpectingDefined(); } - static bool shouldSpeculateDoubleForArithmetic(Node& op1, Node& op2) + static bool shouldSpeculateDoubleForArithmetic(Node* op1, Node* op2) { - return op1.shouldSpeculateDoubleForArithmetic() && op2.shouldSpeculateDoubleForArithmetic(); + return op1->shouldSpeculateDoubleForArithmetic() && op2->shouldSpeculateDoubleForArithmetic(); } - static bool shouldSpeculateNumber(Node& op1, Node& op2) + static bool shouldSpeculateNumber(Node* op1, Node* op2) { - return op1.shouldSpeculateNumber() && op2.shouldSpeculateNumber(); + return op1->shouldSpeculateNumber() && op2->shouldSpeculateNumber(); } - static bool shouldSpeculateNumberExpectingDefined(Node& op1, Node& op2) + static bool shouldSpeculateNumberExpectingDefined(Node* op1, Node* op2) { - return op1.shouldSpeculateNumberExpectingDefined() && op2.shouldSpeculateNumberExpectingDefined(); + return op1->shouldSpeculateNumberExpectingDefined() && op2->shouldSpeculateNumberExpectingDefined(); } - static bool shouldSpeculateFinalObject(Node& op1, Node& op2) + static bool shouldSpeculateFinalObject(Node* op1, Node* op2) { - return op1.shouldSpeculateFinalObject() && op2.shouldSpeculateFinalObject(); + return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject(); } - static bool shouldSpeculateArray(Node& op1, Node& op2) + static bool shouldSpeculateArray(Node* op1, Node* op2) { - return op1.shouldSpeculateArray() && op2.shouldSpeculateArray(); + return op1->shouldSpeculateArray() && op2->shouldSpeculateArray(); } bool canSpeculateInteger() @@ -1162,23 +1290,25 @@ struct Node { { if (!child1()) return; - out.printf("@%u", child1().index()); + out.printf("@%u", child1()->index()); if (!child2()) return; - out.printf(", @%u", child2().index()); + out.printf(", @%u", child2()->index()); if (!child3()) return; - out.printf(", @%u", child3().index()); + out.printf(", @%u", child3()->index()); } + // NB. This class must have a trivial destructor. + // Used to look up exception handling information (currently implemented as a bytecode index). CodeOrigin codeOrigin; // References to up to 3 children, or links to a variable length set of children. AdjacencyList children; private: - uint16_t m_op; // real type is NodeType - NodeFlags m_flags; + unsigned m_op : 10; // real type is NodeType + unsigned m_flags : 22; // 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). @@ -1189,9 +1319,20 @@ private: unsigned m_opInfo2; // The prediction ascribed to this node after propagation. SpeculatedType m_prediction; + +public: + // Fields used by various analyses. + AbstractValue value; + Node* replacement; }; } } // namespace JSC::DFG +namespace WTF { + +void printInternal(PrintStream&, JSC::DFG::Node*); + +} // namespace WTF + #endif #endif |