summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGGraph.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGraph.h')
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.h210
1 files changed, 190 insertions, 20 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 0c8ac2dcf..52654d23b 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -26,12 +26,15 @@
#ifndef DFGGraph_h
#define DFGGraph_h
+#include <wtf/Platform.h>
+
#if ENABLE(DFG_JIT)
#include "CodeBlock.h"
#include "DFGArgumentPosition.h"
#include "DFGAssemblyHelpers.h"
#include "DFGBasicBlock.h"
+#include "DFGDominators.h"
#include "DFGNode.h"
#include "MethodOfGettingAValueProfile.h"
#include "RegisterFile.h"
@@ -77,6 +80,7 @@ public:
: m_globalData(globalData)
, m_codeBlock(codeBlock)
, m_profiledBlock(codeBlock->alternative())
+ , m_hasArguments(false)
{
ASSERT(m_profiledBlock);
}
@@ -105,6 +109,8 @@ public:
void deref(NodeIndex nodeIndex)
{
+ if (!at(nodeIndex).refCount())
+ dump();
if (at(nodeIndex).deref())
derefChildren(nodeIndex);
}
@@ -113,6 +119,24 @@ public:
deref(nodeUse.index());
}
+ void changeIndex(Edge& edge, NodeIndex newIndex, bool changeRef = true)
+ {
+ if (changeRef) {
+ ref(newIndex);
+ deref(edge.index());
+ }
+ edge.setIndex(newIndex);
+ }
+
+ void changeEdge(Edge& edge, Edge newEdge, bool changeRef = true)
+ {
+ if (changeRef) {
+ ref(newEdge);
+ deref(edge);
+ }
+ edge = newEdge;
+ }
+
void clearAndDerefChild1(Node& node)
{
if (!node.child1())
@@ -136,6 +160,22 @@ public:
deref(node.child3());
node.children.child3() = Edge();
}
+
+ // Call this if you've modified the reference counts of nodes that deal with
+ // local variables. This is necessary because local variable references can form
+ // cycles, and hence reference counting is not enough. This will reset the
+ // reference counts according to reachability.
+ void collectGarbage();
+
+ void convertToConstant(NodeIndex nodeIndex, unsigned constantNumber)
+ {
+ at(nodeIndex).convertToConstant(constantNumber);
+ }
+
+ void convertToConstant(NodeIndex nodeIndex, JSValue value)
+ {
+ convertToConstant(nodeIndex, m_codeBlock->addOrFindConstant(value));
+ }
// CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
void dump();
@@ -167,6 +207,21 @@ public:
return Node::shouldSpeculateInteger(left, right) && add.canSpeculateInteger();
}
+ bool mulShouldSpeculateInteger(Node& mul)
+ {
+ ASSERT(mul.op() == ArithMul);
+
+ Node& left = at(mul.child1());
+ Node& right = at(mul.child2());
+
+ if (left.hasConstant())
+ return mulImmediateShouldSpeculateInteger(mul, right, left);
+ if (right.hasConstant())
+ return mulImmediateShouldSpeculateInteger(mul, left, right);
+
+ return Node::shouldSpeculateInteger(left, right) && mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
+ }
+
bool negateShouldSpeculateInteger(Node& negate)
{
ASSERT(negate.op() == ArithNegate);
@@ -255,11 +310,48 @@ public:
return &m_structureTransitionData.last();
}
+ ExecutableBase* executableFor(InlineCallFrame* inlineCallFrame)
+ {
+ if (!inlineCallFrame)
+ return m_codeBlock->ownerExecutable();
+
+ return inlineCallFrame->executable.get();
+ }
+
+ ExecutableBase* executableFor(const CodeOrigin& codeOrigin)
+ {
+ return executableFor(codeOrigin.inlineCallFrame);
+ }
+
CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
{
return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
}
+ int argumentsRegisterFor(const CodeOrigin& codeOrigin)
+ {
+ if (!codeOrigin.inlineCallFrame)
+ return m_codeBlock->argumentsRegister();
+
+ return baselineCodeBlockForInlineCallFrame(
+ codeOrigin.inlineCallFrame)->argumentsRegister() +
+ codeOrigin.inlineCallFrame->stackOffset;
+ }
+
+ int uncheckedArgumentsRegisterFor(const CodeOrigin& codeOrigin)
+ {
+ if (!codeOrigin.inlineCallFrame)
+ return m_codeBlock->uncheckedArgumentsRegister();
+
+ CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(
+ codeOrigin.inlineCallFrame);
+ if (!codeBlock->usesArguments())
+ return InvalidVirtualRegister;
+
+ return codeBlock->argumentsRegister() +
+ codeOrigin.inlineCallFrame->stackOffset;
+ }
+
ValueProfile* valueProfileFor(NodeIndex nodeIndex)
{
if (nodeIndex == NoNode)
@@ -303,37 +395,86 @@ public:
bool needsActivation() const
{
-#if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
- return true;
-#else
return m_codeBlock->needsFullScopeChain() && m_codeBlock->codeType() != GlobalCode;
-#endif
}
- // Pass an argument index. Currently it's ignored, but that's somewhat
- // of a bug.
- bool argumentIsCaptured(int) const
+ bool usesArguments() const
{
- return needsActivation();
+ return m_codeBlock->usesArguments();
}
- bool localIsCaptured(int operand) const
+
+ unsigned numSuccessors(BasicBlock* block)
{
-#if DFG_ENABLE(ALL_VARIABLES_CAPTURED)
- return operand < m_codeBlock->m_numVars;
-#else
- return operand < m_codeBlock->m_numCapturedVars;
-#endif
+ return at(block->last()).numSuccessors();
+ }
+ BlockIndex successor(BasicBlock* block, unsigned index)
+ {
+ return at(block->last()).successor(index);
+ }
+ BlockIndex successorForCondition(BasicBlock* block, bool condition)
+ {
+ return at(block->last()).successorForCondition(condition);
+ }
+
+ bool isPredictedNumerical(Node& node)
+ {
+ PredictedType left = at(node.child1()).prediction();
+ PredictedType right = at(node.child2()).prediction();
+ return isNumberPrediction(left) && isNumberPrediction(right);
+ }
+
+ bool byValIsPure(Node& node)
+ {
+ return at(node.child2()).shouldSpeculateInteger()
+ && ((node.op() == PutByVal || node.op() == PutByValAlias)
+ ? isActionableMutableArrayPrediction(at(node.child1()).prediction())
+ : isActionableArrayPrediction(at(node.child1()).prediction()));
}
- bool isCaptured(int operand) const
+ bool clobbersWorld(Node& node)
{
- if (operandIsArgument(operand))
- return argumentIsCaptured(operandToArgument(operand));
- return localIsCaptured(operand);
+ if (node.flags() & NodeClobbersWorld)
+ return true;
+ if (!(node.flags() & NodeMightClobber))
+ return false;
+ switch (node.op()) {
+ case ValueAdd:
+ case CompareLess:
+ case CompareLessEq:
+ case CompareGreater:
+ case CompareGreaterEq:
+ case CompareEq:
+ return !isPredictedNumerical(node);
+ case GetByVal:
+ return !byValIsPure(node);
+ default:
+ ASSERT_NOT_REACHED();
+ return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
+ }
}
- bool isCaptured(VirtualRegister virtualRegister) const
+
+ bool clobbersWorld(NodeIndex nodeIndex)
{
- return isCaptured(static_cast<int>(virtualRegister));
+ return clobbersWorld(at(nodeIndex));
+ }
+
+ void determineReachability();
+ void resetReachability();
+
+ void resetExitStates();
+
+ unsigned numChildren(Node& node)
+ {
+ if (node.flags() & NodeHasVarArgs)
+ return node.numChildren();
+ return AdjacencyList::Size;
+ }
+
+ Edge child(Node& node, unsigned index)
+ {
+ if (node.flags() & NodeHasVarArgs)
+ return m_varArgChildren[node.firstChild() + index];
+ return node.children.child(index);
}
JSGlobalData& m_globalData;
@@ -349,11 +490,16 @@ public:
SegmentedVector<ArgumentPosition, 8> m_argumentPositions;
SegmentedVector<StructureSet, 16> m_structureSet;
SegmentedVector<StructureTransitionData, 8> m_structureTransitionData;
+ bool m_hasArguments;
+ HashSet<ExecutableBase*> m_executablesWhoseArgumentsEscaped;
BitVector m_preservedVars;
+ Dominators m_dominators;
unsigned m_localVars;
unsigned m_parameterSlots;
private:
+ void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
+
bool addImmediateShouldSpeculateInteger(Node& add, Node& variable, Node& immediate)
{
ASSERT(immediate.hasConstant());
@@ -376,6 +522,30 @@ private:
return nodeCanTruncateInteger(add.arithNodeFlags());
}
+ bool mulImmediateShouldSpeculateInteger(Node& mul, Node& variable, Node& immediate)
+ {
+ ASSERT(immediate.hasConstant());
+
+ JSValue immediateValue = immediate.valueOfJSConstant(m_codeBlock);
+ if (!immediateValue.isInt32())
+ return false;
+
+ if (!variable.shouldSpeculateInteger())
+ return false;
+
+ int32_t intImmediate = immediateValue.asInt32();
+ // Doubles have a 53 bit mantissa so we expect a multiplication of 2^31 (the highest
+ // magnitude possible int32 value) and any value less than 2^22 to not result in any
+ // rounding in a double multiplication - hence it will be equivalent to an integer
+ // multiplication, if we are doing int32 truncation afterwards (which is what
+ // canSpeculateInteger() implies).
+ const int32_t twoToThe22 = 1 << 22;
+ if (intImmediate <= -twoToThe22 || intImmediate >= twoToThe22)
+ return mul.canSpeculateInteger() && !nodeMayOverflow(mul.arithNodeFlags());
+
+ return mul.canSpeculateInteger();
+ }
+
// When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
void refChildren(NodeIndex);
void derefChildren(NodeIndex);