Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Unified Diff: src/compiler/escape-analysis.cc

Issue 1485183002: [turbofan] Deopt support for escape analysis (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@ea-local
Patch Set: Fix --always-opt triggered bug Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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());
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698