1 /* 2 * Copyright (C) 2012 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_DEX_LOCAL_VALUE_NUMBERING_H_ 18 #define ART_COMPILER_DEX_LOCAL_VALUE_NUMBERING_H_ 19 20 #include <memory> 21 22 #include "compiler_internals.h" 23 #include "global_value_numbering.h" 24 #include "utils/scoped_arena_allocator.h" 25 #include "utils/scoped_arena_containers.h" 26 27 namespace art { 28 29 class DexFile; 30 31 // Enable/disable tracking values stored in the FILLED_NEW_ARRAY result. 32 static constexpr bool kLocalValueNumberingEnableFilledNewArrayTracking = true; 33 34 class LocalValueNumbering { 35 private: 36 static constexpr uint16_t kNoValue = GlobalValueNumbering::kNoValue; 37 38 public: 39 LocalValueNumbering(GlobalValueNumbering* gvn, BasicBlockId id, ScopedArenaAllocator* allocator); 40 Id()41 BasicBlockId Id() const { 42 return id_; 43 } 44 45 bool Equals(const LocalValueNumbering& other) const; 46 GetSRegValueName(uint16_t s_reg)47 uint16_t GetSRegValueName(uint16_t s_reg) const { 48 return GetOperandValue(s_reg); 49 } 50 SetValueNameNullChecked(uint16_t value_name)51 void SetValueNameNullChecked(uint16_t value_name) { 52 null_checked_.insert(value_name); 53 } 54 IsValueNullChecked(uint16_t value_name)55 bool IsValueNullChecked(uint16_t value_name) const { 56 return null_checked_.find(value_name) != null_checked_.end(); 57 } 58 IsSregValue(uint16_t s_reg,uint16_t value_name)59 bool IsSregValue(uint16_t s_reg, uint16_t value_name) const { 60 auto it = sreg_value_map_.find(s_reg); 61 if (it != sreg_value_map_.end()) { 62 return it->second == value_name; 63 } else { 64 return gvn_->HasValue(kNoValue, s_reg, kNoValue, kNoValue, value_name); 65 } 66 } 67 68 enum MergeType { 69 kNormalMerge, 70 kCatchMerge, 71 kReturnMerge, // RETURN or PHI+RETURN. Merge only sreg maps. 72 }; 73 74 void MergeOne(const LocalValueNumbering& other, MergeType merge_type); 75 void Merge(MergeType merge_type); // Merge gvn_->merge_lvns_. 76 77 uint16_t GetValueNumber(MIR* mir); 78 79 // LocalValueNumbering should be allocated on the ArenaStack (or the native stack). new(size_t size,ScopedArenaAllocator * allocator)80 static void* operator new(size_t size, ScopedArenaAllocator* allocator) { 81 return allocator->Alloc(sizeof(LocalValueNumbering), kArenaAllocMisc); 82 } 83 84 // Allow delete-expression to destroy a LocalValueNumbering object without deallocation. delete(void * ptr)85 static void operator delete(void* ptr) { UNUSED(ptr); } 86 87 private: 88 // A set of value names. 89 typedef GlobalValueNumbering::ValueNameSet ValueNameSet; 90 91 // Field types correspond to the ordering of GET/PUT instructions; this order is the same 92 // for IGET, IPUT, SGET, SPUT, AGET and APUT: 93 // op 0 94 // op_WIDE 1 95 // op_OBJECT 2 96 // op_BOOLEAN 3 97 // op_BYTE 4 98 // op_CHAR 5 99 // op_SHORT 6 100 static constexpr size_t kFieldTypeCount = 7; 101 102 // Key is s_reg, value is value name. 103 typedef ScopedArenaSafeMap<uint16_t, uint16_t> SregValueMap; 104 SetOperandValueImpl(uint16_t s_reg,uint16_t value,SregValueMap * map)105 void SetOperandValueImpl(uint16_t s_reg, uint16_t value, SregValueMap* map) { 106 DCHECK_EQ(map->count(s_reg), 0u) << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file) 107 << " LVN id: " << id_ << ", s_reg: " << s_reg; 108 map->Put(s_reg, value); 109 } 110 GetOperandValueImpl(int s_reg,const SregValueMap * map)111 uint16_t GetOperandValueImpl(int s_reg, const SregValueMap* map) const { 112 uint16_t res = kNoValue; 113 auto lb = map->find(s_reg); 114 if (lb != map->end()) { 115 res = lb->second; 116 } else { 117 // Using the original value; s_reg refers to an input reg. 118 res = gvn_->LookupValue(kNoValue, s_reg, kNoValue, kNoValue); 119 } 120 return res; 121 } 122 SetOperandValue(uint16_t s_reg,uint16_t value)123 void SetOperandValue(uint16_t s_reg, uint16_t value) { 124 SetOperandValueImpl(s_reg, value, &sreg_value_map_); 125 }; 126 GetOperandValue(int s_reg)127 uint16_t GetOperandValue(int s_reg) const { 128 return GetOperandValueImpl(s_reg, &sreg_value_map_); 129 }; 130 SetOperandValueWide(uint16_t s_reg,uint16_t value)131 void SetOperandValueWide(uint16_t s_reg, uint16_t value) { 132 SetOperandValueImpl(s_reg, value, &sreg_wide_value_map_); 133 }; 134 GetOperandValueWide(int s_reg)135 uint16_t GetOperandValueWide(int s_reg) const { 136 return GetOperandValueImpl(s_reg, &sreg_wide_value_map_); 137 }; 138 139 struct RangeCheckKey { 140 uint16_t array; 141 uint16_t index; 142 143 // NOTE: Can't define this at namespace scope for a private struct. 144 bool operator==(const RangeCheckKey& other) const { 145 return array == other.array && index == other.index; 146 } 147 }; 148 149 struct RangeCheckKeyComparator { operatorRangeCheckKeyComparator150 bool operator()(const RangeCheckKey& lhs, const RangeCheckKey& rhs) const { 151 if (lhs.array != rhs.array) { 152 return lhs.array < rhs.array; 153 } 154 return lhs.index < rhs.index; 155 } 156 }; 157 158 typedef ScopedArenaSet<RangeCheckKey, RangeCheckKeyComparator> RangeCheckSet; 159 160 // Maps instance field "location" (derived from base, field_id and type) to value name. 161 typedef ScopedArenaSafeMap<uint16_t, uint16_t> IFieldLocToValueMap; 162 163 // Maps static field id to value name 164 typedef ScopedArenaSafeMap<uint16_t, uint16_t> SFieldToValueMap; 165 166 struct EscapedIFieldClobberKey { 167 uint16_t base; // Or array. 168 uint16_t type; 169 uint16_t field_id; // None (kNoValue) for arrays and unresolved instance field stores. 170 171 // NOTE: Can't define this at namespace scope for a private struct. 172 bool operator==(const EscapedIFieldClobberKey& other) const { 173 return base == other.base && type == other.type && field_id == other.field_id; 174 } 175 }; 176 177 struct EscapedIFieldClobberKeyComparator { operatorEscapedIFieldClobberKeyComparator178 bool operator()(const EscapedIFieldClobberKey& lhs, const EscapedIFieldClobberKey& rhs) const { 179 // Compare base first. This makes sequential iteration respect the order of base. 180 if (lhs.base != rhs.base) { 181 return lhs.base < rhs.base; 182 } 183 // Compare type second. This makes the type-clobber entries (field_id == kNoValue) last 184 // for given base and type and makes it easy to prune unnecessary entries when merging 185 // escaped_ifield_clobber_set_ from multiple LVNs. 186 if (lhs.type != rhs.type) { 187 return lhs.type < rhs.type; 188 } 189 return lhs.field_id < rhs.field_id; 190 } 191 }; 192 193 typedef ScopedArenaSet<EscapedIFieldClobberKey, EscapedIFieldClobberKeyComparator> 194 EscapedIFieldClobberSet; 195 196 struct EscapedArrayClobberKey { 197 uint16_t base; 198 uint16_t type; 199 200 // NOTE: Can't define this at namespace scope for a private struct. 201 bool operator==(const EscapedArrayClobberKey& other) const { 202 return base == other.base && type == other.type; 203 } 204 }; 205 206 struct EscapedArrayClobberKeyComparator { operatorEscapedArrayClobberKeyComparator207 bool operator()(const EscapedArrayClobberKey& lhs, const EscapedArrayClobberKey& rhs) const { 208 // Compare base first. This makes sequential iteration respect the order of base. 209 if (lhs.base != rhs.base) { 210 return lhs.base < rhs.base; 211 } 212 return lhs.type < rhs.type; 213 } 214 }; 215 216 // Clobber set for previously non-aliasing array refs that escaped. 217 typedef ScopedArenaSet<EscapedArrayClobberKey, EscapedArrayClobberKeyComparator> 218 EscapedArrayClobberSet; 219 220 // Known location values for an aliasing set. The set can be tied to one of: 221 // 1. Instance field. The locations are aliasing references used to access the field. 222 // 2. Non-aliasing array reference. The locations are indexes to the array. 223 // 3. Aliasing array type. The locations are (reference, index) pair ids assigned by GVN. 224 // In each case we keep track of the last stored value, if any, and the set of locations 225 // where it was stored. We also keep track of all values known for the current write state 226 // (load_value_map), which can be known either because they have been loaded since the last 227 // store or because they contained the last_stored_value before the store and thus could not 228 // have changed as a result. 229 struct AliasingValues { AliasingValuesAliasingValues230 explicit AliasingValues(LocalValueNumbering* lvn) 231 : memory_version_before_stores(kNoValue), 232 last_stored_value(kNoValue), 233 store_loc_set(std::less<uint16_t>(), lvn->null_checked_.get_allocator()), 234 last_load_memory_version(kNoValue), 235 load_value_map(std::less<uint16_t>(), lvn->null_checked_.get_allocator()) { 236 } 237 238 uint16_t memory_version_before_stores; // kNoValue if start version for the field. 239 uint16_t last_stored_value; // Last stored value name, kNoValue if none. 240 ValueNameSet store_loc_set; // Where was last_stored_value stored. 241 242 // Maps refs (other than stored_to) to currently known values for this field other. On write, 243 // anything that differs from the written value is removed as it may be overwritten. 244 uint16_t last_load_memory_version; // kNoValue if not known. 245 ScopedArenaSafeMap<uint16_t, uint16_t> load_value_map; 246 247 // NOTE: Can't define this at namespace scope for a private struct. 248 bool operator==(const AliasingValues& other) const { 249 return memory_version_before_stores == other.memory_version_before_stores && 250 last_load_memory_version == other.last_load_memory_version && 251 last_stored_value == other.last_stored_value && 252 store_loc_set == other.store_loc_set && 253 load_value_map == other.load_value_map; 254 } 255 }; 256 257 // Maps instance field id to AliasingValues, locations are object refs. 258 typedef ScopedArenaSafeMap<uint16_t, AliasingValues> AliasingIFieldValuesMap; 259 260 // Maps non-aliasing array reference to AliasingValues, locations are array indexes. 261 typedef ScopedArenaSafeMap<uint16_t, AliasingValues> NonAliasingArrayValuesMap; 262 263 // Maps aliasing array type to AliasingValues, locations are (array, index) pair ids. 264 typedef ScopedArenaSafeMap<uint16_t, AliasingValues> AliasingArrayValuesMap; 265 266 // Helper classes defining versions for updating and merging the AliasingValues maps above. 267 class AliasingIFieldVersions; 268 class NonAliasingArrayVersions; 269 class AliasingArrayVersions; 270 271 template <typename Map> 272 AliasingValues* GetAliasingValues(Map* map, const typename Map::key_type& key); 273 274 template <typename Versions, typename KeyType> 275 void UpdateAliasingValuesLoadVersion(const KeyType& key, AliasingValues* values); 276 277 template <typename Versions, typename Map> 278 static uint16_t AliasingValuesMergeGet(GlobalValueNumbering* gvn, 279 const LocalValueNumbering* lvn, 280 Map* map, const typename Map::key_type& key, 281 uint16_t location); 282 283 template <typename Versions, typename Map> 284 uint16_t HandleAliasingValuesGet(Map* map, const typename Map::key_type& key, 285 uint16_t location); 286 287 template <typename Versions, typename Map> 288 bool HandleAliasingValuesPut(Map* map, const typename Map::key_type& key, 289 uint16_t location, uint16_t value); 290 291 template <typename K> 292 void CopyAliasingValuesMap(ScopedArenaSafeMap<K, AliasingValues>* dest, 293 const ScopedArenaSafeMap<K, AliasingValues>& src); 294 295 uint16_t MarkNonAliasingNonNull(MIR* mir); 296 bool IsNonAliasing(uint16_t reg) const; 297 bool IsNonAliasingIField(uint16_t reg, uint16_t field_id, uint16_t type) const; 298 bool IsNonAliasingArray(uint16_t reg, uint16_t type) const; 299 void HandleNullCheck(MIR* mir, uint16_t reg); 300 void HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index); 301 void HandlePutObject(MIR* mir); 302 void HandleEscapingRef(uint16_t base); 303 uint16_t HandlePhi(MIR* mir); 304 uint16_t HandleAGet(MIR* mir, uint16_t opcode); 305 void HandleAPut(MIR* mir, uint16_t opcode); 306 uint16_t HandleIGet(MIR* mir, uint16_t opcode); 307 void HandleIPut(MIR* mir, uint16_t opcode); 308 uint16_t HandleSGet(MIR* mir, uint16_t opcode); 309 void HandleSPut(MIR* mir, uint16_t opcode); 310 void RemoveSFieldsForType(uint16_t type); 311 void HandleInvokeOrClInit(MIR* mir); 312 313 bool SameMemoryVersion(const LocalValueNumbering& other) const; 314 315 uint16_t NewMemoryVersion(uint16_t* new_version); 316 void MergeMemoryVersions(bool clobbered_catch); 317 318 void PruneNonAliasingRefsForCatch(); 319 320 template <typename Set, Set LocalValueNumbering::* set_ptr> 321 void IntersectSets(); 322 323 void CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src); 324 325 // Intersect maps as sets. The value type must be equality-comparable. 326 template <SregValueMap LocalValueNumbering::* map_ptr> 327 void IntersectSregValueMaps(); 328 329 // Intersect maps as sets. The value type must be equality-comparable. 330 template <typename Map> 331 static void InPlaceIntersectMaps(Map* work_map, const Map& other_map); 332 333 template <typename Set, Set LocalValueNumbering::*set_ptr, void (LocalValueNumbering::*MergeFn)( 334 const typename Set::value_type& entry, typename Set::iterator hint)> 335 void MergeSets(); 336 337 void IntersectAliasingValueLocations(AliasingValues* work_values, const AliasingValues* values); 338 339 void MergeEscapedRefs(const ValueNameSet::value_type& entry, ValueNameSet::iterator hint); 340 void MergeEscapedIFieldTypeClobberSets(const EscapedIFieldClobberSet::value_type& entry, 341 EscapedIFieldClobberSet::iterator hint); 342 void MergeEscapedIFieldClobberSets(const EscapedIFieldClobberSet::value_type& entry, 343 EscapedIFieldClobberSet::iterator hint); 344 void MergeEscapedArrayClobberSets(const EscapedArrayClobberSet::value_type& entry, 345 EscapedArrayClobberSet::iterator hint); 346 void MergeNullChecked(const ValueNameSet::value_type& entry, ValueNameSet::iterator hint); 347 void MergeSFieldValues(const SFieldToValueMap::value_type& entry, 348 SFieldToValueMap::iterator hint); 349 void MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry, 350 IFieldLocToValueMap::iterator hint); 351 352 template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions> 353 void MergeAliasingValues(const typename Map::value_type& entry, typename Map::iterator hint); 354 355 GlobalValueNumbering* gvn_; 356 357 // We're using the block id as a 16-bit operand value for some lookups. 358 COMPILE_ASSERT(sizeof(BasicBlockId) == sizeof(uint16_t), BasicBlockId_must_be_16_bit); 359 BasicBlockId id_; 360 361 SregValueMap sreg_value_map_; 362 SregValueMap sreg_wide_value_map_; 363 364 SFieldToValueMap sfield_value_map_; 365 IFieldLocToValueMap non_aliasing_ifield_value_map_; 366 AliasingIFieldValuesMap aliasing_ifield_value_map_; 367 NonAliasingArrayValuesMap non_aliasing_array_value_map_; 368 AliasingArrayValuesMap aliasing_array_value_map_; 369 370 // Data for dealing with memory clobbering and store/load aliasing. 371 uint16_t global_memory_version_; 372 uint16_t unresolved_sfield_version_[kFieldTypeCount]; 373 uint16_t unresolved_ifield_version_[kFieldTypeCount]; 374 // Value names of references to objects that cannot be reached through a different value name. 375 ValueNameSet non_aliasing_refs_; 376 // Previously non-aliasing refs that escaped but can still be used for non-aliasing AGET/IGET. 377 ValueNameSet escaped_refs_; 378 // Blacklists for cases where escaped_refs_ can't be used. 379 EscapedIFieldClobberSet escaped_ifield_clobber_set_; 380 EscapedArrayClobberSet escaped_array_clobber_set_; 381 382 // Range check and null check elimination. 383 RangeCheckSet range_checked_; 384 ValueNameSet null_checked_; 385 386 // Reuse one vector for all merges to avoid leaking too much memory on the ArenaStack. 387 ScopedArenaVector<BasicBlockId> merge_names_; 388 // Map to identify when different locations merge the same values. 389 ScopedArenaSafeMap<ScopedArenaVector<BasicBlockId>, uint16_t> merge_map_; 390 // New memory version for merge, kNoValue if all memory versions matched. 391 uint16_t merge_new_memory_version_; 392 393 DISALLOW_COPY_AND_ASSIGN(LocalValueNumbering); 394 }; 395 396 } // namespace art 397 398 #endif // ART_COMPILER_DEX_LOCAL_VALUE_NUMBERING_H_ 399