| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" | 
| 6 | 6 | 
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" | 
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" | 
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" | 
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" | 
| (...skipping 5469 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 5480     return (kind_ == other->kind_) && | 5480     return (kind_ == other->kind_) && | 
| 5481         (representation_ == other->representation_) && | 5481         (representation_ == other->representation_) && | 
| 5482         (instance_ == other->instance_) && | 5482         (instance_ == other->instance_) && | 
| 5483         SameField(other); | 5483         SameField(other); | 
| 5484   } | 5484   } | 
| 5485 | 5485 | 
| 5486   // Create a zone allocated copy of this place and assign given id to it. | 5486   // Create a zone allocated copy of this place and assign given id to it. | 
| 5487   static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id); | 5487   static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id); | 
| 5488 | 5488 | 
| 5489   static bool IsAllocation(Definition* defn) { | 5489   static bool IsAllocation(Definition* defn) { | 
| 5490     // TODO(vegorov): add CreateContext to this list. |  | 
| 5491     return (defn != NULL) && | 5490     return (defn != NULL) && | 
| 5492         (defn->IsAllocateObject() || | 5491         (defn->IsAllocateObject() || | 
| 5493          defn->IsCreateArray() || | 5492          defn->IsCreateArray() || | 
|  | 5493          defn->IsAllocateUninitializedContext() || | 
| 5494          (defn->IsStaticCall() && | 5494          (defn->IsStaticCall() && | 
| 5495           defn->AsStaticCall()->IsRecognizedFactory())); | 5495           defn->AsStaticCall()->IsRecognizedFactory())); | 
| 5496   } | 5496   } | 
| 5497 | 5497 | 
| 5498  private: | 5498  private: | 
| 5499   Place(Kind kind, Definition* instance, intptr_t selector) | 5499   Place(Kind kind, Definition* instance, intptr_t selector) | 
| 5500       : kind_(kind), | 5500       : kind_(kind), | 
| 5501         representation_(kNoRepresentation), | 5501         representation_(kNoRepresentation), | 
| 5502         instance_(instance), | 5502         instance_(instance), | 
| 5503         raw_selector_(selector), | 5503         raw_selector_(selector), | 
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 5917 | 5917 | 
| 5918     return ((place->kind() == Place::kField) || | 5918     return ((place->kind() == Place::kField) || | 
| 5919          (place->kind() == Place::kVMField)) && | 5919          (place->kind() == Place::kVMField)) && | 
| 5920         !CanBeAliased(place->instance()); | 5920         !CanBeAliased(place->instance()); | 
| 5921   } | 5921   } | 
| 5922 | 5922 | 
| 5923   // Returns true if there are direct loads from the given place. | 5923   // Returns true if there are direct loads from the given place. | 
| 5924   bool HasLoadsFromPlace(Definition* defn, const Place* place) { | 5924   bool HasLoadsFromPlace(Definition* defn, const Place* place) { | 
| 5925     ASSERT((place->kind() == Place::kField) || | 5925     ASSERT((place->kind() == Place::kField) || | 
| 5926            (place->kind() == Place::kVMField)); | 5926            (place->kind() == Place::kVMField)); | 
| 5927     ASSERT(place->instance() == defn); |  | 
| 5928 | 5927 | 
| 5929     for (Value* use = defn->input_use_list(); | 5928     for (Value* use = defn->input_use_list(); | 
| 5930          use != NULL; | 5929          use != NULL; | 
| 5931          use = use->next_use()) { | 5930          use = use->next_use()) { | 
|  | 5931       Instruction* instr = use->instruction(); | 
|  | 5932       if ((instr->IsRedefinition() || | 
|  | 5933            instr->IsAssertAssignable()) && | 
|  | 5934           HasLoadsFromPlace(instr->AsDefinition(), place)) { | 
|  | 5935         return true; | 
|  | 5936       } | 
| 5932       bool is_load = false, is_store; | 5937       bool is_load = false, is_store; | 
| 5933       Place load_place(use->instruction(), &is_load, &is_store); | 5938       Place load_place(instr, &is_load, &is_store); | 
| 5934 | 5939 | 
| 5935       if (is_load && load_place.Equals(place)) { | 5940       if (is_load && load_place.Equals(place)) { | 
| 5936         return true; | 5941         return true; | 
| 5937       } | 5942       } | 
| 5938     } | 5943     } | 
| 5939 | 5944 | 
| 5940     return false; | 5945     return false; | 
| 5941   } | 5946   } | 
| 5942 | 5947 | 
| 5943   // Check if any use of the definition can create an alias. | 5948   // Check if any use of the definition can create an alias. | 
| 5944   // Can add more objects into aliasing_worklist_. | 5949   // Can add more objects into aliasing_worklist_. | 
| 5945   bool AnyUseCreatesAlias(Definition* defn) { | 5950   bool AnyUseCreatesAlias(Definition* defn) { | 
| 5946     for (Value* use = defn->input_use_list(); | 5951     for (Value* use = defn->input_use_list(); | 
| 5947          use != NULL; | 5952          use != NULL; | 
| 5948          use = use->next_use()) { | 5953          use = use->next_use()) { | 
| 5949       Instruction* instr = use->instruction(); | 5954       Instruction* instr = use->instruction(); | 
| 5950       if (instr->IsPushArgument() || | 5955       if (instr->IsPushArgument() || | 
| 5951           (instr->IsStoreIndexed() | 5956           (instr->IsStoreIndexed() | 
| 5952            && (use->use_index() == StoreIndexedInstr::kValuePos)) || | 5957            && (use->use_index() == StoreIndexedInstr::kValuePos)) || | 
| 5953           instr->IsStoreStaticField() || | 5958           instr->IsStoreStaticField() || | 
| 5954           instr->IsPhi() || | 5959           instr->IsPhi()) { | 
| 5955           instr->IsAssertAssignable() || | 5960         return true; | 
| 5956           instr->IsRedefinition()) { | 5961       } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) && | 
|  | 5962                  AnyUseCreatesAlias(instr->AsDefinition())) { | 
| 5957         return true; | 5963         return true; | 
| 5958       } else if ((instr->IsStoreInstanceField() | 5964       } else if ((instr->IsStoreInstanceField() | 
| 5959            && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { | 5965            && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { | 
| 5960         ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); | 5966         ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); | 
| 5961         // If we store this value into an object that is not aliased itself | 5967         // If we store this value into an object that is not aliased itself | 
| 5962         // and we never load again then the store does not create an alias. | 5968         // and we never load again then the store does not create an alias. | 
| 5963         StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); | 5969         StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); | 
| 5964         Definition* instance = store->instance()->definition(); | 5970         Definition* instance = | 
| 5965         if (instance->IsAllocateObject() && !instance->Identity().IsAliased()) { | 5971             store->instance()->definition()->OriginalDefinition(); | 
|  | 5972         if (Place::IsAllocation(instance) && | 
|  | 5973             !instance->Identity().IsAliased()) { | 
| 5966           bool is_load, is_store; | 5974           bool is_load, is_store; | 
| 5967           Place store_place(instr, &is_load, &is_store); | 5975           Place store_place(instr, &is_load, &is_store); | 
| 5968 | 5976 | 
| 5969           if (!HasLoadsFromPlace(instance, &store_place)) { | 5977           if (!HasLoadsFromPlace(instance, &store_place)) { | 
| 5970             // No loads found that match this store. If it is yet unknown if | 5978             // No loads found that match this store. If it is yet unknown if | 
| 5971             // the object is not aliased then optimistically assume this but | 5979             // the object is not aliased then optimistically assume this but | 
| 5972             // add it to the worklist to check its uses transitively. | 5980             // add it to the worklist to check its uses transitively. | 
| 5973             if (instance->Identity().IsUnknown()) { | 5981             if (instance->Identity().IsUnknown()) { | 
| 5974               instance->SetIdentity(AliasIdentity::NotAliased()); | 5982               instance->SetIdentity(AliasIdentity::NotAliased()); | 
| 5975               aliasing_worklist_.Add(instance); | 5983               aliasing_worklist_.Add(instance); | 
| 5976             } | 5984             } | 
| 5977             continue; | 5985             continue; | 
| 5978           } | 5986           } | 
| 5979         } | 5987         } | 
| 5980 |  | 
| 5981         return true; | 5988         return true; | 
| 5982       } | 5989       } | 
| 5983     } | 5990     } | 
| 5984     return false; | 5991     return false; | 
| 5985   } | 5992   } | 
| 5986 | 5993 | 
| 5987   // Mark any value stored into the given object as potentially aliased. | 5994   // Mark any value stored into the given object as potentially aliased. | 
| 5988   void MarkStoredValuesEscaping(Definition* defn) { | 5995   void MarkStoredValuesEscaping(Definition* defn) { | 
| 5989     if (!defn->IsAllocateObject()) { |  | 
| 5990       return; |  | 
| 5991     } |  | 
| 5992 |  | 
| 5993     // Find all stores into this object. | 5996     // Find all stores into this object. | 
| 5994     for (Value* use = defn->input_use_list(); | 5997     for (Value* use = defn->input_use_list(); | 
| 5995          use != NULL; | 5998          use != NULL; | 
| 5996          use = use->next_use()) { | 5999          use = use->next_use()) { | 
|  | 6000       if (use->instruction()->IsRedefinition() || | 
|  | 6001           use->instruction()->IsAssertAssignable()) { | 
|  | 6002         MarkStoredValuesEscaping(use->instruction()->AsDefinition()); | 
|  | 6003         continue; | 
|  | 6004       } | 
| 5997       if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && | 6005       if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && | 
| 5998           use->instruction()->IsStoreInstanceField()) { | 6006           use->instruction()->IsStoreInstanceField()) { | 
| 5999         StoreInstanceFieldInstr* store = | 6007         StoreInstanceFieldInstr* store = | 
| 6000             use->instruction()->AsStoreInstanceField(); | 6008             use->instruction()->AsStoreInstanceField(); | 
| 6001         Definition* value = store->value()->definition(); | 6009         Definition* value = store->value()->definition()->OriginalDefinition(); | 
| 6002         if (value->Identity().IsNotAliased()) { | 6010         if (value->Identity().IsNotAliased()) { | 
| 6003           value->SetIdentity(AliasIdentity::Aliased()); | 6011           value->SetIdentity(AliasIdentity::Aliased()); | 
| 6004           identity_rollback_.Add(value); | 6012           identity_rollback_.Add(value); | 
| 6005 | 6013 | 
| 6006           // Add to worklist to propagate the mark transitively. | 6014           // Add to worklist to propagate the mark transitively. | 
| 6007           aliasing_worklist_.Add(value); | 6015           aliasing_worklist_.Add(value); | 
| 6008         } | 6016         } | 
| 6009       } | 6017       } | 
| 6010     } | 6018     } | 
| 6011   } | 6019   } | 
| 6012 | 6020 | 
| 6013   // Determine if the given definition can't be aliased. | 6021   // Determine if the given definition can't be aliased. | 
| 6014   void ComputeAliasing(Definition* alloc) { | 6022   void ComputeAliasing(Definition* alloc) { | 
|  | 6023     ASSERT(Place::IsAllocation(alloc)); | 
| 6015     ASSERT(alloc->Identity().IsUnknown()); | 6024     ASSERT(alloc->Identity().IsUnknown()); | 
| 6016     ASSERT(aliasing_worklist_.is_empty()); | 6025     ASSERT(aliasing_worklist_.is_empty()); | 
| 6017 | 6026 | 
| 6018     alloc->SetIdentity(AliasIdentity::NotAliased()); | 6027     alloc->SetIdentity(AliasIdentity::NotAliased()); | 
| 6019     aliasing_worklist_.Add(alloc); | 6028     aliasing_worklist_.Add(alloc); | 
| 6020 | 6029 | 
| 6021     while (!aliasing_worklist_.is_empty()) { | 6030     while (!aliasing_worklist_.is_empty()) { | 
| 6022       Definition* defn = aliasing_worklist_.RemoveLast(); | 6031       Definition* defn = aliasing_worklist_.RemoveLast(); | 
| 6023 | 6032       ASSERT(Place::IsAllocation(defn)); | 
| 6024       // If the definition in the worklist was optimistically marked as | 6033       // If the definition in the worklist was optimistically marked as | 
| 6025       // not-aliased check that optimistic assumption still holds: check if | 6034       // not-aliased check that optimistic assumption still holds: check if | 
| 6026       // any of its uses can create an alias. | 6035       // any of its uses can create an alias. | 
| 6027       if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) { | 6036       if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) { | 
| 6028         defn->SetIdentity(AliasIdentity::Aliased()); | 6037         defn->SetIdentity(AliasIdentity::Aliased()); | 
| 6029         identity_rollback_.Add(defn); | 6038         identity_rollback_.Add(defn); | 
| 6030       } | 6039       } | 
| 6031 | 6040 | 
| 6032       // If the allocation site is marked as aliased conservatively mark | 6041       // If the allocation site is marked as aliased conservatively mark | 
| 6033       // any values stored into the object aliased too. | 6042       // any values stored into the object aliased too. | 
| (...skipping 3401 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 9435   } | 9444   } | 
| 9436 | 9445 | 
| 9437   return false; | 9446   return false; | 
| 9438 } | 9447 } | 
| 9439 | 9448 | 
| 9440 | 9449 | 
| 9441 // Right now we are attempting to sink allocation only into | 9450 // Right now we are attempting to sink allocation only into | 
| 9442 // deoptimization exit. So candidate should only be used in StoreInstanceField | 9451 // deoptimization exit. So candidate should only be used in StoreInstanceField | 
| 9443 // instructions that write into fields of the allocated object. | 9452 // instructions that write into fields of the allocated object. | 
| 9444 // We do not support materialization of the object that has type arguments. | 9453 // We do not support materialization of the object that has type arguments. | 
| 9445 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc, | 9454 static bool IsAllocationSinkingCandidate(Definition* alloc, | 
| 9446                                          SafeUseCheck check_type) { | 9455                                          SafeUseCheck check_type) { | 
| 9447   for (Value* use = alloc->input_use_list(); | 9456   for (Value* use = alloc->input_use_list(); | 
| 9448        use != NULL; | 9457        use != NULL; | 
| 9449        use = use->next_use()) { | 9458        use = use->next_use()) { | 
| 9450     if (!IsSafeUse(use, check_type)) { | 9459     if (!IsSafeUse(use, check_type)) { | 
| 9451       if (FLAG_trace_optimization) { | 9460       if (FLAG_trace_optimization) { | 
| 9452         OS::Print("use of %s at %s is unsafe for allocation sinking\n", | 9461         OS::Print("use of %s at %s is unsafe for allocation sinking\n", | 
| 9453                   alloc->ToCString(), | 9462                   alloc->ToCString(), | 
| 9454                   use->instruction()->ToCString()); | 9463                   use->instruction()->ToCString()); | 
| 9455       } | 9464       } | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 9468   if (store != NULL) { | 9477   if (store != NULL) { | 
| 9469     return store->instance()->definition(); | 9478     return store->instance()->definition(); | 
| 9470   } | 9479   } | 
| 9471 | 9480 | 
| 9472   return NULL; | 9481   return NULL; | 
| 9473 } | 9482 } | 
| 9474 | 9483 | 
| 9475 | 9484 | 
| 9476 // Remove the given allocation from the graph. It is not observable. | 9485 // Remove the given allocation from the graph. It is not observable. | 
| 9477 // If deoptimization occurs the object will be materialized. | 9486 // If deoptimization occurs the object will be materialized. | 
| 9478 void AllocationSinking::EliminateAllocation(AllocateObjectInstr* alloc) { | 9487 void AllocationSinking::EliminateAllocation(Definition* alloc) { | 
| 9479   ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); | 9488   ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); | 
| 9480 | 9489 | 
| 9481   if (FLAG_trace_optimization) { | 9490   if (FLAG_trace_optimization) { | 
| 9482     OS::Print("removing allocation from the graph: v%" Pd "\n", | 9491     OS::Print("removing allocation from the graph: v%" Pd "\n", | 
| 9483               alloc->ssa_temp_index()); | 9492               alloc->ssa_temp_index()); | 
| 9484   } | 9493   } | 
| 9485 | 9494 | 
| 9486   // As an allocation sinking candidate it is only used in stores to its own | 9495   // As an allocation sinking candidate it is only used in stores to its own | 
| 9487   // fields. Remove these stores. | 9496   // fields. Remove these stores. | 
| 9488   for (Value* use = alloc->input_use_list(); | 9497   for (Value* use = alloc->input_use_list(); | 
| (...skipping 25 matching lines...) Expand all  Loading... | 
| 9514 // Find allocation instructions that can be potentially eliminated and | 9523 // Find allocation instructions that can be potentially eliminated and | 
| 9515 // rematerialized at deoptimization exits if needed. See IsSafeUse | 9524 // rematerialized at deoptimization exits if needed. See IsSafeUse | 
| 9516 // for the description of algorithm used below. | 9525 // for the description of algorithm used below. | 
| 9517 void AllocationSinking::CollectCandidates() { | 9526 void AllocationSinking::CollectCandidates() { | 
| 9518   // Optimistically collect all potential candidates. | 9527   // Optimistically collect all potential candidates. | 
| 9519   for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 9528   for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 
| 9520        !block_it.Done(); | 9529        !block_it.Done(); | 
| 9521        block_it.Advance()) { | 9530        block_it.Advance()) { | 
| 9522     BlockEntryInstr* block = block_it.Current(); | 9531     BlockEntryInstr* block = block_it.Current(); | 
| 9523     for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 9532     for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 
| 9524       AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); | 9533       { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); | 
| 9525       if ((alloc != NULL) && | 9534         if ((alloc != NULL) && | 
| 9526           IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 9535             IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 
| 9527         alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 9536           alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 
| 9528         candidates_.Add(alloc); | 9537           candidates_.Add(alloc); | 
|  | 9538         } | 
|  | 9539       } | 
|  | 9540       { AllocateUninitializedContextInstr* alloc = | 
|  | 9541             it.Current()->AsAllocateUninitializedContext(); | 
|  | 9542         if ((alloc != NULL) && | 
|  | 9543             IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 
|  | 9544           alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 
|  | 9545           candidates_.Add(alloc); | 
|  | 9546         } | 
| 9529       } | 9547       } | 
| 9530     } | 9548     } | 
| 9531   } | 9549   } | 
| 9532 | 9550 | 
| 9533   // Transitively unmark all candidates that are not strictly valid. | 9551   // Transitively unmark all candidates that are not strictly valid. | 
| 9534   bool changed; | 9552   bool changed; | 
| 9535   do { | 9553   do { | 
| 9536     changed = false; | 9554     changed = false; | 
| 9537     for (intptr_t i = 0; i < candidates_.length(); i++) { | 9555     for (intptr_t i = 0; i < candidates_.length(); i++) { | 
| 9538       AllocateObjectInstr* alloc = candidates_[i]; | 9556       Definition* alloc = candidates_[i]; | 
| 9539       if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9557       if (alloc->Identity().IsAllocationSinkingCandidate()) { | 
| 9540         if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 9558         if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 
| 9541           alloc->SetIdentity(AliasIdentity::Unknown()); | 9559           alloc->SetIdentity(AliasIdentity::Unknown()); | 
| 9542           changed = true; | 9560           changed = true; | 
| 9543         } | 9561         } | 
| 9544       } | 9562       } | 
| 9545     } | 9563     } | 
| 9546   } while (changed); | 9564   } while (changed); | 
| 9547 | 9565 | 
| 9548   // Shrink the list of candidates removing all unmarked ones. | 9566   // Shrink the list of candidates removing all unmarked ones. | 
| 9549   intptr_t j = 0; | 9567   intptr_t j = 0; | 
| 9550   for (intptr_t i = 0; i < candidates_.length(); i++) { | 9568   for (intptr_t i = 0; i < candidates_.length(); i++) { | 
| 9551     AllocateObjectInstr* alloc = candidates_[i]; | 9569     Definition* alloc = candidates_[i]; | 
| 9552     if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9570     if (alloc->Identity().IsAllocationSinkingCandidate()) { | 
| 9553       if (FLAG_trace_optimization) { | 9571       if (FLAG_trace_optimization) { | 
| 9554         OS::Print("discovered allocation sinking candidate: v%" Pd "\n", | 9572         OS::Print("discovered allocation sinking candidate: v%" Pd "\n", | 
| 9555                   alloc->ssa_temp_index()); | 9573                   alloc->ssa_temp_index()); | 
| 9556       } | 9574       } | 
| 9557 | 9575 | 
| 9558       if (j != i) { | 9576       if (j != i) { | 
| 9559         candidates_[j] = alloc; | 9577         candidates_[j] = alloc; | 
| 9560       } | 9578       } | 
| 9561       j++; | 9579       j++; | 
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 9623 // the load forwarding because they flow into phis that load forwarding | 9641 // the load forwarding because they flow into phis that load forwarding | 
| 9624 // inserts. Discover such allocations and remove them from the list | 9642 // inserts. Discover such allocations and remove them from the list | 
| 9625 // of allocation sinking candidates undoing all changes that we did | 9643 // of allocation sinking candidates undoing all changes that we did | 
| 9626 // in preparation for sinking these allocations. | 9644 // in preparation for sinking these allocations. | 
| 9627 void AllocationSinking::DiscoverFailedCandidates() { | 9645 void AllocationSinking::DiscoverFailedCandidates() { | 
| 9628   // Transitively unmark all candidates that are not strictly valid. | 9646   // Transitively unmark all candidates that are not strictly valid. | 
| 9629   bool changed; | 9647   bool changed; | 
| 9630   do { | 9648   do { | 
| 9631     changed = false; | 9649     changed = false; | 
| 9632     for (intptr_t i = 0; i < candidates_.length(); i++) { | 9650     for (intptr_t i = 0; i < candidates_.length(); i++) { | 
| 9633       AllocateObjectInstr* alloc = candidates_[i]; | 9651       Definition* alloc = candidates_[i]; | 
| 9634       if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9652       if (alloc->Identity().IsAllocationSinkingCandidate()) { | 
| 9635         if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 9653         if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 
| 9636           alloc->SetIdentity(AliasIdentity::Unknown()); | 9654           alloc->SetIdentity(AliasIdentity::Unknown()); | 
| 9637           changed = true; | 9655           changed = true; | 
| 9638         } | 9656         } | 
| 9639       } | 9657       } | 
| 9640     } | 9658     } | 
| 9641   } while (changed); | 9659   } while (changed); | 
| 9642 | 9660 | 
| 9643   // Remove all failed candidates from the candidates list. | 9661   // Remove all failed candidates from the candidates list. | 
| 9644   intptr_t j = 0; | 9662   intptr_t j = 0; | 
| 9645   for (intptr_t i = 0; i < candidates_.length(); i++) { | 9663   for (intptr_t i = 0; i < candidates_.length(); i++) { | 
| 9646     AllocateObjectInstr* alloc = candidates_[i]; | 9664     Definition* alloc = candidates_[i]; | 
| 9647     if (!alloc->Identity().IsAllocationSinkingCandidate()) { | 9665     if (!alloc->Identity().IsAllocationSinkingCandidate()) { | 
| 9648       if (FLAG_trace_optimization) { | 9666       if (FLAG_trace_optimization) { | 
| 9649         OS::Print("allocation v%" Pd " can't be eliminated\n", | 9667         OS::Print("allocation v%" Pd " can't be eliminated\n", | 
| 9650                   alloc->ssa_temp_index()); | 9668                   alloc->ssa_temp_index()); | 
| 9651       } | 9669       } | 
| 9652 | 9670 | 
| 9653 #ifdef DEBUG | 9671 #ifdef DEBUG | 
| 9654       for (Value* use = alloc->env_use_list(); | 9672       for (Value* use = alloc->env_use_list(); | 
| 9655            use != NULL; | 9673            use != NULL; | 
| 9656            use = use->next_use()) { | 9674            use = use->next_use()) { | 
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 9820   } | 9838   } | 
| 9821 | 9839 | 
| 9822   return NULL; | 9840   return NULL; | 
| 9823 } | 9841 } | 
| 9824 | 9842 | 
| 9825 | 9843 | 
| 9826 // Insert MaterializeObject instruction for the given allocation before | 9844 // Insert MaterializeObject instruction for the given allocation before | 
| 9827 // the given instruction that can deoptimize. | 9845 // the given instruction that can deoptimize. | 
| 9828 void AllocationSinking::CreateMaterializationAt( | 9846 void AllocationSinking::CreateMaterializationAt( | 
| 9829     Instruction* exit, | 9847     Instruction* exit, | 
| 9830     AllocateObjectInstr* alloc, | 9848     Definition* alloc, | 
| 9831     const Class& cls, |  | 
| 9832     const ZoneGrowableArray<const Object*>& slots) { | 9849     const ZoneGrowableArray<const Object*>& slots) { | 
| 9833   ZoneGrowableArray<Value*>* values = | 9850   ZoneGrowableArray<Value*>* values = | 
| 9834       new(I) ZoneGrowableArray<Value*>(slots.length()); | 9851       new(I) ZoneGrowableArray<Value*>(slots.length()); | 
| 9835 | 9852 | 
| 9836   // All loads should be inserted before the first materialization so that | 9853   // All loads should be inserted before the first materialization so that | 
| 9837   // IR follows the following pattern: loads, materializations, deoptimizing | 9854   // IR follows the following pattern: loads, materializations, deoptimizing | 
| 9838   // instruction. | 9855   // instruction. | 
| 9839   Instruction* load_point = FirstMaterializationAt(exit); | 9856   Instruction* load_point = FirstMaterializationAt(exit); | 
| 9840 | 9857 | 
| 9841   // Insert load instruction for every field. | 9858   // Insert load instruction for every field. | 
| 9842   for (intptr_t i = 0; i < slots.length(); i++) { | 9859   for (intptr_t i = 0; i < slots.length(); i++) { | 
| 9843     LoadFieldInstr* load = slots[i]->IsField() | 9860     LoadFieldInstr* load = slots[i]->IsField() | 
| 9844         ? new(I) LoadFieldInstr( | 9861         ? new(I) LoadFieldInstr( | 
| 9845             new(I) Value(alloc), | 9862             new(I) Value(alloc), | 
| 9846             &Field::Cast(*slots[i]), | 9863             &Field::Cast(*slots[i]), | 
| 9847             AbstractType::ZoneHandle(I), | 9864             AbstractType::ZoneHandle(I), | 
| 9848             alloc->token_pos()) | 9865             alloc->token_pos()) | 
| 9849         : new(I) LoadFieldInstr( | 9866         : new(I) LoadFieldInstr( | 
| 9850             new(I) Value(alloc), | 9867             new(I) Value(alloc), | 
| 9851             Smi::Cast(*slots[i]).Value(), | 9868             Smi::Cast(*slots[i]).Value(), | 
| 9852             AbstractType::ZoneHandle(I), | 9869             AbstractType::ZoneHandle(I), | 
| 9853             alloc->token_pos()); | 9870             alloc->token_pos()); | 
| 9854     flow_graph_->InsertBefore( | 9871     flow_graph_->InsertBefore( | 
| 9855         load_point, load, NULL, FlowGraph::kValue); | 9872         load_point, load, NULL, FlowGraph::kValue); | 
| 9856     values->Add(new(I) Value(load)); | 9873     values->Add(new(I) Value(load)); | 
| 9857   } | 9874   } | 
| 9858 | 9875 | 
| 9859   MaterializeObjectInstr* mat = | 9876   MaterializeObjectInstr* mat = NULL; | 
| 9860       new(I) MaterializeObjectInstr(alloc, cls, slots, values); | 9877   if (alloc->IsAllocateObject()) { | 
|  | 9878     mat = new(I) MaterializeObjectInstr( | 
|  | 9879         alloc->AsAllocateObject(), slots, values); | 
|  | 9880   } else { | 
|  | 9881     ASSERT(alloc->IsAllocateUninitializedContext()); | 
|  | 9882     mat = new(I) MaterializeObjectInstr( | 
|  | 9883         alloc->AsAllocateUninitializedContext(), slots, values); | 
|  | 9884   } | 
|  | 9885 | 
| 9861   flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); | 9886   flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); | 
| 9862 | 9887 | 
| 9863   // Replace all mentions of this allocation with a newly inserted | 9888   // Replace all mentions of this allocation with a newly inserted | 
| 9864   // MaterializeObject instruction. | 9889   // MaterializeObject instruction. | 
| 9865   // We must preserve the identity: all mentions are replaced by the same | 9890   // We must preserve the identity: all mentions are replaced by the same | 
| 9866   // materialization. | 9891   // materialization. | 
| 9867   for (Environment::DeepIterator env_it(exit->env()); | 9892   for (Environment::DeepIterator env_it(exit->env()); | 
| 9868        !env_it.Done(); | 9893        !env_it.Done(); | 
| 9869        env_it.Advance()) { | 9894        env_it.Advance()) { | 
| 9870     Value* use = env_it.CurrentValue(); | 9895     Value* use = env_it.CurrentValue(); | 
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 9943   // We are not removing allocations from the worklist not to waste space on | 9968   // We are not removing allocations from the worklist not to waste space on | 
| 9944   // the side maintaining BitVector of already processed allocations: worklist | 9969   // the side maintaining BitVector of already processed allocations: worklist | 
| 9945   // is expected to be very small thus linear search in it is just as effecient | 9970   // is expected to be very small thus linear search in it is just as effecient | 
| 9946   // as a bitvector. | 9971   // as a bitvector. | 
| 9947   for (intptr_t i = 0; i < worklist_.length(); i++) { | 9972   for (intptr_t i = 0; i < worklist_.length(); i++) { | 
| 9948     Collect(worklist_[i]); | 9973     Collect(worklist_[i]); | 
| 9949   } | 9974   } | 
| 9950 } | 9975 } | 
| 9951 | 9976 | 
| 9952 | 9977 | 
| 9953 void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) { | 9978 void AllocationSinking::InsertMaterializations(Definition* alloc) { | 
| 9954   // Collect all fields that are written for this instance. | 9979   // Collect all fields that are written for this instance. | 
| 9955   ZoneGrowableArray<const Object*>* slots = | 9980   ZoneGrowableArray<const Object*>* slots = | 
| 9956       new(I) ZoneGrowableArray<const Object*>(5); | 9981       new(I) ZoneGrowableArray<const Object*>(5); | 
| 9957 | 9982 | 
| 9958   for (Value* use = alloc->input_use_list(); | 9983   for (Value* use = alloc->input_use_list(); | 
| 9959        use != NULL; | 9984        use != NULL; | 
| 9960        use = use->next_use()) { | 9985        use = use->next_use()) { | 
| 9961     StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); | 9986     StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); | 
| 9962     if ((store != NULL) && (store->instance()->definition() == alloc)) { | 9987     if ((store != NULL) && (store->instance()->definition() == alloc)) { | 
| 9963       if (!store->field().IsNull()) { | 9988       if (!store->field().IsNull()) { | 
| 9964         AddSlot(slots, store->field()); | 9989         AddSlot(slots, store->field()); | 
| 9965       } else { | 9990       } else { | 
| 9966         AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes()))); | 9991         AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes()))); | 
| 9967       } | 9992       } | 
| 9968     } | 9993     } | 
| 9969   } | 9994   } | 
| 9970 | 9995 | 
| 9971   if (alloc->ArgumentCount() > 0) { | 9996   if (alloc->ArgumentCount() > 0) { | 
| 9972     ASSERT(alloc->ArgumentCount() == 1); | 9997     AllocateObjectInstr* alloc_object = alloc->AsAllocateObject(); | 
| 9973     intptr_t type_args_offset = alloc->cls().type_arguments_field_offset(); | 9998     ASSERT(alloc_object->ArgumentCount() == 1); | 
|  | 9999     intptr_t type_args_offset = | 
|  | 10000         alloc_object->cls().type_arguments_field_offset(); | 
| 9974     AddSlot(slots, Smi::ZoneHandle(I, Smi::New(type_args_offset))); | 10001     AddSlot(slots, Smi::ZoneHandle(I, Smi::New(type_args_offset))); | 
| 9975   } | 10002   } | 
| 9976 | 10003 | 
| 9977   // Collect all instructions that mention this object in the environment. | 10004   // Collect all instructions that mention this object in the environment. | 
| 9978   exits_collector_.CollectTransitively(alloc); | 10005   exits_collector_.CollectTransitively(alloc); | 
| 9979 | 10006 | 
| 9980   // Insert materializations at environment uses. | 10007   // Insert materializations at environment uses. | 
| 9981   for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 10008   for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 
| 9982     CreateMaterializationAt( | 10009     CreateMaterializationAt( | 
| 9983         exits_collector_.exits()[i], alloc, alloc->cls(), *slots); | 10010         exits_collector_.exits()[i], alloc, *slots); | 
| 9984   } | 10011   } | 
| 9985 } | 10012 } | 
| 9986 | 10013 | 
| 9987 | 10014 | 
| 9988 }  // namespace dart | 10015 }  // namespace dart | 
| OLD | NEW | 
|---|