Index: src/compiler/escape-analysis.cc |
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc |
index 2cf96762a7226a3a3a837b817efc13af350d0be2..7d8b166fd9bbc5010b33b65f43213f890a9e730d 100644 |
--- a/src/compiler/escape-analysis.cc |
+++ b/src/compiler/escape-analysis.cc |
@@ -24,7 +24,7 @@ namespace v8 { |
namespace internal { |
namespace compiler { |
-using Alias = EscapeStatusAnalysis::Alias; |
+using Alias = EscapeAnalysis::Alias; |
#ifdef DEBUG |
#define TRACE(...) \ |
@@ -35,6 +35,90 @@ using Alias = EscapeStatusAnalysis::Alias; |
#define TRACE(...) |
#endif |
+// EscapeStatusAnalysis determines for each allocation whether it escapes. |
+class EscapeStatusAnalysis : public ZoneObject { |
+ public: |
+ enum Status { |
+ kUnknown = 0u, |
+ kTracked = 1u << 0, |
+ kEscaped = 1u << 1, |
+ kOnStack = 1u << 2, |
+ kVisited = 1u << 3, |
+ // A node is dangling, if it is a load of some kind, and does not have |
+ // an effect successor. |
+ kDanglingComputed = 1u << 4, |
+ kDangling = 1u << 5, |
+ // A node is is an effect branch point, if it has more than 2 non-dangling |
+ // effect successors. |
+ kBranchPointComputed = 1u << 6, |
+ kBranchPoint = 1u << 7, |
+ kInQueue = 1u << 8 |
+ }; |
+ typedef base::Flags<Status, uint16_t> StatusFlags; |
+ |
+ void RunStatusAnalysis(); |
+ |
+ bool IsVirtual(Node* node); |
+ bool IsEscaped(Node* node); |
+ bool IsAllocation(Node* node); |
+ |
+ bool IsInQueue(NodeId id); |
+ void SetInQueue(NodeId id, bool on_stack); |
+ |
+ void DebugPrint(); |
+ |
+ EscapeStatusAnalysis(EscapeAnalysis* object_analysis, Graph* graph, |
+ Zone* zone); |
+ void EnqueueForStatusAnalysis(Node* node); |
+ bool SetEscaped(Node* node); |
+ bool IsEffectBranchPoint(Node* node); |
+ bool IsDanglingEffectNode(Node* node); |
+ void ResizeStatusVector(); |
+ size_t GetStatusVectorSize(); |
+ bool IsVirtual(NodeId id); |
+ |
+ Graph* graph() const { return graph_; } |
+ void AssignAliases(); |
+ Alias GetAlias(NodeId id) const { return aliases_[id]; } |
+ const ZoneVector<Alias>& GetAliasMap() const { return aliases_; } |
+ Alias AliasCount() const { return next_free_alias_; } |
+ static const Alias kNotReachable; |
+ static const Alias kUntrackable; |
+ |
+ bool IsNotReachable(Node* node); |
+ |
+ private: |
+ void Process(Node* node); |
+ void ProcessAllocate(Node* node); |
+ void ProcessFinishRegion(Node* node); |
+ void ProcessStoreField(Node* node); |
+ void ProcessStoreElement(Node* node); |
+ bool CheckUsesForEscape(Node* node, bool phi_escaping = false) { |
+ return CheckUsesForEscape(node, node, phi_escaping); |
+ } |
+ bool CheckUsesForEscape(Node* node, Node* rep, bool phi_escaping = false); |
+ void RevisitUses(Node* node); |
+ void RevisitInputs(Node* node); |
+ |
+ Alias NextAlias() { return next_free_alias_++; } |
+ |
+ bool HasEntry(Node* node); |
+ |
+ bool IsAllocationPhi(Node* node); |
+ |
+ ZoneVector<Node*> stack_; |
+ EscapeAnalysis* object_analysis_; |
+ Graph* const graph_; |
+ ZoneVector<StatusFlags> status_; |
+ Alias next_free_alias_; |
+ ZoneVector<Node*> status_stack_; |
+ ZoneVector<Alias> aliases_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(EscapeStatusAnalysis); |
+}; |
+ |
+DEFINE_OPERATORS_FOR_FLAGS(EscapeStatusAnalysis::StatusFlags) |
+ |
const Alias EscapeStatusAnalysis::kNotReachable = |
std::numeric_limits<Alias>::max(); |
const Alias EscapeStatusAnalysis::kUntrackable = |
@@ -475,14 +559,11 @@ EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
: stack_(zone), |
object_analysis_(object_analysis), |
graph_(graph), |
- zone_(zone), |
status_(zone), |
next_free_alias_(0), |
status_stack_(zone), |
aliases_(zone) {} |
-EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
- |
bool EscapeStatusAnalysis::HasEntry(Node* node) { |
return status_[node->id()] & (kTracked | kEscaped); |
} |
@@ -761,8 +842,9 @@ void EscapeStatusAnalysis::DebugPrint() { |
EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
Zone* zone) |
- : status_analysis_(this, graph, zone), |
+ : zone_(zone), |
common_(common), |
+ status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)), |
virtual_states_(zone), |
replacements_(zone), |
cache_(nullptr) {} |
@@ -771,13 +853,13 @@ EscapeAnalysis::~EscapeAnalysis() {} |
void EscapeAnalysis::Run() { |
replacements_.resize(graph()->NodeCount()); |
- status_analysis_.AssignAliases(); |
- if (status_analysis_.AliasCount() > 0) { |
+ status_analysis_->AssignAliases(); |
+ if (status_analysis_->AliasCount() > 0) { |
cache_ = new (zone()) MergeCache(zone()); |
replacements_.resize(graph()->NodeCount()); |
- status_analysis_.ResizeStatusVector(); |
+ status_analysis_->ResizeStatusVector(); |
RunObjectAnalysis(); |
- status_analysis_.RunStatusAnalysis(); |
+ status_analysis_->RunStatusAnalysis(); |
} |
} |
@@ -855,11 +937,11 @@ void EscapeAnalysis::RunObjectAnalysis() { |
while (!queue.empty()) { |
Node* node = queue.back(); |
queue.pop_back(); |
- status_analysis_.SetInQueue(node->id(), false); |
+ status_analysis_->SetInQueue(node->id(), false); |
if (Process(node)) { |
for (Edge edge : node->use_edges()) { |
Node* use = edge.from(); |
- if (IsNotReachable(use)) { |
+ if (status_analysis_->IsNotReachable(use)) { |
continue; |
} |
if (NodeProperties::IsEffectEdge(edge)) { |
@@ -867,14 +949,14 @@ void EscapeAnalysis::RunObjectAnalysis() { |
// We need DFS do avoid some duplication of VirtualStates and |
// VirtualObjects, and we want to delay phis to improve performance. |
if (use->opcode() == IrOpcode::kEffectPhi) { |
- if (!status_analysis_.IsInQueue(use->id())) { |
+ if (!status_analysis_->IsInQueue(use->id())) { |
queue.push_front(use); |
} |
} else if ((use->opcode() != IrOpcode::kLoadField && |
use->opcode() != IrOpcode::kLoadElement) || |
- !IsDanglingEffectNode(use)) { |
- if (!status_analysis_.IsInQueue(use->id())) { |
- status_analysis_.SetInQueue(use->id(), true); |
+ !status_analysis_->IsDanglingEffectNode(use)) { |
+ if (!status_analysis_->IsInQueue(use->id())) { |
+ status_analysis_->SetInQueue(use->id(), true); |
queue.push_back(use); |
} |
} else { |
@@ -1047,7 +1129,8 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) { |
#ifdef DEBUG |
if (node->opcode() != IrOpcode::kLoadField && |
node->opcode() != IrOpcode::kLoadElement && |
- node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
+ node->opcode() != IrOpcode::kLoad && |
+ status_analysis_->IsDanglingEffectNode(node)) { |
PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
node->op()->mnemonic()); |
UNREACHABLE(); |
@@ -1064,7 +1147,7 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) { |
static_cast<void*>(virtual_states_[effect->id()]), |
effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), |
node->id()); |
- if (IsEffectBranchPoint(effect) || |
+ if (status_analysis_->IsEffectBranchPoint(effect) || |
OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
virtual_states_[node->id()]->SetCopyRequired(); |
TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), |
@@ -1124,7 +1207,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
if (changed) { |
- status_analysis_.ResizeStatusVector(); |
+ status_analysis_->ResizeStatusVector(); |
} |
return changed; |
} |
@@ -1221,21 +1304,21 @@ Node* EscapeAnalysis::GetReplacement(NodeId id) { |
} |
bool EscapeAnalysis::IsVirtual(Node* node) { |
- if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
+ if (node->id() >= status_analysis_->GetStatusVectorSize()) { |
return false; |
} |
- return status_analysis_.IsVirtual(node); |
+ return status_analysis_->IsVirtual(node); |
} |
bool EscapeAnalysis::IsEscaped(Node* node) { |
- if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
+ if (node->id() >= status_analysis_->GetStatusVectorSize()) { |
return false; |
} |
- return status_analysis_.IsEscaped(node); |
+ return status_analysis_->IsEscaped(node); |
} |
bool EscapeAnalysis::SetEscaped(Node* node) { |
- return status_analysis_.SetEscaped(node); |
+ return status_analysis_->SetEscaped(node); |
} |
VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
@@ -1271,7 +1354,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
} |
cache_->LoadVirtualObjectsForFieldsFrom(state, |
- status_analysis_.GetAliasMap()); |
+ status_analysis_->GetAliasMap()); |
if (cache_->objects().size() == cache_->fields().size()) { |
cache_->GetFields(offset); |
if (cache_->fields().size() == cache_->objects().size()) { |
@@ -1282,7 +1365,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
Node* phi = graph()->NewNode( |
common()->Phi(MachineRepresentation::kTagged, value_input_count), |
value_input_count + 1, &cache_->fields().front()); |
- status_analysis_.ResizeStatusVector(); |
+ status_analysis_->ResizeStatusVector(); |
SetReplacement(load, phi); |
TRACE(" got phi created.\n"); |
} else { |
@@ -1513,17 +1596,17 @@ void EscapeAnalysis::DebugPrint() { |
VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
Node* node) { |
- if (node->id() >= status_analysis_.GetAliasMap().size()) return nullptr; |
+ if (node->id() >= status_analysis_->GetAliasMap().size()) return nullptr; |
Alias alias = GetAlias(node->id()); |
if (alias >= state->size()) return nullptr; |
return state->VirtualObjectFromAlias(alias); |
} |
bool EscapeAnalysis::ExistsVirtualAllocate() { |
- for (size_t id = 0; id < status_analysis_.GetAliasMap().size(); ++id) { |
+ for (size_t id = 0; id < status_analysis_->GetAliasMap().size(); ++id) { |
Alias alias = GetAlias(static_cast<NodeId>(id)); |
if (alias < EscapeStatusAnalysis::kUntrackable) { |
- if (status_analysis_.IsVirtual(static_cast<int>(id))) { |
+ if (status_analysis_->IsVirtual(static_cast<int>(id))) { |
return true; |
} |
} |
@@ -1531,6 +1614,16 @@ bool EscapeAnalysis::ExistsVirtualAllocate() { |
return false; |
} |
+Alias EscapeAnalysis::GetAlias(NodeId id) const { |
+ return status_analysis_->GetAlias(id); |
+} |
+ |
+Alias EscapeAnalysis::AliasCount() const { |
+ return status_analysis_->AliasCount(); |
+} |
+ |
+Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } |
+ |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |