Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Side by Side Diff: runtime/vm/flow_graph_optimizer.cc

Issue 16799003: Support type arguments for allocation sinking in certain conditions. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/language/allocation_sinking_vm_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | tests/language/allocation_sinking_vm_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698