| 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/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) | 48 #if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32) |
| 49 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); | 49 DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass."); |
| 50 #endif | 50 #endif |
| 51 | 51 |
| 52 DECLARE_FLAG(bool, polymorphic_with_deopt); | 52 DECLARE_FLAG(bool, polymorphic_with_deopt); |
| 53 DECLARE_FLAG(bool, source_lines); | 53 DECLARE_FLAG(bool, source_lines); |
| 54 DECLARE_FLAG(bool, trace_cha); | 54 DECLARE_FLAG(bool, trace_cha); |
| 55 DECLARE_FLAG(bool, trace_field_guards); | 55 DECLARE_FLAG(bool, trace_field_guards); |
| 56 DECLARE_FLAG(bool, trace_type_check_elimination); | 56 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 57 DECLARE_FLAG(bool, warn_on_javascript_compatibility); | 57 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
| 58 DECLARE_FLAG(bool, fields_may_be_reset); |
| 58 | 59 |
| 59 // Quick access to the current isolate and zone. | 60 // Quick access to the current isolate and zone. |
| 60 #define I (isolate()) | 61 #define I (isolate()) |
| 61 #define Z (zone()) | 62 #define Z (zone()) |
| 62 | 63 |
| 63 static bool ShouldInlineSimd() { | 64 static bool ShouldInlineSimd() { |
| 64 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 65 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 65 } | 66 } |
| 66 | 67 |
| 67 | 68 |
| (...skipping 5578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5646 "<%s[%" Pd "|%" Pd "]>", | 5647 "<%s[%" Pd "|%" Pd "]>", |
| 5647 DefinitionName(instance()), | 5648 DefinitionName(instance()), |
| 5648 index_constant(), | 5649 index_constant(), |
| 5649 ElementSizeMultiplier(element_size())); | 5650 ElementSizeMultiplier(element_size())); |
| 5650 } | 5651 } |
| 5651 } | 5652 } |
| 5652 UNREACHABLE(); | 5653 UNREACHABLE(); |
| 5653 return "<?>"; | 5654 return "<?>"; |
| 5654 } | 5655 } |
| 5655 | 5656 |
| 5656 bool IsFinalField() const { | 5657 // Fields that are considered immutable by load optimization. |
| 5657 return (kind() == kField) && field().is_final(); | 5658 // Handle static finals as non-final with precompilation because |
| 5659 // they may be reset to uninitialized after compilation. |
| 5660 bool IsImmutableField() const { |
| 5661 return (kind() == kField) |
| 5662 && field().is_final() |
| 5663 && (!field().is_static() || !FLAG_fields_may_be_reset); |
| 5658 } | 5664 } |
| 5659 | 5665 |
| 5660 intptr_t Hashcode() const { | 5666 intptr_t Hashcode() const { |
| 5661 return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 + | 5667 return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 + |
| 5662 FieldHashcode(); | 5668 FieldHashcode(); |
| 5663 } | 5669 } |
| 5664 | 5670 |
| 5665 bool Equals(const Place* other) const { | 5671 bool Equals(const Place* other) const { |
| 5666 return (flags_ == other->flags_) && | 5672 return (flags_ == other->flags_) && |
| 5667 (instance_ == other->instance_) && | 5673 (instance_ == other->instance_) && |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5984 // Artificial alias that is used to collect all representatives of | 5990 // Artificial alias that is used to collect all representatives of |
| 5985 // X[*] alias for all X. | 5991 // X[*] alias for all X. |
| 5986 kAnyAllocationIndexedAlias = 3, | 5992 kAnyAllocationIndexedAlias = 3, |
| 5987 | 5993 |
| 5988 // *[*] alias. | 5994 // *[*] alias. |
| 5989 kAnyInstanceAnyIndexAlias = 4 | 5995 kAnyInstanceAnyIndexAlias = 4 |
| 5990 }; | 5996 }; |
| 5991 | 5997 |
| 5992 // Compute least generic alias for the place and assign alias id to it. | 5998 // Compute least generic alias for the place and assign alias id to it. |
| 5993 void AddRepresentative(Place* place) { | 5999 void AddRepresentative(Place* place) { |
| 5994 if (!place->IsFinalField()) { | 6000 if (!place->IsImmutableField()) { |
| 5995 const Place* alias = CanonicalizeAlias(place->ToAlias()); | 6001 const Place* alias = CanonicalizeAlias(place->ToAlias()); |
| 5996 EnsureSet(&representatives_, alias->id())->Add(place->id()); | 6002 EnsureSet(&representatives_, alias->id())->Add(place->id()); |
| 5997 | 6003 |
| 5998 // Update cumulative representative sets that are used during | 6004 // Update cumulative representative sets that are used during |
| 5999 // killed sets computation. | 6005 // killed sets computation. |
| 6000 if (alias->kind() == Place::kConstantIndexed) { | 6006 if (alias->kind() == Place::kConstantIndexed) { |
| 6001 if (CanBeAliased(alias->instance())) { | 6007 if (CanBeAliased(alias->instance())) { |
| 6002 EnsureSet(&representatives_, kAnyConstantIndexedAlias)-> | 6008 EnsureSet(&representatives_, kAnyConstantIndexedAlias)-> |
| 6003 Add(place->id()); | 6009 Add(place->id()); |
| 6004 } | 6010 } |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6190 | 6196 |
| 6191 case Place::kNone: | 6197 case Place::kNone: |
| 6192 UNREACHABLE(); | 6198 UNREACHABLE(); |
| 6193 } | 6199 } |
| 6194 } | 6200 } |
| 6195 | 6201 |
| 6196 // Returns true if the given load is unaffected by external side-effects. | 6202 // Returns true if the given load is unaffected by external side-effects. |
| 6197 // This essentially means that no stores to the same location can | 6203 // This essentially means that no stores to the same location can |
| 6198 // occur in other functions. | 6204 // occur in other functions. |
| 6199 bool IsIndependentFromEffects(Place* place) { | 6205 bool IsIndependentFromEffects(Place* place) { |
| 6200 if (place->IsFinalField()) { | 6206 if (place->IsImmutableField()) { |
| 6201 // Note that we can't use LoadField's is_immutable attribute here because | 6207 // Note that we can't use LoadField's is_immutable attribute here because |
| 6202 // some VM-fields (those that have no corresponding Field object and | 6208 // some VM-fields (those that have no corresponding Field object and |
| 6203 // accessed through offset alone) can share offset but have different | 6209 // accessed through offset alone) can share offset but have different |
| 6204 // immutability properties. | 6210 // immutability properties. |
| 6205 // One example is the length property of growable and fixed size list. If | 6211 // One example is the length property of growable and fixed size list. If |
| 6206 // loads of these two properties occur in the same function for the same | 6212 // loads of these two properties occur in the same function for the same |
| 6207 // receiver then they will get the same expression number. However | 6213 // receiver then they will get the same expression number. However |
| 6208 // immutability of the length of fixed size list does not mean that | 6214 // immutability of the length of fixed size list does not mean that |
| 6209 // growable list also has immutable property. Thus we will make a | 6215 // growable list also has immutable property. Thus we will make a |
| 6210 // conservative assumption for the VM-properties. | 6216 // conservative assumption for the VM-properties. |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6624 | 6630 |
| 6625 bool is_load = false, is_store = false; | 6631 bool is_load = false, is_store = false; |
| 6626 Place place(instr, &is_load, &is_store); | 6632 Place place(instr, &is_load, &is_store); |
| 6627 | 6633 |
| 6628 BitVector* killed = NULL; | 6634 BitVector* killed = NULL; |
| 6629 if (is_store) { | 6635 if (is_store) { |
| 6630 const intptr_t alias_id = | 6636 const intptr_t alias_id = |
| 6631 aliased_set_->LookupAliasId(place.ToAlias()); | 6637 aliased_set_->LookupAliasId(place.ToAlias()); |
| 6632 if (alias_id != AliasedSet::kNoAlias) { | 6638 if (alias_id != AliasedSet::kNoAlias) { |
| 6633 killed = aliased_set_->GetKilledSet(alias_id); | 6639 killed = aliased_set_->GetKilledSet(alias_id); |
| 6634 } else if (!place.IsFinalField()) { | 6640 } else if (!place.IsImmutableField()) { |
| 6635 // We encountered unknown alias: this means intrablock load | 6641 // We encountered unknown alias: this means intrablock load |
| 6636 // forwarding refined parameter of this store, for example | 6642 // forwarding refined parameter of this store, for example |
| 6637 // | 6643 // |
| 6638 // o <- alloc() | 6644 // o <- alloc() |
| 6639 // a.f <- o | 6645 // a.f <- o |
| 6640 // u <- a.f | 6646 // u <- a.f |
| 6641 // u.x <- null ;; this store alias is *.x | 6647 // u.x <- null ;; this store alias is *.x |
| 6642 // | 6648 // |
| 6643 // after intrablock load forwarding | 6649 // after intrablock load forwarding |
| 6644 // | 6650 // |
| (...skipping 883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7528 | 7534 |
| 7529 // Iterate backwards starting at the last instruction. | 7535 // Iterate backwards starting at the last instruction. |
| 7530 for (BackwardInstructionIterator instr_it(block); | 7536 for (BackwardInstructionIterator instr_it(block); |
| 7531 !instr_it.Done(); | 7537 !instr_it.Done(); |
| 7532 instr_it.Advance()) { | 7538 instr_it.Advance()) { |
| 7533 Instruction* instr = instr_it.Current(); | 7539 Instruction* instr = instr_it.Current(); |
| 7534 | 7540 |
| 7535 bool is_load = false; | 7541 bool is_load = false; |
| 7536 bool is_store = false; | 7542 bool is_store = false; |
| 7537 Place place(instr, &is_load, &is_store); | 7543 Place place(instr, &is_load, &is_store); |
| 7538 if (place.IsFinalField()) { | 7544 if (place.IsImmutableField()) { |
| 7539 // Loads/stores of final fields do not participate. | 7545 // Loads/stores of final fields do not participate. |
| 7540 continue; | 7546 continue; |
| 7541 } | 7547 } |
| 7542 | 7548 |
| 7543 // Handle stores. | 7549 // Handle stores. |
| 7544 if (is_store) { | 7550 if (is_store) { |
| 7545 if (kill->Contains(instr->place_id())) { | 7551 if (kill->Contains(instr->place_id())) { |
| 7546 if (!live_in->Contains(instr->place_id()) && | 7552 if (!live_in->Contains(instr->place_id()) && |
| 7547 CanEliminateStore(instr)) { | 7553 CanEliminateStore(instr)) { |
| 7548 if (FLAG_trace_optimization) { | 7554 if (FLAG_trace_optimization) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7617 exposed_stores_[postorder_number]; | 7623 exposed_stores_[postorder_number]; |
| 7618 if (exposed_stores == NULL) continue; // No exposed stores. | 7624 if (exposed_stores == NULL) continue; // No exposed stores. |
| 7619 | 7625 |
| 7620 // Iterate over candidate stores. | 7626 // Iterate over candidate stores. |
| 7621 for (intptr_t i = 0; i < exposed_stores->length(); ++i) { | 7627 for (intptr_t i = 0; i < exposed_stores->length(); ++i) { |
| 7622 Instruction* instr = (*exposed_stores)[i]; | 7628 Instruction* instr = (*exposed_stores)[i]; |
| 7623 bool is_load = false; | 7629 bool is_load = false; |
| 7624 bool is_store = false; | 7630 bool is_store = false; |
| 7625 Place place(instr, &is_load, &is_store); | 7631 Place place(instr, &is_load, &is_store); |
| 7626 ASSERT(!is_load && is_store); | 7632 ASSERT(!is_load && is_store); |
| 7627 if (place.IsFinalField()) { | 7633 if (place.IsImmutableField()) { |
| 7628 // Final field do not participate in dead store elimination. | 7634 // Final field do not participate in dead store elimination. |
| 7629 continue; | 7635 continue; |
| 7630 } | 7636 } |
| 7631 // Eliminate a downward exposed store if the corresponding place is not | 7637 // Eliminate a downward exposed store if the corresponding place is not |
| 7632 // in live-out. | 7638 // in live-out. |
| 7633 if (!live_out->Contains(instr->place_id()) && | 7639 if (!live_out->Contains(instr->place_id()) && |
| 7634 CanEliminateStore(instr)) { | 7640 CanEliminateStore(instr)) { |
| 7635 if (FLAG_trace_optimization) { | 7641 if (FLAG_trace_optimization) { |
| 7636 THR_Print("Removing dead store to place %" Pd " block B%" Pd "\n", | 7642 THR_Print("Removing dead store to place %" Pd " block B%" Pd "\n", |
| 7637 instr->place_id(), block->block_id()); | 7643 instr->place_id(), block->block_id()); |
| (...skipping 1187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8825 | 8831 |
| 8826 // Insert materializations at environment uses. | 8832 // Insert materializations at environment uses. |
| 8827 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { | 8833 for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) { |
| 8828 CreateMaterializationAt( | 8834 CreateMaterializationAt( |
| 8829 exits_collector_.exits()[i], alloc, *slots); | 8835 exits_collector_.exits()[i], alloc, *slots); |
| 8830 } | 8836 } |
| 8831 } | 8837 } |
| 8832 | 8838 |
| 8833 | 8839 |
| 8834 } // namespace dart | 8840 } // namespace dart |
| OLD | NEW |