• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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