Chromium Code Reviews| 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 5417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5428 return (kind_ == other->kind_) && | 5428 return (kind_ == other->kind_) && |
| 5429 (representation_ == other->representation_) && | 5429 (representation_ == other->representation_) && |
| 5430 (instance_ == other->instance_) && | 5430 (instance_ == other->instance_) && |
| 5431 SameField(other); | 5431 SameField(other); |
| 5432 } | 5432 } |
| 5433 | 5433 |
| 5434 // Create a zone allocated copy of this place and assign given id to it. | 5434 // Create a zone allocated copy of this place and assign given id to it. |
| 5435 static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id); | 5435 static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id); |
| 5436 | 5436 |
| 5437 static bool IsAllocation(Definition* defn) { | 5437 static bool IsAllocation(Definition* defn) { |
| 5438 // TODO(vegorov): add CreateContext to this list. | |
| 5439 return (defn != NULL) && | 5438 return (defn != NULL) && |
| 5440 (defn->IsAllocateObject() || | 5439 (defn->IsAllocateObject() || |
| 5441 defn->IsCreateArray() || | 5440 defn->IsCreateArray() || |
| 5441 defn->IsAllocateUninitializedContext() || | |
| 5442 (defn->IsStaticCall() && | 5442 (defn->IsStaticCall() && |
| 5443 defn->AsStaticCall()->IsRecognizedFactory())); | 5443 defn->AsStaticCall()->IsRecognizedFactory())); |
| 5444 } | 5444 } |
| 5445 | 5445 |
| 5446 private: | 5446 private: |
| 5447 Place(Kind kind, Definition* instance, intptr_t selector) | 5447 Place(Kind kind, Definition* instance, intptr_t selector) |
| 5448 : kind_(kind), | 5448 : kind_(kind), |
| 5449 representation_(kNoRepresentation), | 5449 representation_(kNoRepresentation), |
| 5450 instance_(instance), | 5450 instance_(instance), |
| 5451 raw_selector_(selector), | 5451 raw_selector_(selector), |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5892 // Can add more objects into aliasing_worklist_. | 5892 // Can add more objects into aliasing_worklist_. |
| 5893 bool AnyUseCreatesAlias(Definition* defn) { | 5893 bool AnyUseCreatesAlias(Definition* defn) { |
| 5894 for (Value* use = defn->input_use_list(); | 5894 for (Value* use = defn->input_use_list(); |
| 5895 use != NULL; | 5895 use != NULL; |
| 5896 use = use->next_use()) { | 5896 use = use->next_use()) { |
| 5897 Instruction* instr = use->instruction(); | 5897 Instruction* instr = use->instruction(); |
| 5898 if (instr->IsPushArgument() || | 5898 if (instr->IsPushArgument() || |
| 5899 (instr->IsStoreIndexed() | 5899 (instr->IsStoreIndexed() |
| 5900 && (use->use_index() == StoreIndexedInstr::kValuePos)) || | 5900 && (use->use_index() == StoreIndexedInstr::kValuePos)) || |
| 5901 instr->IsStoreStaticField() || | 5901 instr->IsStoreStaticField() || |
| 5902 instr->IsPhi() || | 5902 instr->IsPhi()) { |
| 5903 instr->IsAssertAssignable() || | |
| 5904 instr->IsRedefinition()) { | |
| 5905 return true; | 5903 return true; |
| 5904 } else if (instr->IsAssertAssignable() || | |
| 5905 instr->IsRedefinition()) { | |
| 5906 return AnyUseCreatesAlias(instr->AsDefinition()); | |
| 5906 } else if ((instr->IsStoreInstanceField() | 5907 } else if ((instr->IsStoreInstanceField() |
| 5907 && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { | 5908 && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) { |
| 5908 ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); | 5909 ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos); |
| 5909 // If we store this value into an object that is not aliased itself | 5910 // If we store this value into an object that is not aliased itself |
| 5910 // and we never load again then the store does not create an alias. | 5911 // and we never load again then the store does not create an alias. |
| 5911 StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); | 5912 StoreInstanceFieldInstr* store = instr->AsStoreInstanceField(); |
| 5912 Definition* instance = store->instance()->definition(); | 5913 Definition* instance = store->instance()->definition(); |
| 5913 if (instance->IsAllocateObject() && !instance->Identity().IsAliased()) { | 5914 if (Place::IsAllocation(instance) && |
| 5915 !instance->Identity().IsAliased()) { | |
| 5914 bool is_load, is_store; | 5916 bool is_load, is_store; |
| 5915 Place store_place(instr, &is_load, &is_store); | 5917 Place store_place(instr, &is_load, &is_store); |
| 5916 | 5918 |
| 5917 if (!HasLoadsFromPlace(instance, &store_place)) { | 5919 if (!HasLoadsFromPlace(instance, &store_place)) { |
|
Vyacheslav Egorov (Google)
2014/11/03 13:37:48
HasLoadsFromPlace has to account for redifinitions
| |
| 5918 // No loads found that match this store. If it is yet unknown if | 5920 // No loads found that match this store. If it is yet unknown if |
| 5919 // the object is not aliased then optimistically assume this but | 5921 // the object is not aliased then optimistically assume this but |
| 5920 // add it to the worklist to check its uses transitively. | 5922 // add it to the worklist to check its uses transitively. |
| 5921 if (instance->Identity().IsUnknown()) { | 5923 if (instance->Identity().IsUnknown()) { |
| 5922 instance->SetIdentity(AliasIdentity::NotAliased()); | 5924 instance->SetIdentity(AliasIdentity::NotAliased()); |
| 5923 aliasing_worklist_.Add(instance); | 5925 aliasing_worklist_.Add(instance); |
| 5924 } | 5926 } |
| 5925 continue; | 5927 continue; |
| 5926 } | 5928 } |
| 5927 } | 5929 } |
| 5928 | 5930 |
| 5929 return true; | 5931 return true; |
| 5930 } | 5932 } |
| 5931 } | 5933 } |
| 5932 return false; | 5934 return false; |
| 5933 } | 5935 } |
| 5934 | 5936 |
| 5935 // Mark any value stored into the given object as potentially aliased. | 5937 // Mark any value stored into the given object as potentially aliased. |
| 5936 void MarkStoredValuesEscaping(Definition* defn) { | 5938 void MarkStoredValuesEscaping(Definition* defn) { |
| 5937 if (!defn->IsAllocateObject()) { | 5939 if (!Place::IsAllocation(defn)) { |
| 5938 return; | 5940 return; |
| 5939 } | 5941 } |
| 5940 | 5942 |
| 5941 // Find all stores into this object. | 5943 // Find all stores into this object. |
| 5942 for (Value* use = defn->input_use_list(); | 5944 for (Value* use = defn->input_use_list(); |
| 5943 use != NULL; | 5945 use != NULL; |
| 5944 use = use->next_use()) { | 5946 use = use->next_use()) { |
| 5945 if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && | 5947 if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) && |
| 5946 use->instruction()->IsStoreInstanceField()) { | 5948 use->instruction()->IsStoreInstanceField()) { |
| 5947 StoreInstanceFieldInstr* store = | 5949 StoreInstanceFieldInstr* store = |
| (...skipping 3432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9380 } | 9382 } |
| 9381 | 9383 |
| 9382 return false; | 9384 return false; |
| 9383 } | 9385 } |
| 9384 | 9386 |
| 9385 | 9387 |
| 9386 // Right now we are attempting to sink allocation only into | 9388 // Right now we are attempting to sink allocation only into |
| 9387 // deoptimization exit. So candidate should only be used in StoreInstanceField | 9389 // deoptimization exit. So candidate should only be used in StoreInstanceField |
| 9388 // instructions that write into fields of the allocated object. | 9390 // instructions that write into fields of the allocated object. |
| 9389 // We do not support materialization of the object that has type arguments. | 9391 // We do not support materialization of the object that has type arguments. |
| 9390 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc, | 9392 static bool IsAllocationSinkingCandidate(Definition* alloc, |
| 9391 SafeUseCheck check_type) { | 9393 SafeUseCheck check_type) { |
| 9392 for (Value* use = alloc->input_use_list(); | 9394 for (Value* use = alloc->input_use_list(); |
| 9393 use != NULL; | 9395 use != NULL; |
| 9394 use = use->next_use()) { | 9396 use = use->next_use()) { |
| 9395 if (!IsSafeUse(use, check_type)) { | 9397 if (!IsSafeUse(use, check_type)) { |
| 9396 if (FLAG_trace_optimization) { | 9398 if (FLAG_trace_optimization) { |
| 9397 OS::Print("use of %s at %s is unsafe for allocation sinking\n", | 9399 OS::Print("use of %s at %s is unsafe for allocation sinking\n", |
| 9398 alloc->ToCString(), | 9400 alloc->ToCString(), |
| 9399 use->instruction()->ToCString()); | 9401 use->instruction()->ToCString()); |
| 9400 } | 9402 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 9413 if (store != NULL) { | 9415 if (store != NULL) { |
| 9414 return store->instance()->definition(); | 9416 return store->instance()->definition(); |
| 9415 } | 9417 } |
| 9416 | 9418 |
| 9417 return NULL; | 9419 return NULL; |
| 9418 } | 9420 } |
| 9419 | 9421 |
| 9420 | 9422 |
| 9421 // Remove the given allocation from the graph. It is not observable. | 9423 // Remove the given allocation from the graph. It is not observable. |
| 9422 // If deoptimization occurs the object will be materialized. | 9424 // If deoptimization occurs the object will be materialized. |
| 9423 void AllocationSinking::EliminateAllocation(AllocateObjectInstr* alloc) { | 9425 void AllocationSinking::EliminateAllocation(Definition* alloc) { |
| 9424 ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); | 9426 ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck)); |
| 9425 | 9427 |
| 9426 if (FLAG_trace_optimization) { | 9428 if (FLAG_trace_optimization) { |
| 9427 OS::Print("removing allocation from the graph: v%" Pd "\n", | 9429 OS::Print("removing allocation from the graph: v%" Pd "\n", |
| 9428 alloc->ssa_temp_index()); | 9430 alloc->ssa_temp_index()); |
| 9429 } | 9431 } |
| 9430 | 9432 |
| 9431 // As an allocation sinking candidate it is only used in stores to its own | 9433 // As an allocation sinking candidate it is only used in stores to its own |
| 9432 // fields. Remove these stores. | 9434 // fields. Remove these stores. |
| 9433 for (Value* use = alloc->input_use_list(); | 9435 for (Value* use = alloc->input_use_list(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 9459 // Find allocation instructions that can be potentially eliminated and | 9461 // Find allocation instructions that can be potentially eliminated and |
| 9460 // rematerialized at deoptimization exits if needed. See IsSafeUse | 9462 // rematerialized at deoptimization exits if needed. See IsSafeUse |
| 9461 // for the description of algorithm used below. | 9463 // for the description of algorithm used below. |
| 9462 void AllocationSinking::CollectCandidates() { | 9464 void AllocationSinking::CollectCandidates() { |
| 9463 // Optimistically collect all potential candidates. | 9465 // Optimistically collect all potential candidates. |
| 9464 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 9466 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 9465 !block_it.Done(); | 9467 !block_it.Done(); |
| 9466 block_it.Advance()) { | 9468 block_it.Advance()) { |
| 9467 BlockEntryInstr* block = block_it.Current(); | 9469 BlockEntryInstr* block = block_it.Current(); |
| 9468 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 9470 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 9469 AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); | 9471 { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); |
| 9470 if ((alloc != NULL) && | 9472 if ((alloc != NULL) && |
| 9471 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | 9473 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { |
| 9472 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | 9474 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); |
| 9473 candidates_.Add(alloc); | 9475 candidates_.Add(alloc); |
| 9476 } | |
| 9477 } | |
| 9478 { AllocateUninitializedContextInstr* alloc = | |
| 9479 it.Current()->AsAllocateUninitializedContext(); | |
| 9480 if ((alloc != NULL) && | |
| 9481 IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) { | |
| 9482 alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate()); | |
| 9483 candidates_.Add(alloc); | |
| 9484 } | |
| 9474 } | 9485 } |
| 9475 } | 9486 } |
| 9476 } | 9487 } |
| 9477 | 9488 |
| 9478 // Transitively unmark all candidates that are not strictly valid. | 9489 // Transitively unmark all candidates that are not strictly valid. |
| 9479 bool changed; | 9490 bool changed; |
| 9480 do { | 9491 do { |
| 9481 changed = false; | 9492 changed = false; |
| 9482 for (intptr_t i = 0; i < candidates_.length(); i++) { | 9493 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 9483 AllocateObjectInstr* alloc = candidates_[i]; | 9494 Definition* alloc = candidates_[i]; |
| 9484 if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9495 if (alloc->Identity().IsAllocationSinkingCandidate()) { |
| 9485 if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 9496 if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { |
| 9486 alloc->SetIdentity(AliasIdentity::Unknown()); | 9497 alloc->SetIdentity(AliasIdentity::Unknown()); |
| 9487 changed = true; | 9498 changed = true; |
| 9488 } | 9499 } |
| 9489 } | 9500 } |
| 9490 } | 9501 } |
| 9491 } while (changed); | 9502 } while (changed); |
| 9492 | 9503 |
| 9493 // Shrink the list of candidates removing all unmarked ones. | 9504 // Shrink the list of candidates removing all unmarked ones. |
| 9494 intptr_t j = 0; | 9505 intptr_t j = 0; |
| 9495 for (intptr_t i = 0; i < candidates_.length(); i++) { | 9506 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 9496 AllocateObjectInstr* alloc = candidates_[i]; | 9507 Definition* alloc = candidates_[i]; |
| 9497 if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9508 if (alloc->Identity().IsAllocationSinkingCandidate()) { |
| 9498 if (FLAG_trace_optimization) { | 9509 if (FLAG_trace_optimization) { |
| 9499 OS::Print("discovered allocation sinking candidate: v%" Pd "\n", | 9510 OS::Print("discovered allocation sinking candidate: v%" Pd "\n", |
| 9500 alloc->ssa_temp_index()); | 9511 alloc->ssa_temp_index()); |
| 9501 } | 9512 } |
| 9502 | 9513 |
| 9503 if (j != i) { | 9514 if (j != i) { |
| 9504 candidates_[j] = alloc; | 9515 candidates_[j] = alloc; |
| 9505 } | 9516 } |
| 9506 j++; | 9517 j++; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9568 // the load forwarding because they flow into phis that load forwarding | 9579 // the load forwarding because they flow into phis that load forwarding |
| 9569 // inserts. Discover such allocations and remove them from the list | 9580 // inserts. Discover such allocations and remove them from the list |
| 9570 // of allocation sinking candidates undoing all changes that we did | 9581 // of allocation sinking candidates undoing all changes that we did |
| 9571 // in preparation for sinking these allocations. | 9582 // in preparation for sinking these allocations. |
| 9572 void AllocationSinking::DiscoverFailedCandidates() { | 9583 void AllocationSinking::DiscoverFailedCandidates() { |
| 9573 // Transitively unmark all candidates that are not strictly valid. | 9584 // Transitively unmark all candidates that are not strictly valid. |
| 9574 bool changed; | 9585 bool changed; |
| 9575 do { | 9586 do { |
| 9576 changed = false; | 9587 changed = false; |
| 9577 for (intptr_t i = 0; i < candidates_.length(); i++) { | 9588 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 9578 AllocateObjectInstr* alloc = candidates_[i]; | 9589 Definition* alloc = candidates_[i]; |
| 9579 if (alloc->Identity().IsAllocationSinkingCandidate()) { | 9590 if (alloc->Identity().IsAllocationSinkingCandidate()) { |
| 9580 if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { | 9591 if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) { |
| 9581 alloc->SetIdentity(AliasIdentity::Unknown()); | 9592 alloc->SetIdentity(AliasIdentity::Unknown()); |
| 9582 changed = true; | 9593 changed = true; |
| 9583 } | 9594 } |
| 9584 } | 9595 } |
| 9585 } | 9596 } |
| 9586 } while (changed); | 9597 } while (changed); |
| 9587 | 9598 |
| 9588 // Remove all failed candidates from the candidates list. | 9599 // Remove all failed candidates from the candidates list. |
| 9589 intptr_t j = 0; | 9600 intptr_t j = 0; |
| 9590 for (intptr_t i = 0; i < candidates_.length(); i++) { | 9601 for (intptr_t i = 0; i < candidates_.length(); i++) { |
| 9591 AllocateObjectInstr* alloc = candidates_[i]; | 9602 Definition* alloc = candidates_[i]; |
| 9592 if (!alloc->Identity().IsAllocationSinkingCandidate()) { | 9603 if (!alloc->Identity().IsAllocationSinkingCandidate()) { |
| 9593 if (FLAG_trace_optimization) { | 9604 if (FLAG_trace_optimization) { |
| 9594 OS::Print("allocation v%" Pd " can't be eliminated\n", | 9605 OS::Print("allocation v%" Pd " can't be eliminated\n", |
| 9595 alloc->ssa_temp_index()); | 9606 alloc->ssa_temp_index()); |
| 9596 } | 9607 } |
| 9597 | 9608 |
| 9598 #ifdef DEBUG | 9609 #ifdef DEBUG |
| 9599 for (Value* use = alloc->env_use_list(); | 9610 for (Value* use = alloc->env_use_list(); |
| 9600 use != NULL; | 9611 use != NULL; |
| 9601 use = use->next_use()) { | 9612 use = use->next_use()) { |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9765 } | 9776 } |
| 9766 | 9777 |
| 9767 return NULL; | 9778 return NULL; |
| 9768 } | 9779 } |
| 9769 | 9780 |
| 9770 | 9781 |
| 9771 // Insert MaterializeObject instruction for the given allocation before | 9782 // Insert MaterializeObject instruction for the given allocation before |
| 9772 // the given instruction that can deoptimize. | 9783 // the given instruction that can deoptimize. |
| 9773 void AllocationSinking::CreateMaterializationAt( | 9784 void AllocationSinking::CreateMaterializationAt( |
| 9774 Instruction* exit, | 9785 Instruction* exit, |
| 9775 AllocateObjectInstr* alloc, | 9786 Definition* alloc, |
| 9776 const Class& cls, | |
| 9777 const ZoneGrowableArray<const Object*>& slots) { | 9787 const ZoneGrowableArray<const Object*>& slots) { |
| 9778 ZoneGrowableArray<Value*>* values = | 9788 ZoneGrowableArray<Value*>* values = |
| 9779 new(I) ZoneGrowableArray<Value*>(slots.length()); | 9789 new(I) ZoneGrowableArray<Value*>(slots.length()); |
| 9780 | 9790 |
| 9781 // All loads should be inserted before the first materialization so that | 9791 // All loads should be inserted before the first materialization so that |
| 9782 // IR follows the following pattern: loads, materializations, deoptimizing | 9792 // IR follows the following pattern: loads, materializations, deoptimizing |
| 9783 // instruction. | 9793 // instruction. |
| 9784 Instruction* load_point = FirstMaterializationAt(exit); | 9794 Instruction* load_point = FirstMaterializationAt(exit); |
| 9785 | 9795 |
| 9786 // Insert load instruction for every field. | 9796 // Insert load instruction for every field. |
| 9787 for (intptr_t i = 0; i < slots.length(); i++) { | 9797 for (intptr_t i = 0; i < slots.length(); i++) { |
| 9788 LoadFieldInstr* load = slots[i]->IsField() | 9798 LoadFieldInstr* load = slots[i]->IsField() |
| 9789 ? new(I) LoadFieldInstr( | 9799 ? new(I) LoadFieldInstr( |
| 9790 new(I) Value(alloc), | 9800 new(I) Value(alloc), |
| 9791 &Field::Cast(*slots[i]), | 9801 &Field::Cast(*slots[i]), |
| 9792 AbstractType::ZoneHandle(I), | 9802 AbstractType::ZoneHandle(I), |
| 9793 alloc->token_pos()) | 9803 alloc->token_pos()) |
| 9794 : new(I) LoadFieldInstr( | 9804 : new(I) LoadFieldInstr( |
| 9795 new(I) Value(alloc), | 9805 new(I) Value(alloc), |
| 9796 Smi::Cast(*slots[i]).Value(), | 9806 Smi::Cast(*slots[i]).Value(), |
| 9797 AbstractType::ZoneHandle(I), | 9807 AbstractType::ZoneHandle(I), |
| 9798 alloc->token_pos()); | 9808 alloc->token_pos()); |
| 9799 flow_graph_->InsertBefore( | 9809 flow_graph_->InsertBefore( |
| 9800 load_point, load, NULL, FlowGraph::kValue); | 9810 load_point, load, NULL, FlowGraph::kValue); |
| 9801 values->Add(new(I) Value(load)); | 9811 values->Add(new(I) Value(load)); |
| 9802 } | 9812 } |
| 9803 | 9813 |
| 9804 MaterializeObjectInstr* mat = | 9814 MaterializeObjectInstr* mat = NULL; |
| 9805 new(I) MaterializeObjectInstr(alloc, cls, slots, values); | 9815 if (alloc->IsAllocateObject()) { |
| 9816 mat = new(I) MaterializeObjectInstr( | |
| 9817 alloc->AsAllocateObject(), slots, values); | |
| 9818 } else { | |
| 9819 ASSERT(alloc->IsAllocateUninitializedContext()); | |
| 9820 mat = new(I) MaterializeObjectInstr( | |
| 9821 alloc->AsAllocateUninitializedContext(), slots, values); | |
| 9822 } | |
| 9823 | |
| 9806 flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); | 9824 flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue); |
| 9807 | 9825 |
| 9808 // Replace all mentions of this allocation with a newly inserted | 9826 // Replace all mentions of this allocation with a newly inserted |
| 9809 // MaterializeObject instruction. | 9827 // MaterializeObject instruction. |
| 9810 // We must preserve the identity: all mentions are replaced by the same | 9828 // We must preserve the identity: all mentions are replaced by the same |
| 9811 // materialization. | 9829 // materialization. |
| 9812 for (Environment::DeepIterator env_it(exit->env()); | 9830 for (Environment::DeepIterator env_it(exit->env()); |
| 9813 !env_it.Done(); | 9831 !env_it.Done(); |
| 9814 env_it.Advance()) { | 9832 env_it.Advance()) { |
| 9815 Value* use = env_it.CurrentValue(); | 9833 Value* use = env_it.CurrentValue(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9888 // We are not removing allocations from the worklist not to waste space on | 9906 // We are not removing allocations from the worklist not to waste space on |
| 9889 // the side maintaining BitVector of already processed allocations: worklist | 9907 // the side maintaining BitVector of already processed allocations: worklist |
| 9890 // is expected to be very small thus linear search in it is just as effecient | 9908 // is expected to be very small thus linear search in it is just as effecient |
| 9891 // as a bitvector. | 9909 // as a bitvector. |
| 9892 for (intptr_t i = 0; i < worklist_.length(); i++) { | 9910 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 9893 Collect(worklist_[i]); | 9911 Collect(worklist_[i]); |
| 9894 } | 9912 } |
| 9895 } | 9913 } |
| 9896 | 9914 |
| 9897 | 9915 |
| 9898 void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) { | 9916 void AllocationSinking::InsertMaterializations(Definition* alloc) { |
| 9899 // Collect all fields that are written for this instance. | 9917 // Collect all fields that are written for this instance. |
| 9900 ZoneGrowableArray<const Object*>* slots = | 9918 ZoneGrowableArray<const Object*>* slots = |
| 9901 new(I) ZoneGrowableArray<const Object*>(5); | 9919 new(I) ZoneGrowableArray<const Object*>(5); |
| 9902 | 9920 |
| 9903 for (Value* use = alloc->input_use_list(); | 9921 for (Value* use = alloc->input_use_list(); |
| 9904 use != NULL; | 9922 use != NULL; |
| 9905 use = use->next_use()) { | 9923 use = use->next_use()) { |
| 9906 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); | 9924 StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField(); |
| 9907 if ((store != NULL) && (store->instance()->definition() == alloc)) { | 9925 if ((store != NULL) && (store->instance()->definition() == alloc)) { |
| 9908 if (!store->field().IsNull()) { | 9926 if (!store->field().IsNull()) { |
| 9909 AddSlot(slots, store->field()); | 9927 AddSlot(slots, store->field()); |
| 9910 } else { | 9928 } else { |
| 9911 AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes()))); | 9929 AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes()))); |
| 9912 } | 9930 } |
| 9913 } | 9931 } |
| 9914 } | 9932 } |
| 9915 | 9933 |
| 9916 if (alloc->ArgumentCount() > 0) { | 9934 if (alloc->ArgumentCount() > 0) { |
| 9917 ASSERT(alloc->ArgumentCount() == 1); | 9935 AllocateObjectInstr* alloc_object = alloc->AsAllocateObject(); |
| 9918 intptr_t type_args_offset = alloc->cls().type_arguments_field_offset(); | 9936 ASSERT(alloc_object->ArgumentCount() == 1); |
| 9937 intptr_t type_args_offset = | |
| 9938 alloc_object->cls().type_arguments_field_offset(); | |
| 9919 AddSlot(slots, Smi::ZoneHandle(I, Smi::New(type_args_offset))); | 9939 AddSlot(slots, Smi::ZoneHandle(I, Smi::New(type_args_offset))); |
| 9920 } | 9940 } |
| 9921 | 9941 |
| 9922 // Collect all instructions that mention this object in the environment. | 9942 // Collect all instructions that mention this object in the environment. |
| 9923 exits_collector_.CollectTransitively(alloc); | 9943 exits_collector_.CollectTransitively(alloc); |
| 9924 | 9944 |
| 9925 // Insert materializations at environment uses. | 9945 // Insert materializations at environment uses. |
| 9926 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 9946 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 9927 CreateMaterializationAt( | 9947 CreateMaterializationAt( |
| 9928 exits_collector_.exits()[i], alloc, alloc->cls(), *slots); | 9948 exits_collector_.exits()[i], alloc, *slots); |
| 9929 } | 9949 } |
| 9930 } | 9950 } |
| 9931 | 9951 |
| 9932 | 9952 |
| 9933 } // namespace dart | 9953 } // namespace dart |
| OLD | NEW |