| Index: src/compiler/escape-analysis.cc
|
| diff --git a/src/compiler/escape-analysis.cc b/src/compiler/escape-analysis.cc
|
| index dc331bbbe68e0e344f2f6e44258dd2fe32f08add..7fc8fbfced01ce30c28df6dd6303903527ee506d 100644
|
| --- a/src/compiler/escape-analysis.cc
|
| +++ b/src/compiler/escape-analysis.cc
|
| @@ -63,15 +63,25 @@ 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;
|
| }
|
| -
|
| + bool ClearAllFields() {
|
| + bool changed = false;
|
| + for (size_t i = 0; i < fields_.size(); ++i) {
|
| + if (fields_[i] != nullptr) {
|
| + fields_[i] = nullptr;
|
| + changed = true;
|
| + }
|
| + }
|
| + return changed;
|
| + }
|
| bool UpdateFrom(const VirtualObject& other);
|
|
|
| NodeId id() { return id_; }
|
| @@ -112,6 +122,7 @@ class VirtualState : public ZoneObject {
|
| VirtualState(Zone* zone, size_t size);
|
| VirtualState(const VirtualState& states);
|
|
|
| + VirtualObject* ResolveVirtualObject(Node* node);
|
| VirtualObject* GetVirtualObject(Node* node);
|
| VirtualObject* GetVirtualObject(size_t id);
|
| VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone);
|
| @@ -157,7 +168,10 @@ VirtualState::VirtualState(const VirtualState& state)
|
| }
|
|
|
|
|
| -VirtualObject* VirtualState::GetVirtualObject(size_t id) { return info_[id]; }
|
| +VirtualObject* VirtualState::GetVirtualObject(size_t id) {
|
| + if (id >= info_.size()) return nullptr;
|
| + return info_[id];
|
| +}
|
|
|
|
|
| VirtualObject* VirtualState::GetVirtualObject(Node* node) {
|
| @@ -165,6 +179,16 @@ VirtualObject* VirtualState::GetVirtualObject(Node* node) {
|
| }
|
|
|
|
|
| +VirtualObject* VirtualState::ResolveVirtualObject(Node* node) {
|
| + VirtualObject* obj = GetVirtualObject(node->id());
|
| + while (obj && !obj->IsTracked() && obj->GetReplacement() &&
|
| + GetVirtualObject(obj->GetReplacement())) {
|
| + obj = GetVirtualObject(obj->GetReplacement());
|
| + }
|
| + return obj;
|
| +}
|
| +
|
| +
|
| VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id,
|
| Zone* zone) {
|
| if (VirtualObject* obj = GetVirtualObject(id)) {
|
| @@ -246,7 +270,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)) {
|
| @@ -256,19 +280,36 @@ bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right,
|
| ls->GetField(i)->id());
|
| }
|
| } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) {
|
| - Node* phi = graph->NewNode(common->Phi(kMachAnyTagged, 2),
|
| - ls->GetField(i), rs->GetField(i), control);
|
| - if (mergeObject->SetField(i, phi)) {
|
| + Node* rep = mergeObject->GetField(i);
|
| + if (!rep || rep->opcode() != IrOpcode::kPhi ||
|
| + NodeProperties::GetValueInput(rep, 0) != ls->GetField(i) ||
|
| + NodeProperties::GetValueInput(rep, 1) != rs->GetField(i)) {
|
| + Node* phi =
|
| + graph->NewNode(common->Phi(kMachAnyTagged, 2), ls->GetField(i),
|
| + rs->GetField(i), control);
|
| + if (mergeObject->SetField(i, phi)) {
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF(" Creating Phi #%d as merge of #%d and #%d\n",
|
| + phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
|
| + }
|
| + changed = true;
|
| + }
|
| + } else {
|
| if (FLAG_trace_turbo_escape) {
|
| - PrintF(" Creating Phi #%d as merge of #%d and #%d\n",
|
| - phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
|
| + PrintF(" Retaining Phi #%d as merge of #%d and #%d\n",
|
| + rep->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
|
| }
|
| - changed = true;
|
| }
|
| } else {
|
| changed = mergeObject->SetField(i, nullptr) || changed;
|
| }
|
| }
|
| + } else if (ls) {
|
| + VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
|
| + changed = mergeObject->UpdateFrom(*ls) || changed;
|
| + } else if (rs) {
|
| + VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
|
| + changed = mergeObject->UpdateFrom(*rs) || changed;
|
| }
|
| }
|
| return changed;
|
| @@ -276,12 +317,13 @@ bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right,
|
|
|
|
|
| Node* VirtualState::ResolveReplacement(Node* node) {
|
| - if (VirtualObject* obj = GetVirtualObject(node)) {
|
| - if (Node* rep = obj->GetReplacement()) {
|
| - return rep;
|
| - }
|
| + Node* replacement = node;
|
| + VirtualObject* obj = GetVirtualObject(node);
|
| + while (obj != nullptr && obj->GetReplacement()) {
|
| + replacement = obj->GetReplacement();
|
| + obj = GetVirtualObject(replacement);
|
| }
|
| - return node;
|
| + return replacement;
|
| }
|
|
|
|
|
| @@ -388,7 +430,11 @@ void EscapeStatusAnalysis::Process(Node* node) {
|
| case IrOpcode::kStoreField:
|
| ProcessStoreField(node);
|
| break;
|
| - case IrOpcode::kLoadField: {
|
| + case IrOpcode::kStoreElement:
|
| + ProcessStoreElement(node);
|
| + break;
|
| + case IrOpcode::kLoadField:
|
| + case IrOpcode::kLoadElement: {
|
| if (Node* rep = object_analysis_->GetReplacement(node, node->id())) {
|
| if (rep->opcode() == IrOpcode::kAllocate ||
|
| rep->opcode() == IrOpcode::kFinishRegion) {
|
| @@ -425,6 +471,20 @@ void EscapeStatusAnalysis::ProcessStoreField(Node* node) {
|
| }
|
|
|
|
|
| +void EscapeStatusAnalysis::ProcessStoreElement(Node* node) {
|
| + DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
|
| + Node* to = NodeProperties::GetValueInput(node, 0);
|
| + Node* val = NodeProperties::GetValueInput(node, 2);
|
| + if (IsEscaped(to) && SetEscaped(val)) {
|
| + RevisitUses(val);
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
|
| + val->id(), val->op()->mnemonic(), to->id());
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
|
| DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
|
| if (!HasEntry(node)) {
|
| @@ -444,19 +504,24 @@ void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
|
| return;
|
| }
|
| }
|
| - if (CheckUsesForEscape(node)) {
|
| + if (CheckUsesForEscape(node, true)) {
|
| RevisitUses(node);
|
| }
|
| }
|
|
|
|
|
| -bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep) {
|
| +bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
|
| + bool phi_escaping) {
|
| for (Edge edge : uses->use_edges()) {
|
| Node* use = edge.from();
|
| - if (!NodeProperties::IsValueEdge(edge)) continue;
|
| + if (!NodeProperties::IsValueEdge(edge) &&
|
| + !NodeProperties::IsContextEdge(edge))
|
| + 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:
|
| @@ -472,6 +537,17 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep) {
|
| }
|
| return true;
|
| }
|
| + if (phi_escaping && use->opcode() == IrOpcode::kPhi &&
|
| + SetEscaped(rep)) {
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF(
|
| + "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;
|
| + }
|
| break;
|
| default:
|
| if (SetEscaped(rep)) {
|
| @@ -503,7 +579,7 @@ void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
|
| info_[node->id()] = kVirtual;
|
| RevisitUses(node);
|
| }
|
| - if (CheckUsesForEscape(node)) {
|
| + if (CheckUsesForEscape(node, true)) {
|
| RevisitInputs(node);
|
| }
|
| }
|
| @@ -542,18 +618,19 @@ void EscapeAnalysis::Run() {
|
|
|
| void EscapeAnalysis::RunObjectAnalysis() {
|
| 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());
|
| + 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 ||
|
| + if ((use->opcode() != IrOpcode::kLoadField &&
|
| + use->opcode() != IrOpcode::kLoadElement) ||
|
| !IsDanglingEffectNode(use)) {
|
| - queue.push_back(use);
|
| + stack.push_back(use);
|
| }
|
| }
|
| }
|
| @@ -561,9 +638,12 @@ void EscapeAnalysis::RunObjectAnalysis() {
|
| for (Edge edge : node->use_edges()) {
|
| if (NodeProperties::IsEffectEdge(edge)) {
|
| Node* use = edge.from();
|
| - if (use->opcode() == IrOpcode::kLoadField &&
|
| + if ((use->opcode() == IrOpcode::kLoadField ||
|
| + use->opcode() == IrOpcode::kLoadElement) &&
|
| +
|
| +
|
| IsDanglingEffectNode(use)) {
|
| - queue.push_back(use);
|
| + stack.push_back(use);
|
| }
|
| }
|
| }
|
| @@ -604,6 +684,12 @@ bool EscapeAnalysis::Process(Node* node) {
|
| case IrOpcode::kLoadField:
|
| ProcessLoadField(node);
|
| break;
|
| + case IrOpcode::kStoreElement:
|
| + ProcessStoreElement(node);
|
| + break;
|
| + case IrOpcode::kLoadElement:
|
| + ProcessLoadElement(node);
|
| + break;
|
| case IrOpcode::kStart:
|
| ProcessStart(node);
|
| break;
|
| @@ -614,12 +700,43 @@ bool EscapeAnalysis::Process(Node* node) {
|
| if (node->op()->EffectInputCount() > 0) {
|
| ForwardVirtualState(node);
|
| }
|
| + ProcessAllocationUsers(node);
|
| break;
|
| }
|
| return true;
|
| }
|
|
|
|
|
| +void EscapeAnalysis::ProcessAllocationUsers(Node* node) {
|
| + for (Edge edge : node->input_edges()) {
|
| + Node* input = edge.to();
|
| + if (!NodeProperties::IsValueEdge(edge) &&
|
| + !NodeProperties::IsContextEdge(edge))
|
| + continue;
|
| + switch (node->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:
|
| + break;
|
| + default:
|
| + VirtualState* states = virtual_states_[node->id()];
|
| + if (VirtualObject* obj = states->ResolveVirtualObject(input)) {
|
| + if (obj->ClearAllFields()) {
|
| + states->LastChangedAt(node);
|
| + }
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| bool EscapeAnalysis::IsEffectBranchPoint(Node* node) {
|
| int count = 0;
|
| for (Edge edge : node->use_edges()) {
|
| @@ -637,10 +754,12 @@ 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::kLoadElement &&
|
| + node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) {
|
| PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
|
| node->op()->mnemonic());
|
| - DCHECK(false);
|
| + UNREACHABLE();
|
| }
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| // Break the cycle for effect phis.
|
| @@ -652,9 +771,13 @@ void EscapeAnalysis::ForwardVirtualState(Node* node) {
|
| }
|
| DCHECK_NOT_NULL(virtual_states_[effect->id()]);
|
| if (IsEffectBranchPoint(effect)) {
|
| - if (virtual_states_[node->id()]) return;
|
| - virtual_states_[node->id()] =
|
| - new (zone()) VirtualState(*virtual_states_[effect->id()]);
|
| + if (!virtual_states_[node->id()]) {
|
| + virtual_states_[node->id()] =
|
| + new (zone()) VirtualState(*virtual_states_[effect->id()]);
|
| + } else {
|
| + virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()],
|
| + zone());
|
| + }
|
| if (FLAG_trace_turbo_escape) {
|
| PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
|
| static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
|
| @@ -681,7 +804,7 @@ void EscapeAnalysis::ProcessStart(Node* node) {
|
| bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
|
| // For now only support binary phis.
|
| - DCHECK_EQ(node->op()->EffectInputCount(), 2);
|
| + CHECK_EQ(node->op()->EffectInputCount(), 2);
|
| Node* left = NodeProperties::GetEffectInput(node, 0);
|
| Node* right = NodeProperties::GetEffectInput(node, 1);
|
| bool changed = false;
|
| @@ -692,7 +815,7 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| virtual_states_[node->id()] = mergeState;
|
| changed = true;
|
| if (FLAG_trace_turbo_escape) {
|
| - PrintF("Phi #%d got new states map %p.\n", node->id(),
|
| + PrintF("Effect Phi #%d got new states map %p.\n", node->id(),
|
| static_cast<void*>(mergeState));
|
| }
|
| } else if (mergeState->GetLastChanged() != node) {
|
| @@ -707,9 +830,11 @@ bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
|
| }
|
|
|
| if (FLAG_trace_turbo_escape) {
|
| - PrintF("At Phi #%d, merging states %p (from #%d) and %p (from #%d)\n",
|
| - node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r),
|
| - right->id());
|
| + PrintF(
|
| + "At Effect Phi #%d, merging states %p (from #%d) and %p (from #%d) "
|
| + "into %p\n",
|
| + node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r),
|
| + right->id(), static_cast<void*>(mergeState));
|
| }
|
|
|
| if (r && l == nullptr) {
|
| @@ -790,68 +915,119 @@ 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;
|
| +}
|
| +
|
| +
|
| int EscapeAnalysis::OffsetFromAccess(Node* node) {
|
| DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
|
| return OpParameter<FieldAccess>(node).offset / kPointerSize;
|
| }
|
|
|
|
|
| +void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
|
| + VirtualState* state) {
|
| + // Only binary phis are supported for now.
|
| + CHECK_EQ(from->op()->ValueInputCount(), 2);
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF("Load #%d from phi #%d", node->id(), from->id());
|
| + }
|
| + Node* left = NodeProperties::GetValueInput(from, 0);
|
| + Node* right = NodeProperties::GetValueInput(from, 1);
|
| + VirtualObject* l = state->GetVirtualObject(left);
|
| + VirtualObject* r = state->GetVirtualObject(right);
|
| + if (l && r) {
|
| + Node* lv = l->GetField(offset);
|
| + Node* rv = r->GetField(offset);
|
| + if (lv && rv) {
|
| + if (!state->GetVirtualObject(node)) {
|
| + state->SetVirtualObject(node->id(),
|
| + new (zone()) VirtualObject(node->id(), zone()));
|
| + }
|
| + Node* rep = state->GetVirtualObject(node)->GetReplacement();
|
| + if (!rep || rep->opcode() != IrOpcode::kPhi ||
|
| + NodeProperties::GetValueInput(rep, 0) != lv ||
|
| + NodeProperties::GetValueInput(rep, 1) != rv) {
|
| + Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv,
|
| + NodeProperties::GetControlInput(from));
|
| + state->GetVirtualObject(node)->SetReplacement(phi);
|
| + state->LastChangedAt(node);
|
| + if (FLAG_trace_turbo_escape) {
|
| + PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id());
|
| + }
|
| + } else if (FLAG_trace_turbo_escape) {
|
| + PrintF(" has already the right phi representation.\n");
|
| + }
|
| + } else if (FLAG_trace_turbo_escape) {
|
| + PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv),
|
| + static_cast<void*>(rv));
|
| + }
|
| + } else if (FLAG_trace_turbo_escape) {
|
| + PrintF(" has incomplete virtual object info: %p %p\n",
|
| + static_cast<void*>(l), static_cast<void*>(r));
|
| + }
|
| +}
|
| +
|
| +
|
| 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)) {
|
| - if (!state->IsTracked()) return;
|
| - Node* value = state->GetField(offset);
|
| + VirtualState* state = virtual_states_[node->id()];
|
| + if (VirtualObject* object = state->ResolveVirtualObject(from)) {
|
| + int offset = OffsetFromAccess(node);
|
| + if (!object->IsTracked()) return;
|
| + Node* value = object->GetField(offset);
|
| if (value) {
|
| + value = state->ResolveReplacement(value);
|
| // Record that the load has this alias.
|
| - states->UpdateReplacement(node, value, zone());
|
| + state->UpdateReplacement(node, value, zone());
|
| } else if (FLAG_trace_turbo_escape) {
|
| PrintF("No field %d on record for #%d\n", offset, from->id());
|
| }
|
| } 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) {
|
| - PrintF("Load #%d from phi #%d", node->id(), from->id());
|
| - }
|
| - Node* left = NodeProperties::GetValueInput(from, 0);
|
| - Node* right = NodeProperties::GetValueInput(from, 1);
|
| - VirtualObject* l = states->GetVirtualObject(left);
|
| - VirtualObject* r = states->GetVirtualObject(right);
|
| - if (l && r) {
|
| - Node* lv = l->GetField(offset);
|
| - Node* rv = r->GetField(offset);
|
| - if (lv && rv) {
|
| - if (!states->GetVirtualObject(node)) {
|
| - states->SetVirtualObject(
|
| - node->id(), new (zone()) VirtualObject(node->id(), zone()));
|
| - }
|
| - Node* rep = states->GetVirtualObject(node)->GetReplacement();
|
| - if (!rep || rep->opcode() != IrOpcode::kPhi ||
|
| - NodeProperties::GetValueInput(rep, 0) != lv ||
|
| - NodeProperties::GetValueInput(rep, 1) != rv) {
|
| - Node* phi =
|
| - graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv,
|
| - NodeProperties::GetControlInput(from));
|
| - states->GetVirtualObject(node)->SetReplacement(phi);
|
| - states->LastChangedAt(node);
|
| - if (FLAG_trace_turbo_escape) {
|
| - PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id());
|
| - }
|
| - } else if (FLAG_trace_turbo_escape) {
|
| - PrintF(" has already the right phi representation.\n");
|
| - }
|
| - } else if (FLAG_trace_turbo_escape) {
|
| - PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv),
|
| - static_cast<void*>(rv));
|
| - }
|
| + ProcessLoadFromPhi(offset, from, node, state);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void EscapeAnalysis::ProcessLoadElement(Node* node) {
|
| + DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement);
|
| + ForwardVirtualState(node);
|
| + Node* from = NodeProperties::GetValueInput(node, 0);
|
| + VirtualState* state = virtual_states_[node->id()];
|
| + if (VirtualObject* object = state->ResolveVirtualObject(from)) {
|
| + NumberMatcher index(node->InputAt(1));
|
| + ElementAccess access = OpParameter<ElementAccess>(node);
|
| + if (index.HasValue()) {
|
| + CHECK_EQ(ElementSizeLog2Of(access.machine_type), kPointerSizeLog2);
|
| + CHECK_EQ(access.header_size % kPointerSize, 0);
|
| + int offset = index.Value() + access.header_size / kPointerSize;
|
| + if (!object->IsTracked()) return;
|
| + Node* value = object->GetField(offset);
|
| + if (value) {
|
| + value = state->ResolveReplacement(value);
|
| + // Record that the load has this alias.
|
| + state->UpdateReplacement(node, value, zone());
|
| } else if (FLAG_trace_turbo_escape) {
|
| - PrintF(" has incomplete virtual object info: %p %p\n",
|
| - static_cast<void*>(l), static_cast<void*>(r));
|
| + PrintF("No field %d on record for #%d\n", offset, from->id());
|
| + }
|
| + }
|
| + } else {
|
| + if (from->opcode() == IrOpcode::kPhi) {
|
| + NumberMatcher index(node->InputAt(1));
|
| + ElementAccess access = OpParameter<ElementAccess>(node);
|
| + int offset = index.Value() + access.header_size / kPointerSize;
|
| + if (index.HasValue()) {
|
| + ProcessLoadFromPhi(offset, from, node, state);
|
| }
|
| }
|
| }
|
| @@ -865,7 +1041,7 @@ void EscapeAnalysis::ProcessStoreField(Node* node) {
|
| Node* val = NodeProperties::GetValueInput(node, 1);
|
| int offset = OffsetFromAccess(node);
|
| VirtualState* states = virtual_states_[node->id()];
|
| - if (VirtualObject* obj = states->GetVirtualObject(to)) {
|
| + if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
|
| if (!obj->IsTracked()) return;
|
| if (obj->SetField(offset, states->ResolveReplacement(val))) {
|
| states->LastChangedAt(node);
|
| @@ -874,6 +1050,56 @@ void EscapeAnalysis::ProcessStoreField(Node* node) {
|
| }
|
|
|
|
|
| +void EscapeAnalysis::ProcessStoreElement(Node* node) {
|
| + DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
|
| + ForwardVirtualState(node);
|
| + Node* to = NodeProperties::GetValueInput(node, 0);
|
| + NumberMatcher index(node->InputAt(1));
|
| + ElementAccess access = OpParameter<ElementAccess>(node);
|
| + Node* val = NodeProperties::GetValueInput(node, 2);
|
| + if (index.HasValue()) {
|
| + CHECK_EQ(ElementSizeLog2Of(access.machine_type), kPointerSizeLog2);
|
| + CHECK_EQ(access.header_size % kPointerSize, 0);
|
| + int offset = index.Value() + access.header_size / kPointerSize;
|
| + VirtualState* states = virtual_states_[node->id()];
|
| + if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
|
| + if (!obj->IsTracked()) return;
|
| + if (obj->SetField(offset, states->ResolveReplacement(val))) {
|
| + states->LastChangedAt(node);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) {
|
| + PrintF(" Object #%d with %zu fields", id, object->field_count());
|
| + if (Node* rep = object->GetReplacement()) {
|
| + PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic());
|
| + }
|
| + PrintF("\n");
|
| + 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());
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +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());
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| void EscapeAnalysis::DebugPrint() {
|
| ZoneVector<VirtualState*> object_states(zone());
|
| for (NodeId id = 0; id < virtual_states_.size(); id++) {
|
| @@ -885,26 +1111,7 @@ void EscapeAnalysis::DebugPrint() {
|
| }
|
| }
|
| for (size_t n = 0; n < object_states.size(); n++) {
|
| - PrintF("Dumping object state %p\n", static_cast<void*>(object_states[n]));
|
| - 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());
|
| - 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) {
|
| - if (Node* f = obj->GetField(i)) {
|
| - PrintF(" Field %zu = #%d (%s)\n", i, f->id(),
|
| - f->op()->mnemonic());
|
| - }
|
| - }
|
| - } else {
|
| - PrintF(" Object #%zu links to object #%d\n", id, obj->id());
|
| - }
|
| - }
|
| - }
|
| + DebugPrintState(object_states[n]);
|
| }
|
| }
|
|
|
|
|