Index: runtime/vm/flow_graph_optimizer.cc |
=================================================================== |
--- runtime/vm/flow_graph_optimizer.cc (revision 41687) |
+++ runtime/vm/flow_graph_optimizer.cc (working copy) |
@@ -5487,10 +5487,10 @@ |
static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id); |
static bool IsAllocation(Definition* defn) { |
- // TODO(vegorov): add CreateContext to this list. |
return (defn != NULL) && |
(defn->IsAllocateObject() || |
defn->IsCreateArray() || |
+ defn->IsAllocateUninitializedContext() || |
(defn->IsStaticCall() && |
defn->AsStaticCall()->IsRecognizedFactory())); |
} |
@@ -5924,13 +5924,18 @@ |
bool HasLoadsFromPlace(Definition* defn, const Place* place) { |
ASSERT((place->kind() == Place::kField) || |
(place->kind() == Place::kVMField)); |
- ASSERT(place->instance() == defn); |
for (Value* use = defn->input_use_list(); |
use != NULL; |
use = use->next_use()) { |
+ Instruction* instr = use->instruction(); |
+ if ((instr->IsRedefinition() || |
+ instr->IsAssertAssignable()) && |
+ HasLoadsFromPlace(instr->AsDefinition(), place)) { |
+ return true; |
+ } |
bool is_load = false, is_store; |
- Place load_place(use->instruction(), &is_load, &is_store); |
+ Place load_place(instr, &is_load, &is_store); |
if (is_load && load_place.Equals(place)) { |
return true; |
@@ -5951,10 +5956,11 @@ |
(instr->IsStoreIndexed() |
&& (use->use_index() == StoreIndexedInstr::kValuePos)) || |
instr->IsStoreStaticField() || |
- instr->IsPhi() || |
- instr->IsAssertAssignable() || |
- instr->IsRedefinition()) { |
+ instr->IsPhi()) { |
return true; |
+ } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) && |
+ AnyUseCreatesAlias(instr->AsDefinition())) { |
+ return true; |
} else if ((instr->IsStoreInstanceField() |
&& (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { |
ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); |
@@ -5961,8 +5967,10 @@ |
// If we store this value into an object that is not aliased itself |
// and we never load again then the store does not create an alias. |
StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); |
- Definition* instance = store->instance()->definition(); |
- if (instance->IsAllocateObject() && !instance->Identity().IsAliased()) { |
+ Definition* instance = |
+ store->instance()->definition()->OriginalDefinition(); |
+ if (Place::IsAllocation(instance) && |
+ !instance->Identity().IsAliased()) { |
bool is_load, is_store; |
Place store_place(instr, &is_load, &is_store); |
@@ -5977,7 +5985,6 @@ |
continue; |
} |
} |
- |
return true; |
} |
} |
@@ -5986,19 +5993,20 @@ |
// Mark any value stored into the given object as potentially aliased. |
void MarkStoredValuesEscaping(Definition* defn) { |
- if (!defn->IsAllocateObject()) { |
- return; |
- } |
- |
// Find all stores into this object. |
for (Value* use = defn->input_use_list(); |
use != NULL; |
use = use->next_use()) { |
+ if (use->instruction()->IsRedefinition() || |
+ use->instruction()->IsAssertAssignable()) { |
+ MarkStoredValuesEscaping(use->instruction()->AsDefinition()); |
+ continue; |
+ } |
if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && |
use->instruction()->IsStoreInstanceField()) { |
StoreInstanceFieldInstr* store = |
use->instruction()->AsStoreInstanceField(); |
- Definition* value = store->value()->definition(); |
+ Definition* value = store->value()->definition()->OriginalDefinition(); |
if (value->Identity().IsNotAliased()) { |
value->SetIdentity(AliasIdentity::Aliased()); |
identity_rollback_.Add(value); |
@@ -6012,6 +6020,7 @@ |
// Determine if the given definition can't be aliased. |
void ComputeAliasing(Definition* alloc) { |
+ ASSERT(Place::IsAllocation(alloc)); |
ASSERT(alloc->Identity().IsUnknown()); |
ASSERT(aliasing_worklist_.is_empty()); |
@@ -6020,7 +6029,7 @@ |
while (!aliasing_worklist_.is_empty()) { |
Definition* defn = aliasing_worklist_.RemoveLast(); |
- |
+ ASSERT(Place::IsAllocation(defn)); |
// If the definition in the worklist was optimistically marked as |
// not-aliased check that optimistic assumption still holds: check if |
// any of its uses can create an alias. |
@@ -9442,7 +9451,7 @@ |
// deoptimization exit. So candidate should only be used in StoreInstanceField |
// instructions that write into fields of the allocated object. |
// We do not support materialization of the object that has type arguments. |
-static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc, |
+static bool IsAllocationSinkingCandidate(Definition* alloc, |
SafeUseCheck check_type) { |
for (Value* use = alloc->input_use_list(); |
use != NULL; |
@@ -9475,7 +9484,7 @@ |
// Remove the given allocation from the graph. It is not observable. |
// If deoptimization occurs the object will be materialized. |
-void AllocationSinking::EliminateAllocation(AllocateObjectInstr* alloc) { |
+void AllocationSinking::EliminateAllocation(Definition* alloc) { |
ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); |
if (FLAG_trace_optimization) { |
@@ -9521,12 +9530,21 @@ |
block_it.Advance()) { |
BlockEntryInstr* block = block_it.Current(); |
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
- AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); |
- if ((alloc != NULL) && |
- IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
- alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
- candidates_.Add(alloc); |
+ { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); |
+ if ((alloc != NULL) && |
+ IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
+ alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
+ candidates_.Add(alloc); |
+ } |
} |
+ { AllocateUninitializedContextInstr* alloc = |
+ it.Current()->AsAllocateUninitializedContext(); |
+ if ((alloc != NULL) && |
+ IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
+ alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
+ candidates_.Add(alloc); |
+ } |
+ } |
} |
} |
@@ -9535,7 +9553,7 @@ |
do { |
changed = false; |
for (intptr_t i = 0; i < candidates_.length(); i++) { |
- AllocateObjectInstr* alloc = candidates_[i]; |
+ Definition* alloc = candidates_[i]; |
if (alloc->Identity().IsAllocationSinkingCandidate()) { |
if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { |
alloc->SetIdentity(AliasIdentity::Unknown()); |
@@ -9548,7 +9566,7 @@ |
// Shrink the list of candidates removing all unmarked ones. |
intptr_t j = 0; |
for (intptr_t i = 0; i < candidates_.length(); i++) { |
- AllocateObjectInstr* alloc = candidates_[i]; |
+ Definition* alloc = candidates_[i]; |
if (alloc->Identity().IsAllocationSinkingCandidate()) { |
if (FLAG_trace_optimization) { |
OS::Print("discovered allocation sinking candidate: v%" Pd "\n", |
@@ -9630,7 +9648,7 @@ |
do { |
changed = false; |
for (intptr_t i = 0; i < candidates_.length(); i++) { |
- AllocateObjectInstr* alloc = candidates_[i]; |
+ Definition* alloc = candidates_[i]; |
if (alloc->Identity().IsAllocationSinkingCandidate()) { |
if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { |
alloc->SetIdentity(AliasIdentity::Unknown()); |
@@ -9643,7 +9661,7 @@ |
// Remove all failed candidates from the candidates list. |
intptr_t j = 0; |
for (intptr_t i = 0; i < candidates_.length(); i++) { |
- AllocateObjectInstr* alloc = candidates_[i]; |
+ Definition* alloc = candidates_[i]; |
if (!alloc->Identity().IsAllocationSinkingCandidate()) { |
if (FLAG_trace_optimization) { |
OS::Print("allocation v%" Pd " can't be eliminated\n", |
@@ -9827,8 +9845,7 @@ |
// the given instruction that can deoptimize. |
void AllocationSinking::CreateMaterializationAt( |
Instruction* exit, |
- AllocateObjectInstr* alloc, |
- const Class& cls, |
+ Definition* alloc, |
const ZoneGrowableArray<const Object*>& slots) { |
ZoneGrowableArray<Value*>* values = |
new(I) ZoneGrowableArray<Value*>(slots.length()); |
@@ -9856,8 +9873,16 @@ |
values->Add(new(I) Value(load)); |
} |
- MaterializeObjectInstr* mat = |
- new(I) MaterializeObjectInstr(alloc, cls, slots, values); |
+ MaterializeObjectInstr* mat = NULL; |
+ if (alloc->IsAllocateObject()) { |
+ mat = new(I) MaterializeObjectInstr( |
+ alloc->AsAllocateObject(), slots, values); |
+ } else { |
+ ASSERT(alloc->IsAllocateUninitializedContext()); |
+ mat = new(I) MaterializeObjectInstr( |
+ alloc->AsAllocateUninitializedContext(), slots, values); |
+ } |
+ |
flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); |
// Replace all mentions of this allocation with a newly inserted |
@@ -9950,7 +9975,7 @@ |
} |
-void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) { |
+void AllocationSinking::InsertMaterializations(Definition* alloc) { |
// Collect all fields that are written for this instance. |
ZoneGrowableArray<const Object*>* slots = |
new(I) ZoneGrowableArray<const Object*>(5); |
@@ -9969,8 +9994,10 @@ |
} |
if (alloc->ArgumentCount() > 0) { |
- ASSERT(alloc->ArgumentCount() == 1); |
- intptr_t type_args_offset = alloc->cls().type_arguments_field_offset(); |
+ AllocateObjectInstr* alloc_object = alloc->AsAllocateObject(); |
+ ASSERT(alloc_object->ArgumentCount() == 1); |
+ intptr_t type_args_offset = |
+ alloc_object->cls().type_arguments_field_offset(); |
AddSlot(slots, Smi::ZoneHandle(I, Smi::New(type_args_offset))); |
} |
@@ -9980,7 +10007,7 @@ |
// Insert materializations at environment uses. |
for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
CreateMaterializationAt( |
- exits_collector_.exits()[i], alloc, alloc->cls(), *slots); |
+ exits_collector_.exits()[i], alloc, *slots); |
} |
} |