Index: src/compiler/escape-analysis.cc |
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc |
index ccb2346ded7d4bbd40ff5c105ffbe05524389df2..b1a12b201ee16ac2aa849b4354bdf1a2b01addb0 100644 |
--- a/src/compiler/escape-analysis.cc |
+++ b/src/compiler/escape-analysis.cc |
@@ -116,6 +116,8 @@ class VirtualObject : public ZoneObject { |
return true; |
} |
bool UpdateFrom(const VirtualObject& other); |
+ bool MergeFrom(MergeCache* cache, Node* at, Graph* graph, |
+ CommonOperatorBuilder* common); |
void SetObjectState(Node* node) { object_state_ = node; } |
Node* GetObjectState() const { return object_state_; } |
bool IsCopyRequired() const { return status_ & kCopyRequired; } |
@@ -131,6 +133,9 @@ class VirtualObject : public ZoneObject { |
void id(NodeId id) { id_ = id; } |
private: |
+ bool MergeFields(size_t i, Node* at, MergeCache* cache, Graph* graph, |
+ CommonOperatorBuilder* common); |
+ |
NodeId id_; |
StatusFlags status_; |
ZoneVector<Node*> fields_; |
@@ -176,14 +181,10 @@ class VirtualState : public ZoneObject { |
} |
VirtualObject* VirtualObjectFromAlias(size_t alias); |
- VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, |
- size_t fields, |
- bool initialized, Zone* zone, |
- bool force_copy); |
void SetVirtualObject(Alias alias, VirtualObject* state); |
bool UpdateFrom(VirtualState* state, Zone* zone); |
bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
- CommonOperatorBuilder* common, Node* control, int arity); |
+ CommonOperatorBuilder* common, Node* at); |
size_t size() const { return info_.size(); } |
Node* owner() const { return owner_; } |
VirtualObject* Copy(VirtualObject* obj, Alias alias); |
@@ -288,19 +289,6 @@ VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
return info_[alias]; |
} |
-VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
- Alias alias, NodeId id, size_t field_number, bool initialized, Zone* zone, |
- bool force_copy) { |
- if (!force_copy) { |
- if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
- return obj; |
- } |
- } |
- VirtualObject* obj = new (zone) VirtualObject(id, this, zone, 0, initialized); |
- SetVirtualObject(alias, obj); |
- return obj; |
-} |
- |
void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { |
info_[alias] = obj; |
} |
@@ -362,19 +350,72 @@ bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) { |
} // namespace |
-Node* EscapeAnalysis::GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { |
- Node* rep = GetReplacement(objs.front()->id()); |
- for (VirtualObject* obj : objs) { |
- if (GetReplacement(obj->id()) != rep) { |
- return nullptr; |
+bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache, |
+ Graph* graph, CommonOperatorBuilder* common) { |
+ bool changed = false; |
+ int value_input_count = static_cast<int>(cache->fields().size()); |
+ Node* rep = GetField(i); |
+ if (!rep || !IsCreatedPhi(i)) { |
+ Node* control = NodeProperties::GetControlInput(at); |
+ cache->fields().push_back(control); |
+ Node* phi = graph->NewNode( |
+ common->Phi(MachineRepresentation::kTagged, value_input_count), |
+ value_input_count + 1, &cache->fields().front()); |
+ SetField(i, phi, true); |
+#ifdef DEBUG |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" Creating Phi #%d as merge of", phi->id()); |
+ for (int i = 0; i < value_input_count; i++) { |
+ PrintF(" #%d (%s)", cache->fields()[i]->id(), |
+ cache->fields()[i]->op()->mnemonic()); |
+ } |
+ PrintF("\n"); |
+ } |
+#endif |
+ changed = true; |
+ } else { |
+ DCHECK(rep->opcode() == IrOpcode::kPhi); |
+ for (int n = 0; n < value_input_count; ++n) { |
+ Node* old = NodeProperties::GetValueInput(rep, n); |
+ if (old != cache->fields()[n]) { |
+ changed = true; |
+ NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); |
+ } |
} |
} |
- return rep; |
+ return changed; |
+} |
+ |
+bool VirtualObject::MergeFrom(MergeCache* cache, Node* at, Graph* graph, |
+ CommonOperatorBuilder* common) { |
+ DCHECK(at->opcode() == IrOpcode::kEffectPhi || |
+ at->opcode() == IrOpcode::kPhi); |
+ bool changed = false; |
+ for (size_t i = 0; i < field_count(); ++i) { |
+ if (Node* field = cache->GetFields(i)) { |
+ changed = changed || GetField(i) != field; |
+ SetField(i, field); |
+ TRACE(" Field %zu agree on rep #%d\n", i, field->id()); |
+ } else { |
+ int arity = at->opcode() == IrOpcode::kEffectPhi |
+ ? at->op()->EffectInputCount() |
+ : at->op()->ValueInputCount(); |
+ if (cache->fields().size() == arity) { |
+ changed = MergeFields(i, at, cache, graph, common) || changed; |
+ } else { |
+ if (GetField(i) != nullptr) { |
+ TRACE(" Field %zu cleared\n", i); |
+ changed = true; |
+ } |
+ SetField(i, nullptr); |
+ } |
+ } |
+ } |
+ return changed; |
} |
bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
- CommonOperatorBuilder* common, Node* control, |
- int arity) { |
+ CommonOperatorBuilder* common, Node* at) { |
DCHECK_GT(cache->states().size(), 0u); |
bool changed = false; |
for (Alias alias = 0; alias < size(); ++alias) { |
@@ -387,16 +428,26 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
cache->objects().push_back(obj); |
if (mergeObject == obj) { |
copy_merge_object = true; |
- changed = true; |
} |
fields = std::min(obj->field_count(), fields); |
} |
} |
if (cache->objects().size() == cache->states().size()) { |
- mergeObject = GetOrCreateTrackedVirtualObject( |
- alias, cache->objects().front()->id(), |
- cache->objects().front()->IsInitialized(), fields, zone, |
- copy_merge_object); |
+ if (!mergeObject) { |
+ VirtualObject* obj = new (zone) |
+ VirtualObject(cache->objects().front()->id(), this, zone, fields, |
+ cache->objects().front()->IsInitialized()); |
+ SetVirtualObject(alias, obj); |
+ mergeObject = obj; |
+ changed = true; |
+ } else if (copy_merge_object) { |
+ VirtualObject* obj = new (zone) VirtualObject(this, *mergeObject); |
+ SetVirtualObject(alias, obj); |
+ mergeObject = obj; |
+ changed = true; |
+ } else { |
+ changed = mergeObject->ResizeFields(fields) || changed; |
+ } |
#ifdef DEBUG |
if (FLAG_trace_turbo_escape) { |
PrintF(" Alias @%d, merging into %p virtual objects", alias, |
@@ -407,53 +458,7 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
PrintF("\n"); |
} |
#endif // DEBUG |
- changed = mergeObject->ResizeFields(fields) || changed; |
- for (size_t i = 0; i < fields; ++i) { |
- if (Node* field = cache->GetFields(i)) { |
- changed = changed || mergeObject->GetField(i) != field; |
- mergeObject->SetField(i, field); |
- TRACE(" Field %zu agree on rep #%d\n", i, field->id()); |
- } else { |
- int value_input_count = static_cast<int>(cache->fields().size()); |
- if (cache->fields().size() == arity) { |
- Node* rep = mergeObject->GetField(i); |
- if (!rep || !mergeObject->IsCreatedPhi(i)) { |
- cache->fields().push_back(control); |
- Node* phi = graph->NewNode( |
- common->Phi(MachineRepresentation::kTagged, |
- value_input_count), |
- value_input_count + 1, &cache->fields().front()); |
- mergeObject->SetField(i, phi, true); |
-#ifdef DEBUG |
- if (FLAG_trace_turbo_escape) { |
- PrintF(" Creating Phi #%d as merge of", phi->id()); |
- for (int i = 0; i < value_input_count; i++) { |
- PrintF(" #%d (%s)", cache->fields()[i]->id(), |
- cache->fields()[i]->op()->mnemonic()); |
- } |
- PrintF("\n"); |
- } |
-#endif // DEBUG |
- changed = true; |
- } else { |
- DCHECK(rep->opcode() == IrOpcode::kPhi); |
- for (int n = 0; n < value_input_count; ++n) { |
- Node* old = NodeProperties::GetValueInput(rep, n); |
- if (old != cache->fields()[n]) { |
- changed = true; |
- NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n); |
- } |
- } |
- } |
- } else { |
- if (mergeObject->GetField(i) != nullptr) { |
- TRACE(" Field %zu cleared\n", i); |
- changed = true; |
- } |
- mergeObject->SetField(i, nullptr); |
- } |
- } |
- } |
+ changed = mergeObject->MergeFrom(cache, at, graph, common) || changed; |
} else { |
if (mergeObject) { |
TRACE(" Alias %d, virtual object removed\n", alias); |
@@ -471,7 +476,7 @@ EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
object_analysis_(object_analysis), |
graph_(graph), |
zone_(zone), |
- status_(graph->NodeCount(), kUnknown, zone), |
+ status_(zone), |
next_free_alias_(0), |
status_stack_(zone), |
aliases_(zone) {} |
@@ -777,11 +782,8 @@ void EscapeAnalysis::Run() { |
void EscapeStatusAnalysis::AssignAliases() { |
size_t max_size = 1024; |
size_t min_size = 32; |
- size_t stack_size = std::min( |
- std::max( |
- std::min(graph()->NodeCount() / 5, graph()->NodeCount() / 20 + 128), |
- min_size), |
- max_size); |
+ size_t stack_size = |
+ std::min(std::max(graph()->NodeCount() / 5, min_size), max_size); |
stack_.reserve(stack_size); |
ResizeStatusVector(); |
stack_.push_back(graph()->end()); |
@@ -1001,7 +1003,8 @@ void EscapeAnalysis::ProcessAllocationUsers(Node* node) { |
break; |
default: |
VirtualState* state = virtual_states_[node->id()]; |
- if (VirtualObject* obj = ResolveVirtualObject(state, input)) { |
+ if (VirtualObject* obj = |
+ GetVirtualObject(state, ResolveReplacement(input))) { |
if (!obj->AllFieldsClear()) { |
obj = CopyForModificationAt(obj, state, node); |
obj->ClearAllFields(); |
@@ -1113,10 +1116,8 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
return changed; |
} |
- changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), |
- NodeProperties::GetControlInput(node), |
- node->op()->EffectInputCount()) || |
- changed; |
+ changed = |
+ mergeState->MergeFrom(cache_, zone(), graph(), common(), node) || changed; |
TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
@@ -1242,11 +1243,6 @@ VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
return nullptr; |
} |
-VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
- Node* node) { |
- return GetVirtualObject(state, ResolveReplacement(node)); |
-} |
- |
bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
DCHECK(IsVirtual(left) && IsVirtual(right)); |
left = ResolveReplacement(left); |
@@ -1262,13 +1258,13 @@ int EscapeAnalysis::OffsetFromAccess(Node* node) { |
return OpParameter<FieldAccess>(node).offset / kPointerSize; |
} |
-void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
+void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, |
VirtualState* state) { |
- TRACE("Load #%d from phi #%d", node->id(), from->id()); |
+ TRACE("Load #%d from phi #%d", load->id(), from->id()); |
cache_->fields().clear(); |
- for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
- Node* input = NodeProperties::GetValueInput(node, i); |
+ for (int i = 0; i < load->op()->ValueInputCount(); ++i) { |
+ Node* input = NodeProperties::GetValueInput(load, i); |
cache_->fields().push_back(input); |
} |
@@ -1277,7 +1273,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
if (cache_->objects().size() == cache_->fields().size()) { |
cache_->GetFields(offset); |
if (cache_->fields().size() == cache_->objects().size()) { |
- Node* rep = replacement(node); |
+ Node* rep = replacement(load); |
if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
int value_input_count = static_cast<int>(cache_->fields().size()); |
cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
@@ -1285,7 +1281,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
common()->Phi(MachineRepresentation::kTagged, value_input_count), |
value_input_count + 1, &cache_->fields().front()); |
status_analysis_.ResizeStatusVector(); |
- SetReplacement(node, phi); |
+ SetReplacement(load, phi); |
TRACE(" got phi created.\n"); |
} else { |
TRACE(" has already phi #%d.\n", rep->id()); |
@@ -1441,8 +1437,8 @@ Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
if ((node->opcode() == IrOpcode::kFinishRegion || |
node->opcode() == IrOpcode::kAllocate) && |
IsVirtual(node)) { |
- if (VirtualObject* vobj = |
- ResolveVirtualObject(virtual_states_[effect->id()], node)) { |
+ if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], |
+ ResolveReplacement(node))) { |
if (Node* object_state = vobj->GetObjectState()) { |
return object_state; |
} else { |