• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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_RUNTIME_STACK_MAP_H_
18 #define ART_RUNTIME_STACK_MAP_H_
19 
20 #include <limits>
21 
22 #include "arch/instruction_set.h"
23 #include "base/bit_memory_region.h"
24 #include "base/bit_table.h"
25 #include "base/bit_utils.h"
26 #include "base/bit_vector.h"
27 #include "base/leb128.h"
28 #include "base/memory_region.h"
29 #include "dex/dex_file_types.h"
30 #include "dex_register_location.h"
31 #include "quick/quick_method_frame_info.h"
32 
33 namespace art {
34 
35 class OatQuickMethodHeader;
36 class VariableIndentationOutputStream;
37 
38 // Size of a frame slot, in bytes.  This constant is a signed value,
39 // to please the compiler in arithmetic operations involving int32_t
40 // (signed) values.
41 static constexpr ssize_t kFrameSlotSize = 4;
42 
43 // The delta compression of dex register maps means we need to scan the stackmaps backwards.
44 // We compress the data in such a way so that there is an upper bound on the search distance.
45 // Max distance 0 means each stack map must be fully defined and no scanning back is allowed.
46 // If this value is changed, the oat file version should be incremented (for DCHECK to pass).
47 static constexpr size_t kMaxDexRegisterMapSearchDistance = 32;
48 
49 class ArtMethod;
50 class CodeInfo;
51 class Stats;
52 
53 std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg);
54 
55 // Information on Dex register locations for a specific PC.
56 // Effectively just a convenience wrapper for DexRegisterLocation vector.
57 // If the size is small enough, it keeps the data on the stack.
58 // TODO: Replace this with generic purpose "small-vector" implementation.
59 class DexRegisterMap {
60  public:
61   using iterator = DexRegisterLocation*;
62   using const_iterator = const DexRegisterLocation*;
63 
64   // Create map for given number of registers and initialize them to the given value.
DexRegisterMap(size_t count,DexRegisterLocation value)65   DexRegisterMap(size_t count, DexRegisterLocation value) : count_(count), regs_small_{} {
66     if (count_ <= kSmallCount) {
67       std::fill_n(regs_small_.begin(), count, value);
68     } else {
69       regs_large_.resize(count, value);
70     }
71   }
72 
data()73   DexRegisterLocation* data() {
74     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
75   }
data()76   const DexRegisterLocation* data() const {
77     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
78   }
79 
begin()80   iterator begin() { return data(); }
end()81   iterator end() { return data() + count_; }
begin()82   const_iterator begin() const { return data(); }
end()83   const_iterator end() const { return data() + count_; }
size()84   size_t size() const { return count_; }
empty()85   bool empty() const { return count_ == 0; }
86 
87   DexRegisterLocation& operator[](size_t index) {
88     DCHECK_LT(index, count_);
89     return data()[index];
90   }
91   const DexRegisterLocation& operator[](size_t index) const {
92     DCHECK_LT(index, count_);
93     return data()[index];
94   }
95 
GetNumberOfLiveDexRegisters()96   size_t GetNumberOfLiveDexRegisters() const {
97     return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
98   }
99 
HasAnyLiveDexRegisters()100   bool HasAnyLiveDexRegisters() const {
101     return std::any_of(begin(), end(), [](auto& loc) { return loc.IsLive(); });
102   }
103 
104   void Dump(VariableIndentationOutputStream* vios) const;
105 
106  private:
107   // Store the data inline if the number of registers is small to avoid memory allocations.
108   // If count_ <= kSmallCount, we use the regs_small_ array, and regs_large_ otherwise.
109   static constexpr size_t kSmallCount = 16;
110   size_t count_;
111   std::array<DexRegisterLocation, kSmallCount> regs_small_;
112   dchecked_vector<DexRegisterLocation> regs_large_;
113 };
114 
115 /**
116  * A Stack Map holds compilation information for a specific PC necessary for:
117  * - Mapping it to a dex PC,
118  * - Knowing which stack entries are objects,
119  * - Knowing which registers hold objects,
120  * - Knowing the inlining information,
121  * - Knowing the values of dex registers.
122  */
123 class StackMap : public BitTableAccessor<8> {
124  public:
125   enum Kind {
126     Default = -1,
127     Catch = 0,
128     OSR = 1,
129     Debug = 2,
130   };
131   BIT_TABLE_HEADER(StackMap)
132   BIT_TABLE_COLUMN(0, Kind)
133   BIT_TABLE_COLUMN(1, PackedNativePc)
134   BIT_TABLE_COLUMN(2, DexPc)
135   BIT_TABLE_COLUMN(3, RegisterMaskIndex)
136   BIT_TABLE_COLUMN(4, StackMaskIndex)
137   BIT_TABLE_COLUMN(5, InlineInfoIndex)
138   BIT_TABLE_COLUMN(6, DexRegisterMaskIndex)
139   BIT_TABLE_COLUMN(7, DexRegisterMapIndex)
140 
GetNativePcOffset(InstructionSet instruction_set)141   ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
142     return UnpackNativePc(GetPackedNativePc(), instruction_set);
143   }
144 
HasInlineInfo()145   ALWAYS_INLINE bool HasInlineInfo() const {
146     return HasInlineInfoIndex();
147   }
148 
HasDexRegisterMap()149   ALWAYS_INLINE bool HasDexRegisterMap() const {
150     return HasDexRegisterMapIndex();
151   }
152 
PackNativePc(uint32_t native_pc,InstructionSet isa)153   static uint32_t PackNativePc(uint32_t native_pc, InstructionSet isa) {
154     DCHECK_ALIGNED_PARAM(native_pc, GetInstructionSetInstructionAlignment(isa));
155     return native_pc / GetInstructionSetInstructionAlignment(isa);
156   }
157 
UnpackNativePc(uint32_t packed_native_pc,InstructionSet isa)158   static uint32_t UnpackNativePc(uint32_t packed_native_pc, InstructionSet isa) {
159     uint32_t native_pc = packed_native_pc * GetInstructionSetInstructionAlignment(isa);
160     DCHECK_EQ(native_pc / GetInstructionSetInstructionAlignment(isa), packed_native_pc);
161     return native_pc;
162   }
163 
164   void Dump(VariableIndentationOutputStream* vios,
165             const CodeInfo& code_info,
166             uint32_t code_offset,
167             InstructionSet instruction_set) const;
168 };
169 
170 /**
171  * Inline information for a specific PC.
172  * The row referenced from the StackMap holds information at depth 0.
173  * Following rows hold information for further depths.
174  */
175 class InlineInfo : public BitTableAccessor<6> {
176  public:
177   BIT_TABLE_HEADER(InlineInfo)
178   BIT_TABLE_COLUMN(0, IsLast)  // Determines if there are further rows for further depths.
179   BIT_TABLE_COLUMN(1, DexPc)
180   BIT_TABLE_COLUMN(2, MethodInfoIndex)
181   BIT_TABLE_COLUMN(3, ArtMethodHi)  // High bits of ArtMethod*.
182   BIT_TABLE_COLUMN(4, ArtMethodLo)  // Low bits of ArtMethod*.
183   BIT_TABLE_COLUMN(5, NumberOfDexRegisters)  // Includes outer levels and the main method.
184   BIT_TABLE_COLUMN(6, DexRegisterMapIndex)
185 
186   static constexpr uint32_t kLast = -1;
187   static constexpr uint32_t kMore = 0;
188 
EncodesArtMethod()189   bool EncodesArtMethod() const {
190     return HasArtMethodLo();
191   }
192 
GetArtMethod()193   ArtMethod* GetArtMethod() const {
194     uint64_t lo = GetArtMethodLo();
195     uint64_t hi = GetArtMethodHi();
196     return reinterpret_cast<ArtMethod*>((hi << 32) | lo);
197   }
198 
199   void Dump(VariableIndentationOutputStream* vios,
200             const CodeInfo& info,
201             const StackMap& stack_map) const;
202 };
203 
204 class StackMask : public BitTableAccessor<1> {
205  public:
206   BIT_TABLE_HEADER(StackMask)
207   BIT_TABLE_COLUMN(0, Mask)
208 };
209 
210 class DexRegisterMask : public BitTableAccessor<1> {
211  public:
212   BIT_TABLE_HEADER(DexRegisterMask)
213   BIT_TABLE_COLUMN(0, Mask)
214 };
215 
216 class DexRegisterMapInfo : public BitTableAccessor<1> {
217  public:
218   BIT_TABLE_HEADER(DexRegisterMapInfo)
219   BIT_TABLE_COLUMN(0, CatalogueIndex)
220 };
221 
222 class DexRegisterInfo : public BitTableAccessor<2> {
223  public:
BIT_TABLE_HEADER(DexRegisterInfo)224   BIT_TABLE_HEADER(DexRegisterInfo)
225   BIT_TABLE_COLUMN(0, Kind)
226   BIT_TABLE_COLUMN(1, PackedValue)
227 
228   ALWAYS_INLINE DexRegisterLocation GetLocation() const {
229     DexRegisterLocation::Kind kind = static_cast<DexRegisterLocation::Kind>(GetKind());
230     return DexRegisterLocation(kind, UnpackValue(kind, GetPackedValue()));
231   }
232 
PackValue(DexRegisterLocation::Kind kind,uint32_t value)233   static uint32_t PackValue(DexRegisterLocation::Kind kind, uint32_t value) {
234     uint32_t packed_value = value;
235     if (kind == DexRegisterLocation::Kind::kInStack) {
236       DCHECK(IsAligned<kFrameSlotSize>(packed_value));
237       packed_value /= kFrameSlotSize;
238     }
239     return packed_value;
240   }
241 
UnpackValue(DexRegisterLocation::Kind kind,uint32_t packed_value)242   static uint32_t UnpackValue(DexRegisterLocation::Kind kind, uint32_t packed_value) {
243     uint32_t value = packed_value;
244     if (kind == DexRegisterLocation::Kind::kInStack) {
245       value *= kFrameSlotSize;
246     }
247     return value;
248   }
249 };
250 
251 // Register masks tend to have many trailing zero bits (caller-saves are usually not encoded),
252 // therefore it is worth encoding the mask as value+shift.
253 class RegisterMask : public BitTableAccessor<2> {
254  public:
BIT_TABLE_HEADER(RegisterMask)255   BIT_TABLE_HEADER(RegisterMask)
256   BIT_TABLE_COLUMN(0, Value)
257   BIT_TABLE_COLUMN(1, Shift)
258 
259   ALWAYS_INLINE uint32_t GetMask() const {
260     return GetValue() << GetShift();
261   }
262 };
263 
264 // Method indices are not very dedup friendly.
265 // Separating them greatly improves dedup efficiency of the other tables.
266 class MethodInfo : public BitTableAccessor<1> {
267  public:
268   BIT_TABLE_HEADER(MethodInfo)
269   BIT_TABLE_COLUMN(0, MethodIndex)
270 };
271 
272 /**
273  * Wrapper around all compiler information collected for a method.
274  * See the Decode method at the end for the precise binary format.
275  */
276 class CodeInfo {
277  public:
278   class Deduper {
279    public:
Deduper(std::vector<uint8_t> * output)280     explicit Deduper(std::vector<uint8_t>* output) : writer_(output) {
281       DCHECK_EQ(output->size(), 0u);
282     }
283 
284     // Copy CodeInfo into output while de-duplicating the internal bit tables.
285     // It returns the byte offset of the copied CodeInfo within the output.
286     size_t Dedupe(const uint8_t* code_info);
287 
288    private:
289     BitMemoryWriter<std::vector<uint8_t>> writer_;
290 
291     // Deduplicate at BitTable level. The value is bit offset within the output.
292     std::map<BitMemoryRegion, uint32_t, BitMemoryRegion::Less> dedupe_map_;
293   };
294 
295   enum DecodeFlags {
296     AllTables = 0,
297     // Limits the decoding only to the data needed by GC.
298     GcMasksOnly = 1,
299     // Limits the decoding only to the main stack map table and inline info table.
300     // This is sufficient for many use cases and makes the header decoding faster.
301     InlineInfoOnly = 2,
302   };
303 
CodeInfo()304   CodeInfo() {}
305 
306   explicit CodeInfo(const uint8_t* data, DecodeFlags flags = AllTables) {
307     Decode(reinterpret_cast<const uint8_t*>(data), flags);
308   }
309 
310   explicit CodeInfo(const OatQuickMethodHeader* header, DecodeFlags flags = AllTables);
311 
Size()312   size_t Size() const {
313     return BitsToBytesRoundUp(size_in_bits_);
314   }
315 
GetStackMaps()316   ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
317     return stack_maps_;
318   }
319 
GetStackMapAt(size_t index)320   ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
321     return stack_maps_.GetRow(index);
322   }
323 
GetStackMask(size_t index)324   BitMemoryRegion GetStackMask(size_t index) const {
325     return stack_masks_.GetBitMemoryRegion(index);
326   }
327 
GetStackMaskOf(const StackMap & stack_map)328   BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const {
329     uint32_t index = stack_map.GetStackMaskIndex();
330     return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index);
331   }
332 
GetRegisterMaskOf(const StackMap & stack_map)333   uint32_t GetRegisterMaskOf(const StackMap& stack_map) const {
334     uint32_t index = stack_map.GetRegisterMaskIndex();
335     return (index == StackMap::kNoValue) ? 0 : register_masks_.GetRow(index).GetMask();
336   }
337 
GetNumberOfLocationCatalogEntries()338   uint32_t GetNumberOfLocationCatalogEntries() const {
339     return dex_register_catalog_.NumRows();
340   }
341 
GetDexRegisterCatalogEntry(size_t index)342   ALWAYS_INLINE DexRegisterLocation GetDexRegisterCatalogEntry(size_t index) const {
343     return (index == StackMap::kNoValue)
344       ? DexRegisterLocation::None()
345       : dex_register_catalog_.GetRow(index).GetLocation();
346   }
347 
HasInlineInfo()348   bool HasInlineInfo() const {
349     return inline_infos_.NumRows() > 0;
350   }
351 
GetNumberOfStackMaps()352   uint32_t GetNumberOfStackMaps() const {
353     return stack_maps_.NumRows();
354   }
355 
GetMethodIndexOf(InlineInfo inline_info)356   uint32_t GetMethodIndexOf(InlineInfo inline_info) const {
357     return method_infos_.GetRow(inline_info.GetMethodInfoIndex()).GetMethodIndex();
358   }
359 
GetDexRegisterMapOf(StackMap stack_map)360   ALWAYS_INLINE DexRegisterMap GetDexRegisterMapOf(StackMap stack_map) const {
361     if (stack_map.HasDexRegisterMap()) {
362       DexRegisterMap map(number_of_dex_registers_, DexRegisterLocation::Invalid());
363       DecodeDexRegisterMap(stack_map.Row(), /* first_dex_register= */ 0, &map);
364       return map;
365     }
366     return DexRegisterMap(0, DexRegisterLocation::None());
367   }
368 
GetInlineDexRegisterMapOf(StackMap stack_map,InlineInfo inline_info)369   ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
370                                                          InlineInfo inline_info) const {
371     if (stack_map.HasDexRegisterMap()) {
372       DCHECK(stack_map.HasInlineInfoIndex());
373       uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex();
374       // The register counts are commutative and include all outer levels.
375       // This allows us to determine the range [first, last) in just two lookups.
376       // If we are at depth 0 (the first inlinee), the count from the main method is used.
377       uint32_t first = (depth == 0)
378           ? number_of_dex_registers_
379           : inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
380       uint32_t last = inline_info.GetNumberOfDexRegisters();
381       DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
382       DecodeDexRegisterMap(stack_map.Row(), first, &map);
383       return map;
384     }
385     return DexRegisterMap(0, DexRegisterLocation::None());
386   }
387 
GetInlineInfosOf(StackMap stack_map)388   BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
389     uint32_t index = stack_map.GetInlineInfoIndex();
390     if (index != StackMap::kNoValue) {
391       auto begin = inline_infos_.begin() + index;
392       auto end = begin;
393       while ((*end++).GetIsLast() == InlineInfo::kMore) { }
394       return BitTableRange<InlineInfo>(begin, end);
395     } else {
396       return BitTableRange<InlineInfo>();
397     }
398   }
399 
GetStackMapForDexPc(uint32_t dex_pc)400   StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
401     for (StackMap stack_map : stack_maps_) {
402       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
403         return stack_map;
404       }
405     }
406     return stack_maps_.GetInvalidRow();
407   }
408 
409   // Searches the stack map list backwards because catch stack maps are stored at the end.
GetCatchStackMapForDexPc(uint32_t dex_pc)410   StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const {
411     for (size_t i = GetNumberOfStackMaps(); i > 0; --i) {
412       StackMap stack_map = GetStackMapAt(i - 1);
413       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::Catch) {
414         return stack_map;
415       }
416     }
417     return stack_maps_.GetInvalidRow();
418   }
419 
GetOsrStackMapForDexPc(uint32_t dex_pc)420   StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
421     for (StackMap stack_map : stack_maps_) {
422       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
423         return stack_map;
424       }
425     }
426     return stack_maps_.GetInvalidRow();
427   }
428 
429   StackMap GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa = kRuntimeISA) const;
430 
431   // Dump this CodeInfo object on `vios`.
432   // `code_offset` is the (absolute) native PC of the compiled method.
433   void Dump(VariableIndentationOutputStream* vios,
434             uint32_t code_offset,
435             bool verbose,
436             InstructionSet instruction_set) const;
437 
438   // Accumulate code info size statistics into the given Stats tree.
439   static void CollectSizeStats(const uint8_t* code_info, /*out*/ Stats* parent);
440 
DecodeFrameInfo(const uint8_t * data)441   ALWAYS_INLINE static QuickMethodFrameInfo DecodeFrameInfo(const uint8_t* data) {
442     BitMemoryReader reader(data);
443     return QuickMethodFrameInfo(
444         reader.ReadVarint() * kStackAlignment,  // Decode packed_frame_size_ and unpack.
445         reader.ReadVarint(),  // core_spill_mask_.
446         reader.ReadVarint());  // fp_spill_mask_.
447   }
448 
449  private:
450   // Returns lower bound (fist stack map which has pc greater or equal than the desired one).
451   // It ignores catch stack maps at the end (it is the same as if they had maximum pc value).
452   BitTable<StackMap>::const_iterator BinarySearchNativePc(uint32_t packed_pc) const;
453 
454   // Scan backward to determine dex register locations at given stack map.
455   void DecodeDexRegisterMap(uint32_t stack_map_index,
456                             uint32_t first_dex_register,
457                             /*out*/ DexRegisterMap* map) const;
458 
459   void Decode(const uint8_t* data, DecodeFlags flags);
460 
461   // Invokes the callback with member pointer of each header field.
462   template<typename Callback>
ForEachHeaderField(Callback callback)463   ALWAYS_INLINE static void ForEachHeaderField(Callback callback) {
464     callback(&CodeInfo::packed_frame_size_);
465     callback(&CodeInfo::core_spill_mask_);
466     callback(&CodeInfo::fp_spill_mask_);
467     callback(&CodeInfo::number_of_dex_registers_);
468   }
469 
470   // Invokes the callback with member pointer of each BitTable field.
471   template<typename Callback>
472   ALWAYS_INLINE static void ForEachBitTableField(Callback callback, DecodeFlags flags = AllTables) {
473     callback(&CodeInfo::stack_maps_);
474     callback(&CodeInfo::register_masks_);
475     callback(&CodeInfo::stack_masks_);
476     if (flags & DecodeFlags::GcMasksOnly) {
477       return;
478     }
479     callback(&CodeInfo::inline_infos_);
480     callback(&CodeInfo::method_infos_);
481     if (flags & DecodeFlags::InlineInfoOnly) {
482       return;
483     }
484     callback(&CodeInfo::dex_register_masks_);
485     callback(&CodeInfo::dex_register_maps_);
486     callback(&CodeInfo::dex_register_catalog_);
487   }
488 
489   uint32_t packed_frame_size_ = 0;  // Frame size in kStackAlignment units.
490   uint32_t core_spill_mask_ = 0;
491   uint32_t fp_spill_mask_ = 0;
492   uint32_t number_of_dex_registers_ = 0;
493   BitTable<StackMap> stack_maps_;
494   BitTable<RegisterMask> register_masks_;
495   BitTable<StackMask> stack_masks_;
496   BitTable<InlineInfo> inline_infos_;
497   BitTable<MethodInfo> method_infos_;
498   BitTable<DexRegisterMask> dex_register_masks_;
499   BitTable<DexRegisterMapInfo> dex_register_maps_;
500   BitTable<DexRegisterInfo> dex_register_catalog_;
501   uint32_t size_in_bits_ = 0;
502 };
503 
504 #undef ELEMENT_BYTE_OFFSET_AFTER
505 #undef ELEMENT_BIT_OFFSET_AFTER
506 
507 }  // namespace art
508 
509 #endif  // ART_RUNTIME_STACK_MAP_H_
510