Home | History | Annotate | Download | only in runtime
      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.
     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 
     73   DexRegisterLocation* data() {
     74     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
     75   }
     76   const DexRegisterLocation* data() const {
     77     return count_ <= kSmallCount ? regs_small_.data() : regs_large_.data();
     78   }
     79 
     80   iterator begin() { return data(); }
     81   iterator end() { return data() + count_; }
     82   const_iterator begin() const { return data(); }
     83   const_iterator end() const { return data() + count_; }
     84   size_t size() const { return count_; }
     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 
     96   size_t GetNumberOfLiveDexRegisters() const {
     97     return std::count_if(begin(), end(), [](auto& loc) { return loc.IsLive(); });
     98   }
     99 
    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 
    141   ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const {
    142     return UnpackNativePc(GetPackedNativePc(), instruction_set);
    143   }
    144 
    145   ALWAYS_INLINE bool HasInlineInfo() const {
    146     return HasInlineInfoIndex();
    147   }
    148 
    149   ALWAYS_INLINE bool HasDexRegisterMap() const {
    150     return HasDexRegisterMapIndex();
    151   }
    152 
    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 
    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 
    189   bool EncodesArtMethod() const {
    190     return HasArtMethodLo();
    191   }
    192 
    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:
    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 
    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 
    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:
    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:
    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 
    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 
    312   size_t Size() const {
    313     return BitsToBytesRoundUp(size_in_bits_);
    314   }
    315 
    316   ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
    317     return stack_maps_;
    318   }
    319 
    320   ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
    321     return stack_maps_.GetRow(index);
    322   }
    323 
    324   BitMemoryRegion GetStackMask(size_t index) const {
    325     return stack_masks_.GetBitMemoryRegion(index);
    326   }
    327 
    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 
    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 
    338   uint32_t GetNumberOfLocationCatalogEntries() const {
    339     return dex_register_catalog_.NumRows();
    340   }
    341 
    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 
    348   bool HasInlineInfo() const {
    349     return inline_infos_.NumRows() > 0;
    350   }
    351 
    352   uint32_t GetNumberOfStackMaps() const {
    353     return stack_maps_.NumRows();
    354   }
    355 
    356   uint32_t GetMethodIndexOf(InlineInfo inline_info) const {
    357     return method_infos_.GetRow(inline_info.GetMethodInfoIndex()).GetMethodIndex();
    358   }
    359 
    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 
    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 
    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 
    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.
    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 
    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 
    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>
    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