summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGNode.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGNode.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGNode.h311
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