| 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 {
|
|
|