Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Unified Diff: src/compiler/escape-analysis.cc

Issue 1510973006: Stabilize escape analysis (without deopt) (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@fix-guard-bug
Patch Set: Rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/escape-analysis.cc
diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
index c7c451ce06464f1411f97eb5774ef1cefe9ac06e..0103a6f65766489400860f141378df338ab7430b 100644
--- a/src/compiler/escape-analysis.cc
+++ b/src/compiler/escape-analysis.cc
@@ -29,17 +29,27 @@ class VirtualObject : public ZoneObject {
public:
enum Status { kUntracked = 0, kTracked = 1 };
VirtualObject(NodeId id, Zone* zone)
- : id_(id), status_(kUntracked), fields_(zone), replacement_(nullptr) {}
+ : id_(id),
+ status_(kUntracked),
+ fields_(zone),
+ phi_(zone),
+ replacement_(nullptr) {}
VirtualObject(const VirtualObject& other)
: id_(other.id_),
status_(other.status_),
fields_(other.fields_),
+ phi_(other.phi_),
replacement_(other.replacement_) {}
VirtualObject(NodeId id, Zone* zone, size_t field_number)
- : id_(id), status_(kTracked), fields_(zone), replacement_(nullptr) {
+ : id_(id),
+ status_(kTracked),
+ fields_(zone),
+ phi_(zone),
+ replacement_(nullptr) {
fields_.resize(field_number);
+ phi_.resize(field_number, false);
}
Node* GetField(size_t offset) {
@@ -49,9 +59,21 @@ class VirtualObject : public ZoneObject {
return nullptr;
}
- bool SetField(size_t offset, Node* node) {
- bool changed = fields_[offset] != node;
+ bool IsCreatedPhi(size_t offset) {
+ if (offset < phi_.size()) {
+ return phi_[offset];
+ }
+ return false;
+ }
+
+ bool SetField(size_t offset, Node* node, bool created_phi = false) {
+ bool changed = fields_[offset] != node || phi_[offset] != created_phi;
fields_[offset] = node;
+ phi_[offset] = created_phi;
+ if (changed && FLAG_trace_turbo_escape && node) {
+ PrintF("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(),
+ node->op()->mnemonic());
+ }
return changed;
}
bool IsVirtual() const { return status_ == kTracked; }
@@ -68,6 +90,7 @@ class VirtualObject : public ZoneObject {
bool ResizeFields(size_t field_count) {
if (field_count != fields_.size()) {
fields_.resize(field_count);
+ phi_.resize(field_count);
return true;
}
return false;
@@ -79,6 +102,7 @@ class VirtualObject : public ZoneObject {
fields_[i] = nullptr;
changed = true;
}
+ phi_[i] = false;
}
return changed;
}
@@ -91,6 +115,7 @@ class VirtualObject : public ZoneObject {
NodeId id_;
Status status_;
ZoneVector<Node*> fields_;
+ ZoneVector<bool> phi_;
Node* replacement_;
};
@@ -133,8 +158,8 @@ class VirtualState : public ZoneObject {
Node* ResolveReplacement(Node* node);
bool UpdateReplacement(Node* node, Node* rep, Zone* zone);
bool UpdateFrom(VirtualState* state, Zone* zone);
- bool MergeFrom(VirtualState* left, VirtualState* right, Zone* zone,
- Graph* graph, CommonOperatorBuilder* common, Node* control);
+ bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
+ CommonOperatorBuilder* common, Node* control);
size_t size() { return info_.size(); }
@@ -230,7 +255,6 @@ bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) {
bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
- DCHECK_EQ(size(), from->size());
bool changed = false;
for (NodeId id = 0; id < size(); ++id) {
VirtualObject* ls = GetVirtualObject(id);
@@ -257,59 +281,187 @@ bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
}
-bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right,
- Zone* zone, Graph* graph,
+namespace {
+
+size_t min_size(ZoneVector<VirtualState*>& states) {
+ size_t min = SIZE_MAX;
+ for (VirtualState* state : states) {
+ min = std::min(state->size(), min);
+ }
+ return min;
+}
+
+
+size_t min_field_count(ZoneVector<VirtualObject*>& objs) {
+ size_t min = SIZE_MAX;
+ for (VirtualObject* obj : objs) {
+ min = std::min(obj->field_count(), min);
+ }
+ return min;
+}
+
+
+void GetVirtualObjects(ZoneVector<VirtualState*> states,
+ ZoneVector<VirtualObject*>& objs, NodeId id) {
+ objs.clear();
+ for (VirtualState* state : states) {
+ if (VirtualObject* obj = state->GetVirtualObject(id)) {
+ objs.push_back(obj);
+ }
+ }
+}
+
+
+void GetVirtualObjects(VirtualState* state, ZoneVector<Node*> nodes,
+ ZoneVector<VirtualObject*>& objs) {
+ objs.clear();
+ for (Node* node : nodes) {
+ if (VirtualObject* obj = state->GetVirtualObject(node)) {
+ objs.push_back(obj);
+ }
+ }
+}
+
+
+Node* GetFieldIfSame(size_t pos, ZoneVector<VirtualObject*>& objs) {
+ Node* rep = objs.front()->GetField(pos);
+ for (VirtualObject* obj : objs) {
+ if (obj->GetField(pos) != rep) {
+ return nullptr;
+ }
+ }
+ return rep;
+}
+
+
+Node* GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) {
+ Node* rep = objs.front()->GetReplacement();
+ for (VirtualObject* obj : objs) {
+ if (obj->GetReplacement() != rep) {
+ return nullptr;
+ }
+ }
+ return rep;
+}
+
+
+void GetFields(ZoneVector<VirtualObject*>& objs, ZoneVector<Node*>& fields,
+ size_t pos) {
+ fields.clear();
+ for (VirtualObject* obj : objs) {
+ if (Node* field = obj->GetField(pos)) {
+ fields.push_back(field);
+ }
+ }
+}
+
+
+bool IsEquivalentPhi(Node* node1, Node* node2) {
+ if (node1 == node2) return true;
+ if (node1->opcode() != IrOpcode::kPhi || node2->opcode() != IrOpcode::kPhi ||
+ node1->op()->ValueInputCount() != node2->op()->ValueInputCount()) {
+ return false;
+ }
+ for (int i = 0; i < node1->op()->ValueInputCount(); ++i) {
+ Node* input1 = NodeProperties::GetValueInput(node1, i);
+ Node* input2 = NodeProperties::GetValueInput(node2, i);
+ if (!IsEquivalentPhi(input1, input2)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) {
+ if (phi->opcode() != IrOpcode::kPhi) return false;
+ if (phi->op()->ValueInputCount() != inputs.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i));
+ if (!IsEquivalentPhi(input, inputs[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+
+bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
CommonOperatorBuilder* common, Node* control) {
+ DCHECK_GT(cache->states().size(), 0u);
bool changed = false;
- for (NodeId id = 0; id < std::min(left->size(), right->size()); ++id) {
- VirtualObject* ls = left->GetVirtualObject(id);
- VirtualObject* rs = right->GetVirtualObject(id);
-
- if (ls != nullptr && rs != nullptr) {
+ for (NodeId id = 0; id < min_size(cache->states()); ++id) {
+ GetVirtualObjects(cache->states(), cache->objects(), id);
+ if (cache->objects().size() == cache->states().size()) {
+ // Don't process linked objects.
+ if (cache->objects()[0]->id() != id) continue;
if (FLAG_trace_turbo_escape) {
- PrintF(" Merging fields of #%d\n", id);
+ PrintF(" Merging virtual objects of #%d\n", id);
}
VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
- size_t fields = std::max(ls->field_count(), rs->field_count());
+ mergeObject->SetReplacement(GetReplacementIfSame(cache->objects()));
+ size_t fields = min_field_count(cache->objects());
changed = mergeObject->ResizeFields(fields) || changed;
for (size_t i = 0; i < fields; ++i) {
- if (ls->GetField(i) == rs->GetField(i)) {
- changed = mergeObject->SetField(i, ls->GetField(i)) || changed;
- if (FLAG_trace_turbo_escape && ls->GetField(i)) {
- PrintF(" Field %zu agree on rep #%d\n", i,
- ls->GetField(i)->id());
+ if (Node* field = GetFieldIfSame(i, cache->objects())) {
+ changed = mergeObject->SetField(i, field) || changed;
+ if (FLAG_trace_turbo_escape) {
+ PrintF(" Field %zu agree on rep #%d\n", i, field->id());
}
- } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) {
- Node* rep = mergeObject->GetField(i);
- if (!rep || rep->opcode() != IrOpcode::kPhi ||
- NodeProperties::GetValueInput(rep, 0) != ls->GetField(i) ||
- NodeProperties::GetValueInput(rep, 1) != rs->GetField(i)) {
- Node* phi =
- graph->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
- ls->GetField(i), rs->GetField(i), control);
- if (mergeObject->SetField(i, phi)) {
- if (FLAG_trace_turbo_escape) {
- PrintF(" Creating Phi #%d as merge of #%d and #%d\n",
- phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
+ } else {
+ GetFields(cache->objects(), cache->fields(), i);
+ if (cache->fields().size() == cache->objects().size()) {
+ Node* rep = mergeObject->GetField(i);
+ if (!rep || !mergeObject->IsCreatedPhi(i)) {
+ cache->fields().push_back(control);
+ Node* phi =
+ graph->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
+ static_cast<int>(cache->fields().size()),
+ &cache->fields().front());
+ if (mergeObject->SetField(i, phi, true)) {
+ if (FLAG_trace_turbo_escape) {
+ PrintF(" Creating Phi #%d as merge of", phi->id());
+ for (size_t i = 0; i + 1 < cache->fields().size(); i++) {
+ PrintF(" #%d (%s)", cache->fields()[i]->id(),
+ cache->fields()[i]->op()->mnemonic());
+ }
+ PrintF("\n");
+ }
+ changed = true;
+ }
+ } else {
+ DCHECK(rep->opcode() == IrOpcode::kPhi);
+ for (size_t n = 0; n < cache->fields().size(); ++n) {
+ Node* old =
+ NodeProperties::GetValueInput(rep, static_cast<int>(n));
+ if (old != cache->fields()[n]) {
+ changed = true;
+ NodeProperties::ReplaceValueInput(rep, cache->fields()[n],
+ static_cast<int>(n));
+ }
}
- changed = true;
}
} else {
- if (FLAG_trace_turbo_escape) {
- PrintF(" Retaining Phi #%d as merge of #%d and #%d\n",
- rep->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
- }
+ changed = mergeObject->SetField(i, nullptr) || changed;
}
- } else {
- changed = mergeObject->SetField(i, nullptr) || changed;
}
}
- } else if (ls) {
- VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
- changed = mergeObject->UpdateFrom(*ls) || changed;
- } else if (rs) {
- VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
- changed = mergeObject->UpdateFrom(*rs) || changed;
+
+ } else {
+ SetVirtualObject(id, nullptr);
+ }
+ }
+ // Update linked objects.
+ for (NodeId id = 0; id < min_size(cache->states()); ++id) {
+ GetVirtualObjects(cache->states(), cache->objects(), id);
+ if (cache->objects().size() == cache->states().size()) {
+ if (cache->objects()[0]->id() != id) {
+ SetVirtualObject(id, GetVirtualObject(cache->objects()[0]->id()));
+ }
}
}
return changed;
@@ -329,13 +481,21 @@ Node* VirtualState::ResolveReplacement(Node* node) {
bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) {
if (!GetVirtualObject(node)) {
- SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone));
+ if (rep) {
+ SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone));
+ } else {
+ return false;
+ }
}
if (GetVirtualObject(node)->SetReplacement(rep)) {
LastChangedAt(node);
if (FLAG_trace_turbo_escape) {
- PrintF("Representation of #%d is #%d (%s)\n", node->id(), rep->id(),
- rep->op()->mnemonic());
+ if (rep) {
+ PrintF("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(),
+ rep->op()->mnemonic());
+ } else {
+ PrintF("Replacement of #%d cleared\n", node->id());
+ }
}
return true;
}
@@ -352,7 +512,9 @@ EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
graph_(graph),
zone_(zone),
info_(zone),
- queue_(zone) {}
+ queue_(zone) {
+ info_.resize(graph->NodeCount());
+}
EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
@@ -376,6 +538,12 @@ bool EscapeStatusAnalysis::IsEscaped(Node* node) {
}
+bool EscapeStatusAnalysis::IsAllocation(Node* node) {
+ return node->opcode() == IrOpcode::kAllocate ||
+ node->opcode() == IrOpcode::kFinishRegion;
+}
+
+
bool EscapeStatusAnalysis::SetEscaped(Node* node) {
bool changed = info_[node->id()] != kEscaped;
info_[node->id()] = kEscaped;
@@ -436,12 +604,9 @@ void EscapeStatusAnalysis::Process(Node* node) {
case IrOpcode::kLoadField:
case IrOpcode::kLoadElement: {
if (Node* rep = object_analysis_->GetReplacement(node, node->id())) {
- if (rep->opcode() == IrOpcode::kAllocate ||
- rep->opcode() == IrOpcode::kFinishRegion) {
- if (CheckUsesForEscape(node, rep)) {
- RevisitInputs(rep);
- RevisitUses(rep);
- }
+ if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) {
+ RevisitInputs(rep);
+ RevisitUses(rep);
}
}
break;
@@ -461,8 +626,9 @@ void EscapeStatusAnalysis::ProcessStoreField(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
Node* to = NodeProperties::GetValueInput(node, 0);
Node* val = NodeProperties::GetValueInput(node, 1);
- if (IsEscaped(to) && SetEscaped(val)) {
+ if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
RevisitUses(val);
+ RevisitInputs(val);
if (FLAG_trace_turbo_escape) {
PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
val->id(), val->op()->mnemonic(), to->id());
@@ -475,8 +641,9 @@ void EscapeStatusAnalysis::ProcessStoreElement(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
Node* to = NodeProperties::GetValueInput(node, 0);
Node* val = NodeProperties::GetValueInput(node, 2);
- if (IsEscaped(to) && SetEscaped(val)) {
+ if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
RevisitUses(val);
+ RevisitInputs(val);
if (FLAG_trace_turbo_escape) {
PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
val->id(), val->op()->mnemonic(), to->id());
@@ -549,7 +716,21 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
return true;
}
break;
+ case IrOpcode::kObjectIsSmi:
+ if (!IsAllocation(rep) && 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) {
+ PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(),
+ use->op()->mnemonic());
+ UNREACHABLE();
+ }
if (SetEscaped(rep)) {
if (FLAG_trace_turbo_escape) {
PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
@@ -558,15 +739,6 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
}
return true;
}
- if (use->op()->EffectInputCount() == 0 &&
- uses->op()->EffectInputCount() > 0 &&
- uses->opcode() != IrOpcode::kLoadField) {
- if (FLAG_trace_turbo_escape) {
- PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(),
- use->op()->mnemonic());
- }
- UNREACHABLE();
- }
}
}
return false;
@@ -604,7 +776,8 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
common_(common),
zone_(zone),
virtual_states_(zone),
- escape_status_(this, graph, zone) {}
+ escape_status_(this, graph, zone),
+ cache_(zone) {}
EscapeAnalysis::~EscapeAnalysis() {}
@@ -658,6 +831,13 @@ void EscapeAnalysis::RunObjectAnalysis() {
bool EscapeAnalysis::IsDanglingEffectNode(Node* node) {
if (node->op()->EffectInputCount() == 0) return false;
if (node->op()->EffectOutputCount() == 0) return false;
+ if (node->op()->EffectInputCount() == 1 &&
+ NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) {
+ // The start node is used as sentinel for nodes that are in general
+ // effectful, but of which an analysis has determined that they do not
+ // produce effects in this instance. We don't consider these nodes dangling.
+ return false;
+ }
for (Edge edge : node->use_edges()) {
if (NodeProperties::IsEffectEdge(edge)) {
return false;
@@ -740,9 +920,7 @@ void EscapeAnalysis::ProcessAllocationUsers(Node* node) {
bool EscapeAnalysis::IsEffectBranchPoint(Node* node) {
int count = 0;
for (Edge edge : node->use_edges()) {
- Node* use = edge.from();
- if (NodeProperties::IsEffectEdge(edge) &&
- use->opcode() != IrOpcode::kLoadField) {
+ if (NodeProperties::IsEffectEdge(edge)) {
if (++count > 1) {
return true;
}
@@ -771,6 +949,11 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
}
DCHECK_NOT_NULL(virtual_states_[effect->id()]);
if (IsEffectBranchPoint(effect)) {
+ if (FLAG_trace_turbo_escape) {
+ PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
+ static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
+ effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
+ }
if (!virtual_states_[node->id()]) {
virtual_states_[node->id()] =
new (zone()) VirtualState(*virtual_states_[effect->id()]);
@@ -778,11 +961,6 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()],
zone());
}
- if (FLAG_trace_turbo_escape) {
- PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
- static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
- effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
- }
} else {
virtual_states_[node->id()] = virtual_states_[effect->id()];
if (FLAG_trace_turbo_escape) {
@@ -803,10 +981,6 @@ void EscapeAnalysis::ProcessStart(Node* node) {
bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
- // For now only support binary phis.
- CHECK_EQ(node->op()->EffectInputCount(), 2);
- Node* left = NodeProperties::GetEffectInput(node, 0);
- Node* right = NodeProperties::GetEffectInput(node, 1);
bool changed = false;
VirtualState* mergeState = virtual_states_[node->id()];
@@ -822,33 +996,40 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
changed = true;
}
- VirtualState* l = virtual_states_[left->id()];
- VirtualState* r = virtual_states_[right->id()];
+ cache_.Clear();
- if (l == nullptr && r == nullptr) {
- return changed;
+ if (FLAG_trace_turbo_escape) {
+ PrintF("At Effect Phi #%d, merging states into %p:", node->id(),
+ static_cast<void*>(mergeState));
}
+ for (int i = 0; i < node->op()->EffectInputCount(); ++i) {
+ Node* input = NodeProperties::GetEffectInput(node, i);
+ VirtualState* state = virtual_states_[input->id()];
+ if (state) {
+ cache_.states().push_back(state);
+ }
+ if (FLAG_trace_turbo_escape) {
+ PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(),
+ input->op()->mnemonic());
+ }
+ }
if (FLAG_trace_turbo_escape) {
- PrintF(
- "At Effect Phi #%d, merging states %p (from #%d) and %p (from #%d) "
- "into %p\n",
- node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r),
- right->id(), static_cast<void*>(mergeState));
+ PrintF("\n");
}
- if (r && l == nullptr) {
- changed = mergeState->UpdateFrom(r, zone()) || changed;
- } else if (l && r == nullptr) {
- changed = mergeState->UpdateFrom(l, zone()) || changed;
- } else {
- changed = mergeState->MergeFrom(l, r, zone(), graph(), common(),
- NodeProperties::GetControlInput(node)) ||
- changed;
+ if (cache_.states().size() == 0) {
+ return changed;
}
+
+ changed = mergeState->MergeFrom(&cache_, zone(), graph(), common(),
+ NodeProperties::GetControlInput(node)) ||
+ changed;
+
if (FLAG_trace_turbo_escape) {
PrintF("Merge %s the node.\n", changed ? "changed" : "did not change");
}
+
if (changed) {
mergeState->LastChangedAt(node);
}
@@ -915,6 +1096,11 @@ bool EscapeAnalysis::IsEscaped(Node* node) {
}
+bool EscapeAnalysis::SetEscaped(Node* node) {
+ return escape_status_.SetEscaped(node);
+}
+
+
VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
if (VirtualState* states = virtual_states_[at->id()]) {
return states->GetVirtualObject(id);
@@ -931,45 +1117,43 @@ int EscapeAnalysis::OffsetFromAccess(Node* node) {
void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
VirtualState* state) {
- // Only binary phis are supported for now.
- CHECK_EQ(from->op()->ValueInputCount(), 2);
if (FLAG_trace_turbo_escape) {
PrintF("Load #%d from phi #%d", node->id(), from->id());
}
- Node* left = NodeProperties::GetValueInput(from, 0);
- Node* right = NodeProperties::GetValueInput(from, 1);
- VirtualObject* l = state->GetVirtualObject(left);
- VirtualObject* r = state->GetVirtualObject(right);
- if (l && r) {
- Node* lv = l->GetField(offset);
- Node* rv = r->GetField(offset);
- if (lv && rv) {
+
+ ZoneVector<Node*> inputs(zone());
+ for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
+ Node* input = NodeProperties::GetValueInput(node, i);
+ inputs.push_back(input);
+ }
+
+ GetVirtualObjects(state, inputs, cache_.objects());
+ if (cache_.objects().size() == inputs.size()) {
+ GetFields(cache_.objects(), cache_.fields(), offset);
+ if (cache_.fields().size() == cache_.objects().size()) {
if (!state->GetVirtualObject(node)) {
state->SetVirtualObject(node->id(),
new (zone()) VirtualObject(node->id(), zone()));
}
Node* rep = state->GetVirtualObject(node)->GetReplacement();
- if (!rep || rep->opcode() != IrOpcode::kPhi ||
- NodeProperties::GetValueInput(rep, 0) != lv ||
- NodeProperties::GetValueInput(rep, 1) != rv) {
- Node* phi =
- graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
- lv, rv, NodeProperties::GetControlInput(from));
+ if (!rep || !IsEquivalentPhi(rep, cache_.fields())) {
+ cache_.fields().push_back(NodeProperties::GetControlInput(from));
+ Node* phi = graph()->NewNode(
+ common()->Phi(MachineRepresentation::kTagged, 2),
+ static_cast<int>(cache_.fields().size()), &cache_.fields().front());
state->GetVirtualObject(node)->SetReplacement(phi);
state->LastChangedAt(node);
if (FLAG_trace_turbo_escape) {
- PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id());
+ PrintF(" got phi created.\n");
}
} else if (FLAG_trace_turbo_escape) {
- PrintF(" has already the right phi representation.\n");
+ PrintF(" has already phi #%d.\n", rep->id());
}
} else if (FLAG_trace_turbo_escape) {
- PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv),
- static_cast<void*>(rv));
+ PrintF(" has incomplete field info.\n");
}
} else if (FLAG_trace_turbo_escape) {
- PrintF(" has incomplete virtual object info: %p %p\n",
- static_cast<void*>(l), static_cast<void*>(r));
+ PrintF(" has incomplete virtual object info.\n");
}
}
@@ -985,11 +1169,9 @@ void EscapeAnalysis::ProcessLoadField(Node* node) {
Node* value = object->GetField(offset);
if (value) {
value = state->ResolveReplacement(value);
- // Record that the load has this alias.
- state->UpdateReplacement(node, value, zone());
- } else if (FLAG_trace_turbo_escape) {
- PrintF("No field %d on record for #%d\n", offset, from->id());
}
+ // Record that the load has this alias.
+ state->UpdateReplacement(node, value, zone());
} else {
if (from->opcode() == IrOpcode::kPhi) {
int offset = OffsetFromAccess(node);
@@ -1005,31 +1187,38 @@ void EscapeAnalysis::ProcessLoadElement(Node* node) {
ForwardVirtualState(node);
Node* from = NodeProperties::GetValueInput(node, 0);
VirtualState* state = virtual_states_[node->id()];
- if (VirtualObject* object = state->ResolveVirtualObject(from)) {
- NumberMatcher index(node->InputAt(1));
- ElementAccess access = OpParameter<ElementAccess>(node);
- if (index.HasValue()) {
- CHECK_EQ(ElementSizeLog2Of(access.machine_type.representation()),
+ Node* index_node = node->InputAt(1);
+ NumberMatcher index(index_node);
+ ElementAccess access = OpParameter<ElementAccess>(node);
+ if (index.HasValue()) {
+ int offset = index.Value() + access.header_size / kPointerSize;
+ if (VirtualObject* object = state->ResolveVirtualObject(from)) {
+ CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
kPointerSizeLog2);
CHECK_EQ(access.header_size % kPointerSize, 0);
- int offset = index.Value() + access.header_size / kPointerSize;
+
if (!object->IsTracked()) return;
Node* value = object->GetField(offset);
if (value) {
value = state->ResolveReplacement(value);
- // Record that the load has this alias.
- state->UpdateReplacement(node, value, zone());
- } else if (FLAG_trace_turbo_escape) {
- PrintF("No field %d on record for #%d\n", offset, from->id());
}
- }
- } else {
- if (from->opcode() == IrOpcode::kPhi) {
- NumberMatcher index(node->InputAt(1));
+ // Record that the load has this alias.
+ state->UpdateReplacement(node, value, zone());
+ } else if (from->opcode() == IrOpcode::kPhi) {
ElementAccess access = OpParameter<ElementAccess>(node);
int offset = index.Value() + access.header_size / kPointerSize;
- if (index.HasValue()) {
- ProcessLoadFromPhi(offset, from, node, state);
+ ProcessLoadFromPhi(offset, from, node, state);
+ }
+ } 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 "
+ "non-const "
+ "index #%d (%s)\n",
+ from->id(), from->op()->mnemonic(), node->id(), index_node->id(),
+ index_node->op()->mnemonic());
}
}
}
@@ -1056,21 +1245,34 @@ void EscapeAnalysis::ProcessStoreElement(Node* node) {
DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
ForwardVirtualState(node);
Node* to = NodeProperties::GetValueInput(node, 0);
- NumberMatcher index(node->InputAt(1));
+ Node* index_node = node->InputAt(1);
+ NumberMatcher index(index_node);
ElementAccess access = OpParameter<ElementAccess>(node);
Node* val = NodeProperties::GetValueInput(node, 2);
if (index.HasValue()) {
- CHECK_EQ(ElementSizeLog2Of(access.machine_type.representation()),
- kPointerSizeLog2);
- CHECK_EQ(access.header_size % kPointerSize, 0);
int offset = index.Value() + access.header_size / kPointerSize;
VirtualState* states = virtual_states_[node->id()];
if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
if (!obj->IsTracked()) return;
+ CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
+ kPointerSizeLog2);
+ CHECK_EQ(access.header_size % kPointerSize, 0);
if (obj->SetField(offset, states->ResolveReplacement(val))) {
states->LastChangedAt(node);
}
}
+ } else {
+ // We have a store to a non-const index, cannot eliminate object.
+ if (SetEscaped(to)) {
+ if (FLAG_trace_turbo_escape) {
+ PrintF(
+ "Setting #%d (%s) to escaped because store element #%d to "
+ "non-const "
+ "index #%d (%s)\n",
+ to->id(), to->op()->mnemonic(), node->id(), index_node->id(),
+ index_node->op()->mnemonic());
+ }
+ }
}
}
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698