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

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

Issue 145133009: Improve aliasing info for load elimination of array loads. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 11 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/vm/load_to_load_forwarding_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/dart_entry.h" 9 #include "vm/dart_entry.h"
10 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 290
291 291
292 292
293 // Used by TryMergeDivMod. 293 // Used by TryMergeDivMod.
294 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction, 294 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction,
295 // and the using instruction. This is an intermediate step before merging. 295 // and the using instruction. This is an intermediate step before merging.
296 void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr, 296 void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr,
297 intptr_t ix, 297 intptr_t ix,
298 intptr_t cid) { 298 intptr_t cid) {
299 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid); 299 const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid);
300 ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix))); 300 ConstantInstr* index_instr =
301 flow_graph()->InsertAfter(instr, index_instr, NULL, Definition::kValue); 301 flow_graph()->GetConstant(Smi::Handle(Smi::New(ix)));
Florian Schneider 2014/01/23 13:02:29 Unrelated cleanup to use constant pool here.
302 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr), 302 LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr),
303 new Value(index_instr), 303 new Value(index_instr),
304 index_scale, 304 index_scale,
305 cid, 305 cid,
306 Isolate::kNoDeoptId); 306 Isolate::kNoDeoptId);
307 instr->ReplaceUsesWith(load); 307 instr->ReplaceUsesWith(load);
308 flow_graph()->InsertAfter(index_instr, load, NULL, Definition::kValue); 308 flow_graph()->InsertAfter(instr, load, NULL, Definition::kValue);
309 } 309 }
310 310
311 311
312 // Dart: 312 // Dart:
313 // var x = d % 10; 313 // var x = d % 10;
314 // var y = d ~/ 10; 314 // var y = d ~/ 10;
315 // var z = x + y; 315 // var z = x + y;
316 // 316 //
317 // IL: 317 // IL:
318 // v4 <- %(v2, v3) 318 // v4 <- %(v2, v3)
(...skipping 4298 matching lines...) Expand 10 before | Expand all | Expand 10 after
4617 // between stores and loads. Store can alias another load or store if and only 4617 // between stores and loads. Store can alias another load or store if and only
4618 // if they have the same alias. 4618 // if they have the same alias.
4619 class Alias : public ValueObject { 4619 class Alias : public ValueObject {
4620 public: 4620 public:
4621 Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { } 4621 Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { }
4622 4622
4623 // All indexed load/stores alias each other. 4623 // All indexed load/stores alias each other.
4624 // TODO(vegorov): incorporate type of array into alias to disambiguate 4624 // TODO(vegorov): incorporate type of array into alias to disambiguate
4625 // different typed data and normal arrays. 4625 // different typed data and normal arrays.
4626 static Alias Indexes() { 4626 static Alias Indexes() {
4627 return Alias(kIndexesAlias); 4627 return Alias(kIndexesAlias, 0);
4628 }
4629
4630 static Alias ConstantIndex(intptr_t id) {
4631 ASSERT(id != 0);
4632 return Alias(kConstantIndex, id);
4628 } 4633 }
4629 4634
4630 // Field load/stores alias each other only when they access the same field. 4635 // Field load/stores alias each other only when they access the same field.
4631 // AliasedSet assigns ids to a combination of instance and field during 4636 // AliasedSet assigns ids to a combination of instance and field during
4632 // the optimization phase. 4637 // the optimization phase.
4633 static Alias Field(intptr_t id) { 4638 static Alias Field(intptr_t id) {
4634 ASSERT(id >= kFirstFieldAlias); 4639 ASSERT(id != 0);
4635 return Alias(id * 2 + 1); 4640 return Alias(kFieldAlias, id);
4636 } 4641 }
4637 4642
4638 // VMField load/stores alias each other when field offset matches. 4643 // VMField load/stores alias each other when field offset matches.
4639 // TODO(vegorov) storing a context variable does not alias loading array 4644 // TODO(vegorov) storing a context variable does not alias loading array
4640 // length. 4645 // length.
4641 static Alias VMField(intptr_t offset_in_bytes) { 4646 static Alias VMField(intptr_t offset_in_bytes) {
4647 ASSERT(offset_in_byes >= 0);
4642 const intptr_t idx = offset_in_bytes / kWordSize; 4648 const intptr_t idx = offset_in_bytes / kWordSize;
4643 ASSERT(idx >= kFirstFieldAlias); 4649 return Alias(kVMFieldAlias, idx);
4644 return Alias(idx * 2);
4645 } 4650 }
4646 4651
4647 // Current context load/stores alias each other. 4652 // Current context load/stores alias each other.
4648 static Alias CurrentContext() { 4653 static Alias CurrentContext() {
4649 return Alias(kCurrentContextAlias); 4654 return Alias(kCurrentContextAlias, 0);
4650 } 4655 }
4651 4656
4652 // Operation does not alias anything. 4657 // Operation does not alias anything.
4653 static Alias None() { 4658 static Alias None() {
4654 return Alias(kNoneAlias); 4659 return Alias(kNoneAlias);
4655 } 4660 }
4656 4661
4657 bool IsNone() const { 4662 bool IsNone() const {
4658 return alias_ == kNoneAlias; 4663 return alias_ == kNoneAlias;
4659 } 4664 }
4660 4665
4661 // Convert this alias to a positive array index. 4666 // Convert this alias to a positive array index.
4662 intptr_t ToIndex() const { 4667 intptr_t ToIndex() const {
4663 ASSERT(!IsNone()); 4668 ASSERT(!IsNone());
4664 return alias_ - kAliasBase; 4669 return alias_;
4665 } 4670 }
4666 4671
4667 private: 4672 private:
4673 enum {
4674 // Number of bits required to encode Kind value.
4675 // The payload occupies the rest of the bits, but leaves the MSB (sign bit)
4676 // empty so that the resulting encoded value is always a positive integer.
4677 kBitsForKind = 3,
4678 kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind - 1,
4679 };
4680
4681 enum Kind {
4682 kNoneAlias = -1,
4683 kCurrentContextAlias = 0,
4684 kIndexesAlias = 1,
4685 kFieldAlias = 2,
4686 kVMFieldAlias = 3,
4687 kConstantIndex = 4,
4688 kNumKinds = kConstantIndex + 1
4689 };
4690 COMPILE_ASSERT(kNumKinds < ((1 << kBitsForKind) - 1), InvalidBitFieldSize);
4691
4668 explicit Alias(intptr_t alias) : alias_(alias) { } 4692 explicit Alias(intptr_t alias) : alias_(alias) { }
4669 4693
4670 enum { 4694 Alias(Kind kind, uword payload)
4671 kNoneAlias = -2, 4695 : alias_(KindField::encode(kind) | PayloadField::encode(payload)) { }
4672 kCurrentContextAlias = -1, 4696
4673 kIndexesAlias = 0, 4697 uword payload() const {
4674 kFirstFieldAlias = kIndexesAlias + 1, 4698 return PayloadField::decode(alias_);
4675 kAliasBase = kCurrentContextAlias 4699 }
4676 }; 4700
4701 Kind kind() const {
4702 return IsNone() ? kNoneAlias : KindField::decode(alias_);
4703 }
4704
4705 typedef BitField<Kind, 0, kBitsForKind> KindField;
4706 typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
Florian Schneider 2014/01/23 13:02:29 Instead of encoding as the ids as odd/even positiv
4677 4707
4678 const intptr_t alias_; 4708 const intptr_t alias_;
4679 }; 4709 };
4680 4710
4681 4711
4682 // Place describes an abstract location (e.g. field) that IR can load 4712 // Place describes an abstract location (e.g. field) that IR can load
4683 // from or store to. 4713 // from or store to.
4684 class Place : public ValueObject { 4714 class Place : public ValueObject {
4685 public: 4715 public:
4686 enum Kind { 4716 enum Kind {
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
4985 // those that are affected by calls. 5015 // those that are affected by calls.
4986 class AliasedSet : public ZoneAllocated { 5016 class AliasedSet : public ZoneAllocated {
4987 public: 5017 public:
4988 explicit AliasedSet(ZoneGrowableArray<Place*>* places, 5018 explicit AliasedSet(ZoneGrowableArray<Place*>* places,
4989 PhiPlaceMoves* phi_moves) 5019 PhiPlaceMoves* phi_moves)
4990 : places_(*places), 5020 : places_(*places),
4991 phi_moves_(phi_moves), 5021 phi_moves_(phi_moves),
4992 sets_(), 5022 sets_(),
4993 aliased_by_effects_(new BitVector(places->length())), 5023 aliased_by_effects_(new BitVector(places->length())),
4994 max_field_id_(0), 5024 max_field_id_(0),
4995 field_ids_() { } 5025 field_ids_(),
5026 max_index_id_(0),
5027 index_ids_() { }
4996 5028
4997 Alias ComputeAlias(Place* place) { 5029 Alias ComputeAlias(Place* place) {
4998 switch (place->kind()) { 5030 switch (place->kind()) {
4999 case Place::kIndexed: 5031 case Place::kIndexed:
5032 if (place->index()->IsConstant()) {
5033 const Object& index = place->index()->AsConstant()->value();
5034 if (index.IsSmi()) {
5035 return Alias::ConstantIndex(GetIndexId(Smi::Cast(index).Value()));
5036 }
5037 }
5000 return Alias::Indexes(); 5038 return Alias::Indexes();
5001 case Place::kField: 5039 case Place::kField:
5002 return Alias::Field( 5040 return Alias::Field(
5003 GetInstanceFieldId(place->instance(), place->field())); 5041 GetInstanceFieldId(place->instance(), place->field()));
5004 case Place::kVMField: 5042 case Place::kVMField:
5005 return Alias::VMField(place->offset_in_bytes()); 5043 return Alias::VMField(place->offset_in_bytes());
5006 case Place::kContext: 5044 case Place::kContext:
5007 return Alias::CurrentContext(); 5045 return Alias::CurrentContext();
5008 case Place::kNone: 5046 case Place::kNone:
5009 UNREACHABLE(); 5047 UNREACHABLE();
5010 } 5048 }
5011 5049
5012 UNREACHABLE(); 5050 UNREACHABLE();
5013 return Alias::None(); 5051 return Alias::None();
5014 } 5052 }
5015 5053
5016 Alias ComputeAliasForStore(Instruction* instr) { 5054 Alias ComputeAliasForStore(Instruction* instr) {
5017 if (instr->IsStoreIndexed()) { 5055 StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
5056 if (store_indexed != NULL) {
5057 if (store_indexed->index()->definition()->IsConstant()) {
5058 const Object& index =
5059 store_indexed->index()->definition()->AsConstant()->value();
5060 if (index.IsSmi()) {
5061 return Alias::ConstantIndex(GetIndexId(Smi::Cast(index).Value()));
5062 }
5063 }
5018 return Alias::Indexes(); 5064 return Alias::Indexes();
5019 } 5065 }
5020 5066
5021 StoreInstanceFieldInstr* store_instance_field = 5067 StoreInstanceFieldInstr* store_instance_field =
5022 instr->AsStoreInstanceField(); 5068 instr->AsStoreInstanceField();
5023 if (store_instance_field != NULL) { 5069 if (store_instance_field != NULL) {
5024 Definition* instance = store_instance_field->instance()->definition(); 5070 Definition* instance = store_instance_field->instance()->definition();
5025 return Alias::Field(GetInstanceFieldId(instance, 5071 return Alias::Field(GetInstanceFieldId(instance,
5026 store_instance_field->field())); 5072 store_instance_field->field()));
5027 } 5073 }
(...skipping 10 matching lines...) Expand all
5038 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField(); 5084 StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
5039 if (store_static_field != NULL) { 5085 if (store_static_field != NULL) {
5040 return Alias::Field(GetStaticFieldId(store_static_field->field())); 5086 return Alias::Field(GetStaticFieldId(store_static_field->field()));
5041 } 5087 }
5042 5088
5043 return Alias::None(); 5089 return Alias::None();
5044 } 5090 }
5045 5091
5046 BitVector* Get(const Alias alias) { 5092 BitVector* Get(const Alias alias) {
5047 const intptr_t idx = alias.ToIndex(); 5093 const intptr_t idx = alias.ToIndex();
5048 return (idx < sets_.length()) ? sets_[idx] : NULL; 5094 BitVector* ret = (idx < sets_.length()) ? sets_[idx] : NULL;
5095 return ret;
5049 } 5096 }
5050 5097
5051 void AddRepresentative(Place* place) { 5098 void AddRepresentative(Place* place) {
5052 if (!place->IsFinalField()) { 5099 if (!place->IsFinalField()) {
5053 AddIdForAlias(ComputeAlias(place), place->id()); 5100 AddIdForAlias(ComputeAlias(place), place->id());
5054 if (!IsIndependentFromEffects(place)) { 5101 if (!IsIndependentFromEffects(place)) {
5055 aliased_by_effects_->Add(place->id()); 5102 aliased_by_effects_->Add(place->id());
5056 } 5103 }
5057 } 5104 }
5058 } 5105 }
5059 5106
5107 void EnsureAliasingForIndexes() {
5108 BitVector* indexes = Get(Alias::Indexes());
5109 if (indexes == NULL) {
5110 return;
5111 }
5112
5113 // Constant indexes alias all non-constant indexes. Ids start at 1.
5114 for (intptr_t id = 1; id <= max_index_id_; id++) {
5115 BitVector* const_indexes = Get(Alias::ConstantIndex(id));
5116 if (const_indexes != NULL) {
5117 const_indexes->AddAll(indexes);
5118 }
5119 }
5120
5121 // Non-constant indexes alias all constant indexes.
Cutch 2014/01/24 23:07:15 Can these two loops not be merged?
Florian Schneider 2014/01/27 14:29:00 No, at first I thought they can, but Slava pointed
5122 for (intptr_t id = 1; id <= max_index_id_; id++) {
5123 BitVector* const_indexes = Get(Alias::ConstantIndex(id));
5124 if (const_indexes != NULL) {
5125 indexes->AddAll(const_indexes);
5126 }
5127 }
5128 }
5129
5060 void AddIdForAlias(const Alias alias, intptr_t place_id) { 5130 void AddIdForAlias(const Alias alias, intptr_t place_id) {
5061 const intptr_t idx = alias.ToIndex(); 5131 const intptr_t idx = alias.ToIndex();
5062
5063 while (sets_.length() <= idx) { 5132 while (sets_.length() <= idx) {
5064 sets_.Add(NULL); 5133 sets_.Add(NULL);
5065 } 5134 }
5066 5135
5067 if (sets_[idx] == NULL) { 5136 if (sets_[idx] == NULL) {
5068 sets_[idx] = new BitVector(max_place_id()); 5137 sets_[idx] = new BitVector(max_place_id());
5069 } 5138 }
5070 5139
5071 sets_[idx]->Add(place_id); 5140 sets_[idx]->Add(place_id);
5072 } 5141 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
5132 // for the first time. 5201 // for the first time.
5133 intptr_t GetFieldId(intptr_t instance_id, const Field& field) { 5202 intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
5134 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field)); 5203 intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
5135 if (id == 0) { 5204 if (id == 0) {
5136 id = ++max_field_id_; 5205 id = ++max_field_id_;
5137 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id)); 5206 field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
5138 } 5207 }
5139 return id; 5208 return id;
5140 } 5209 }
5141 5210
5211 intptr_t GetIndexId(intptr_t index) {
5212 intptr_t id = index_ids_.Lookup(index);
5213 if (id == 0) {
5214 // Zero is used to indicate element not found. The first id is one.
5215 id = ++max_index_id_;
5216 index_ids_.Insert(IndexIdPair(index, id));
5217 }
5218 return id;
5219 }
5220
5142 enum { 5221 enum {
5143 kAnyInstance = -1 5222 kAnyInstance = -1
5144 }; 5223 };
5145 5224
5146 // Get or create an identifier for an instance field belonging to the 5225 // Get or create an identifier for an instance field belonging to the
5147 // given instance. 5226 // given instance.
5148 // The space of identifiers assigned to instance fields is split into 5227 // The space of identifiers assigned to instance fields is split into
5149 // parts based on the instance that contains the field. 5228 // parts based on the instance that contains the field.
5150 // If compiler can prove that instance has a single SSA name in the compiled 5229 // If compiler can prove that instance has a single SSA name in the compiled
5151 // function then we use that SSA name to distinguish fields of this object 5230 // function then we use that SSA name to distinguish fields of this object
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
5234 static inline bool IsKeyEqual(Pair kv, Key key) { 5313 static inline bool IsKeyEqual(Pair kv, Key key) {
5235 return (KeyOf(kv).field_->raw() == key.field_->raw()) && 5314 return (KeyOf(kv).field_->raw() == key.field_->raw()) &&
5236 (KeyOf(kv).instance_id_ == key.instance_id_); 5315 (KeyOf(kv).instance_id_ == key.instance_id_);
5237 } 5316 }
5238 5317
5239 private: 5318 private:
5240 Key key_; 5319 Key key_;
5241 Value value_; 5320 Value value_;
5242 }; 5321 };
5243 5322
5323 class IndexIdPair {
5324 public:
5325 typedef intptr_t Key;
5326 typedef intptr_t Value;
5327 typedef IndexIdPair Pair;
Cutch 2014/01/24 23:07:15 Why not just pick one name for this class: Pair or
Florian Schneider 2014/01/27 14:29:00 Done. I can replace Pair below with IndexIdPair, b
5328
5329 IndexIdPair(Key key, Value value) : key_(key), value_(value) { }
5330
5331 static Key KeyOf(Pair kv) {
5332 return kv.key_;
5333 }
5334
5335 static Value ValueOf(Pair kv) {
5336 return kv.value_;
5337 }
5338
5339 static intptr_t Hashcode(Key key) {
5340 return key;
5341 }
5342
5343 static inline bool IsKeyEqual(Pair kv, Key key) {
5344 return KeyOf(kv) == key;
5345 }
5346
5347 private:
5348 Key key_;
5349 Value value_;
5350 };
5351
5244 const ZoneGrowableArray<Place*>& places_; 5352 const ZoneGrowableArray<Place*>& places_;
5245 5353
5246 const PhiPlaceMoves* phi_moves_; 5354 const PhiPlaceMoves* phi_moves_;
5247 5355
5248 // Maps alias index to a set of ssa indexes corresponding to loads with the 5356 // Maps alias index to a set of ssa indexes corresponding to loads with the
5249 // given alias. 5357 // given alias.
5250 GrowableArray<BitVector*> sets_; 5358 GrowableArray<BitVector*> sets_;
5251 5359
5252 BitVector* aliased_by_effects_; 5360 BitVector* aliased_by_effects_;
5253 5361
5254 // Table mapping static field to their id used during optimization pass. 5362 // Table mapping static field to their id used during optimization pass.
5255 intptr_t max_field_id_; 5363 intptr_t max_field_id_;
5256 DirectChainedHashMap<FieldIdPair> field_ids_; 5364 DirectChainedHashMap<FieldIdPair> field_ids_;
5365
5366 intptr_t max_index_id_;
5367 DirectChainedHashMap<IndexIdPair> index_ids_;
5257 }; 5368 };
5258 5369
5259 5370
5260 static Definition* GetStoredValue(Instruction* instr) { 5371 static Definition* GetStoredValue(Instruction* instr) {
5261 if (instr->IsStoreIndexed()) { 5372 if (instr->IsStoreIndexed()) {
5262 return instr->AsStoreIndexed()->value()->definition(); 5373 return instr->AsStoreIndexed()->value()->definition();
5263 } 5374 }
5264 5375
5265 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField(); 5376 StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField();
5266 if (store_instance_field != NULL) { 5377 if (store_instance_field != NULL) {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
5387 5498
5388 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places); 5499 PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places);
5389 5500
5390 // Build aliasing sets mapping aliases to loads. 5501 // Build aliasing sets mapping aliases to loads.
5391 AliasedSet* aliased_set = new AliasedSet(places, phi_moves); 5502 AliasedSet* aliased_set = new AliasedSet(places, phi_moves);
5392 for (intptr_t i = 0; i < places->length(); i++) { 5503 for (intptr_t i = 0; i < places->length(); i++) {
5393 Place* place = (*places)[i]; 5504 Place* place = (*places)[i];
5394 aliased_set->AddRepresentative(place); 5505 aliased_set->AddRepresentative(place);
5395 } 5506 }
5396 5507
5508 aliased_set->EnsureAliasingForIndexes();
5509
5397 return aliased_set; 5510 return aliased_set;
5398 } 5511 }
5399 5512
5400 5513
5401 static bool HasSimpleTypeArguments(AllocateObjectInstr* alloc) { 5514 static bool HasSimpleTypeArguments(AllocateObjectInstr* alloc) {
5402 if (alloc->ArgumentCount() == 0) return true; 5515 if (alloc->ArgumentCount() == 0) return true;
5403 ASSERT(alloc->ArgumentCount() == 2); 5516 ASSERT(alloc->ArgumentCount() == 2);
5404 Value* arg1 = alloc->PushArgumentAt(1)->value(); 5517 Value* arg1 = alloc->PushArgumentAt(1)->value();
5405 if (!arg1->BindsToConstant()) return false; 5518 if (!arg1->BindsToConstant()) return false;
5406 5519
(...skipping 2921 matching lines...) Expand 10 before | Expand all | Expand 10 after
8328 } 8441 }
8329 8442
8330 // Insert materializations at environment uses. 8443 // Insert materializations at environment uses.
8331 for (intptr_t i = 0; i < exits.length(); i++) { 8444 for (intptr_t i = 0; i < exits.length(); i++) {
8332 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); 8445 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields);
8333 } 8446 }
8334 } 8447 }
8335 8448
8336 8449
8337 } // namespace dart 8450 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | tests/language/vm/load_to_load_forwarding_vm_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698