1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_ 18 #define ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_ 19 20 #include "base/arena_allocator.h" 21 #include "base/arena_bit_vector.h" 22 #include "base/bit_vector-inl.h" 23 #include "base/scoped_arena_allocator.h" 24 #include "base/scoped_arena_containers.h" 25 #include "base/stl_util.h" 26 #include "escape.h" 27 #include "execution_subgraph.h" 28 #include "nodes.h" 29 #include "optimizing/optimizing_compiler_stats.h" 30 31 namespace art { 32 33 enum class LoadStoreAnalysisType { 34 kBasic, 35 kNoPredicatedInstructions, 36 kFull, 37 }; 38 39 // A ReferenceInfo contains additional info about a reference such as 40 // whether it's a singleton, returned, etc. 41 class ReferenceInfo : public DeletableArenaObject<kArenaAllocLSA> { 42 public: ReferenceInfo(HInstruction * reference,ScopedArenaAllocator * allocator,size_t pos,LoadStoreAnalysisType elimination_type)43 ReferenceInfo(HInstruction* reference, 44 ScopedArenaAllocator* allocator, 45 size_t pos, 46 LoadStoreAnalysisType elimination_type) 47 : reference_(reference), 48 position_(pos), 49 is_singleton_(true), 50 is_singleton_and_not_returned_(true), 51 is_singleton_and_not_deopt_visible_(true), 52 allocator_(allocator), 53 subgraph_(nullptr) { 54 // TODO We can do this in one pass. 55 // TODO NewArray is possible but will need to get a handle on how to deal with the dynamic loads 56 // for now just ignore it. 57 bool can_be_partial = elimination_type != LoadStoreAnalysisType::kBasic && 58 (/* reference_->IsNewArray() || */ reference_->IsNewInstance()); 59 if (can_be_partial) { 60 subgraph_.reset( 61 new (allocator) ExecutionSubgraph(reference->GetBlock()->GetGraph(), allocator)); 62 CollectPartialEscapes(reference_->GetBlock()->GetGraph()); 63 } 64 CalculateEscape(reference_, 65 nullptr, 66 &is_singleton_, 67 &is_singleton_and_not_returned_, 68 &is_singleton_and_not_deopt_visible_); 69 if (can_be_partial) { 70 if (elimination_type == LoadStoreAnalysisType::kNoPredicatedInstructions) { 71 // This is to mark writes to partially escaped values as also part of the escaped subset. 72 // TODO We can avoid this if we have a 'ConditionalWrite' instruction. Will require testing 73 // to see if the additional branches are worth it. 74 PrunePartialEscapeWrites(); 75 } 76 DCHECK(subgraph_ != nullptr); 77 subgraph_->Finalize(); 78 } else { 79 DCHECK(subgraph_ == nullptr); 80 } 81 } 82 GetNoEscapeSubgraph()83 const ExecutionSubgraph* GetNoEscapeSubgraph() const { 84 DCHECK(IsPartialSingleton()); 85 return subgraph_.get(); 86 } 87 GetReference()88 HInstruction* GetReference() const { 89 return reference_; 90 } 91 GetPosition()92 size_t GetPosition() const { 93 return position_; 94 } 95 96 // Returns true if reference_ is the only name that can refer to its value during 97 // the lifetime of the method. So it's guaranteed to not have any alias in 98 // the method (including its callees). IsSingleton()99 bool IsSingleton() const { 100 return is_singleton_; 101 } 102 103 // This is a singleton and there are paths that don't escape the method IsPartialSingleton()104 bool IsPartialSingleton() const { 105 auto ref = GetReference(); 106 // TODO NewArray is possible but will need to get a handle on how to deal with the dynamic loads 107 // for now just ignore it. 108 return (/* ref->IsNewArray() || */ ref->IsNewInstance()) && 109 subgraph_ != nullptr && 110 subgraph_->IsValid(); 111 } 112 113 // Returns true if reference_ is a singleton and not returned to the caller or 114 // used as an environment local of an HDeoptimize instruction. 115 // The allocation and stores into reference_ may be eliminated for such cases. IsSingletonAndRemovable()116 bool IsSingletonAndRemovable() const { 117 return is_singleton_and_not_returned_ && is_singleton_and_not_deopt_visible_; 118 } 119 120 // Returns true if reference_ is a singleton and returned to the caller or 121 // used as an environment local of an HDeoptimize instruction. IsSingletonAndNonRemovable()122 bool IsSingletonAndNonRemovable() const { 123 return is_singleton_ && 124 (!is_singleton_and_not_returned_ || !is_singleton_and_not_deopt_visible_); 125 } 126 127 private: 128 void CollectPartialEscapes(HGraph* graph); HandleEscape(HBasicBlock * escape)129 void HandleEscape(HBasicBlock* escape) { 130 DCHECK(subgraph_ != nullptr); 131 subgraph_->RemoveBlock(escape); 132 } HandleEscape(HInstruction * escape)133 void HandleEscape(HInstruction* escape) { 134 HandleEscape(escape->GetBlock()); 135 } 136 137 // Make sure we mark any writes/potential writes to heap-locations within partially 138 // escaped values as escaping. 139 void PrunePartialEscapeWrites(); 140 141 HInstruction* const reference_; 142 const size_t position_; // position in HeapLocationCollector's ref_info_array_. 143 144 // Can only be referred to by a single name in the method. 145 bool is_singleton_; 146 // Is singleton and not returned to caller. 147 bool is_singleton_and_not_returned_; 148 // Is singleton and not used as an environment local of HDeoptimize. 149 bool is_singleton_and_not_deopt_visible_; 150 151 ScopedArenaAllocator* allocator_; 152 153 std::unique_ptr<ExecutionSubgraph> subgraph_; 154 155 DISALLOW_COPY_AND_ASSIGN(ReferenceInfo); 156 }; 157 158 // A heap location is a reference-offset/index pair that a value can be loaded from 159 // or stored to. 160 class HeapLocation : public ArenaObject<kArenaAllocLSA> { 161 public: 162 static constexpr size_t kInvalidFieldOffset = -1; 163 // Default value for heap locations which are not vector data. 164 static constexpr size_t kScalar = 1; 165 // TODO: more fine-grained array types. 166 static constexpr int16_t kDeclaringClassDefIndexForArrays = -1; 167 HeapLocation(ReferenceInfo * ref_info,DataType::Type type,size_t offset,HInstruction * index,size_t vector_length,int16_t declaring_class_def_index)168 HeapLocation(ReferenceInfo* ref_info, 169 DataType::Type type, 170 size_t offset, 171 HInstruction* index, 172 size_t vector_length, 173 int16_t declaring_class_def_index) 174 : ref_info_(ref_info), 175 type_(DataType::ToSigned(type)), 176 offset_(offset), 177 index_(index), 178 vector_length_(vector_length), 179 declaring_class_def_index_(declaring_class_def_index), 180 has_aliased_locations_(false) { 181 DCHECK(ref_info != nullptr); 182 DCHECK((offset == kInvalidFieldOffset && index != nullptr) || 183 (offset != kInvalidFieldOffset && index == nullptr)); 184 } 185 GetReferenceInfo()186 ReferenceInfo* GetReferenceInfo() const { return ref_info_; } GetType()187 DataType::Type GetType() const { return type_; } GetOffset()188 size_t GetOffset() const { return offset_; } GetIndex()189 HInstruction* GetIndex() const { return index_; } GetVectorLength()190 size_t GetVectorLength() const { return vector_length_; } 191 192 // Returns the definition of declaring class' dex index. 193 // It's kDeclaringClassDefIndexForArrays for an array element. GetDeclaringClassDefIndex()194 int16_t GetDeclaringClassDefIndex() const { 195 return declaring_class_def_index_; 196 } 197 IsArray()198 bool IsArray() const { 199 return index_ != nullptr; 200 } 201 HasAliasedLocations()202 bool HasAliasedLocations() const { 203 return has_aliased_locations_; 204 } 205 SetHasAliasedLocations(bool val)206 void SetHasAliasedLocations(bool val) { 207 has_aliased_locations_ = val; 208 } 209 210 private: 211 // Reference for instance/static field, array element or vector data. 212 ReferenceInfo* const ref_info_; 213 // Type of data residing at HeapLocation (always signed for integral 214 // data since e.g. a[i] and a[i] & 0xff are represented by differently 215 // signed types; char vs short are disambiguated through the reference). 216 const DataType::Type type_; 217 // Offset of static/instance field. 218 // Invalid when this HeapLocation is not field. 219 const size_t offset_; 220 // Index of an array element or starting index of vector data. 221 // Invalid when this HeapLocation is not array. 222 HInstruction* const index_; 223 // Vector length of vector data. 224 // When this HeapLocation is not vector data, it's value is kScalar. 225 const size_t vector_length_; 226 // Declaring class's def's dex index. 227 // Invalid when this HeapLocation is not field access. 228 const int16_t declaring_class_def_index_; 229 230 // Has aliased heap locations in the method, due to either the 231 // reference is aliased or the array element is aliased via different 232 // index names. 233 bool has_aliased_locations_; 234 235 DISALLOW_COPY_AND_ASSIGN(HeapLocation); 236 }; 237 238 // A HeapLocationCollector collects all relevant heap locations and keeps 239 // an aliasing matrix for all locations. 240 class HeapLocationCollector : public HGraphVisitor { 241 public: 242 static constexpr size_t kHeapLocationNotFound = -1; 243 // Start with a single uint32_t word. That's enough bits for pair-wise 244 // aliasing matrix of 8 heap locations. 245 static constexpr uint32_t kInitialAliasingMatrixBitVectorSize = 32; 246 HeapLocationCollector(HGraph * graph,ScopedArenaAllocator * allocator,LoadStoreAnalysisType lse_type)247 HeapLocationCollector(HGraph* graph, 248 ScopedArenaAllocator* allocator, 249 LoadStoreAnalysisType lse_type) 250 : HGraphVisitor(graph), 251 allocator_(allocator), 252 ref_info_array_(allocator->Adapter(kArenaAllocLSA)), 253 heap_locations_(allocator->Adapter(kArenaAllocLSA)), 254 aliasing_matrix_(allocator, kInitialAliasingMatrixBitVectorSize, true, kArenaAllocLSA), 255 has_heap_stores_(false), 256 has_volatile_(false), 257 has_monitor_operations_(false), 258 lse_type_(lse_type) { 259 aliasing_matrix_.ClearAllBits(); 260 } 261 ~HeapLocationCollector()262 ~HeapLocationCollector() { 263 CleanUp(); 264 } 265 CleanUp()266 void CleanUp() { 267 heap_locations_.clear(); 268 STLDeleteContainerPointers(ref_info_array_.begin(), ref_info_array_.end()); 269 ref_info_array_.clear(); 270 } 271 CountPartialSingletons()272 size_t CountPartialSingletons() const { 273 return std::count_if(ref_info_array_.begin(), 274 ref_info_array_.end(), 275 [](ReferenceInfo* ri) { return ri->IsPartialSingleton(); }); 276 } 277 GetNumberOfHeapLocations()278 size_t GetNumberOfHeapLocations() const { 279 return heap_locations_.size(); 280 } 281 GetHeapLocation(size_t index)282 HeapLocation* GetHeapLocation(size_t index) const { 283 return heap_locations_[index]; 284 } 285 GetHeapLocationIndex(const HeapLocation * hl)286 size_t GetHeapLocationIndex(const HeapLocation* hl) const { 287 auto res = std::find(heap_locations_.cbegin(), heap_locations_.cend(), hl); 288 return std::distance(heap_locations_.cbegin(), res); 289 } 290 HuntForOriginalReference(HInstruction * ref)291 HInstruction* HuntForOriginalReference(HInstruction* ref) const { 292 // An original reference can be transformed by instructions like: 293 // i0 NewArray 294 // i1 HInstruction(i0) <-- NullCheck, BoundType, IntermediateAddress. 295 // i2 ArrayGet(i1, index) 296 DCHECK(ref != nullptr); 297 while (ref->IsNullCheck() || ref->IsBoundType() || ref->IsIntermediateAddress()) { 298 ref = ref->InputAt(0); 299 } 300 return ref; 301 } 302 FindReferenceInfoOf(HInstruction * ref)303 ReferenceInfo* FindReferenceInfoOf(HInstruction* ref) const { 304 for (size_t i = 0; i < ref_info_array_.size(); i++) { 305 ReferenceInfo* ref_info = ref_info_array_[i]; 306 if (ref_info->GetReference() == ref) { 307 DCHECK_EQ(i, ref_info->GetPosition()); 308 return ref_info; 309 } 310 } 311 return nullptr; 312 } 313 GetFieldHeapLocation(HInstruction * object,const FieldInfo * field)314 size_t GetFieldHeapLocation(HInstruction* object, const FieldInfo* field) const { 315 DCHECK(object != nullptr); 316 DCHECK(field != nullptr); 317 return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(object)), 318 field->GetFieldType(), 319 field->GetFieldOffset().SizeValue(), 320 nullptr, 321 HeapLocation::kScalar, 322 field->GetDeclaringClassDefIndex()); 323 } 324 GetArrayHeapLocation(HInstruction * instruction)325 size_t GetArrayHeapLocation(HInstruction* instruction) const { 326 DCHECK(instruction != nullptr); 327 HInstruction* array = instruction->InputAt(0); 328 HInstruction* index = instruction->InputAt(1); 329 DataType::Type type = instruction->GetType(); 330 size_t vector_length = HeapLocation::kScalar; 331 if (instruction->IsArraySet()) { 332 type = instruction->AsArraySet()->GetComponentType(); 333 } else if (instruction->IsVecStore() || 334 instruction->IsVecLoad()) { 335 HVecOperation* vec_op = instruction->AsVecOperation(); 336 type = vec_op->GetPackedType(); 337 vector_length = vec_op->GetVectorLength(); 338 } else { 339 DCHECK(instruction->IsArrayGet()); 340 } 341 return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(array)), 342 type, 343 HeapLocation::kInvalidFieldOffset, 344 index, 345 vector_length, 346 HeapLocation::kDeclaringClassDefIndexForArrays); 347 } 348 HasHeapStores()349 bool HasHeapStores() const { 350 return has_heap_stores_; 351 } 352 HasVolatile()353 bool HasVolatile() const { 354 return has_volatile_; 355 } 356 HasMonitorOps()357 bool HasMonitorOps() const { 358 return has_monitor_operations_; 359 } 360 361 // Find and return the heap location index in heap_locations_. 362 // NOTE: When heap locations are created, potentially aliasing/overlapping 363 // accesses are given different indexes. This find function also 364 // doesn't take aliasing/overlapping into account. For example, 365 // this function returns three different indexes for: 366 // - ref_info=array, index=i, vector_length=kScalar; 367 // - ref_info=array, index=i, vector_length=2; 368 // - ref_info=array, index=i, vector_length=4; 369 // In later analysis, ComputeMayAlias() and MayAlias() compute and tell whether 370 // these indexes alias. FindHeapLocationIndex(ReferenceInfo * ref_info,DataType::Type type,size_t offset,HInstruction * index,size_t vector_length,int16_t declaring_class_def_index)371 size_t FindHeapLocationIndex(ReferenceInfo* ref_info, 372 DataType::Type type, 373 size_t offset, 374 HInstruction* index, 375 size_t vector_length, 376 int16_t declaring_class_def_index) const { 377 DataType::Type lookup_type = DataType::ToSigned(type); 378 for (size_t i = 0; i < heap_locations_.size(); i++) { 379 HeapLocation* loc = heap_locations_[i]; 380 if (loc->GetReferenceInfo() == ref_info && 381 loc->GetType() == lookup_type && 382 loc->GetOffset() == offset && 383 loc->GetIndex() == index && 384 loc->GetVectorLength() == vector_length && 385 loc->GetDeclaringClassDefIndex() == declaring_class_def_index) { 386 return i; 387 } 388 } 389 return kHeapLocationNotFound; 390 } 391 392 bool InstructionEligibleForLSERemoval(HInstruction* inst) const; 393 394 // Get some estimated statistics based on our analysis. 395 void DumpReferenceStats(OptimizingCompilerStats* stats); 396 397 // Returns true if heap_locations_[index1] and heap_locations_[index2] may alias. MayAlias(size_t index1,size_t index2)398 bool MayAlias(size_t index1, size_t index2) const { 399 if (index1 < index2) { 400 return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index1, index2)); 401 } else if (index1 > index2) { 402 return aliasing_matrix_.IsBitSet(AliasingMatrixPosition(index2, index1)); 403 } else { 404 DCHECK(false) << "index1 and index2 are expected to be different"; 405 return true; 406 } 407 } 408 BuildAliasingMatrix()409 void BuildAliasingMatrix() { 410 const size_t number_of_locations = heap_locations_.size(); 411 if (number_of_locations == 0) { 412 return; 413 } 414 size_t pos = 0; 415 // Compute aliasing info between every pair of different heap locations. 416 // Save the result in a matrix represented as a BitVector. 417 for (size_t i = 0; i < number_of_locations - 1; i++) { 418 for (size_t j = i + 1; j < number_of_locations; j++) { 419 if (ComputeMayAlias(i, j)) { 420 aliasing_matrix_.SetBit(CheckedAliasingMatrixPosition(i, j, pos)); 421 } 422 pos++; 423 } 424 } 425 } 426 CanReferencesAlias(ReferenceInfo * ref_info1,ReferenceInfo * ref_info2)427 static bool CanReferencesAlias(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) { 428 if (ref_info1 == ref_info2) { 429 return true; 430 } else if (ref_info1->IsSingleton()) { 431 return false; 432 } else if (ref_info2->IsSingleton()) { 433 return false; 434 } else if (!MayAliasWithPreexistenceChecking(ref_info1, ref_info2) || 435 !MayAliasWithPreexistenceChecking(ref_info2, ref_info1)) { 436 return false; 437 } 438 return true; 439 } 440 441 private: 442 // An allocation cannot alias with a name which already exists at the point 443 // of the allocation, such as a parameter or a load happening before the allocation. MayAliasWithPreexistenceChecking(ReferenceInfo * ref_info1,ReferenceInfo * ref_info2)444 static bool MayAliasWithPreexistenceChecking(ReferenceInfo* ref_info1, ReferenceInfo* ref_info2) { 445 if (ref_info1->GetReference()->IsNewInstance() || ref_info1->GetReference()->IsNewArray()) { 446 // Any reference that can alias with the allocation must appear after it in the block/in 447 // the block's successors. In reverse post order, those instructions will be visited after 448 // the allocation. 449 return ref_info2->GetPosition() >= ref_info1->GetPosition(); 450 } 451 return true; 452 } 453 454 bool CanArrayElementsAlias(const HInstruction* idx1, 455 const size_t vector_length1, 456 const HInstruction* idx2, 457 const size_t vector_length2) const; 458 459 // `index1` and `index2` are indices in the array of collected heap locations. 460 // Returns the position in the bit vector that tracks whether the two heap 461 // locations may alias. AliasingMatrixPosition(size_t index1,size_t index2)462 size_t AliasingMatrixPosition(size_t index1, size_t index2) const { 463 DCHECK(index2 > index1); 464 const size_t number_of_locations = heap_locations_.size(); 465 // It's (num_of_locations - 1) + ... + (num_of_locations - index1) + (index2 - index1 - 1). 466 return (number_of_locations * index1 - (1 + index1) * index1 / 2 + (index2 - index1 - 1)); 467 } 468 469 // An additional position is passed in to make sure the calculated position is correct. CheckedAliasingMatrixPosition(size_t index1,size_t index2,size_t position)470 size_t CheckedAliasingMatrixPosition(size_t index1, size_t index2, size_t position) { 471 size_t calculated_position = AliasingMatrixPosition(index1, index2); 472 DCHECK_EQ(calculated_position, position); 473 return calculated_position; 474 } 475 476 // Compute if two locations may alias to each other. ComputeMayAlias(size_t index1,size_t index2)477 bool ComputeMayAlias(size_t index1, size_t index2) const { 478 DCHECK_NE(index1, index2); 479 HeapLocation* loc1 = heap_locations_[index1]; 480 HeapLocation* loc2 = heap_locations_[index2]; 481 if (loc1->GetOffset() != loc2->GetOffset()) { 482 // Either two different instance fields, or one is an instance 483 // field and the other is an array data. 484 return false; 485 } 486 if (loc1->GetDeclaringClassDefIndex() != loc2->GetDeclaringClassDefIndex()) { 487 // Different types. 488 return false; 489 } 490 if (!CanReferencesAlias(loc1->GetReferenceInfo(), loc2->GetReferenceInfo())) { 491 return false; 492 } 493 if (loc1->IsArray() && loc2->IsArray()) { 494 HInstruction* idx1 = loc1->GetIndex(); 495 HInstruction* idx2 = loc2->GetIndex(); 496 size_t vector_length1 = loc1->GetVectorLength(); 497 size_t vector_length2 = loc2->GetVectorLength(); 498 if (!CanArrayElementsAlias(idx1, vector_length1, idx2, vector_length2)) { 499 return false; 500 } 501 } 502 loc1->SetHasAliasedLocations(true); 503 loc2->SetHasAliasedLocations(true); 504 return true; 505 } 506 GetOrCreateReferenceInfo(HInstruction * instruction)507 ReferenceInfo* GetOrCreateReferenceInfo(HInstruction* instruction) { 508 ReferenceInfo* ref_info = FindReferenceInfoOf(instruction); 509 if (ref_info == nullptr) { 510 size_t pos = ref_info_array_.size(); 511 ref_info = new (allocator_) ReferenceInfo(instruction, allocator_, pos, lse_type_); 512 ref_info_array_.push_back(ref_info); 513 } 514 return ref_info; 515 } 516 CreateReferenceInfoForReferenceType(HInstruction * instruction)517 void CreateReferenceInfoForReferenceType(HInstruction* instruction) { 518 if (instruction->GetType() != DataType::Type::kReference) { 519 return; 520 } 521 DCHECK(FindReferenceInfoOf(instruction) == nullptr); 522 GetOrCreateReferenceInfo(instruction); 523 } 524 MaybeCreateHeapLocation(HInstruction * ref,DataType::Type type,size_t offset,HInstruction * index,size_t vector_length,int16_t declaring_class_def_index)525 void MaybeCreateHeapLocation(HInstruction* ref, 526 DataType::Type type, 527 size_t offset, 528 HInstruction* index, 529 size_t vector_length, 530 int16_t declaring_class_def_index) { 531 HInstruction* original_ref = HuntForOriginalReference(ref); 532 ReferenceInfo* ref_info = GetOrCreateReferenceInfo(original_ref); 533 size_t heap_location_idx = FindHeapLocationIndex( 534 ref_info, type, offset, index, vector_length, declaring_class_def_index); 535 if (heap_location_idx == kHeapLocationNotFound) { 536 HeapLocation* heap_loc = new (allocator_) 537 HeapLocation(ref_info, type, offset, index, vector_length, declaring_class_def_index); 538 heap_locations_.push_back(heap_loc); 539 } 540 } 541 VisitFieldAccess(HInstruction * ref,const FieldInfo & field_info)542 void VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) { 543 if (field_info.IsVolatile()) { 544 has_volatile_ = true; 545 } 546 DataType::Type type = field_info.GetFieldType(); 547 const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex(); 548 const size_t offset = field_info.GetFieldOffset().SizeValue(); 549 MaybeCreateHeapLocation(ref, 550 type, 551 offset, 552 nullptr, 553 HeapLocation::kScalar, 554 declaring_class_def_index); 555 } 556 VisitArrayAccess(HInstruction * array,HInstruction * index,DataType::Type type,size_t vector_length)557 void VisitArrayAccess(HInstruction* array, 558 HInstruction* index, 559 DataType::Type type, 560 size_t vector_length) { 561 MaybeCreateHeapLocation(array, 562 type, 563 HeapLocation::kInvalidFieldOffset, 564 index, 565 vector_length, 566 HeapLocation::kDeclaringClassDefIndexForArrays); 567 } 568 VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet * instruction)569 void VisitPredicatedInstanceFieldGet(HPredicatedInstanceFieldGet* instruction) override { 570 VisitFieldAccess(instruction->GetTarget(), instruction->GetFieldInfo()); 571 CreateReferenceInfoForReferenceType(instruction); 572 } VisitInstanceFieldGet(HInstanceFieldGet * instruction)573 void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override { 574 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); 575 CreateReferenceInfoForReferenceType(instruction); 576 } 577 VisitInstanceFieldSet(HInstanceFieldSet * instruction)578 void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override { 579 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); 580 has_heap_stores_ = true; 581 } 582 VisitStaticFieldGet(HStaticFieldGet * instruction)583 void VisitStaticFieldGet(HStaticFieldGet* instruction) override { 584 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); 585 CreateReferenceInfoForReferenceType(instruction); 586 } 587 VisitStaticFieldSet(HStaticFieldSet * instruction)588 void VisitStaticFieldSet(HStaticFieldSet* instruction) override { 589 VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); 590 has_heap_stores_ = true; 591 } 592 593 // We intentionally don't collect HUnresolvedInstanceField/HUnresolvedStaticField accesses 594 // since we cannot accurately track the fields. 595 VisitArrayGet(HArrayGet * instruction)596 void VisitArrayGet(HArrayGet* instruction) override { 597 HInstruction* array = instruction->InputAt(0); 598 HInstruction* index = instruction->InputAt(1); 599 DataType::Type type = instruction->GetType(); 600 VisitArrayAccess(array, index, type, HeapLocation::kScalar); 601 CreateReferenceInfoForReferenceType(instruction); 602 } 603 VisitArraySet(HArraySet * instruction)604 void VisitArraySet(HArraySet* instruction) override { 605 HInstruction* array = instruction->InputAt(0); 606 HInstruction* index = instruction->InputAt(1); 607 DataType::Type type = instruction->GetComponentType(); 608 VisitArrayAccess(array, index, type, HeapLocation::kScalar); 609 has_heap_stores_ = true; 610 } 611 VisitVecLoad(HVecLoad * instruction)612 void VisitVecLoad(HVecLoad* instruction) override { 613 HInstruction* array = instruction->InputAt(0); 614 HInstruction* index = instruction->InputAt(1); 615 DataType::Type type = instruction->GetPackedType(); 616 VisitArrayAccess(array, index, type, instruction->GetVectorLength()); 617 CreateReferenceInfoForReferenceType(instruction); 618 } 619 VisitVecStore(HVecStore * instruction)620 void VisitVecStore(HVecStore* instruction) override { 621 HInstruction* array = instruction->InputAt(0); 622 HInstruction* index = instruction->InputAt(1); 623 DataType::Type type = instruction->GetPackedType(); 624 VisitArrayAccess(array, index, type, instruction->GetVectorLength()); 625 has_heap_stores_ = true; 626 } 627 VisitInstruction(HInstruction * instruction)628 void VisitInstruction(HInstruction* instruction) override { 629 // Any new-instance or new-array cannot alias with references that 630 // pre-exist the new-instance/new-array. We append entries into 631 // ref_info_array_ which keeps track of the order of creation 632 // of reference values since we visit the blocks in reverse post order. 633 // 634 // By default, VisitXXX() (including VisitPhi()) calls VisitInstruction(), 635 // unless VisitXXX() is overridden. VisitInstanceFieldGet() etc. above 636 // also call CreateReferenceInfoForReferenceType() explicitly. 637 CreateReferenceInfoForReferenceType(instruction); 638 } 639 VisitMonitorOperation(HMonitorOperation * monitor ATTRIBUTE_UNUSED)640 void VisitMonitorOperation(HMonitorOperation* monitor ATTRIBUTE_UNUSED) override { 641 has_monitor_operations_ = true; 642 } 643 644 ScopedArenaAllocator* allocator_; 645 ScopedArenaVector<ReferenceInfo*> ref_info_array_; // All references used for heap accesses. 646 ScopedArenaVector<HeapLocation*> heap_locations_; // All heap locations. 647 ArenaBitVector aliasing_matrix_; // aliasing info between each pair of locations. 648 bool has_heap_stores_; // If there is no heap stores, LSE acts as GVN with better 649 // alias analysis and won't be as effective. 650 bool has_volatile_; // If there are volatile field accesses. 651 bool has_monitor_operations_; // If there are monitor operations. 652 LoadStoreAnalysisType lse_type_; 653 654 DISALLOW_COPY_AND_ASSIGN(HeapLocationCollector); 655 }; 656 657 class LoadStoreAnalysis { 658 public: 659 // for_elimination controls whether we should keep track of escapes at a per-block level for 660 // partial LSE. LoadStoreAnalysis(HGraph * graph,OptimizingCompilerStats * stats,ScopedArenaAllocator * local_allocator,LoadStoreAnalysisType lse_type)661 explicit LoadStoreAnalysis(HGraph* graph, 662 OptimizingCompilerStats* stats, 663 ScopedArenaAllocator* local_allocator, 664 LoadStoreAnalysisType lse_type) 665 : graph_(graph), 666 stats_(stats), 667 heap_location_collector_( 668 graph, 669 local_allocator, 670 ExecutionSubgraph::CanAnalyse(graph_) ? lse_type : LoadStoreAnalysisType::kBasic) {} 671 GetHeapLocationCollector()672 const HeapLocationCollector& GetHeapLocationCollector() const { 673 return heap_location_collector_; 674 } 675 676 bool Run(); 677 678 private: 679 HGraph* graph_; 680 OptimizingCompilerStats* stats_; 681 HeapLocationCollector heap_location_collector_; 682 683 DISALLOW_COPY_AND_ASSIGN(LoadStoreAnalysis); 684 }; 685 686 } // namespace art 687 688 #endif // ART_COMPILER_OPTIMIZING_LOAD_STORE_ANALYSIS_H_ 689