| 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/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
| (...skipping 4328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4339 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); | 4339 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); |
| 4340 for (intptr_t i = 0; i < places->length(); i++) { | 4340 for (intptr_t i = 0; i < places->length(); i++) { |
| 4341 Place* place = (*places)[i]; | 4341 Place* place = (*places)[i]; |
| 4342 aliased_set->AddRepresentative(place); | 4342 aliased_set->AddRepresentative(place); |
| 4343 } | 4343 } |
| 4344 | 4344 |
| 4345 return aliased_set; | 4345 return aliased_set; |
| 4346 } | 4346 } |
| 4347 | 4347 |
| 4348 | 4348 |
| 4349 static bool HasSimpleTypeArguments(AllocateObjectInstr* alloc) { |
| 4350 if (alloc->ArgumentCount() == 0) return true; |
| 4351 ASSERT(alloc->ArgumentCount() == 2); |
| 4352 Value* arg1 = alloc->PushArgumentAt(1)->value(); |
| 4353 if (!arg1->BindsToConstant()) return false; |
| 4354 |
| 4355 const Object& obj = arg1->BoundConstant(); |
| 4356 return obj.IsSmi() |
| 4357 && (Smi::Cast(obj).Value() == StubCode::kNoInstantiator); |
| 4358 } |
| 4359 |
| 4360 |
| 4349 class LoadOptimizer : public ValueObject { | 4361 class LoadOptimizer : public ValueObject { |
| 4350 public: | 4362 public: |
| 4351 LoadOptimizer(FlowGraph* graph, | 4363 LoadOptimizer(FlowGraph* graph, |
| 4352 AliasedSet* aliased_set, | 4364 AliasedSet* aliased_set, |
| 4353 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) | 4365 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) |
| 4354 : graph_(graph), | 4366 : graph_(graph), |
| 4355 map_(map), | 4367 map_(map), |
| 4356 aliased_set_(aliased_set), | 4368 aliased_set_(aliased_set), |
| 4357 in_(graph_->preorder().length()), | 4369 in_(graph_->preorder().length()), |
| 4358 out_(graph_->preorder().length()), | 4370 out_(graph_->preorder().length()), |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4500 // type arguments. | 4512 // type arguments. |
| 4501 // The reason to ignore escaping objects is that final fields are | 4513 // The reason to ignore escaping objects is that final fields are |
| 4502 // initialized in constructor that potentially can be not inlined into | 4514 // initialized in constructor that potentially can be not inlined into |
| 4503 // the function that we are currently optimizing. However at the same | 4515 // the function that we are currently optimizing. However at the same |
| 4504 // time we assume that values of the final fields can be forwarded | 4516 // time we assume that values of the final fields can be forwarded |
| 4505 // across side-effects. If we add 'null' as known values for these | 4517 // across side-effects. If we add 'null' as known values for these |
| 4506 // fields here we will incorrectly propagate this null across | 4518 // fields here we will incorrectly propagate this null across |
| 4507 // constructor invocation. | 4519 // constructor invocation. |
| 4508 // TODO(vegorov): record null-values at least for not final fields of | 4520 // TODO(vegorov): record null-values at least for not final fields of |
| 4509 // escaping object. | 4521 // escaping object. |
| 4510 // TODO(vegorov): enable forwarding of type arguments. | |
| 4511 AllocateObjectInstr* alloc = instr->AsAllocateObject(); | 4522 AllocateObjectInstr* alloc = instr->AsAllocateObject(); |
| 4512 if ((alloc != NULL) && | 4523 if ((alloc != NULL) && |
| 4513 (alloc->identity() == AllocateObjectInstr::kNotAliased) && | 4524 (alloc->identity() == AllocateObjectInstr::kNotAliased) && |
| 4514 (alloc->ArgumentCount() == 0)) { | 4525 HasSimpleTypeArguments(alloc)) { |
| 4515 for (Value* use = alloc->input_use_list(); | 4526 for (Value* use = alloc->input_use_list(); |
| 4516 use != NULL; | 4527 use != NULL; |
| 4517 use = use->next_use()) { | 4528 use = use->next_use()) { |
| 4518 // Look for all immediate loads from this object. | 4529 // Look for all immediate loads from this object. |
| 4519 if (use->use_index() != 0) { | 4530 if (use->use_index() != 0) { |
| 4520 continue; | 4531 continue; |
| 4521 } | 4532 } |
| 4522 | 4533 |
| 4523 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 4534 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
| 4524 if (load != NULL) { | 4535 if (load != NULL) { |
| 4525 // Found a load. Initialize current value of the field to null. | 4536 // Found a load. Initialize current value of the field to null for |
| 4537 // normal fields, or with type arguments. |
| 4526 gen->Add(load->place_id()); | 4538 gen->Add(load->place_id()); |
| 4527 if (out_values == NULL) out_values = CreateBlockOutValues(); | 4539 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 4540 |
| 4541 if (alloc->ArgumentCount() > 0) { |
| 4542 ASSERT(alloc->ArgumentCount() == 2); |
| 4543 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 4544 intptr_t type_args_offset = cls.type_arguments_field_offset(); |
| 4545 if (load->offset_in_bytes() == type_args_offset) { |
| 4546 (*out_values)[load->place_id()] = |
| 4547 alloc->PushArgumentAt(0)->value()->definition(); |
| 4548 continue; |
| 4549 } |
| 4550 } |
| 4528 (*out_values)[load->place_id()] = graph_->constant_null(); | 4551 (*out_values)[load->place_id()] = graph_->constant_null(); |
| 4529 } | 4552 } |
| 4530 } | 4553 } |
| 4531 continue; | 4554 continue; |
| 4532 } | 4555 } |
| 4533 | 4556 |
| 4534 if (!IsLoadEliminationCandidate(defn)) { | 4557 if (!IsLoadEliminationCandidate(defn)) { |
| 4535 continue; | 4558 continue; |
| 4536 } | 4559 } |
| 4537 | 4560 |
| (...skipping 2332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6870 } | 6893 } |
| 6871 } | 6894 } |
| 6872 } | 6895 } |
| 6873 | 6896 |
| 6874 | 6897 |
| 6875 // Right now we are attempting to sink allocation only into | 6898 // Right now we are attempting to sink allocation only into |
| 6876 // deoptimization exit. So candidate should only be used in StoreInstanceField | 6899 // deoptimization exit. So candidate should only be used in StoreInstanceField |
| 6877 // instructions that write into fields of the allocated object. | 6900 // instructions that write into fields of the allocated object. |
| 6878 // We do not support materialization of the object that has type arguments. | 6901 // We do not support materialization of the object that has type arguments. |
| 6879 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { | 6902 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { |
| 6880 // TODO(vegorov): support AllocateObject with type arguments. | 6903 if (!HasSimpleTypeArguments(alloc)) return false; |
| 6881 if (alloc->ArgumentCount() > 0) { | |
| 6882 return false; | |
| 6883 } | |
| 6884 | 6904 |
| 6885 for (Value* use = alloc->input_use_list(); | 6905 for (Value* use = alloc->input_use_list(); |
| 6886 use != NULL; | 6906 use != NULL; |
| 6887 use = use->next_use()) { | 6907 use = use->next_use()) { |
| 6888 if (!(use->instruction()->IsStoreInstanceField() && | 6908 if (!(use->instruction()->IsStoreInstanceField() && |
| 6889 use->use_index() == 0)) { | 6909 use->use_index() == 0)) { |
| 6890 return false; | 6910 return false; |
| 6891 } | 6911 } |
| 6892 } | 6912 } |
| 6893 | 6913 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 6911 use != NULL; | 6931 use != NULL; |
| 6912 use = alloc->input_use_list()) { | 6932 use = alloc->input_use_list()) { |
| 6913 use->instruction()->RemoveFromGraph(); | 6933 use->instruction()->RemoveFromGraph(); |
| 6914 } | 6934 } |
| 6915 | 6935 |
| 6916 // There should be no environment uses. The pass replaced them with | 6936 // There should be no environment uses. The pass replaced them with |
| 6917 // MaterializeObject instructions. | 6937 // MaterializeObject instructions. |
| 6918 ASSERT(alloc->env_use_list() == NULL); | 6938 ASSERT(alloc->env_use_list() == NULL); |
| 6919 ASSERT(alloc->input_use_list() == NULL); | 6939 ASSERT(alloc->input_use_list() == NULL); |
| 6920 alloc->RemoveFromGraph(); | 6940 alloc->RemoveFromGraph(); |
| 6941 if (alloc->ArgumentCount() > 0) { |
| 6942 ASSERT(alloc->ArgumentCount() == 2); |
| 6943 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { |
| 6944 alloc->PushArgumentAt(i)->RemoveFromGraph(); |
| 6945 } |
| 6946 } |
| 6921 } | 6947 } |
| 6922 | 6948 |
| 6923 | 6949 |
| 6924 void AllocationSinking::Optimize() { | 6950 void AllocationSinking::Optimize() { |
| 6925 GrowableArray<AllocateObjectInstr*> candidates(5); | 6951 GrowableArray<AllocateObjectInstr*> candidates(5); |
| 6926 | 6952 |
| 6927 // Collect sinking candidates. | 6953 // Collect sinking candidates. |
| 6928 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder(); | 6954 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder(); |
| 6929 for (BlockIterator block_it(postorder); | 6955 for (BlockIterator block_it(postorder); |
| 6930 !block_it.Done(); | 6956 !block_it.Done(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 6961 } | 6987 } |
| 6962 | 6988 |
| 6963 // Run load forwarding to eliminate LoadField instructions inserted above. | 6989 // Run load forwarding to eliminate LoadField instructions inserted above. |
| 6964 // All loads will be successfully eliminated because: | 6990 // All loads will be successfully eliminated because: |
| 6965 // a) they use fields (not offsets) and thus provide precise aliasing | 6991 // a) they use fields (not offsets) and thus provide precise aliasing |
| 6966 // information | 6992 // information |
| 6967 // b) candidate does not escape and thus its fields is not affected by | 6993 // b) candidate does not escape and thus its fields is not affected by |
| 6968 // external effects from calls. | 6994 // external effects from calls. |
| 6969 LoadOptimizer::OptimizeGraph(flow_graph_); | 6995 LoadOptimizer::OptimizeGraph(flow_graph_); |
| 6970 | 6996 |
| 6997 if (FLAG_trace_optimization) { |
| 6998 FlowGraphPrinter::PrintGraph("Sinking", flow_graph_); |
| 6999 } |
| 7000 |
| 6971 // At this point we have computed the state of object at each deoptimization | 7001 // At this point we have computed the state of object at each deoptimization |
| 6972 // point and we can eliminate it. Loads inserted above were forwarded so there | 7002 // point and we can eliminate it. Loads inserted above were forwarded so there |
| 6973 // are no uses of the allocation just as in the begging of the pass. | 7003 // are no uses of the allocation just as in the begging of the pass. |
| 6974 for (intptr_t i = 0; i < candidates.length(); i++) { | 7004 for (intptr_t i = 0; i < candidates.length(); i++) { |
| 6975 EliminateAllocation(candidates[i]); | 7005 EliminateAllocation(candidates[i]); |
| 6976 } | 7006 } |
| 6977 | 7007 |
| 6978 // Process materializations and unbox their arguments: materializations | 7008 // Process materializations and unbox their arguments: materializations |
| 6979 // are part of the environment and can materialize boxes for double/mint/simd | 7009 // are part of the environment and can materialize boxes for double/mint/simd |
| 6980 // values when needed. | 7010 // values when needed. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7076 ZoneGrowableArray<const Field*>* fields = | 7106 ZoneGrowableArray<const Field*>* fields = |
| 7077 new ZoneGrowableArray<const Field*>(5); | 7107 new ZoneGrowableArray<const Field*>(5); |
| 7078 | 7108 |
| 7079 for (Value* use = alloc->input_use_list(); | 7109 for (Value* use = alloc->input_use_list(); |
| 7080 use != NULL; | 7110 use != NULL; |
| 7081 use = use->next_use()) { | 7111 use = use->next_use()) { |
| 7082 ASSERT(use->instruction()->IsStoreInstanceField()); | 7112 ASSERT(use->instruction()->IsStoreInstanceField()); |
| 7083 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); | 7113 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); |
| 7084 } | 7114 } |
| 7085 | 7115 |
| 7116 if (alloc->ArgumentCount() > 0) { |
| 7117 ASSERT(alloc->ArgumentCount() == 2); |
| 7118 const String& name = String::Handle(Symbols::New(":type_args")); |
| 7119 const Field& type_args_field = |
| 7120 Field::ZoneHandle(Field::New( |
| 7121 name, |
| 7122 false, // !static |
| 7123 false, // !final |
| 7124 false, // !const |
| 7125 Class::Handle(alloc->constructor().Owner()), |
| 7126 0)); // No token position. |
| 7127 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7128 type_args_field.SetOffset(cls.type_arguments_field_offset()); |
| 7129 AddField(fields, type_args_field); |
| 7130 } |
| 7131 |
| 7086 // Collect all instructions that mention this object in the environment. | 7132 // Collect all instructions that mention this object in the environment. |
| 7087 GrowableArray<Instruction*> exits(10); | 7133 GrowableArray<Instruction*> exits(10); |
| 7088 for (Value* use = alloc->env_use_list(); | 7134 for (Value* use = alloc->env_use_list(); |
| 7089 use != NULL; | 7135 use != NULL; |
| 7090 use = use->next_use()) { | 7136 use = use->next_use()) { |
| 7091 AddInstruction(&exits, use->instruction()); | 7137 AddInstruction(&exits, use->instruction()); |
| 7092 } | 7138 } |
| 7093 | 7139 |
| 7094 // Insert materializations at environment uses. | 7140 // Insert materializations at environment uses. |
| 7095 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7141 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7096 for (intptr_t i = 0; i < exits.length(); i++) { | 7142 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7097 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7143 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 7098 } | 7144 } |
| 7099 } | 7145 } |
| 7100 | 7146 |
| 7101 | 7147 |
| 7102 } // namespace dart | 7148 } // namespace dart |
| OLD | NEW |