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