Chromium Code Reviews| Index: src/compiler/escape-analysis.cc |
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc |
| index dc331bbbe68e0e344f2f6e44258dd2fe32f08add..20f1e45d05cc5f40c8559b5098c9e97da24c6b5d 100644 |
| --- a/src/compiler/escape-analysis.cc |
| +++ b/src/compiler/escape-analysis.cc |
| @@ -29,17 +29,26 @@ 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), |
| + replacement_(nullptr), |
| + object_state_(nullptr) {} |
| VirtualObject(const VirtualObject& other) |
| : id_(other.id_), |
| status_(other.status_), |
| fields_(other.fields_), |
| - replacement_(other.replacement_) {} |
| + replacement_(other.replacement_), |
| + object_state_(other.object_state_) {} |
| - VirtualObject(NodeId id, Zone* zone, size_t field_number) |
| - : id_(id), status_(kTracked), fields_(zone), replacement_(nullptr) { |
| - fields_.resize(field_number); |
| + VirtualObject(NodeId id, Zone* zone, size_t field_count) |
| + : id_(id), |
| + status_(kTracked), |
| + fields_(zone), |
| + replacement_(nullptr), |
| + object_state_(nullptr) { |
| + fields_.resize(field_count); |
| } |
| Node* GetField(size_t offset) { |
| @@ -63,15 +72,17 @@ class VirtualObject : public ZoneObject { |
| return changed; |
| } |
| - size_t fields() { return fields_.size(); } |
| - bool ResizeFields(size_t field_number) { |
| - if (field_number != fields_.size()) { |
| - fields_.resize(field_number); |
| + Node** fields_array() { return &fields_.front(); } |
| + size_t field_count() { return fields_.size(); } |
| + bool ResizeFields(size_t field_count) { |
| + if (field_count != fields_.size()) { |
| + fields_.resize(field_count); |
| return true; |
| } |
| return false; |
| } |
| - |
| + void SetObjectState(Node* node) { object_state_ = node; } |
| + Node* GetObjectState() { return object_state_; } |
| bool UpdateFrom(const VirtualObject& other); |
| NodeId id() { return id_; } |
| @@ -82,6 +93,7 @@ class VirtualObject : public ZoneObject { |
| Status status_; |
| ZoneVector<Node*> fields_; |
| Node* replacement_; |
| + Node* object_state_; |
| }; |
| @@ -246,7 +258,7 @@ bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right, |
| PrintF(" Merging fields of #%d\n", id); |
| } |
| VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); |
| - size_t fields = std::max(ls->fields(), rs->fields()); |
| + size_t fields = std::max(ls->field_count(), rs->field_count()); |
| changed = mergeObject->ResizeFields(fields) || changed; |
| for (size_t i = 0; i < fields; ++i) { |
| if (ls->GetField(i) == rs->GetField(i)) { |
| @@ -528,7 +540,8 @@ EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
| common_(common), |
| zone_(zone), |
| virtual_states_(zone), |
| - escape_status_(this, graph, zone) {} |
| + escape_status_(this, graph, zone), |
| + effects_(zone) {} |
| EscapeAnalysis::~EscapeAnalysis() {} |
| @@ -541,19 +554,20 @@ void EscapeAnalysis::Run() { |
| void EscapeAnalysis::RunObjectAnalysis() { |
| + effects_.resize(graph()->NodeCount()); |
| virtual_states_.resize(graph()->NodeCount()); |
| - ZoneVector<Node*> queue(zone()); |
| - queue.push_back(graph()->start()); |
| - while (!queue.empty()) { |
| - Node* node = queue.back(); |
| - queue.pop_back(); |
| + ZoneVector<Node*> stack(zone()); |
|
Jarin
2015/12/04 13:41:11
Nit: you can actually even say ZoneStack<...> here
|
| + stack.push_back(graph()->start()); |
| + while (!stack.empty()) { |
| + Node* node = stack.back(); |
| + stack.pop_back(); |
| if (Process(node)) { |
| for (Edge edge : node->use_edges()) { |
| if (NodeProperties::IsEffectEdge(edge)) { |
| Node* use = edge.from(); |
| if (use->opcode() != IrOpcode::kLoadField || |
| !IsDanglingEffectNode(use)) { |
| - queue.push_back(use); |
| + stack.push_back(use); |
| } |
| } |
| } |
| @@ -563,7 +577,7 @@ void EscapeAnalysis::RunObjectAnalysis() { |
| Node* use = edge.from(); |
| if (use->opcode() == IrOpcode::kLoadField && |
| IsDanglingEffectNode(use)) { |
| - queue.push_back(use); |
| + stack.push_back(use); |
| } |
| } |
| } |
| @@ -587,6 +601,32 @@ bool EscapeAnalysis::IsDanglingEffectNode(Node* node) { |
| } |
| +void EscapeAnalysis::RecordEffectForFrameStateUses(Node* node, Node* effect) { |
| + DCHECK(effect->op()->EffectInputCount() > 0); |
| + ZoneVector<Node*> stack(zone()); |
| + stack.push_back(node); |
| + while (!stack.empty()) { |
| + Node* cur = stack.back(); |
| + stack.pop_back(); |
| + for (Edge edge : cur->input_edges()) { |
| + Node* input = edge.to(); |
| + if (input->opcode() == IrOpcode::kFrameState || |
| + input->opcode() == IrOpcode::kStateValues) { |
| + if (effects_[input->id()] != effect) { |
| + effects_[input->id()] = effect; |
| + if (FLAG_trace_turbo_escape) { |
| + PrintF("Recorded effect #%d (%s) for frame state %d\n", |
| + effect->id(), effect->op()->mnemonic(), input->id()); |
| + } |
| + } |
| + // Climb up the chain. |
| + stack.push_back(input); |
| + } |
| + } |
| + } |
| +} |
| + |
| + |
| bool EscapeAnalysis::Process(Node* node) { |
| switch (node->opcode()) { |
| case IrOpcode::kAllocate: |
| @@ -613,6 +653,7 @@ bool EscapeAnalysis::Process(Node* node) { |
| default: |
| if (node->op()->EffectInputCount() > 0) { |
| ForwardVirtualState(node); |
| + RecordEffectForFrameStateUses(node, node); |
| } |
| break; |
| } |
| @@ -637,7 +678,8 @@ bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { |
| void EscapeAnalysis::ForwardVirtualState(Node* node) { |
| DCHECK_EQ(node->op()->EffectInputCount(), 1); |
| - if (node->opcode() != IrOpcode::kLoadField && IsDanglingEffectNode(node)) { |
| + if (node->opcode() != IrOpcode::kLoadField && |
| + node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
| PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
| node->op()->mnemonic()); |
| DCHECK(false); |
| @@ -790,6 +832,17 @@ bool EscapeAnalysis::IsEscaped(Node* node) { |
| } |
| +VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| + if (VirtualState* states = virtual_states_[at->id()]) { |
| + return states->GetVirtualObject(id); |
| + } |
| + return nullptr; |
| +} |
| + |
| + |
| +Node* EscapeAnalysis::GetEffect(Node* node) { return effects_[node->id()]; } |
| + |
| + |
| int EscapeAnalysis::OffsetFromAccess(Node* node) { |
| DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
| return OpParameter<FieldAccess>(node).offset / kPointerSize; |
| @@ -800,9 +853,9 @@ void EscapeAnalysis::ProcessLoadField(Node* node) { |
| DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
| ForwardVirtualState(node); |
| Node* from = NodeProperties::GetValueInput(node, 0); |
| - int offset = OffsetFromAccess(node); |
| VirtualState* states = virtual_states_[node->id()]; |
| if (VirtualObject* state = states->GetVirtualObject(from)) { |
| + int offset = OffsetFromAccess(node); |
| if (!state->IsTracked()) return; |
| Node* value = state->GetField(offset); |
| if (value) { |
| @@ -813,6 +866,7 @@ void EscapeAnalysis::ProcessLoadField(Node* node) { |
| } |
| } else { |
| if (from->opcode() == IrOpcode::kPhi) { |
| + int offset = OffsetFromAccess(node); |
| // Only binary phis are supported for now. |
| CHECK_EQ(from->op()->ValueInputCount(), 2); |
| if (FLAG_trace_turbo_escape) { |
| @@ -874,6 +928,37 @@ void EscapeAnalysis::ProcessStoreField(Node* node) { |
| } |
| +Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
| + if ((node->opcode() == IrOpcode::kFinishRegion || |
| + node->opcode() == IrOpcode::kAllocate) && |
| + IsVirtual(node)) { |
| + if (VirtualObject* vobj = GetVirtualObject(effect, node->id())) { |
| + if (Node* object_state = vobj->GetObjectState()) { |
| + return object_state; |
| + } else { |
| + Node* new_object_state = graph()->NewNode( |
| + common()->ObjectState(static_cast<int>(vobj->field_count()), |
| + vobj->id()), |
| + static_cast<int>(vobj->field_count()), vobj->fields_array()); |
| + vobj->SetObjectState(new_object_state); |
| + // Now fix uses of other objects. |
| + for (size_t i = 0; i < vobj->field_count(); ++i) { |
| + if (Node* field = vobj->GetField(i)) { |
| + if (Node* field_object_state = |
| + GetOrCreateObjectState(effect, field)) { |
| + NodeProperties::ReplaceValueInput( |
| + new_object_state, field_object_state, static_cast<int>(i)); |
| + } |
| + } |
| + } |
| + return new_object_state; |
| + } |
| + } |
| + } |
| + return nullptr; |
| +} |
| + |
| + |
| void EscapeAnalysis::DebugPrint() { |
| ZoneVector<VirtualState*> object_states(zone()); |
| for (NodeId id = 0; id < virtual_states_.size(); id++) { |
| @@ -889,12 +974,12 @@ void EscapeAnalysis::DebugPrint() { |
| for (size_t id = 0; id < object_states[n]->size(); id++) { |
| if (VirtualObject* obj = object_states[n]->GetVirtualObject(id)) { |
| if (obj->id() == id) { |
| - PrintF(" Object #%zu with %zu fields", id, obj->fields()); |
| + PrintF(" Object #%zu with %zu fields", id, obj->field_count()); |
| if (Node* rep = obj->GetReplacement()) { |
| PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); |
| } |
| PrintF("\n"); |
| - for (size_t i = 0; i < obj->fields(); ++i) { |
| + for (size_t i = 0; i < obj->field_count(); ++i) { |
| if (Node* f = obj->GetField(i)) { |
| PrintF(" Field %zu = #%d (%s)\n", i, f->id(), |
| f->op()->mnemonic()); |