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 |