| Index: src/compiler/escape-analysis.cc
|
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
|
| index 0103a6f65766489400860f141378df338ab7430b..ebeae3218109786c139b0e31a555d2ce7afce0df 100644
|
| --- a/src/compiler/escape-analysis.cc
|
| +++ b/src/compiler/escape-analysis.cc
|
| @@ -29,25 +29,16 @@ class VirtualObject : public ZoneObject {
|
| public:
|
| enum Status { kUntracked = 0, kTracked = 1 };
|
| VirtualObject(NodeId id, Zone* zone)
|
| - : id_(id),
|
| - status_(kUntracked),
|
| - fields_(zone),
|
| - phi_(zone),
|
| - replacement_(nullptr) {}
|
| + : id_(id), status_(kUntracked), fields_(zone), phi_(zone) {}
|
|
|
| VirtualObject(const VirtualObject& other)
|
| : id_(other.id_),
|
| status_(other.status_),
|
| fields_(other.fields_),
|
| - phi_(other.phi_),
|
| - replacement_(other.replacement_) {}
|
| + phi_(other.phi_) {}
|
|
|
| VirtualObject(NodeId id, Zone* zone, size_t field_number)
|
| - : id_(id),
|
| - status_(kTracked),
|
| - fields_(zone),
|
| - phi_(zone),
|
| - replacement_(nullptr) {
|
| + : id_(id), status_(kTracked), fields_(zone), phi_(zone) {
|
| fields_.resize(field_number);
|
| phi_.resize(field_number, false);
|
| }
|
| @@ -78,12 +69,6 @@ class VirtualObject : public ZoneObject {
|
| }
|
| bool IsVirtual() const { return status_ == kTracked; }
|
| bool IsTracked() const { return status_ != kUntracked; }
|
| - Node* GetReplacement() { return replacement_; }
|
| - bool SetReplacement(Node* node) {
|
| - bool changed = replacement_ != node;
|
| - replacement_ = node;
|
| - return changed;
|
| - }
|
|
|
| Node** fields_array() { return &fields_.front(); }
|
| size_t field_count() { return fields_.size(); }
|
| @@ -116,15 +101,12 @@ class VirtualObject : public ZoneObject {
|
| Status status_;
|
| ZoneVector<Node*> fields_;
|
| ZoneVector<bool> phi_;
|
| - Node* replacement_;
|
| };
|
|
|
|
|
| bool VirtualObject::UpdateFrom(const VirtualObject& other) {
|
| bool changed = status_ != other.status_;
|
| status_ = other.status_;
|
| - changed = replacement_ != other.replacement_ || changed;
|
| - replacement_ = other.replacement_;
|
| if (fields_.size() != other.fields_.size()) {
|
| fields_ = other.fields_;
|
| return true;
|
| @@ -147,7 +129,6 @@ class VirtualState : public ZoneObject {
|
| VirtualState(Zone* zone, size_t size);
|
| VirtualState(const VirtualState& states);
|
|
|
| - VirtualObject* ResolveVirtualObject(Node* node);
|
| VirtualObject* GetVirtualObject(Node* node);
|
| VirtualObject* GetVirtualObject(size_t id);
|
| VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone);
|
| @@ -155,8 +136,6 @@ class VirtualState : public ZoneObject {
|
| void LastChangedAt(Node* node) { last_changed_ = node; }
|
| Node* GetLastChanged() { return last_changed_; }
|
| bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone);
|
| - Node* ResolveReplacement(Node* node);
|
| - bool UpdateReplacement(Node* node, Node* rep, Zone* zone);
|
| bool UpdateFrom(VirtualState* state, Zone* zone);
|
| bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| CommonOperatorBuilder* common, Node* control);
|
| @@ -204,16 +183,6 @@ VirtualObject* VirtualState::GetVirtualObject(Node* node) {
|
| }
|
|
|
|
|
| -VirtualObject* VirtualState::ResolveVirtualObject(Node* node) {
|
| - VirtualObject* obj = GetVirtualObject(node->id());
|
| - while (obj && !obj->IsTracked() && obj->GetReplacement() &&
|
| - GetVirtualObject(obj->GetReplacement())) {
|
| - obj = GetVirtualObject(obj->GetReplacement());
|
| - }
|
| - return obj;
|
| -}
|
| -
|
| -
|
| VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id,
|
| Zone* zone) {
|
| if (VirtualObject* obj = GetVirtualObject(id)) {
|
| @@ -334,17 +303,6 @@ Node* GetFieldIfSame(size_t pos, ZoneVector<VirtualObject*>& objs) {
|
| }
|
|
|
|
|
| -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();
|
| @@ -390,6 +348,17 @@ 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;
|
| + }
|
| + }
|
| + return rep;
|
| +}
|
| +
|
| +
|
| bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| CommonOperatorBuilder* common, Node* control) {
|
| DCHECK_GT(cache->states().size(), 0u);
|
| @@ -403,7 +372,6 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| PrintF(" Merging virtual objects of #%d\n", id);
|
| }
|
| VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
|
| - 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) {
|
| @@ -468,41 +436,6 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| }
|
|
|
|
|
| -Node* VirtualState::ResolveReplacement(Node* node) {
|
| - Node* replacement = node;
|
| - VirtualObject* obj = GetVirtualObject(node);
|
| - while (obj != nullptr && obj->GetReplacement()) {
|
| - replacement = obj->GetReplacement();
|
| - obj = GetVirtualObject(replacement);
|
| - }
|
| - return replacement;
|
| -}
|
| -
|
| -
|
| -bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) {
|
| - if (!GetVirtualObject(node)) {
|
| - 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) {
|
| - 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;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| // ------------------------------EscapeStatusAnalysis---------------------------
|
|
|
|
|
| @@ -603,7 +536,7 @@ void EscapeStatusAnalysis::Process(Node* node) {
|
| break;
|
| case IrOpcode::kLoadField:
|
| case IrOpcode::kLoadElement: {
|
| - if (Node* rep = object_analysis_->GetReplacement(node, node->id())) {
|
| + if (Node* rep = object_analysis_->GetReplacement(node)) {
|
| if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) {
|
| RevisitInputs(rep);
|
| RevisitUses(rep);
|
| @@ -776,6 +709,7 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
|
| common_(common),
|
| zone_(zone),
|
| virtual_states_(zone),
|
| + replacements_(zone),
|
| escape_status_(this, graph, zone),
|
| cache_(zone) {}
|
|
|
| @@ -784,6 +718,7 @@ EscapeAnalysis::~EscapeAnalysis() {}
|
|
|
|
|
| void EscapeAnalysis::Run() {
|
| + replacements_.resize(graph()->NodeCount());
|
| RunObjectAnalysis();
|
| escape_status_.Run();
|
| }
|
| @@ -905,10 +840,10 @@ void EscapeAnalysis::ProcessAllocationUsers(Node* node) {
|
| case IrOpcode::kPhi:
|
| break;
|
| default:
|
| - VirtualState* states = virtual_states_[node->id()];
|
| - if (VirtualObject* obj = states->ResolveVirtualObject(input)) {
|
| + VirtualState* state = virtual_states_[node->id()];
|
| + if (VirtualObject* obj = ResolveVirtualObject(state, input)) {
|
| if (obj->ClearAllFields()) {
|
| - states->LastChangedAt(node);
|
| + state->LastChangedAt(node);
|
| }
|
| }
|
| break;
|
| @@ -1077,12 +1012,62 @@ void EscapeAnalysis::ProcessFinishRegion(Node* node) {
|
| }
|
|
|
|
|
| -Node* EscapeAnalysis::GetReplacement(Node* at, NodeId id) {
|
| - VirtualState* states = virtual_states_[at->id()];
|
| - if (VirtualObject* obj = states->GetVirtualObject(id)) {
|
| - return obj->GetReplacement();
|
| +Node* EscapeAnalysis::replacement(NodeId id) {
|
| + if (id >= replacements_.size()) return nullptr;
|
| + return replacements_[id];
|
| +}
|
| +
|
| +
|
| +Node* EscapeAnalysis::replacement(Node* node) {
|
| + return replacement(node->id());
|
| +}
|
| +
|
| +
|
| +bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) {
|
| + bool changed = replacements_[node->id()] != rep;
|
| + replacements_[node->id()] = rep;
|
| + return changed;
|
| +}
|
| +
|
| +
|
| +bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node,
|
| + Node* rep) {
|
| + if (SetReplacement(node, rep)) {
|
| + state->LastChangedAt(node);
|
| + if (FLAG_trace_turbo_escape) {
|
| + 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;
|
| }
|
| - return nullptr;
|
| + return false;
|
| +}
|
| +
|
| +
|
| +Node* EscapeAnalysis::ResolveReplacement(Node* node) {
|
| + while (replacement(node)) {
|
| + node = replacement(node);
|
| + }
|
| + return node;
|
| +}
|
| +
|
| +
|
| +Node* EscapeAnalysis::GetReplacement(Node* node) {
|
| + return GetReplacement(node->id());
|
| +}
|
| +
|
| +
|
| +Node* EscapeAnalysis::GetReplacement(NodeId id) {
|
| + Node* node = nullptr;
|
| + while (replacement(id)) {
|
| + node = replacement(id);
|
| + id = node->id();
|
| + }
|
| + return node;
|
| }
|
|
|
|
|
| @@ -1109,6 +1094,17 @@ VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
|
| }
|
|
|
|
|
| +VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state,
|
| + Node* node) {
|
| + VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node));
|
| + while (obj && replacement(obj->id()) &&
|
| + state->GetVirtualObject(replacement(obj->id()))) {
|
| + obj = state->GetVirtualObject(replacement(obj->id()));
|
| + }
|
| + return obj;
|
| +}
|
| +
|
| +
|
| int EscapeAnalysis::OffsetFromAccess(Node* node) {
|
| DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
|
| return OpParameter<FieldAccess>(node).offset / kPointerSize;
|
| @@ -1131,17 +1127,13 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
|
| 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();
|
| + Node* rep = replacement(node);
|
| 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);
|
| + SetReplacement(node, phi);
|
| state->LastChangedAt(node);
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(" got phi created.\n");
|
| @@ -1163,17 +1155,18 @@ void EscapeAnalysis::ProcessLoadField(Node* node) {
|
| ForwardVirtualState(node);
|
| Node* from = NodeProperties::GetValueInput(node, 0);
|
| VirtualState* state = virtual_states_[node->id()];
|
| - if (VirtualObject* object = state->ResolveVirtualObject(from)) {
|
| + if (VirtualObject* object = ResolveVirtualObject(state, from)) {
|
| int offset = OffsetFromAccess(node);
|
| if (!object->IsTracked()) return;
|
| Node* value = object->GetField(offset);
|
| if (value) {
|
| - value = state->ResolveReplacement(value);
|
| + value = ResolveReplacement(value);
|
| }
|
| // Record that the load has this alias.
|
| - state->UpdateReplacement(node, value, zone());
|
| + UpdateReplacement(state, node, value);
|
| } else {
|
| - if (from->opcode() == IrOpcode::kPhi) {
|
| + 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);
|
| @@ -1192,7 +1185,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 = state->ResolveVirtualObject(from)) {
|
| + if (VirtualObject* object = ResolveVirtualObject(state, from)) {
|
| CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
|
| kPointerSizeLog2);
|
| CHECK_EQ(access.header_size % kPointerSize, 0);
|
| @@ -1200,10 +1193,10 @@ void EscapeAnalysis::ProcessLoadElement(Node* node) {
|
| if (!object->IsTracked()) return;
|
| Node* value = object->GetField(offset);
|
| if (value) {
|
| - value = state->ResolveReplacement(value);
|
| + value = ResolveReplacement(value);
|
| }
|
| // Record that the load has this alias.
|
| - state->UpdateReplacement(node, value, zone());
|
| + UpdateReplacement(state, node, value);
|
| } else if (from->opcode() == IrOpcode::kPhi) {
|
| ElementAccess access = OpParameter<ElementAccess>(node);
|
| int offset = index.Value() + access.header_size / kPointerSize;
|
| @@ -1230,12 +1223,12 @@ void EscapeAnalysis::ProcessStoreField(Node* node) {
|
| ForwardVirtualState(node);
|
| Node* to = NodeProperties::GetValueInput(node, 0);
|
| Node* val = NodeProperties::GetValueInput(node, 1);
|
| - int offset = OffsetFromAccess(node);
|
| - VirtualState* states = virtual_states_[node->id()];
|
| - if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
|
| + VirtualState* state = virtual_states_[node->id()];
|
| + if (VirtualObject* obj = ResolveVirtualObject(state, to)) {
|
| if (!obj->IsTracked()) return;
|
| - if (obj->SetField(offset, states->ResolveReplacement(val))) {
|
| - states->LastChangedAt(node);
|
| + int offset = OffsetFromAccess(node);
|
| + if (obj->SetField(offset, ResolveReplacement(val))) {
|
| + state->LastChangedAt(node);
|
| }
|
| }
|
| }
|
| @@ -1252,12 +1245,12 @@ void EscapeAnalysis::ProcessStoreElement(Node* node) {
|
| if (index.HasValue()) {
|
| int offset = index.Value() + access.header_size / kPointerSize;
|
| VirtualState* states = virtual_states_[node->id()];
|
| - if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
|
| + if (VirtualObject* obj = ResolveVirtualObject(states, 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))) {
|
| + if (obj->SetField(offset, ResolveReplacement(val))) {
|
| states->LastChangedAt(node);
|
| }
|
| }
|
| @@ -1278,11 +1271,7 @@ void EscapeAnalysis::ProcessStoreElement(Node* node) {
|
|
|
|
|
| void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) {
|
| - PrintF(" Object #%d with %zu fields", id, object->field_count());
|
| - if (Node* rep = object->GetReplacement()) {
|
| - PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic());
|
| - }
|
| - PrintF("\n");
|
| + PrintF(" Object #%d with %zu fields\n", id, object->field_count());
|
| for (size_t i = 0; i < object->field_count(); ++i) {
|
| if (Node* f = object->GetField(i)) {
|
| PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic());
|
|
|