• Home
  • History
  • Annotate
  • 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