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/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 4079 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4090 // Build aliasing sets mapping aliases to loads. | 4090 // Build aliasing sets mapping aliases to loads. |
| 4091 AliasedSet* aliased_set = new AliasedSet(expr_id); | 4091 AliasedSet* aliased_set = new AliasedSet(expr_id); |
| 4092 for (intptr_t i = 0; i < loads.length(); i++) { | 4092 for (intptr_t i = 0; i < loads.length(); i++) { |
| 4093 Definition* defn = loads[i]; | 4093 Definition* defn = loads[i]; |
| 4094 aliased_set->AddRepresentative(defn); | 4094 aliased_set->AddRepresentative(defn); |
| 4095 } | 4095 } |
| 4096 return aliased_set; | 4096 return aliased_set; |
| 4097 } | 4097 } |
| 4098 | 4098 |
| 4099 | 4099 |
| 4100 static bool HasSupportedArguments(AllocateObjectInstr* alloc) { | |
|
Vyacheslav Egorov (Google)
2013/06/12 13:26:17
The name is a bit confusing. Maybe AllocationHasSi
Florian Schneider
2013/06/13 14:38:39
Done.
| |
| 4101 if (alloc->ArgumentCount() == 0) return true; | |
|
srdjan
2013/06/12 16:22:07
What Slava said and maybe add an itty-bitty commen
| |
| 4102 ASSERT(alloc->ArgumentCount() == 2); | |
| 4103 Value* arg1 = alloc->PushArgumentAt(1)->value(); | |
| 4104 if (!arg1->BindsToConstant()) return false; | |
| 4105 | |
| 4106 const Object& obj = arg1->BoundConstant(); | |
| 4107 return obj.IsSmi() | |
| 4108 && (Smi::Cast(obj).Value() == StubCode::kNoInstantiator); | |
| 4109 } | |
| 4110 | |
| 4111 | |
| 4100 class LoadOptimizer : public ValueObject { | 4112 class LoadOptimizer : public ValueObject { |
| 4101 public: | 4113 public: |
| 4102 LoadOptimizer(FlowGraph* graph, | 4114 LoadOptimizer(FlowGraph* graph, |
| 4103 AliasedSet* aliased_set, | 4115 AliasedSet* aliased_set, |
| 4104 DirectChainedHashMap<LoadKeyValueTrait>* map) | 4116 DirectChainedHashMap<LoadKeyValueTrait>* map) |
| 4105 : graph_(graph), | 4117 : graph_(graph), |
| 4106 map_(map), | 4118 map_(map), |
| 4107 aliased_set_(aliased_set), | 4119 aliased_set_(aliased_set), |
| 4108 in_(graph_->preorder().length()), | 4120 in_(graph_->preorder().length()), |
| 4109 out_(graph_->preorder().length()), | 4121 out_(graph_->preorder().length()), |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4235 // type arguments. | 4247 // type arguments. |
| 4236 // The reason to ignore escaping objects is that final fields are | 4248 // The reason to ignore escaping objects is that final fields are |
| 4237 // initialized in constructor that potentially can be not inlined into | 4249 // initialized in constructor that potentially can be not inlined into |
| 4238 // the function that we are currently optimizing. However at the same | 4250 // the function that we are currently optimizing. However at the same |
| 4239 // time we assume that values of the final fields can be forwarded | 4251 // time we assume that values of the final fields can be forwarded |
| 4240 // across side-effects. If we add 'null' as known values for these | 4252 // across side-effects. If we add 'null' as known values for these |
| 4241 // fields here we will incorrectly propagate this null across | 4253 // fields here we will incorrectly propagate this null across |
| 4242 // constructor invocation. | 4254 // constructor invocation. |
| 4243 // TODO(vegorov): record null-values at least for not final fields of | 4255 // TODO(vegorov): record null-values at least for not final fields of |
| 4244 // escaping object. | 4256 // escaping object. |
| 4245 // TODO(vegorov): enable forwarding of type arguments. | |
| 4246 AllocateObjectInstr* alloc = instr->AsAllocateObject(); | 4257 AllocateObjectInstr* alloc = instr->AsAllocateObject(); |
| 4247 if ((alloc != NULL) && | 4258 if ((alloc != NULL) && |
| 4248 (alloc->identity() == AllocateObjectInstr::kNotAliased) && | 4259 (alloc->identity() == AllocateObjectInstr::kNotAliased) && |
| 4249 (alloc->ArgumentCount() == 0)) { | 4260 HasSupportedArguments(alloc)) { |
| 4250 for (Value* use = alloc->input_use_list(); | 4261 for (Value* use = alloc->input_use_list(); |
| 4251 use != NULL; | 4262 use != NULL; |
| 4252 use = use->next_use()) { | 4263 use = use->next_use()) { |
| 4253 // Look for all immediate loads from this object. | 4264 // Look for all immediate loads from this object. |
| 4254 if (use->use_index() != 0) { | 4265 if (use->use_index() != 0) { |
| 4255 continue; | 4266 continue; |
| 4256 } | 4267 } |
| 4257 | 4268 |
| 4258 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 4269 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
| 4259 if (load != NULL) { | 4270 if (load != NULL) { |
| 4260 // Found a load. Initialize current value of the field to null. | 4271 // Found a load. Initialize current value of the field to null for |
| 4272 // normal fields, or with type arguments. | |
| 4261 gen->Add(load->expr_id()); | 4273 gen->Add(load->expr_id()); |
| 4262 if (out_values == NULL) out_values = CreateBlockOutValues(); | 4274 if (out_values == NULL) out_values = CreateBlockOutValues(); |
| 4275 | |
| 4276 if (alloc->ArgumentCount() > 0) { | |
|
Vyacheslav Egorov (Google)
2013/06/12 13:26:17
ASSERT(alloc->ArgumentCount() == 2);
Florian Schneider
2013/06/13 14:38:39
Done.
| |
| 4277 const Class& cls = Class::Handle(alloc->constructor().Owner()); | |
|
srdjan
2013/06/12 16:22:07
We have alloc->ArgumentCount() > 0 (or its variati
Florian Schneider
2013/06/20 14:06:26
Done. I guess it does not hurt to have more assert
| |
| 4278 intptr_t type_args_offset = cls.type_arguments_field_offset(); | |
| 4279 if (load->offset_in_bytes() == type_args_offset) { | |
| 4280 (*out_values)[load->expr_id()] = | |
| 4281 alloc->PushArgumentAt(0)->value()->definition(); | |
| 4282 continue; | |
| 4283 } | |
| 4284 } | |
| 4263 (*out_values)[load->expr_id()] = graph_->constant_null(); | 4285 (*out_values)[load->expr_id()] = graph_->constant_null(); |
| 4264 } | 4286 } |
| 4265 } | 4287 } |
| 4266 continue; | 4288 continue; |
| 4267 } | 4289 } |
| 4268 | 4290 |
| 4269 if (!IsLoadEliminationCandidate(defn)) { | 4291 if (!IsLoadEliminationCandidate(defn)) { |
| 4270 continue; | 4292 continue; |
| 4271 } | 4293 } |
| 4272 | 4294 |
| (...skipping 2097 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6370 } | 6392 } |
| 6371 } | 6393 } |
| 6372 } | 6394 } |
| 6373 | 6395 |
| 6374 | 6396 |
| 6375 // Right now we are attempting to sink allocation only into | 6397 // Right now we are attempting to sink allocation only into |
| 6376 // deoptimization exit. So candidate should only be used in StoreInstanceField | 6398 // deoptimization exit. So candidate should only be used in StoreInstanceField |
| 6377 // instructions that write into fields of the allocated object. | 6399 // instructions that write into fields of the allocated object. |
| 6378 // We do not support materialization of the object that has type arguments. | 6400 // We do not support materialization of the object that has type arguments. |
| 6379 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { | 6401 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { |
| 6380 // TODO(vegorov): support AllocateObject with type arguments. | 6402 if (!HasSupportedArguments(alloc)) return false; |
| 6381 if (alloc->ArgumentCount() > 0) { | |
| 6382 return false; | |
| 6383 } | |
| 6384 | 6403 |
| 6385 for (Value* use = alloc->input_use_list(); | 6404 for (Value* use = alloc->input_use_list(); |
| 6386 use != NULL; | 6405 use != NULL; |
| 6387 use = use->next_use()) { | 6406 use = use->next_use()) { |
| 6388 if (!(use->instruction()->IsStoreInstanceField() && | 6407 if (!(use->instruction()->IsStoreInstanceField() && |
| 6389 use->use_index() == 0)) { | 6408 use->use_index() == 0)) { |
| 6390 return false; | 6409 return false; |
| 6391 } | 6410 } |
| 6392 } | 6411 } |
| 6393 | 6412 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 6411 use != NULL; | 6430 use != NULL; |
| 6412 use = alloc->input_use_list()) { | 6431 use = alloc->input_use_list()) { |
| 6413 use->instruction()->RemoveFromGraph(); | 6432 use->instruction()->RemoveFromGraph(); |
| 6414 } | 6433 } |
| 6415 | 6434 |
| 6416 // There should be no environment uses. The pass replaced them with | 6435 // There should be no environment uses. The pass replaced them with |
| 6417 // MaterializeObject instructions. | 6436 // MaterializeObject instructions. |
| 6418 ASSERT(alloc->env_use_list() == NULL); | 6437 ASSERT(alloc->env_use_list() == NULL); |
| 6419 ASSERT(alloc->input_use_list() == NULL); | 6438 ASSERT(alloc->input_use_list() == NULL); |
| 6420 alloc->RemoveFromGraph(); | 6439 alloc->RemoveFromGraph(); |
| 6440 if (alloc->ArgumentCount() > 0) { | |
| 6441 ASSERT(alloc->ArgumentCount() == 2); | |
| 6442 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { | |
| 6443 alloc->PushArgumentAt(i)->RemoveFromGraph(); | |
| 6444 } | |
| 6445 } | |
| 6421 } | 6446 } |
| 6422 | 6447 |
| 6423 | 6448 |
| 6424 void AllocationSinking::Optimize() { | 6449 void AllocationSinking::Optimize() { |
| 6425 GrowableArray<AllocateObjectInstr*> candidates(5); | 6450 GrowableArray<AllocateObjectInstr*> candidates(5); |
| 6426 | 6451 |
| 6427 // Collect sinking candidates. | 6452 // Collect sinking candidates. |
| 6428 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder(); | 6453 const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder(); |
| 6429 for (BlockIterator block_it(postorder); | 6454 for (BlockIterator block_it(postorder); |
| 6430 !block_it.Done(); | 6455 !block_it.Done(); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 6454 } | 6479 } |
| 6455 | 6480 |
| 6456 // Run load forwarding to eliminate LoadField instructions inserted above. | 6481 // Run load forwarding to eliminate LoadField instructions inserted above. |
| 6457 // All loads will be successfully eliminated because: | 6482 // All loads will be successfully eliminated because: |
| 6458 // a) they use fields (not offsets) and thus provide precise aliasing | 6483 // a) they use fields (not offsets) and thus provide precise aliasing |
| 6459 // information | 6484 // information |
| 6460 // b) candidate does not escape and thus its fields is not affected by | 6485 // b) candidate does not escape and thus its fields is not affected by |
| 6461 // external effects from calls. | 6486 // external effects from calls. |
| 6462 LoadOptimizer::OptimizeGraph(flow_graph_); | 6487 LoadOptimizer::OptimizeGraph(flow_graph_); |
| 6463 | 6488 |
| 6489 if (FLAG_trace_optimization) { | |
| 6490 FlowGraphPrinter::PrintGraph("Sinking", flow_graph_); | |
| 6491 } | |
| 6492 | |
| 6464 // At this point we have computed the state of object at each deoptimization | 6493 // At this point we have computed the state of object at each deoptimization |
| 6465 // point and we can eliminate it. Loads inserted above were forwarded so there | 6494 // point and we can eliminate it. Loads inserted above were forwarded so there |
| 6466 // are no uses of the allocation just as in the begging of the pass. | 6495 // are no uses of the allocation just as in the begging of the pass. |
| 6467 for (intptr_t i = 0; i < candidates.length(); i++) { | 6496 for (intptr_t i = 0; i < candidates.length(); i++) { |
| 6468 EliminateAllocation(candidates[i]); | 6497 EliminateAllocation(candidates[i]); |
| 6469 } | 6498 } |
| 6470 | 6499 |
| 6471 // Process materializations and unbox their arguments: materializations | 6500 // Process materializations and unbox their arguments: materializations |
| 6472 // are part of the environment and can materialize boxes for double/mint/simd | 6501 // are part of the environment and can materialize boxes for double/mint/simd |
| 6473 // values when needed. | 6502 // values when needed. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6569 ZoneGrowableArray<const Field*>* fields = | 6598 ZoneGrowableArray<const Field*>* fields = |
| 6570 new ZoneGrowableArray<const Field*>(5); | 6599 new ZoneGrowableArray<const Field*>(5); |
| 6571 | 6600 |
| 6572 for (Value* use = alloc->input_use_list(); | 6601 for (Value* use = alloc->input_use_list(); |
| 6573 use != NULL; | 6602 use != NULL; |
| 6574 use = use->next_use()) { | 6603 use = use->next_use()) { |
| 6575 ASSERT(use->instruction()->IsStoreInstanceField()); | 6604 ASSERT(use->instruction()->IsStoreInstanceField()); |
| 6576 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); | 6605 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); |
| 6577 } | 6606 } |
| 6578 | 6607 |
| 6608 if (alloc->ArgumentCount() > 0) { | |
| 6609 const String& name = String::Handle(Symbols::New(":type_args")); | |
| 6610 const Field& type_args_field = | |
| 6611 Field::ZoneHandle(Field::New( | |
| 6612 name, | |
| 6613 false, // !static | |
| 6614 false, // !final | |
| 6615 false, // !const | |
| 6616 Class::Handle(alloc->constructor().Owner()), | |
| 6617 0)); // No token position. | |
| 6618 const Class& cls = Class::Handle(alloc->constructor().Owner()); | |
| 6619 type_args_field.SetOffset(cls.type_arguments_field_offset()); | |
| 6620 AddField(fields, type_args_field); | |
| 6621 } | |
| 6622 | |
| 6579 // Collect all instructions that mention this object in the environment. | 6623 // Collect all instructions that mention this object in the environment. |
| 6580 GrowableArray<Instruction*> exits(10); | 6624 GrowableArray<Instruction*> exits(10); |
| 6581 for (Value* use = alloc->env_use_list(); | 6625 for (Value* use = alloc->env_use_list(); |
| 6582 use != NULL; | 6626 use != NULL; |
| 6583 use = use->next_use()) { | 6627 use = use->next_use()) { |
| 6584 AddInstruction(&exits, use->instruction()); | 6628 AddInstruction(&exits, use->instruction()); |
| 6585 } | 6629 } |
| 6586 | 6630 |
| 6587 // Insert materializations at environment uses. | 6631 // Insert materializations at environment uses. |
| 6588 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 6632 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 6589 for (intptr_t i = 0; i < exits.length(); i++) { | 6633 for (intptr_t i = 0; i < exits.length(); i++) { |
| 6590 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 6634 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 6591 } | 6635 } |
| 6592 } | 6636 } |
| 6593 | 6637 |
| 6594 | 6638 |
| 6595 } // namespace dart | 6639 } // namespace dart |
| OLD | NEW |