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

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

Issue 18055004: Fix a bug in allocation sinking and load elimination. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: improved unit test Created 7 years, 5 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 4029 matching lines...) Expand 10 before | Expand all | Expand 10 after
4040 if (comma) { 4040 if (comma) {
4041 OS::Print(", "); 4041 OS::Print(", ");
4042 } 4042 }
4043 OS::Print("%s", places_[it.Current()]->ToCString()); 4043 OS::Print("%s", places_[it.Current()]->ToCString());
4044 comma = true; 4044 comma = true;
4045 } 4045 }
4046 } 4046 }
4047 4047
4048 const PhiPlaceMoves* phi_moves() const { return phi_moves_; } 4048 const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
4049 4049
4050 // Returns true if the result of AllocateObject can be aliased by some
4051 // other SSA variable and false otherwise. Currently simply checks if
4052 // this value is stored in a field, escapes to another function or
4053 // participates in a phi.
4054 static bool CanBeAliased(AllocateObjectInstr* alloc) {
4055 if (alloc->identity() == AllocateObjectInstr::kUnknown) {
4056 bool escapes = false;
4057 for (Value* use = alloc->input_use_list();
4058 use != NULL;
4059 use = use->next_use()) {
4060 Instruction* instr = use->instruction();
4061 if (instr->IsPushArgument() ||
4062 (instr->IsStoreVMField() && (use->use_index() != 1)) ||
Vyacheslav Egorov (Google) 2013/06/27 13:15:45 Good catch!
4063 (instr->IsStoreInstanceField() && (use->use_index() != 0)) ||
4064 (instr->IsStoreStaticField()) ||
4065 (instr->IsPhi())) {
4066 escapes = true;
4067 break;
4068 }
4069 }
4070
4071 alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
4072 : AllocateObjectInstr::kNotAliased);
4073 }
4074
4075 return alloc->identity() != AllocateObjectInstr::kNotAliased;
4076 }
4077
4050 private: 4078 private:
4051 // Get id assigned to the given field. Assign a new id if the field is seen 4079 // Get id assigned to the given field. Assign a new id if the field is seen
4052 // for the first time. 4080 // for the first time.
4053 intptr_t GetFieldId(intptr_t instance_id, const Field& field) { 4081 intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
4054 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field)); 4082 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
4055 if (id == 0) { 4083 if (id == 0) {
4056 id = ++max_field_id_; 4084 id = ++max_field_id_;
4057 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id)); 4085 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
4058 } 4086 }
4059 return id; 4087 return id;
(...skipping 27 matching lines...) Expand all
4087 4115
4088 return GetFieldId(instance_id, field); 4116 return GetFieldId(instance_id, field);
4089 } 4117 }
4090 4118
4091 // Get or create an identifier for a static field. 4119 // Get or create an identifier for a static field.
4092 intptr_t GetStaticFieldId(const Field& field) { 4120 intptr_t GetStaticFieldId(const Field& field) {
4093 ASSERT(field.is_static()); 4121 ASSERT(field.is_static());
4094 return GetFieldId(kAnyInstance, field); 4122 return GetFieldId(kAnyInstance, field);
4095 } 4123 }
4096 4124
4097 // Returns true if the result of AllocateObject can be aliased by some
4098 // other SSA variable and false otherwise. Currently simply checks if
4099 // this value is stored in a field, escapes to another function or
4100 // participates in a phi.
4101 bool CanBeAliased(AllocateObjectInstr* alloc) {
4102 if (alloc->identity() == AllocateObjectInstr::kUnknown) {
4103 bool escapes = false;
4104 for (Value* use = alloc->input_use_list();
4105 use != NULL;
4106 use = use->next_use()) {
4107 Instruction* instr = use->instruction();
4108 if (instr->IsPushArgument() ||
4109 (instr->IsStoreVMField() && (use->use_index() != 0)) ||
4110 (instr->IsStoreInstanceField() && (use->use_index() != 0)) ||
4111 (instr->IsStoreStaticField()) ||
4112 (instr->IsPhi())) {
4113 escapes = true;
4114 break;
4115 }
4116 }
4117
4118 alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
4119 : AllocateObjectInstr::kNotAliased);
4120 }
4121
4122 return alloc->identity() != AllocateObjectInstr::kNotAliased;
4123 }
4124
4125 // Returns true if the given load is unaffected by external side-effects. 4125 // Returns true if the given load is unaffected by external side-effects.
4126 // This essentially means that no stores to the same location can 4126 // This essentially means that no stores to the same location can
4127 // occur in other functions. 4127 // occur in other functions.
4128 bool IsIndependentFromEffects(Place* place) { 4128 bool IsIndependentFromEffects(Place* place) {
4129 if (place->IsFinalField()) { 4129 if (place->IsFinalField()) {
4130 // Note that we can't use LoadField's is_immutable attribute here because 4130 // Note that we can't use LoadField's is_immutable attribute here because
4131 // some VM-fields (those that have no corresponding Field object and 4131 // some VM-fields (those that have no corresponding Field object and
4132 // accessed through offset alone) can share offset but have different 4132 // accessed through offset alone) can share offset but have different
4133 // immutability properties. 4133 // immutability properties.
4134 // One example is the length property of growable and fixed size list. If 4134 // One example is the length property of growable and fixed size list. If
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after
4500 gen->RemoveAll(aliased_set_->aliased_by_effects()); 4500 gen->RemoveAll(aliased_set_->aliased_by_effects());
4501 continue; 4501 continue;
4502 } 4502 }
4503 4503
4504 Definition* defn = instr->AsDefinition(); 4504 Definition* defn = instr->AsDefinition();
4505 if (defn == NULL) { 4505 if (defn == NULL) {
4506 continue; 4506 continue;
4507 } 4507 }
4508 4508
4509 // For object allocation forward initial values of the fields to 4509 // For object allocation forward initial values of the fields to
4510 // subsequent loads. 4510 // subsequent loads. For simplicity we ignore escaping objects.
4511 // For simplicity we ignore escaping objects and objects that have 4511 //
4512 // type arguments.
4513 // The reason to ignore escaping objects is that final fields are 4512 // The reason to ignore escaping objects is that final fields are
4514 // initialized in constructor that potentially can be not inlined into 4513 // initialized in constructor that potentially can be not inlined into
4515 // the function that we are currently optimizing. However at the same 4514 // the function that we are currently optimizing. However at the same
4516 // time we assume that values of the final fields can be forwarded 4515 // time we assume that values of the final fields can be forwarded
4517 // across side-effects. If we add 'null' as known values for these 4516 // across side-effects. If we add 'null' as known values for these
4518 // fields here we will incorrectly propagate this null across 4517 // fields here we will incorrectly propagate this null across
4519 // constructor invocation. 4518 // constructor invocation.
4520 // TODO(vegorov): record null-values at least for not final fields of 4519 // TODO(vegorov): record null-values at least for not final fields of
4521 // escaping object. 4520 // escaping object.
4522 AllocateObjectInstr* alloc = instr->AsAllocateObject(); 4521 AllocateObjectInstr* alloc = instr->AsAllocateObject();
4523 if ((alloc != NULL) && 4522 if ((alloc != NULL) &&
4524 (alloc->identity() == AllocateObjectInstr::kNotAliased) && 4523 !AliasedSet::CanBeAliased(alloc) &&
4525 HasSimpleTypeArguments(alloc)) { 4524 HasSimpleTypeArguments(alloc)) {
4526 for (Value* use = alloc->input_use_list(); 4525 for (Value* use = alloc->input_use_list();
4527 use != NULL; 4526 use != NULL;
4528 use = use->next_use()) { 4527 use = use->next_use()) {
4529 // Look for all immediate loads from this object. 4528 // Look for all immediate loads from this object.
4530 if (use->use_index() != 0) { 4529 if (use->use_index() != 0) {
4531 continue; 4530 continue;
4532 } 4531 }
4533 4532
4534 LoadFieldInstr* load = use->instruction()->AsLoadField(); 4533 LoadFieldInstr* load = use->instruction()->AsLoadField();
(...skipping 2422 matching lines...) Expand 10 before | Expand all | Expand 10 after
6957 block_it.Advance()) { 6956 block_it.Advance()) {
6958 BlockEntryInstr* block = block_it.Current(); 6957 BlockEntryInstr* block = block_it.Current();
6959 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 6958 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
6960 AllocateObjectInstr* alloc = it.Current()->AsAllocateObject(); 6959 AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
6961 if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) { 6960 if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) {
6962 if (FLAG_trace_optimization) { 6961 if (FLAG_trace_optimization) {
6963 OS::Print("discovered allocation sinking candidate: v%"Pd"\n", 6962 OS::Print("discovered allocation sinking candidate: v%"Pd"\n",
6964 alloc->ssa_temp_index()); 6963 alloc->ssa_temp_index());
6965 } 6964 }
6966 6965
6967 if (alloc->identity() == AllocateObjectInstr::kAliased) { 6966 // All sinking candidate are known to be not aliased.
6968 // Allocation might have been classified as aliased earlier due to 6967 alloc->set_identity(AllocateObjectInstr::kNotAliased);
6969 // some operations that are now eliminated.
6970 alloc->set_identity(AllocateObjectInstr::kNotAliased);
6971 }
6972 6968
6973 candidates.Add(alloc); 6969 candidates.Add(alloc);
6974 } 6970 }
6975 } 6971 }
6976 } 6972 }
6977 6973
6978 // Insert MaterializeObject instructions that will describe the state of the 6974 // Insert MaterializeObject instructions that will describe the state of the
6979 // object at all deoptimization points. Each inserted materialization looks 6975 // object at all deoptimization points. Each inserted materialization looks
6980 // like this (where v_0 is allocation that we are going to eliminate): 6976 // like this (where v_0 is allocation that we are going to eliminate):
6981 // v_1 <- LoadField(v_0, field_1) 6977 // v_1 <- LoadField(v_0, field_1)
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
7139 7135
7140 // Insert materializations at environment uses. 7136 // Insert materializations at environment uses.
7141 const Class& cls = Class::Handle(alloc->constructor().Owner()); 7137 const Class& cls = Class::Handle(alloc->constructor().Owner());
7142 for (intptr_t i = 0; i < exits.length(); i++) { 7138 for (intptr_t i = 0; i < exits.length(); i++) {
7143 CreateMaterializationAt(exits[i], alloc, cls, *fields); 7139 CreateMaterializationAt(exits[i], alloc, cls, *fields);
7144 } 7140 }
7145 } 7141 }
7146 7142
7147 7143
7148 } // namespace dart 7144 } // 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