| Index: src/compiler/escape-analysis.cc
|
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
|
| index 150634f764fb63f453a0bb87fc5e9752c816b407..af0ba6a63986dc58004798a2386d348514acf734 100644
|
| --- a/src/compiler/escape-analysis.cc
|
| +++ b/src/compiler/escape-analysis.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "src/compiler/escape-analysis.h"
|
|
|
| +#include <limits>
|
| +
|
| #include "src/base/flags.h"
|
| #include "src/bootstrapper.h"
|
| #include "src/compilation-dependencies.h"
|
| @@ -13,6 +15,7 @@
|
| #include "src/compiler/node.h"
|
| #include "src/compiler/node-matchers.h"
|
| #include "src/compiler/node-properties.h"
|
| +#include "src/compiler/operator-properties.h"
|
| #include "src/compiler/simplified-operator.h"
|
| #include "src/objects-inl.h"
|
| #include "src/type-cache.h"
|
| @@ -21,6 +24,12 @@ namespace v8 {
|
| namespace internal {
|
| namespace compiler {
|
|
|
| +const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable =
|
| + std::numeric_limits<Alias>::max();
|
| +const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable =
|
| + std::numeric_limits<Alias>::max() - 1;
|
| +
|
| +
|
| class VirtualObject : public ZoneObject {
|
| public:
|
| enum Status { kUntracked = 0, kTracked = 1 };
|
| @@ -98,9 +107,9 @@ class VirtualObject : public ZoneObject {
|
| }
|
| bool UpdateFrom(const VirtualObject& other);
|
| void SetObjectState(Node* node) { object_state_ = node; }
|
| - Node* GetObjectState() { return object_state_; }
|
| + Node* GetObjectState() const { return object_state_; }
|
|
|
| - NodeId id() { return id_; }
|
| + NodeId id() const { return id_; }
|
| void id(NodeId id) { id_ = id; }
|
|
|
| private:
|
| @@ -134,18 +143,16 @@ class VirtualState : public ZoneObject {
|
| VirtualState(Zone* zone, size_t size);
|
| VirtualState(const VirtualState& states);
|
|
|
| - VirtualObject* GetVirtualObject(Node* node);
|
| - VirtualObject* GetVirtualObject(size_t id);
|
| - VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone);
|
| - void SetVirtualObject(NodeId id, VirtualObject* state);
|
| + VirtualObject* VirtualObjectFromAlias(size_t alias);
|
| + VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias,
|
| + NodeId id, Zone* zone);
|
| + void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state);
|
| void LastChangedAt(Node* node) { last_changed_ = node; }
|
| Node* GetLastChanged() { return last_changed_; }
|
| - bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone);
|
| bool UpdateFrom(VirtualState* state, Zone* zone);
|
| bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| CommonOperatorBuilder* common, Node* control);
|
| -
|
| - size_t size() { return info_.size(); }
|
| + size_t size() const { return info_.size(); }
|
|
|
| private:
|
| ZoneVector<VirtualObject*> info_;
|
| @@ -156,7 +163,7 @@ class VirtualState : public ZoneObject {
|
| class MergeCache : public ZoneObject {
|
| public:
|
| explicit MergeCache(Zone* zone)
|
| - : states_(zone), objects_(zone), fields_(zone), min_size_(SIZE_MAX) {
|
| + : states_(zone), objects_(zone), fields_(zone) {
|
| states_.reserve(4);
|
| objects_.reserve(4);
|
| fields_.reserve(4);
|
| @@ -168,32 +175,26 @@ class MergeCache : public ZoneObject {
|
| 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);
|
| + size_t LoadVirtualObjectsFromStatesFor(EscapeAnalysis::Alias alias);
|
| + void LoadVirtualObjectsForFieldsFrom(
|
| + VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases);
|
| 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) {
|
| +size_t MergeCache::LoadVirtualObjectsFromStatesFor(
|
| + EscapeAnalysis::Alias alias) {
|
| objects_.clear();
|
| DCHECK_GT(states_.size(), 0u);
|
| - size_t min = SIZE_MAX;
|
| + size_t min = std::numeric_limits<size_t>::max();
|
| for (VirtualState* state : states_) {
|
| - if (VirtualObject* obj = state->GetVirtualObject(id)) {
|
| + if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
|
| objects_.push_back(obj);
|
| min = std::min(obj->field_count(), min);
|
| }
|
| @@ -202,10 +203,14 @@ size_t MergeCache::LoadVirtualObjectsFromStatesFor(NodeId id) {
|
| }
|
|
|
|
|
| -void MergeCache::LoadVirtualObjectsForFieldsFrom(VirtualState* state) {
|
| +void MergeCache::LoadVirtualObjectsForFieldsFrom(
|
| + VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases) {
|
| objects_.clear();
|
| + size_t max_alias = state->size();
|
| for (Node* field : fields_) {
|
| - if (VirtualObject* obj = state->GetVirtualObject(field)) {
|
| + EscapeAnalysis::Alias alias = aliases[field->id()];
|
| + if (alias >= max_alias) continue;
|
| + if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
|
| objects_.push_back(obj);
|
| }
|
| }
|
| @@ -236,75 +241,41 @@ VirtualState::VirtualState(const VirtualState& state)
|
| : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()),
|
| last_changed_(state.last_changed_) {
|
| for (size_t i = 0; i < state.info_.size(); ++i) {
|
| - if (state.info_[i] && state.info_[i]->id() == i) {
|
| - info_[i] = new (state.info_.get_allocator().zone())
|
| - VirtualObject(*state.info_[i]);
|
| + if (state.info_[i]) {
|
| + info_[i] =
|
| + new (info_.get_allocator().zone()) VirtualObject(*state.info_[i]);
|
| }
|
| }
|
| - for (size_t i = 0; i < state.info_.size(); ++i) {
|
| - if (state.info_[i] && state.info_[i]->id() != i) {
|
| - info_[i] = info_[state.info_[i]->id()];
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -VirtualObject* VirtualState::GetVirtualObject(size_t id) {
|
| - if (id >= info_.size()) return nullptr;
|
| - return info_[id];
|
| }
|
|
|
|
|
| -VirtualObject* VirtualState::GetVirtualObject(Node* node) {
|
| - return GetVirtualObject(node->id());
|
| +VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) {
|
| + return info_[alias];
|
| }
|
|
|
|
|
| -VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id,
|
| - Zone* zone) {
|
| - if (VirtualObject* obj = GetVirtualObject(id)) {
|
| +VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(
|
| + EscapeAnalysis::Alias alias, NodeId id, Zone* zone) {
|
| + if (VirtualObject* obj = VirtualObjectFromAlias(alias)) {
|
| return obj;
|
| }
|
| VirtualObject* obj = new (zone) VirtualObject(id, zone, 0);
|
| - SetVirtualObject(id, obj);
|
| + SetVirtualObject(alias, obj);
|
| return obj;
|
| }
|
|
|
|
|
| -void VirtualState::SetVirtualObject(NodeId id, VirtualObject* obj) {
|
| - info_[id] = obj;
|
| -}
|
| -
|
| -
|
| -bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) {
|
| - VirtualObject* obj = GetVirtualObject(id);
|
| - if (!obj) {
|
| - obj = new (zone) VirtualObject(*fromObj);
|
| - SetVirtualObject(id, obj);
|
| - if (FLAG_trace_turbo_escape) {
|
| - PrintF(" Taking field for #%d from %p\n", id,
|
| - static_cast<void*>(fromObj));
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - if (obj->UpdateFrom(*fromObj)) {
|
| - if (FLAG_trace_turbo_escape) {
|
| - PrintF(" Updating field for #%d from %p\n", id,
|
| - static_cast<void*>(fromObj));
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| +void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias,
|
| + VirtualObject* obj) {
|
| + info_[alias] = obj;
|
| }
|
|
|
|
|
| bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
|
| bool changed = false;
|
| - for (NodeId id = 0; id < size(); ++id) {
|
| - VirtualObject* ls = GetVirtualObject(id);
|
| - VirtualObject* rs = from->GetVirtualObject(id);
|
| + for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) {
|
| + VirtualObject* ls = VirtualObjectFromAlias(alias);
|
| + VirtualObject* rs = from->VirtualObjectFromAlias(alias);
|
|
|
| if (rs == nullptr) {
|
| continue;
|
| @@ -312,13 +283,13 @@ bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
|
|
|
| if (ls == nullptr) {
|
| ls = new (zone) VirtualObject(*rs);
|
| - SetVirtualObject(id, ls);
|
| + SetVirtualObject(alias, ls);
|
| changed = true;
|
| continue;
|
| }
|
|
|
| if (FLAG_trace_turbo_escape) {
|
| - PrintF(" Updating fields of #%d\n", id);
|
| + PrintF(" Updating fields of @%d\n", alias);
|
| }
|
|
|
| changed = ls->UpdateFrom(*rs) || changed;
|
| @@ -378,15 +349,14 @@ 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 < cache->min_size(); ++id) {
|
| - size_t fields = cache->LoadVirtualObjectsFromStatesFor(id);
|
| + for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) {
|
| + size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias);
|
| 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 virtual objects of #%d\n", id);
|
| + PrintF(" Merging virtual objects of @%d\n", alias);
|
| }
|
| - VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
|
| + VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(
|
| + alias, cache->objects().front()->id(), zone);
|
| changed = mergeObject->ResizeFields(fields) || changed;
|
| for (size_t i = 0; i < fields; ++i) {
|
| if (Node* field = cache->GetFields(i)) {
|
| @@ -445,15 +415,7 @@ bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
|
| }
|
| }
|
| } else {
|
| - SetVirtualObject(id, nullptr);
|
| - }
|
| - }
|
| - // Update linked objects.
|
| - 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()));
|
| - }
|
| + SetVirtualObject(alias, nullptr);
|
| }
|
| }
|
| return changed;
|
| @@ -465,7 +427,7 @@ EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
|
| : object_analysis_(object_analysis),
|
| graph_(graph),
|
| zone_(zone),
|
| - info_(graph->NodeCount(), kUnknown, zone),
|
| + status_(graph->NodeCount(), kUnknown, zone),
|
| queue_(zone) {}
|
|
|
|
|
| @@ -473,17 +435,17 @@ EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
|
|
|
|
|
| bool EscapeStatusAnalysis::HasEntry(Node* node) {
|
| - return info_[node->id()] != kUnknown;
|
| + return status_[node->id()] & (kTracked | kEscaped);
|
| }
|
|
|
|
|
| bool EscapeStatusAnalysis::IsVirtual(Node* node) {
|
| - return info_[node->id()] == kVirtual;
|
| + return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped);
|
| }
|
|
|
|
|
| bool EscapeStatusAnalysis::IsEscaped(Node* node) {
|
| - return info_[node->id()] == kEscaped;
|
| + return status_[node->id()] & kEscaped;
|
| }
|
|
|
|
|
| @@ -494,36 +456,37 @@ bool EscapeStatusAnalysis::IsAllocation(Node* node) {
|
|
|
|
|
| bool EscapeStatusAnalysis::SetEscaped(Node* node) {
|
| - bool changed = info_[node->id()] != kEscaped;
|
| - info_[node->id()] = kEscaped;
|
| + bool changed = !(status_[node->id()] & kEscaped);
|
| + status_[node->id()] |= kEscaped | kTracked;
|
| return changed;
|
| }
|
|
|
|
|
| void EscapeStatusAnalysis::Resize() {
|
| - info_.resize(graph()->NodeCount(), kUnknown);
|
| + status_.resize(graph()->NodeCount(), kUnknown);
|
| }
|
|
|
|
|
| -size_t EscapeStatusAnalysis::size() { return info_.size(); }
|
| +size_t EscapeStatusAnalysis::size() { return status_.size(); }
|
|
|
|
|
| void EscapeStatusAnalysis::Run() {
|
| Resize();
|
| - ZoneVector<bool> visited(zone());
|
| - visited.resize(graph()->NodeCount());
|
| queue_.push_back(graph()->end());
|
| + status_[graph()->end()->id()] |= kOnStack;
|
| while (!queue_.empty()) {
|
| Node* node = queue_.front();
|
| queue_.pop_front();
|
| + status_[node->id()] &= ~kOnStack;
|
| Process(node);
|
| - if (!visited[node->id()]) {
|
| - RevisitInputs(node);
|
| + status_[node->id()] |= kVisited;
|
| + for (Edge edge : node->input_edges()) {
|
| + Node* input = edge.to();
|
| + if (!(status_[input->id()] & (kVisited | kOnStack))) {
|
| + queue_.push_back(input);
|
| + status_[input->id()] |= kOnStack;
|
| + }
|
| }
|
| - visited[node->id()] = true;
|
| - }
|
| - if (FLAG_trace_turbo_escape) {
|
| - DebugPrint();
|
| }
|
| }
|
|
|
| @@ -531,7 +494,10 @@ void EscapeStatusAnalysis::Run() {
|
| void EscapeStatusAnalysis::RevisitInputs(Node* node) {
|
| for (Edge edge : node->input_edges()) {
|
| Node* input = edge.to();
|
| - queue_.push_back(input);
|
| + if (!(status_[input->id()] & kOnStack)) {
|
| + queue_.push_back(input);
|
| + status_[input->id()] |= kOnStack;
|
| + }
|
| }
|
| }
|
|
|
| @@ -539,7 +505,10 @@ void EscapeStatusAnalysis::RevisitInputs(Node* node) {
|
| void EscapeStatusAnalysis::RevisitUses(Node* node) {
|
| for (Edge edge : node->use_edges()) {
|
| Node* use = edge.from();
|
| - queue_.push_back(use);
|
| + if (!(status_[use->id()] & kOnStack)) {
|
| + queue_.push_back(use);
|
| + status_[use->id()] |= kOnStack;
|
| + }
|
| }
|
| }
|
|
|
| @@ -570,7 +539,7 @@ void EscapeStatusAnalysis::Process(Node* node) {
|
| }
|
| case IrOpcode::kPhi:
|
| if (!HasEntry(node)) {
|
| - info_[node->id()] = kVirtual;
|
| + status_[node->id()] |= kTracked;
|
| if (!IsAllocationPhi(node)) {
|
| SetEscaped(node);
|
| RevisitUses(node);
|
| @@ -627,7 +596,7 @@ void EscapeStatusAnalysis::ProcessStoreElement(Node* node) {
|
| void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
|
| DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
|
| if (!HasEntry(node)) {
|
| - info_[node->id()] = kVirtual;
|
| + status_[node->id()] |= kTracked;
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF("Created status entry for node #%d (%s)\n", node->id(),
|
| node->op()->mnemonic());
|
| @@ -657,34 +626,34 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
|
| bool phi_escaping) {
|
| for (Edge edge : uses->use_edges()) {
|
| Node* use = edge.from();
|
| - if (!NodeProperties::IsValueEdge(edge) &&
|
| - !NodeProperties::IsContextEdge(edge))
|
| + if (edge.index() >= use->op()->ValueInputCount() +
|
| + OperatorProperties::GetContextInputCount(use->op()))
|
| continue;
|
| switch (use->opcode()) {
|
| - case IrOpcode::kStoreField:
|
| - case IrOpcode::kLoadField:
|
| - case IrOpcode::kStoreElement:
|
| - case IrOpcode::kLoadElement:
|
| - case IrOpcode::kFrameState:
|
| - case IrOpcode::kStateValues:
|
| - case IrOpcode::kReferenceEqual:
|
| - case IrOpcode::kFinishRegion:
|
| case IrOpcode::kPhi:
|
| - if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) {
|
| + if (phi_escaping && SetEscaped(rep)) {
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(
|
| - "Setting #%d (%s) to escaped because of use by escaping node "
|
| + "Setting #%d (%s) to escaped because of use by phi node "
|
| "#%d (%s)\n",
|
| rep->id(), rep->op()->mnemonic(), use->id(),
|
| use->op()->mnemonic());
|
| }
|
| return true;
|
| }
|
| - if (phi_escaping && use->opcode() == IrOpcode::kPhi &&
|
| - SetEscaped(rep)) {
|
| + // Fallthrough.
|
| + case IrOpcode::kStoreField:
|
| + case IrOpcode::kLoadField:
|
| + case IrOpcode::kStoreElement:
|
| + case IrOpcode::kLoadElement:
|
| + case IrOpcode::kFrameState:
|
| + case IrOpcode::kStateValues:
|
| + case IrOpcode::kReferenceEqual:
|
| + case IrOpcode::kFinishRegion:
|
| + if (IsEscaped(use) && SetEscaped(rep)) {
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(
|
| - "Setting #%d (%s) to escaped because of use by phi node "
|
| + "Setting #%d (%s) to escaped because of use by escaping node "
|
| "#%d (%s)\n",
|
| rep->id(), rep->op()->mnemonic(), use->id(),
|
| use->op()->mnemonic());
|
| @@ -724,7 +693,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
|
| void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
|
| DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
|
| if (!HasEntry(node)) {
|
| - info_[node->id()] = kVirtual;
|
| + status_[node->id()] |= kTracked;
|
| RevisitUses(node);
|
| }
|
| if (CheckUsesForEscape(node, true)) {
|
| @@ -734,10 +703,10 @@ void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
|
|
|
|
|
| void EscapeStatusAnalysis::DebugPrint() {
|
| - for (NodeId id = 0; id < info_.size(); id++) {
|
| - if (info_[id] != kUnknown) {
|
| + for (NodeId id = 0; id < status_.size(); id++) {
|
| + if (status_[id] & kTracked) {
|
| PrintF("Node #%d is %s\n", id,
|
| - info_[id] == kEscaped ? "escaping" : "virtual");
|
| + (status_[id] & kEscaped) ? "escaping" : "virtual");
|
| }
|
| }
|
| }
|
| @@ -751,7 +720,9 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
|
| virtual_states_(zone),
|
| replacements_(zone),
|
| escape_status_(this, graph, zone),
|
| - cache_(new (zone) MergeCache(zone)) {}
|
| + cache_(new (zone) MergeCache(zone)),
|
| + aliases_(zone),
|
| + next_free_alias_(0) {}
|
|
|
|
|
| EscapeAnalysis::~EscapeAnalysis() {}
|
| @@ -759,11 +730,69 @@ EscapeAnalysis::~EscapeAnalysis() {}
|
|
|
| void EscapeAnalysis::Run() {
|
| replacements_.resize(graph()->NodeCount());
|
| + AssignAliases();
|
| RunObjectAnalysis();
|
| escape_status_.Run();
|
| }
|
|
|
|
|
| +void EscapeAnalysis::AssignAliases() {
|
| + ZoneVector<Node*> stack(zone());
|
| + stack.push_back(graph()->end());
|
| + CHECK_LT(graph()->NodeCount(), kUntrackable);
|
| + aliases_.resize(graph()->NodeCount(), kNotReachable);
|
| + aliases_[graph()->end()->id()] = kUntrackable;
|
| + while (!stack.empty()) {
|
| + Node* node = stack.back();
|
| + stack.pop_back();
|
| + switch (node->opcode()) {
|
| + case IrOpcode::kAllocate:
|
| + if (aliases_[node->id()] >= kUntrackable) {
|
| + aliases_[node->id()] = NextAlias();
|
| + }
|
| + break;
|
| + case IrOpcode::kFinishRegion: {
|
| + Node* allocate = NodeProperties::GetValueInput(node, 0);
|
| + if (allocate->opcode() == IrOpcode::kAllocate) {
|
| + if (aliases_[allocate->id()] >= kUntrackable) {
|
| + if (aliases_[allocate->id()] == kNotReachable) {
|
| + stack.push_back(allocate);
|
| + }
|
| + aliases_[allocate->id()] = NextAlias();
|
| + }
|
| + aliases_[node->id()] = aliases_[allocate->id()];
|
| + } else {
|
| + aliases_[node->id()] = NextAlias();
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + DCHECK_EQ(aliases_[node->id()], kUntrackable);
|
| + break;
|
| + }
|
| + for (Edge edge : node->input_edges()) {
|
| + Node* input = edge.to();
|
| + if (aliases_[input->id()] == kNotReachable) {
|
| + stack.push_back(input);
|
| + aliases_[input->id()] = kUntrackable;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF("Discovered trackable nodes");
|
| + for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) {
|
| + if (aliases_[id] < kUntrackable) {
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF(" #%u", id);
|
| + }
|
| + }
|
| + }
|
| + PrintF("\n");
|
| + }
|
| +}
|
| +
|
| +
|
| void EscapeAnalysis::RunObjectAnalysis() {
|
| virtual_states_.resize(graph()->NodeCount());
|
| ZoneVector<Node*> stack(zone());
|
| @@ -771,7 +800,7 @@ void EscapeAnalysis::RunObjectAnalysis() {
|
| while (!stack.empty()) {
|
| Node* node = stack.back();
|
| stack.pop_back();
|
| - if (Process(node)) {
|
| + if (aliases_[node->id()] != kNotReachable && Process(node)) {
|
| for (Edge edge : node->use_edges()) {
|
| if (NodeProperties::IsEffectEdge(edge)) {
|
| Node* use = edge.from();
|
| @@ -788,8 +817,6 @@ void EscapeAnalysis::RunObjectAnalysis() {
|
| Node* use = edge.from();
|
| if ((use->opcode() == IrOpcode::kLoadField ||
|
| use->opcode() == IrOpcode::kLoadElement) &&
|
| -
|
| -
|
| IsDanglingEffectNode(use)) {
|
| stack.push_back(use);
|
| }
|
| @@ -919,7 +946,7 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
|
| if (effect->opcode() == IrOpcode::kEffectPhi) {
|
| if (virtual_states_[effect->id()] == nullptr) {
|
| virtual_states_[effect->id()] =
|
| - new (zone()) VirtualState(zone(), graph()->NodeCount());
|
| + new (zone()) VirtualState(zone(), AliasCount());
|
| }
|
| }
|
| DCHECK_NOT_NULL(virtual_states_[effect->id()]);
|
| @@ -949,8 +976,7 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
|
|
|
| void EscapeAnalysis::ProcessStart(Node* node) {
|
| DCHECK_EQ(node->opcode(), IrOpcode::kStart);
|
| - virtual_states_[node->id()] =
|
| - new (zone()) VirtualState(zone(), graph()->NodeCount());
|
| + virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount());
|
| }
|
|
|
|
|
| @@ -960,7 +986,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
|
|
| VirtualState* mergeState = virtual_states_[node->id()];
|
| if (!mergeState) {
|
| - mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount());
|
| + mergeState = new (zone()) VirtualState(zone(), AliasCount());
|
| virtual_states_[node->id()] = mergeState;
|
| changed = true;
|
| if (FLAG_trace_turbo_escape) {
|
| @@ -982,7 +1008,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| Node* input = NodeProperties::GetEffectInput(node, i);
|
| VirtualState* state = virtual_states_[input->id()];
|
| if (state) {
|
| - cache_->push_back(state);
|
| + cache_->states().push_back(state);
|
| }
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(),
|
| @@ -1018,7 +1044,10 @@ void EscapeAnalysis::ProcessAllocation(Node* node) {
|
| ForwardVirtualState(node);
|
|
|
| // Check if we have already processed this node.
|
| - if (virtual_states_[node->id()]->GetVirtualObject(node)) return;
|
| + if (virtual_states_[node->id()]->VirtualObjectFromAlias(
|
| + aliases_[node->id()])) {
|
| + return;
|
| + }
|
|
|
| NumberMatcher size(node->InputAt(0));
|
| DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant &&
|
| @@ -1027,11 +1056,12 @@ void EscapeAnalysis::ProcessAllocation(Node* node) {
|
| node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant);
|
| if (size.HasValue()) {
|
| virtual_states_[node->id()]->SetVirtualObject(
|
| - node->id(), new (zone()) VirtualObject(node->id(), zone(),
|
| - size.Value() / kPointerSize));
|
| + aliases_[node->id()],
|
| + new (zone())
|
| + VirtualObject(node->id(), zone(), size.Value() / kPointerSize));
|
| } else {
|
| virtual_states_[node->id()]->SetVirtualObject(
|
| - node->id(), new (zone()) VirtualObject(node->id(), zone()));
|
| + aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone()));
|
| }
|
| virtual_states_[node->id()]->LastChangedAt(node);
|
| }
|
| @@ -1042,16 +1072,17 @@ void EscapeAnalysis::ProcessFinishRegion(Node* node) {
|
| ForwardVirtualState(node);
|
| Node* allocation = NodeProperties::GetValueInput(node, 0);
|
| if (allocation->opcode() == IrOpcode::kAllocate) {
|
| - VirtualState* states = virtual_states_[node->id()];
|
| - DCHECK_NOT_NULL(states->GetVirtualObject(allocation));
|
| - if (!states->GetVirtualObject(node->id())) {
|
| - states->SetVirtualObject(node->id(),
|
| - states->GetVirtualObject(allocation));
|
| + VirtualState* state = virtual_states_[node->id()];
|
| + if (!state->VirtualObjectFromAlias(aliases_[node->id()])) {
|
| + VirtualObject* vobj_alloc =
|
| + state->VirtualObjectFromAlias(aliases_[allocation->id()]);
|
| + DCHECK_NOT_NULL(vobj_alloc);
|
| + state->SetVirtualObject(aliases_[node->id()], vobj_alloc);
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF("Linked finish region node #%d to node #%d\n", node->id(),
|
| allocation->id());
|
| }
|
| - states->LastChangedAt(node);
|
| + state->LastChangedAt(node);
|
| }
|
| }
|
| }
|
| @@ -1139,7 +1170,7 @@ bool EscapeAnalysis::SetEscaped(Node* node) {
|
|
|
| VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
|
| if (VirtualState* states = virtual_states_[at->id()]) {
|
| - return states->GetVirtualObject(id);
|
| + return states->VirtualObjectFromAlias(aliases_[id]);
|
| }
|
| return nullptr;
|
| }
|
| @@ -1147,10 +1178,13 @@ 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()));
|
| + 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;
|
| }
|
| @@ -1185,7 +1219,7 @@ void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
|
| cache_->fields().push_back(input);
|
| }
|
|
|
| - cache_->LoadVirtualObjectsForFieldsFrom(state);
|
| + cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_);
|
| if (cache_->objects().size() == cache_->fields().size()) {
|
| cache_->GetFields(offset);
|
| if (cache_->fields().size() == cache_->objects().size()) {
|
| @@ -1387,8 +1421,9 @@ Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) {
|
| }
|
|
|
|
|
| -void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) {
|
| - PrintF(" Object #%d with %zu fields\n", id, object->field_count());
|
| +void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) {
|
| + PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->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());
|
| @@ -1399,13 +1434,9 @@ void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) {
|
|
|
| void EscapeAnalysis::DebugPrintState(VirtualState* state) {
|
| PrintF("Dumping object state %p\n", static_cast<void*>(state));
|
| - for (size_t id = 0; id < state->size(); id++) {
|
| - if (VirtualObject* object = state->GetVirtualObject(id)) {
|
| - if (object->id() == id) {
|
| - DebugPrintObject(object, static_cast<int>(id));
|
| - } else {
|
| - PrintF(" Object #%zu links to object #%d\n", id, object->id());
|
| - }
|
| + for (Alias alias = 0; alias < AliasCount(); ++alias) {
|
| + if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) {
|
| + DebugPrintObject(object, alias);
|
| }
|
| }
|
| }
|
| @@ -1426,6 +1457,15 @@ void EscapeAnalysis::DebugPrint() {
|
| }
|
| }
|
|
|
| +
|
| +VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state,
|
| + Node* node) {
|
| + if (node->id() >= aliases_.size()) return nullptr;
|
| + Alias alias = aliases_[node->id()];
|
| + if (alias >= state->size()) return nullptr;
|
| + return state->VirtualObjectFromAlias(alias);
|
| +}
|
| +
|
| } // namespace compiler
|
| } // namespace internal
|
| } // namespace v8
|
|
|