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]); |
} |
} |