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/dart_entry.h" | 9 #include "vm/dart_entry.h" |
10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
(...skipping 5530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5541 Place* place = (*places)[i]; | 5541 Place* place = (*places)[i]; |
5542 aliased_set->AddRepresentative(place); | 5542 aliased_set->AddRepresentative(place); |
5543 } | 5543 } |
5544 | 5544 |
5545 aliased_set->EnsureAliasingForIndexes(); | 5545 aliased_set->EnsureAliasingForIndexes(); |
5546 | 5546 |
5547 return aliased_set; | 5547 return aliased_set; |
5548 } | 5548 } |
5549 | 5549 |
5550 | 5550 |
5551 static bool HasSimpleTypeArguments(AllocateObjectInstr* alloc) { | |
5552 if (alloc->ArgumentCount() == 0) return true; | |
5553 ASSERT(alloc->ArgumentCount() == 2); | |
5554 Value* arg1 = alloc->PushArgumentAt(1)->value(); | |
5555 if (!arg1->BindsToConstant()) return false; | |
5556 | |
5557 const Object& obj = arg1->BoundConstant(); | |
5558 return obj.IsSmi() | |
5559 && (Smi::Cast(obj).Value() == StubCode::kNoInstantiator); | |
5560 } | |
5561 | |
5562 | |
5563 class LoadOptimizer : public ValueObject { | 5551 class LoadOptimizer : public ValueObject { |
5564 public: | 5552 public: |
5565 LoadOptimizer(FlowGraph* graph, | 5553 LoadOptimizer(FlowGraph* graph, |
5566 AliasedSet* aliased_set, | 5554 AliasedSet* aliased_set, |
5567 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) | 5555 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map) |
5568 : graph_(graph), | 5556 : graph_(graph), |
5569 map_(map), | 5557 map_(map), |
5570 aliased_set_(aliased_set), | 5558 aliased_set_(aliased_set), |
5571 in_(graph_->preorder().length()), | 5559 in_(graph_->preorder().length()), |
5572 out_(graph_->preorder().length()), | 5560 out_(graph_->preorder().length()), |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5715 // The reason to ignore escaping objects is that final fields are | 5703 // The reason to ignore escaping objects is that final fields are |
5716 // initialized in constructor that potentially can be not inlined into | 5704 // initialized in constructor that potentially can be not inlined into |
5717 // the function that we are currently optimizing. However at the same | 5705 // the function that we are currently optimizing. However at the same |
5718 // time we assume that values of the final fields can be forwarded | 5706 // time we assume that values of the final fields can be forwarded |
5719 // across side-effects. If we add 'null' as known values for these | 5707 // across side-effects. If we add 'null' as known values for these |
5720 // fields here we will incorrectly propagate this null across | 5708 // fields here we will incorrectly propagate this null across |
5721 // constructor invocation. | 5709 // constructor invocation. |
5722 // TODO(vegorov): record null-values at least for not final fields of | 5710 // TODO(vegorov): record null-values at least for not final fields of |
5723 // escaping object. | 5711 // escaping object. |
5724 AllocateObjectInstr* alloc = instr->AsAllocateObject(); | 5712 AllocateObjectInstr* alloc = instr->AsAllocateObject(); |
5725 if ((alloc != NULL) && | 5713 if ((alloc != NULL) && !AliasedSet::CanBeAliased(alloc)) { |
5726 !AliasedSet::CanBeAliased(alloc) && | |
5727 HasSimpleTypeArguments(alloc)) { | |
5728 for (Value* use = alloc->input_use_list(); | 5714 for (Value* use = alloc->input_use_list(); |
5729 use != NULL; | 5715 use != NULL; |
5730 use = use->next_use()) { | 5716 use = use->next_use()) { |
5731 // Look for all immediate loads from this object. | 5717 // Look for all immediate loads from this object. |
5732 if (use->use_index() != 0) { | 5718 if (use->use_index() != 0) { |
5733 continue; | 5719 continue; |
5734 } | 5720 } |
5735 | 5721 |
5736 LoadFieldInstr* load = use->instruction()->AsLoadField(); | 5722 LoadFieldInstr* load = use->instruction()->AsLoadField(); |
5737 if (load != NULL) { | 5723 if (load != NULL) { |
5738 // Found a load. Initialize current value of the field to null for | 5724 // Found a load. Initialize current value of the field to null for |
5739 // normal fields, or with type arguments. | 5725 // normal fields, or with type arguments. |
5740 gen->Add(load->place_id()); | 5726 gen->Add(load->place_id()); |
5741 if (out_values == NULL) out_values = CreateBlockOutValues(); | 5727 if (out_values == NULL) out_values = CreateBlockOutValues(); |
5742 | 5728 |
5743 if (alloc->ArgumentCount() > 0) { | 5729 if (alloc->ArgumentCount() > 0) { |
5744 ASSERT(alloc->ArgumentCount() == 2); | 5730 ASSERT(alloc->ArgumentCount() == 1); |
5745 intptr_t type_args_offset = | 5731 intptr_t type_args_offset = |
5746 alloc->cls().type_arguments_field_offset(); | 5732 alloc->cls().type_arguments_field_offset(); |
5747 if (load->offset_in_bytes() == type_args_offset) { | 5733 if (load->offset_in_bytes() == type_args_offset) { |
5748 (*out_values)[load->place_id()] = | 5734 (*out_values)[load->place_id()] = |
5749 alloc->PushArgumentAt(0)->value()->definition(); | 5735 alloc->PushArgumentAt(0)->value()->definition(); |
5750 continue; | 5736 continue; |
5751 } | 5737 } |
5752 } | 5738 } |
5753 (*out_values)[load->place_id()] = graph_->constant_null(); | 5739 (*out_values)[load->place_id()] = graph_->constant_null(); |
5754 } | 5740 } |
(...skipping 1468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7223 instr->type_arguments().CanShareInstantiatorTypeArguments( | 7209 instr->type_arguments().CanShareInstantiatorTypeArguments( |
7224 instr->instantiator_class())) { | 7210 instr->instantiator_class())) { |
7225 SetValue(instr, object); | 7211 SetValue(instr, object); |
7226 return; | 7212 return; |
7227 } | 7213 } |
7228 SetValue(instr, non_constant_); | 7214 SetValue(instr, non_constant_); |
7229 } | 7215 } |
7230 } | 7216 } |
7231 | 7217 |
7232 | 7218 |
7233 void ConstantPropagator::VisitExtractConstructorTypeArguments( | |
7234 ExtractConstructorTypeArgumentsInstr* instr) { | |
7235 CompileType* type = instr->instantiator()->Type(); | |
7236 if (type->HasDecidableNullability()) { | |
7237 if (!type->is_nullable()) { | |
7238 SetValue(instr, instr->type_arguments()); | |
7239 return; | |
7240 } | |
7241 ASSERT(type->IsNull()); | |
7242 SetValue(instr, instr->instantiator()->definition()->constant_value()); | |
7243 return; | |
7244 } | |
7245 SetValue(instr, non_constant_); | |
7246 } | |
7247 | |
7248 | |
7249 void ConstantPropagator::VisitExtractConstructorInstantiator( | |
7250 ExtractConstructorInstantiatorInstr* instr) { | |
7251 CompileType* type = instr->instantiator()->Type(); | |
7252 if (type->HasDecidableNullability()) { | |
7253 if (type->IsNull()) { | |
7254 SetValue(instr, Smi::ZoneHandle(Smi::New(StubCode::kNoInstantiator))); | |
7255 return; | |
7256 } | |
7257 ASSERT(!type->is_nullable()); | |
7258 SetValue(instr, instr->instantiator()->definition()->constant_value()); | |
7259 return; | |
7260 } | |
7261 SetValue(instr, non_constant_); | |
7262 } | |
7263 | |
7264 | |
7265 void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) { | 7219 void ConstantPropagator::VisitAllocateContext(AllocateContextInstr* instr) { |
7266 SetValue(instr, non_constant_); | 7220 SetValue(instr, non_constant_); |
7267 } | 7221 } |
7268 | 7222 |
7269 | 7223 |
7270 void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) { | 7224 void ConstantPropagator::VisitCloneContext(CloneContextInstr* instr) { |
7271 SetValue(instr, non_constant_); | 7225 SetValue(instr, non_constant_); |
7272 } | 7226 } |
7273 | 7227 |
7274 | 7228 |
(...skipping 977 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8252 } | 8206 } |
8253 } | 8207 } |
8254 } | 8208 } |
8255 | 8209 |
8256 | 8210 |
8257 // Right now we are attempting to sink allocation only into | 8211 // Right now we are attempting to sink allocation only into |
8258 // deoptimization exit. So candidate should only be used in StoreInstanceField | 8212 // deoptimization exit. So candidate should only be used in StoreInstanceField |
8259 // instructions that write into fields of the allocated object. | 8213 // instructions that write into fields of the allocated object. |
8260 // We do not support materialization of the object that has type arguments. | 8214 // We do not support materialization of the object that has type arguments. |
8261 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { | 8215 static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) { |
8262 if (!HasSimpleTypeArguments(alloc)) return false; | |
8263 | |
8264 for (Value* use = alloc->input_use_list(); | 8216 for (Value* use = alloc->input_use_list(); |
8265 use != NULL; | 8217 use != NULL; |
8266 use = use->next_use()) { | 8218 use = use->next_use()) { |
8267 if (!(use->instruction()->IsStoreInstanceField() && | 8219 if (!(use->instruction()->IsStoreInstanceField() && |
8268 (use->use_index() == 0))) { | 8220 (use->use_index() == 0))) { |
8269 return false; | 8221 return false; |
8270 } | 8222 } |
8271 } | 8223 } |
8272 | 8224 |
8273 return true; | 8225 return true; |
(...skipping 17 matching lines...) Expand all Loading... |
8291 use = alloc->input_use_list()) { | 8243 use = alloc->input_use_list()) { |
8292 use->instruction()->RemoveFromGraph(); | 8244 use->instruction()->RemoveFromGraph(); |
8293 } | 8245 } |
8294 | 8246 |
8295 // There should be no environment uses. The pass replaced them with | 8247 // There should be no environment uses. The pass replaced them with |
8296 // MaterializeObject instructions. | 8248 // MaterializeObject instructions. |
8297 ASSERT(alloc->env_use_list() == NULL); | 8249 ASSERT(alloc->env_use_list() == NULL); |
8298 ASSERT(alloc->input_use_list() == NULL); | 8250 ASSERT(alloc->input_use_list() == NULL); |
8299 alloc->RemoveFromGraph(); | 8251 alloc->RemoveFromGraph(); |
8300 if (alloc->ArgumentCount() > 0) { | 8252 if (alloc->ArgumentCount() > 0) { |
8301 ASSERT(alloc->ArgumentCount() == 2); | 8253 ASSERT(alloc->ArgumentCount() == 1); |
8302 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { | 8254 for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { |
8303 alloc->PushArgumentAt(i)->RemoveFromGraph(); | 8255 alloc->PushArgumentAt(i)->RemoveFromGraph(); |
8304 } | 8256 } |
8305 } | 8257 } |
8306 } | 8258 } |
8307 | 8259 |
8308 | 8260 |
8309 void AllocationSinking::Optimize() { | 8261 void AllocationSinking::Optimize() { |
8310 GrowableArray<AllocateObjectInstr*> candidates(5); | 8262 GrowableArray<AllocateObjectInstr*> candidates(5); |
8311 | 8263 |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8466 new ZoneGrowableArray<const Field*>(5); | 8418 new ZoneGrowableArray<const Field*>(5); |
8467 | 8419 |
8468 for (Value* use = alloc->input_use_list(); | 8420 for (Value* use = alloc->input_use_list(); |
8469 use != NULL; | 8421 use != NULL; |
8470 use = use->next_use()) { | 8422 use = use->next_use()) { |
8471 ASSERT(use->instruction()->IsStoreInstanceField()); | 8423 ASSERT(use->instruction()->IsStoreInstanceField()); |
8472 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); | 8424 AddField(fields, use->instruction()->AsStoreInstanceField()->field()); |
8473 } | 8425 } |
8474 | 8426 |
8475 if (alloc->ArgumentCount() > 0) { | 8427 if (alloc->ArgumentCount() > 0) { |
8476 ASSERT(alloc->ArgumentCount() == 2); | 8428 ASSERT(alloc->ArgumentCount() == 1); |
8477 const String& name = String::Handle(Symbols::New(":type_args")); | 8429 const String& name = String::Handle(Symbols::New(":type_args")); |
8478 const Field& type_args_field = | 8430 const Field& type_args_field = |
8479 Field::ZoneHandle(Field::New( | 8431 Field::ZoneHandle(Field::New( |
8480 name, | 8432 name, |
8481 false, // !static | 8433 false, // !static |
8482 false, // !final | 8434 false, // !final |
8483 false, // !const | 8435 false, // !const |
8484 alloc->cls(), | 8436 alloc->cls(), |
8485 0)); // No token position. | 8437 0)); // No token position. |
8486 type_args_field.SetOffset(alloc->cls().type_arguments_field_offset()); | 8438 type_args_field.SetOffset(alloc->cls().type_arguments_field_offset()); |
8487 AddField(fields, type_args_field); | 8439 AddField(fields, type_args_field); |
8488 } | 8440 } |
8489 | 8441 |
8490 // Collect all instructions that mention this object in the environment. | 8442 // Collect all instructions that mention this object in the environment. |
8491 GrowableArray<Instruction*> exits(10); | 8443 GrowableArray<Instruction*> exits(10); |
8492 for (Value* use = alloc->env_use_list(); | 8444 for (Value* use = alloc->env_use_list(); |
8493 use != NULL; | 8445 use != NULL; |
8494 use = use->next_use()) { | 8446 use = use->next_use()) { |
8495 AddInstruction(&exits, use->instruction()); | 8447 AddInstruction(&exits, use->instruction()); |
8496 } | 8448 } |
8497 | 8449 |
8498 // Insert materializations at environment uses. | 8450 // Insert materializations at environment uses. |
8499 for (intptr_t i = 0; i < exits.length(); i++) { | 8451 for (intptr_t i = 0; i < exits.length(); i++) { |
8500 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 8452 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
8501 } | 8453 } |
8502 } | 8454 } |
8503 | 8455 |
8504 | 8456 |
8505 } // namespace dart | 8457 } // namespace dart |
OLD | NEW |