Index: src/compiler/escape-analysis.cc |
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc |
index af0ba6a63986dc58004798a2386d348514acf734..1d5d5688ef5e0f3fd9c71d87793df719aea0e6ab 100644 |
--- a/src/compiler/escape-analysis.cc |
+++ b/src/compiler/escape-analysis.cc |
@@ -124,6 +124,7 @@ class VirtualObject : public ZoneObject { |
bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
bool changed = status_ != other.status_; |
status_ = other.status_; |
+ phi_ = other.phi_; |
if (fields_.size() != other.fields_.size()) { |
fields_ = other.fields_; |
return true; |
@@ -145,7 +146,8 @@ class VirtualState : public ZoneObject { |
VirtualObject* VirtualObjectFromAlias(size_t alias); |
VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, |
- NodeId id, Zone* zone); |
+ NodeId id, size_t fields, |
+ Zone* zone); |
void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); |
void LastChangedAt(Node* node) { last_changed_ = node; } |
Node* GetLastChanged() { return last_changed_; } |
@@ -255,7 +257,7 @@ VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
- EscapeAnalysis::Alias alias, NodeId id, Zone* zone) { |
+ EscapeAnalysis::Alias alias, NodeId id, size_t field_number, Zone* zone) { |
if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
return obj; |
} |
@@ -356,7 +358,7 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
PrintF(" Merging virtual objects of @%d\n", alias); |
} |
VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( |
- alias, cache->objects().front()->id(), zone); |
+ alias, cache->objects().front()->id(), fields, zone); |
changed = mergeObject->ResizeFields(fields) || changed; |
for (size_t i = 0; i < fields; ++i) { |
if (Node* field = cache->GetFields(i)) { |
@@ -410,6 +412,9 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
} |
} |
} else { |
+ if (FLAG_trace_turbo_escape) { |
+ PrintF(" Field %zu cleared\n", i); |
+ } |
changed = mergeObject->SetField(i, nullptr) || changed; |
} |
} |
@@ -440,7 +445,12 @@ bool EscapeStatusAnalysis::HasEntry(Node* node) { |
bool EscapeStatusAnalysis::IsVirtual(Node* node) { |
- return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped); |
+ return IsVirtual(node->id()); |
+} |
+ |
+ |
+bool EscapeStatusAnalysis::IsVirtual(NodeId id) { |
+ return (status_[id] & kTracked) && !(status_[id] & kEscaped); |
} |
@@ -669,6 +679,14 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
return true; |
} |
break; |
+ case IrOpcode::kSelect: |
+ if (SetEscaped(rep)) { |
+ PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
+ rep->id(), rep->op()->mnemonic(), use->id(), |
+ use->op()->mnemonic()); |
+ return true; |
+ } |
+ break; |
default: |
if (use->op()->EffectInputCount() == 0 && |
uses->op()->EffectInputCount() > 0) { |
@@ -731,6 +749,8 @@ EscapeAnalysis::~EscapeAnalysis() {} |
void EscapeAnalysis::Run() { |
replacements_.resize(graph()->NodeCount()); |
AssignAliases(); |
+ if (AliasCount() == 0) return; |
+ escape_status_.Resize(); |
RunObjectAnalysis(); |
escape_status_.Run(); |
} |
@@ -1042,10 +1062,11 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
void EscapeAnalysis::ProcessAllocation(Node* node) { |
DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
ForwardVirtualState(node); |
+ VirtualState* state = virtual_states_[node->id()]; |
+ Alias alias = aliases_[node->id()]; |
// Check if we have already processed this node. |
- if (virtual_states_[node->id()]->VirtualObjectFromAlias( |
- aliases_[node->id()])) { |
+ if (state->VirtualObjectFromAlias(alias)) { |
return; |
} |
@@ -1055,15 +1076,14 @@ void EscapeAnalysis::ProcessAllocation(Node* node) { |
node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
if (size.HasValue()) { |
- virtual_states_[node->id()]->SetVirtualObject( |
- aliases_[node->id()], |
- new (zone()) |
- VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); |
+ state->SetVirtualObject( |
+ alias, new (zone()) VirtualObject(node->id(), zone(), |
+ size.Value() / kPointerSize)); |
} else { |
- virtual_states_[node->id()]->SetVirtualObject( |
- aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); |
+ state->SetVirtualObject(alias, |
+ new (zone()) VirtualObject(node->id(), zone())); |
} |
- virtual_states_[node->id()]->LastChangedAt(node); |
+ state->LastChangedAt(node); |
} |
@@ -1178,15 +1198,7 @@ VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
Node* node) { |
- VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); |
- while (obj && replacement(obj->id())) { |
- if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) { |
- obj = next; |
- } else { |
- break; |
- } |
- } |
- return obj; |
+ return GetVirtualObject(state, ResolveReplacement(node)); |
} |
@@ -1251,9 +1263,9 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
void EscapeAnalysis::ProcessLoadField(Node* node) { |
DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
ForwardVirtualState(node); |
- Node* from = NodeProperties::GetValueInput(node, 0); |
+ Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
VirtualState* state = virtual_states_[node->id()]; |
- if (VirtualObject* object = ResolveVirtualObject(state, from)) { |
+ if (VirtualObject* object = GetVirtualObject(state, from)) { |
int offset = OffsetFromAccess(node); |
if (!object->IsTracked()) return; |
Node* value = object->GetField(offset); |
@@ -1262,13 +1274,13 @@ void EscapeAnalysis::ProcessLoadField(Node* node) { |
} |
// Record that the load has this alias. |
UpdateReplacement(state, node, value); |
- } else { |
- if (from->opcode() == IrOpcode::kPhi && |
- OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
+ } else if (from->opcode() == IrOpcode::kPhi && |
+ OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
int offset = OffsetFromAccess(node); |
// Only binary phis are supported for now. |
ProcessLoadFromPhi(offset, from, node, state); |
- } |
+ } else { |
+ UpdateReplacement(state, node, nullptr); |
} |
} |
@@ -1276,7 +1288,7 @@ void EscapeAnalysis::ProcessLoadField(Node* node) { |
void EscapeAnalysis::ProcessLoadElement(Node* node) { |
DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
ForwardVirtualState(node); |
- Node* from = NodeProperties::GetValueInput(node, 0); |
+ Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
VirtualState* state = virtual_states_[node->id()]; |
Node* index_node = node->InputAt(1); |
NumberMatcher index(index_node); |
@@ -1287,7 +1299,7 @@ void EscapeAnalysis::ProcessLoadElement(Node* node) { |
ElementAccess access = OpParameter<ElementAccess>(node); |
if (index.HasValue()) { |
int offset = index.Value() + access.header_size / kPointerSize; |
- if (VirtualObject* object = ResolveVirtualObject(state, from)) { |
+ if (VirtualObject* object = GetVirtualObject(state, from)) { |
CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
kPointerSizeLog2); |
CHECK_EQ(access.header_size % kPointerSize, 0); |
@@ -1303,13 +1315,15 @@ void EscapeAnalysis::ProcessLoadElement(Node* node) { |
ElementAccess access = OpParameter<ElementAccess>(node); |
int offset = index.Value() + access.header_size / kPointerSize; |
ProcessLoadFromPhi(offset, from, node, state); |
+ } else { |
+ UpdateReplacement(state, node, nullptr); |
} |
} else { |
// We have a load from a non-const index, cannot eliminate object. |
if (SetEscaped(from)) { |
if (FLAG_trace_turbo_escape) { |
PrintF( |
- "Setting #%d (%s) to escaped because store element #%d to " |
+ "Setting #%d (%s) to escaped because load element #%d from " |
"non-const " |
"index #%d (%s)\n", |
from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
@@ -1323,13 +1337,13 @@ void EscapeAnalysis::ProcessLoadElement(Node* node) { |
void EscapeAnalysis::ProcessStoreField(Node* node) { |
DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
ForwardVirtualState(node); |
- Node* to = NodeProperties::GetValueInput(node, 0); |
- Node* val = NodeProperties::GetValueInput(node, 1); |
+ Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
VirtualState* state = virtual_states_[node->id()]; |
- if (VirtualObject* obj = ResolveVirtualObject(state, to)) { |
- if (!obj->IsTracked()) return; |
+ VirtualObject* obj = GetVirtualObject(state, to); |
+ if (obj && obj->IsTracked()) { |
int offset = OffsetFromAccess(node); |
- if (obj->SetField(offset, ResolveReplacement(val))) { |
+ Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
+ if (obj->SetField(offset, val)) { |
state->LastChangedAt(node); |
} |
} |
@@ -1339,7 +1353,7 @@ void EscapeAnalysis::ProcessStoreField(Node* node) { |
void EscapeAnalysis::ProcessStoreElement(Node* node) { |
DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
ForwardVirtualState(node); |
- Node* to = NodeProperties::GetValueInput(node, 0); |
+ Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
Node* index_node = node->InputAt(1); |
NumberMatcher index(index_node); |
DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
@@ -1347,17 +1361,17 @@ void EscapeAnalysis::ProcessStoreElement(Node* node) { |
index_node->opcode() != IrOpcode::kFloat32Constant && |
index_node->opcode() != IrOpcode::kFloat64Constant); |
ElementAccess access = OpParameter<ElementAccess>(node); |
- Node* val = NodeProperties::GetValueInput(node, 2); |
+ VirtualState* state = virtual_states_[node->id()]; |
+ VirtualObject* obj = GetVirtualObject(state, to); |
if (index.HasValue()) { |
int offset = index.Value() + access.header_size / kPointerSize; |
- VirtualState* states = virtual_states_[node->id()]; |
- if (VirtualObject* obj = ResolveVirtualObject(states, to)) { |
- if (!obj->IsTracked()) return; |
+ if (obj && obj->IsTracked()) { |
CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), |
kPointerSizeLog2); |
CHECK_EQ(access.header_size % kPointerSize, 0); |
- if (obj->SetField(offset, ResolveReplacement(val))) { |
- states->LastChangedAt(node); |
+ Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2)); |
+ if (obj->SetField(offset, val)) { |
+ state->LastChangedAt(node); |
} |
} |
} else { |
@@ -1372,6 +1386,9 @@ void EscapeAnalysis::ProcessStoreElement(Node* node) { |
index_node->op()->mnemonic()); |
} |
} |
+ if (obj && obj->IsTracked() && obj->ClearAllFields()) { |
+ state->LastChangedAt(node); |
+ } |
} |
} |
@@ -1466,6 +1483,19 @@ VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
return state->VirtualObjectFromAlias(alias); |
} |
+ |
+bool EscapeAnalysis::ExistsVirtualAllocate() { |
+ for (size_t id = 0; id < aliases_.size(); ++id) { |
+ Alias alias = aliases_[id]; |
+ if (alias < kUntrackable) { |
+ if (escape_status_.IsVirtual(static_cast<int>(id))) { |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+} |
+ |
} // namespace compiler |
} // namespace internal |
} // namespace v8 |