summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp187
1 files changed, 109 insertions, 78 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
index a10fbe853..09dbf328b 100644
--- a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
#include "DFGBasicBlockInlines.h"
#include "DFGGraph.h"
#include "DFGPhase.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace DFG {
@@ -44,14 +44,19 @@ public:
bool run()
{
+ RELEASE_ASSERT(m_graph.m_refCountState == EverythingIsLive);
+
if (m_graph.m_form == ThreadedCPS)
return false;
clearIsLoadedFrom();
freeUnnecessaryNodes();
+ m_graph.clearReplacements();
canonicalizeLocalsInBlocks();
+ specialCaseArguments();
propagatePhis<LocalOperand>();
propagatePhis<ArgumentOperand>();
+ computeIsFlushed();
m_graph.m_form = ThreadedCPS;
return true;
@@ -69,8 +74,8 @@ private:
{
SamplingRegion samplingRegion("DFG CPS Rethreading: freeUnnecessaryNodes");
- for (BlockIndex blockIndex = m_graph.m_blocks.size(); blockIndex--;) {
- BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
if (!block)
continue;
ASSERT(block->isReachable);
@@ -86,25 +91,24 @@ private:
node->children.setChild1(Edge());
break;
case Phantom:
- if (!node->child1())
+ if (!node->child1()) {
+ m_graph.m_allocator.free(node);
continue;
+ }
switch (node->child1()->op()) {
case Phi:
case SetArgument:
case SetLocal:
- node->convertToPhantomLocal();
+ node->convertPhantomToPhantomLocal();
break;
default:
ASSERT(node->child1()->hasResult());
break;
}
break;
- case Nop:
- continue;
default:
break;
}
- node->replacement = 0; // Reset the replacement since the next phase will use it.
block->at(toIndex++) = node;
}
block->resize(toIndex);
@@ -116,37 +120,37 @@ private:
}
template<OperandKind operandKind>
- void clearVariablesAtHeadAndTail()
+ void clearVariables()
{
ASSERT(
m_block->variablesAtHead.sizeFor<operandKind>()
== m_block->variablesAtTail.sizeFor<operandKind>());
for (unsigned i = m_block->variablesAtHead.sizeFor<operandKind>(); i--;) {
- m_block->variablesAtHead.atFor<operandKind>(i) = 0;
- m_block->variablesAtTail.atFor<operandKind>(i) = 0;
+ m_block->variablesAtHead.atFor<operandKind>(i) = nullptr;
+ m_block->variablesAtTail.atFor<operandKind>(i) = nullptr;
}
}
- ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable)
+ ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const NodeOrigin& origin, VariableAccessData* variable)
{
- Node* result = m_graph.addNode(SpecNone, Phi, codeOrigin, OpInfo(variable));
+ Node* result = m_graph.addNode(SpecNone, Phi, origin, OpInfo(variable));
block->phis.append(result);
return result;
}
template<OperandKind operandKind>
- ALWAYS_INLINE Node* addPhi(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index)
+ ALWAYS_INLINE Node* addPhi(BasicBlock* block, const NodeOrigin& origin, VariableAccessData* variable, size_t index)
{
- Node* result = addPhiSilently(block, codeOrigin, variable);
+ Node* result = addPhiSilently(block, origin, variable);
phiStackFor<operandKind>().append(PhiStackEntry(block, index, result));
return result;
}
template<OperandKind operandKind>
- ALWAYS_INLINE Node* addPhi(const CodeOrigin& codeOrigin, VariableAccessData* variable, size_t index)
+ ALWAYS_INLINE Node* addPhi(const NodeOrigin& origin, VariableAccessData* variable, size_t index)
{
- return addPhi<operandKind>(m_block, codeOrigin, variable, index);
+ return addPhi<operandKind>(m_block, origin, variable, index);
}
template<OperandKind operandKind>
@@ -183,34 +187,19 @@ private:
return;
}
- if (variable->isCaptured()) {
- variable->setIsLoadedFrom(true);
- if (otherNode->op() == GetLocal)
- otherNode = otherNode->child1().node();
- else
- ASSERT(otherNode->op() == SetLocal || otherNode->op() == SetArgument);
-
- ASSERT(otherNode->op() == Phi || otherNode->op() == SetLocal || otherNode->op() == SetArgument);
-
- // Keep this GetLocal but link it to the prior ones.
- node->children.setChild1(Edge(otherNode));
- m_block->variablesAtTail.atFor<operandKind>(idx) = node;
- return;
- }
-
if (otherNode->op() == GetLocal) {
// Replace all references to this GetLocal with otherNode.
- node->replacement = otherNode;
+ node->replaceWith(otherNode);
return;
}
ASSERT(otherNode->op() == SetLocal);
- node->replacement = otherNode->child1().node();
+ node->replaceWith(otherNode->child1().node());
return;
}
variable->setIsLoadedFrom(true);
- Node* phi = addPhi<operandKind>(node->codeOrigin, variable, idx);
+ Node* phi = addPhi<operandKind>(node->origin, variable, idx);
node->children.setChild1(Edge(phi));
m_block->variablesAtHead.atFor<operandKind>(idx) = phi;
m_block->variablesAtTail.atFor<operandKind>(idx) = node;
@@ -219,15 +208,10 @@ private:
void canonicalizeGetLocal(Node* node)
{
VariableAccessData* variable = node->variableAccessData();
- if (operandIsArgument(variable->local()))
- canonicalizeGetLocalFor<ArgumentOperand>(node, variable, operandToArgument(variable->local()));
+ if (variable->local().isArgument())
+ canonicalizeGetLocalFor<ArgumentOperand>(node, variable, variable->local().toArgument());
else
- canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local());
- }
-
- void canonicalizeSetLocal(Node* node)
- {
- m_block->variablesAtTail.setOperand(node->local(), node);
+ canonicalizeGetLocalFor<LocalOperand>(node, variable, variable->local().toLocal());
}
template<NodeType nodeType, OperandKind operandKind>
@@ -256,13 +240,9 @@ private:
// for the purpose of OSR. PhantomLocal(SetLocal) means: at this point I
// know that I would have read the value written by that SetLocal. This is
// redundant and inefficient, since really it just means that we want to
- // be keeping the operand to the SetLocal alive. The SetLocal may die, and
- // we'll be fine because OSR tracks dead SetLocals.
+ // keep the last MovHinted value of that local alive.
- // So we turn this into a Phantom on the child of the SetLocal.
-
- node->convertToPhantom();
- node->children.setChild1(otherNode->child1());
+ node->remove();
return;
}
@@ -278,7 +258,7 @@ private:
}
variable->setIsLoadedFrom(true);
- node->children.setChild1(Edge(addPhi<operandKind>(node->codeOrigin, variable, idx)));
+ node->children.setChild1(Edge(addPhi<operandKind>(node->origin, variable, idx)));
m_block->variablesAtHead.atFor<operandKind>(idx) = node;
m_block->variablesAtTail.atFor<operandKind>(idx) = node;
}
@@ -287,19 +267,15 @@ private:
void canonicalizeFlushOrPhantomLocal(Node* node)
{
VariableAccessData* variable = node->variableAccessData();
- if (operandIsArgument(variable->local()))
- canonicalizeFlushOrPhantomLocalFor<nodeType, ArgumentOperand>(node, variable, operandToArgument(variable->local()));
+ if (variable->local().isArgument())
+ canonicalizeFlushOrPhantomLocalFor<nodeType, ArgumentOperand>(node, variable, variable->local().toArgument());
else
- canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local());
+ canonicalizeFlushOrPhantomLocalFor<nodeType, LocalOperand>(node, variable, variable->local().toLocal());
}
- void canonicalizeSetArgument(Node* node)
+ void canonicalizeSet(Node* node)
{
- int local = node->local();
- ASSERT(operandIsArgument(local));
- int argument = operandToArgument(local);
- m_block->variablesAtHead.setArgumentFirstTime(argument, node);
- m_block->variablesAtTail.setArgumentFirstTime(argument, node);
+ m_block->variablesAtTail.setOperand(node->local(), node);
}
void canonicalizeLocalsInBlock()
@@ -308,8 +284,8 @@ private:
return;
ASSERT(m_block->isReachable);
- clearVariablesAtHeadAndTail<ArgumentOperand>();
- clearVariablesAtHeadAndTail<LocalOperand>();
+ clearVariables<ArgumentOperand>();
+ clearVariables<LocalOperand>();
// Assumes that all phi references have been removed. Assumes that things that
// should be live have a non-zero ref count, but doesn't assume that the ref
@@ -329,17 +305,17 @@ private:
// SetArgument may only appear in the root block.
//
// Tail variable: the last thing that happened to the variable in the block.
- // It may be a Flush, PhantomLocal, GetLocal, SetLocal, or SetArgument.
+ // It may be a Flush, PhantomLocal, GetLocal, SetLocal, SetArgument, or Phi.
// SetArgument may only appear in the root block. Note that if there ever
// was a GetLocal to the variable, and it was followed by PhantomLocals and
// Flushes but not SetLocals, then the tail variable will be the GetLocal.
// This reflects the fact that you only care that the tail variable is a
- // Flush or PhantomLocal if nothing else interesting happened.
+ // Flush or PhantomLocal if nothing else interesting happened. Likewise, if
+ // there ever was a SetLocal and it was followed by Flushes, then the tail
+ // variable will be a SetLocal and not those subsequent Flushes.
//
- // Child of GetLocal: the operation that the GetLocal keeps alive. For
- // uncaptured locals, it may be a Phi from the current block. For arguments,
- // it may be a SetArgument. For captured locals and arguments it may also be
- // a SetLocal.
+ // Child of GetLocal: the operation that the GetLocal keeps alive. It may be
+ // a Phi from the current block. For arguments, it may be a SetArgument.
//
// Child of SetLocal: must be a value producing node.
//
@@ -362,7 +338,7 @@ private:
break;
case SetLocal:
- canonicalizeSetLocal(node);
+ canonicalizeSet(node);
break;
case Flush:
@@ -374,7 +350,7 @@ private:
break;
case SetArgument:
- canonicalizeSetArgument(node);
+ canonicalizeSet(node);
break;
default:
@@ -387,12 +363,22 @@ private:
{
SamplingRegion samplingRegion("DFG CPS Rethreading: canonicalizeLocalsInBlocks");
- for (m_blockIndex = m_graph.m_blocks.size(); m_blockIndex--;) {
- m_block = m_graph.m_blocks[m_blockIndex].get();
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ m_block = m_graph.block(blockIndex);
canonicalizeLocalsInBlock();
}
}
+ void specialCaseArguments()
+ {
+ // Normally, a SetArgument denotes the start of a live range for a local's value on the stack.
+ // But those SetArguments used for the actual arguments to the machine CodeBlock get
+ // special-cased. We could have instead used two different node types - one for the arguments
+ // at the prologue case, and another for the other uses. But this seemed like IR overkill.
+ for (unsigned i = m_graph.m_arguments.size(); i--;)
+ m_graph.block(0)->variablesAtHead.setArgumentFirstTime(i, m_graph.m_arguments[i]);
+ }
+
template<OperandKind operandKind>
void propagatePhis()
{
@@ -402,24 +388,23 @@ private:
// Ensure that attempts to use this fail instantly.
m_block = 0;
- m_blockIndex = NoBlock;
while (!phiStack.isEmpty()) {
PhiStackEntry entry = phiStack.last();
phiStack.removeLast();
BasicBlock* block = entry.m_block;
- PredecessorList& predecessors = block->m_predecessors;
+ PredecessorList& predecessors = block->predecessors;
Node* currentPhi = entry.m_phi;
VariableAccessData* variable = currentPhi->variableAccessData();
size_t index = entry.m_index;
for (size_t i = predecessors.size(); i--;) {
- BasicBlock* predecessorBlock = m_graph.m_blocks[predecessors[i]].get();
+ BasicBlock* predecessorBlock = predecessors[i];
Node* variableInPrevious = predecessorBlock->variablesAtTail.atFor<operandKind>(index);
if (!variableInPrevious) {
- variableInPrevious = addPhi<operandKind>(predecessorBlock, currentPhi->codeOrigin, variable, index);
+ variableInPrevious = addPhi<operandKind>(predecessorBlock, currentPhi->origin, variable, index);
predecessorBlock->variablesAtTail.atFor<operandKind>(index) = variableInPrevious;
predecessorBlock->variablesAtHead.atFor<operandKind>(index) = variableInPrevious;
} else {
@@ -453,7 +438,7 @@ private:
continue;
}
- Node* newPhi = addPhiSilently(block, currentPhi->codeOrigin, variable);
+ Node* newPhi = addPhiSilently(block, currentPhi->origin, variable);
newPhi->children = currentPhi->children;
currentPhi->children.initialize(newPhi, variableInPrevious, 0);
}
@@ -481,10 +466,56 @@ private:
return m_localPhiStack;
}
- BlockIndex m_blockIndex;
+ void computeIsFlushed()
+ {
+ m_graph.clearFlagsOnAllNodes(NodeIsFlushed);
+
+ for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+ for (unsigned nodeIndex = block->size(); nodeIndex--;) {
+ Node* node = block->at(nodeIndex);
+ if (node->op() != Flush)
+ continue;
+ addFlushedLocalOp(node);
+ }
+ }
+ while (!m_flushedLocalOpWorklist.isEmpty()) {
+ Node* node = m_flushedLocalOpWorklist.takeLast();
+ switch (node->op()) {
+ case SetLocal:
+ case SetArgument:
+ break;
+
+ case Flush:
+ case Phi:
+ ASSERT(node->flags() & NodeIsFlushed);
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
+ break;
+
+ default:
+ DFG_CRASH(m_graph, node, "Invalid node in flush graph");
+ break;
+ }
+ }
+ }
+
+ void addFlushedLocalOp(Node* node)
+ {
+ if (node->mergeFlags(NodeIsFlushed))
+ m_flushedLocalOpWorklist.append(node);
+ }
+
+ void addFlushedLocalEdge(Node*, Edge edge)
+ {
+ addFlushedLocalOp(edge.node());
+ }
+
BasicBlock* m_block;
Vector<PhiStackEntry, 128> m_argumentPhiStack;
Vector<PhiStackEntry, 128> m_localPhiStack;
+ Vector<Node*, 128> m_flushedLocalOpWorklist;
};
bool performCPSRethreading(Graph& graph)