| Index: src/compiler/escape-analysis.cc
|
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
|
| index 1575d5ae217dc716044995e95535d42fc032d982..ee768414cd07aee9c56c86f6e9292364abb17fe8 100644
|
| --- a/src/compiler/escape-analysis.cc
|
| +++ b/src/compiler/escape-analysis.cc
|
| @@ -148,6 +148,81 @@ class VirtualState : public ZoneObject {
|
| };
|
|
|
|
|
| +class MergeCache : public ZoneObject {
|
| + public:
|
| + explicit MergeCache(Zone* zone)
|
| + : states_(zone), objects_(zone), fields_(zone), min_size_(SIZE_MAX) {
|
| + states_.reserve(4);
|
| + objects_.reserve(4);
|
| + fields_.reserve(4);
|
| + }
|
| + ZoneVector<VirtualState*>& states() { return states_; }
|
| + ZoneVector<VirtualObject*>& objects() { return objects_; }
|
| + ZoneVector<Node*>& fields() { return fields_; }
|
| + void Clear() {
|
| + states_.clear();
|
| + objects_.clear();
|
| + fields_.clear();
|
| + min_size_ = SIZE_MAX;
|
| + }
|
| + void push_back(VirtualState* state) {
|
| + states_.push_back(state);
|
| + min_size_ = std::min(state->size(), min_size_);
|
| + }
|
| + size_t min_size() { return min_size_; }
|
| +
|
| + size_t LoadVirtualObjectsFromStatesFor(NodeId id);
|
| + void LoadVirtualObjectsForFieldsFrom(VirtualState* state);
|
| + Node* GetFields(size_t pos);
|
| +
|
| + private:
|
| + ZoneVector<VirtualState*> states_;
|
| + ZoneVector<VirtualObject*> objects_;
|
| + ZoneVector<Node*> fields_;
|
| + size_t min_size_;
|
| +};
|
| +
|
| +
|
| +size_t MergeCache::LoadVirtualObjectsFromStatesFor(NodeId id) {
|
| + objects_.clear();
|
| + DCHECK_GT(states_.size(), 0u);
|
| + size_t min = SIZE_MAX;
|
| + for (VirtualState* state : states_) {
|
| + if (VirtualObject* obj = state->GetVirtualObject(id)) {
|
| + objects_.push_back(obj);
|
| + min = std::min(obj->field_count(), min);
|
| + }
|
| + }
|
| + return min;
|
| +}
|
| +
|
| +
|
| +void MergeCache::LoadVirtualObjectsForFieldsFrom(VirtualState* state) {
|
| + objects_.clear();
|
| + for (Node* field : fields_) {
|
| + if (VirtualObject* obj = state->GetVirtualObject(field)) {
|
| + objects_.push_back(obj);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +Node* MergeCache::GetFields(size_t pos) {
|
| + fields_.clear();
|
| + Node* rep = objects_.front()->GetField(pos);
|
| + for (VirtualObject* obj : objects_) {
|
| + Node* field = obj->GetField(pos);
|
| + if (field) {
|
| + fields_.push_back(field);
|
| + }
|
| + if (field != rep) {
|
| + rep = nullptr;
|
| + }
|
| + }
|
| + return rep;
|
| +}
|
| +
|
| +
|
| VirtualState::VirtualState(Zone* zone, size_t size)
|
| : info_(zone), last_changed_(nullptr) {
|
| info_.resize(size);
|
| @@ -252,68 +327,6 @@ bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
|
|
|
| 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;
|
| -}
|
| -
|
| -
|
| -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 ||
|
| @@ -363,8 +376,8 @@ 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 < min_size(cache->states()); ++id) {
|
| - GetVirtualObjects(cache->states(), cache->objects(), id);
|
| + for (NodeId id = 0; id < cache->min_size(); ++id) {
|
| + size_t fields = cache->LoadVirtualObjectsFromStatesFor(id);
|
| if (cache->objects().size() == cache->states().size()) {
|
| // Don't process linked objects.
|
| if (cache->objects()[0]->id() != id) continue;
|
| @@ -372,28 +385,27 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| PrintF(" Merging virtual objects of #%d\n", id);
|
| }
|
| VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
|
| - size_t fields = min_field_count(cache->objects());
|
| changed = mergeObject->ResizeFields(fields) || changed;
|
| for (size_t i = 0; i < fields; ++i) {
|
| - if (Node* field = GetFieldIfSame(i, cache->objects())) {
|
| + if (Node* field = cache->GetFields(i)) {
|
| changed = mergeObject->SetField(i, field) || changed;
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(" Field %zu agree on rep #%d\n", i, field->id());
|
| }
|
| } else {
|
| - GetFields(cache->objects(), cache->fields(), i);
|
| + int value_input_count = static_cast<int>(cache->fields().size());
|
| 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());
|
| + Node* phi = graph->NewNode(
|
| + common->Phi(MachineRepresentation::kTagged,
|
| + value_input_count),
|
| + value_input_count + 1, &cache->fields().front());
|
| 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++) {
|
| + for (int i = 0; i < value_input_count; i++) {
|
| PrintF(" #%d (%s)", cache->fields()[i]->id(),
|
| cache->fields()[i]->op()->mnemonic());
|
| }
|
| @@ -402,15 +414,26 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| 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]) {
|
| + for (int n = 0; n < value_input_count; ++n) {
|
| + if (n < rep->op()->ValueInputCount()) {
|
| + Node* old = NodeProperties::GetValueInput(rep, n);
|
| + if (old != cache->fields()[n]) {
|
| + changed = true;
|
| + NodeProperties::ReplaceValueInput(rep, cache->fields()[n],
|
| + n);
|
| + }
|
| + } else {
|
| changed = true;
|
| - NodeProperties::ReplaceValueInput(rep, cache->fields()[n],
|
| - static_cast<int>(n));
|
| + rep->InsertInput(graph->zone(), n, cache->fields()[n]);
|
| }
|
| }
|
| + if (rep->op()->ValueInputCount() != value_input_count) {
|
| + PrintF(" Widening Phi #%d of arity %d to %d", rep->id(),
|
| + rep->op()->ValueInputCount(), value_input_count);
|
| + NodeProperties::ChangeOp(
|
| + rep, common->Phi(MachineRepresentation::kTagged,
|
| + value_input_count));
|
| + }
|
| }
|
| } else {
|
| changed = mergeObject->SetField(i, nullptr) || changed;
|
| @@ -423,11 +446,10 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| }
|
| }
|
| // 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()));
|
| + for (NodeId id = 0; id < cache->min_size(); ++id) {
|
| + if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) {
|
| + if (obj->id() != id) {
|
| + SetVirtualObject(id, GetVirtualObject(obj->id()));
|
| }
|
| }
|
| }
|
| @@ -713,7 +735,7 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
|
| virtual_states_(zone),
|
| replacements_(zone),
|
| escape_status_(this, graph, zone),
|
| - cache_(zone) {}
|
| + cache_(new (zone) MergeCache(zone)) {}
|
|
|
|
|
| EscapeAnalysis::~EscapeAnalysis() {}
|
| @@ -933,7 +955,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| changed = true;
|
| }
|
|
|
| - cache_.Clear();
|
| + cache_->Clear();
|
|
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF("At Effect Phi #%d, merging states into %p:", node->id(),
|
| @@ -944,7 +966,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| Node* input = NodeProperties::GetEffectInput(node, i);
|
| VirtualState* state = virtual_states_[input->id()];
|
| if (state) {
|
| - cache_.states().push_back(state);
|
| + cache_->push_back(state);
|
| }
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(),
|
| @@ -955,11 +977,11 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| PrintF("\n");
|
| }
|
|
|
| - if (cache_.states().size() == 0) {
|
| + if (cache_->states().size() == 0) {
|
| return changed;
|
| }
|
|
|
| - changed = mergeState->MergeFrom(&cache_, zone(), graph(), common(),
|
| + changed = mergeState->MergeFrom(cache_, zone(), graph(), common(),
|
| NodeProperties::GetControlInput(node)) ||
|
| changed;
|
|
|
| @@ -1126,22 +1148,23 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
|
| PrintF("Load #%d from phi #%d", node->id(), from->id());
|
| }
|
|
|
| - ZoneVector<Node*> inputs(zone());
|
| + cache_->fields().clear();
|
| for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
|
| Node* input = NodeProperties::GetValueInput(node, i);
|
| - inputs.push_back(input);
|
| + cache_->fields().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()) {
|
| + cache_->LoadVirtualObjectsForFieldsFrom(state);
|
| + if (cache_->objects().size() == cache_->fields().size()) {
|
| + cache_->GetFields(offset);
|
| + if (cache_->fields().size() == cache_->objects().size()) {
|
| Node* rep = replacement(node);
|
| - if (!rep || !IsEquivalentPhi(rep, cache_.fields())) {
|
| - cache_.fields().push_back(NodeProperties::GetControlInput(from));
|
| + if (!rep || !IsEquivalentPhi(rep, cache_->fields())) {
|
| + int value_input_count = static_cast<int>(cache_->fields().size());
|
| + 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());
|
| + common()->Phi(MachineRepresentation::kTagged, value_input_count),
|
| + value_input_count + 1, &cache_->fields().front());
|
| escape_status_.Resize();
|
| SetReplacement(node, phi);
|
| state->LastChangedAt(node);
|
|
|