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 "base/bit_vector.h"
     21 #include "memory_region.h"
     22 
     23 namespace art {
     24 
     25 /**
     26  * Classes in the following file are wrapper on stack map information backed
     27  * by a MemoryRegion. As such they read and write to the region, they don't have
     28  * their own fields.
     29  */
     30 
     31 /**
     32  * Inline information for a specific PC. The information is of the form:
     33  * [inlining_depth, [method_dex reference]+]
     34  */
     35 class InlineInfo {
     36  public:
     37   explicit InlineInfo(MemoryRegion region) : region_(region) {}
     38 
     39   uint8_t GetDepth() const {
     40     return region_.Load<uint8_t>(kDepthOffset);
     41   }
     42 
     43   void SetDepth(uint8_t depth) {
     44     region_.Store<uint8_t>(kDepthOffset, depth);
     45   }
     46 
     47   uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
     48     return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
     49   }
     50 
     51   void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
     52     region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
     53   }
     54 
     55   static size_t SingleEntrySize() {
     56     return sizeof(uint32_t);
     57   }
     58 
     59  private:
     60   static constexpr int kDepthOffset = 0;
     61   static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
     62 
     63   static constexpr uint32_t kNoInlineInfo = -1;
     64 
     65   MemoryRegion region_;
     66 
     67   template<typename T> friend class CodeInfo;
     68   template<typename T> friend class StackMap;
     69   template<typename T> friend class StackMapStream;
     70 };
     71 
     72 /**
     73  * Information on dex register values for a specific PC. The information is
     74  * of the form:
     75  * [location_kind, register_value]+.
     76  *
     77  * The location_kind for a Dex register can either be:
     78  * - Constant: register_value holds the constant,
     79  * - Stack: register_value holds the stack offset,
     80  * - Register: register_value holds the register number.
     81  */
     82 class DexRegisterMap {
     83  public:
     84   explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
     85 
     86   enum LocationKind {
     87     kInStack,
     88     kInRegister,
     89     kConstant
     90   };
     91 
     92   LocationKind GetLocationKind(uint16_t register_index) const {
     93     return region_.Load<LocationKind>(
     94         kFixedSize + register_index * SingleEntrySize());
     95   }
     96 
     97   void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
     98     size_t entry = kFixedSize + register_index * SingleEntrySize();
     99     region_.Store<LocationKind>(entry, kind);
    100     region_.Store<int32_t>(entry + sizeof(LocationKind), value);
    101   }
    102 
    103   int32_t GetValue(uint16_t register_index) const {
    104     return region_.Load<int32_t>(
    105         kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
    106   }
    107 
    108   static size_t SingleEntrySize() {
    109     return sizeof(LocationKind) + sizeof(int32_t);
    110   }
    111 
    112  private:
    113   static constexpr int kFixedSize = 0;
    114 
    115   MemoryRegion region_;
    116 
    117   template <typename T> friend class CodeInfo;
    118   template <typename T> friend class StackMapStream;
    119 };
    120 
    121 /**
    122  * A Stack Map holds compilation information for a specific PC necessary for:
    123  * - Mapping it to a dex PC,
    124  * - Knowing which stack entries are objects,
    125  * - Knowing which registers hold objects,
    126  * - Knowing the inlining information,
    127  * - Knowing the values of dex registers.
    128  *
    129  * The information is of the form:
    130  * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
    131  *
    132  * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
    133  * stack size of a method.
    134  */
    135 template <typename T>
    136 class StackMap {
    137  public:
    138   explicit StackMap(MemoryRegion region) : region_(region) {}
    139 
    140   uint32_t GetDexPc() const {
    141     return region_.Load<uint32_t>(kDexPcOffset);
    142   }
    143 
    144   void SetDexPc(uint32_t dex_pc) {
    145     region_.Store<uint32_t>(kDexPcOffset, dex_pc);
    146   }
    147 
    148   T GetNativePc() const {
    149     return region_.Load<T>(kNativePcOffset);
    150   }
    151 
    152   void SetNativePc(T native_pc) {
    153     return region_.Store<T>(kNativePcOffset, native_pc);
    154   }
    155 
    156   uint32_t GetDexRegisterMapOffset() const {
    157     return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
    158   }
    159 
    160   void SetDexRegisterMapOffset(uint32_t offset) {
    161     return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
    162   }
    163 
    164   uint32_t GetInlineDescriptorOffset() const {
    165     return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
    166   }
    167 
    168   void SetInlineDescriptorOffset(uint32_t offset) {
    169     return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
    170   }
    171 
    172   uint32_t GetRegisterMask() const {
    173     return region_.Load<uint32_t>(kRegisterMaskOffset);
    174   }
    175 
    176   void SetRegisterMask(uint32_t mask) {
    177     region_.Store<uint32_t>(kRegisterMaskOffset, mask);
    178   }
    179 
    180   MemoryRegion GetStackMask() const {
    181     return region_.Subregion(kStackMaskOffset, StackMaskSize());
    182   }
    183 
    184   void SetStackMask(const BitVector& sp_map) {
    185     MemoryRegion region = GetStackMask();
    186     for (size_t i = 0; i < region.size_in_bits(); i++) {
    187       region.StoreBit(i, sp_map.IsBitSet(i));
    188     }
    189   }
    190 
    191   bool HasInlineInfo() const {
    192     return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
    193   }
    194 
    195   bool Equals(const StackMap& other) {
    196     return region_.pointer() == other.region_.pointer()
    197        && region_.size() == other.region_.size();
    198   }
    199 
    200  private:
    201   static constexpr int kDexPcOffset = 0;
    202   static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t);
    203   static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T);
    204   static constexpr int kInlineDescriptorOffsetOffset =
    205       kDexRegisterMapOffsetOffset + sizeof(uint32_t);
    206   static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
    207   static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
    208   static constexpr int kStackMaskOffset = kFixedSize;
    209 
    210   size_t StackMaskSize() const { return region_.size() - kFixedSize; }
    211 
    212   MemoryRegion region_;
    213 
    214   template <typename U> friend class CodeInfo;
    215   template <typename U> friend class StackMapStream;
    216 };
    217 
    218 
    219 /**
    220  * Wrapper around all compiler information collected for a method.
    221  * The information is of the form:
    222  * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
    223  */
    224 template <typename T>
    225 class CodeInfo {
    226  public:
    227   explicit CodeInfo(MemoryRegion region) : region_(region) {}
    228 
    229   StackMap<T> GetStackMapAt(size_t i) const {
    230     size_t size = StackMapSize();
    231     return StackMap<T>(GetStackMaps().Subregion(i * size, size));
    232   }
    233 
    234   uint32_t GetStackMaskSize() const {
    235     return region_.Load<uint32_t>(kStackMaskSizeOffset);
    236   }
    237 
    238   void SetStackMaskSize(uint32_t size) {
    239     region_.Store<uint32_t>(kStackMaskSizeOffset, size);
    240   }
    241 
    242   size_t GetNumberOfStackMaps() const {
    243     return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
    244   }
    245 
    246   void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
    247     region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
    248   }
    249 
    250   size_t StackMapSize() const {
    251     return StackMap<T>::kFixedSize + GetStackMaskSize();
    252   }
    253 
    254   DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) {
    255     uint32_t offset = stack_map.GetDexRegisterMapOffset();
    256     return DexRegisterMap(region_.Subregion(offset,
    257         DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
    258   }
    259 
    260   InlineInfo GetInlineInfoOf(StackMap<T> stack_map) {
    261     uint32_t offset = stack_map.GetInlineDescriptorOffset();
    262     uint8_t depth = region_.Load<uint8_t>(offset);
    263     return InlineInfo(region_.Subregion(offset,
    264         InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
    265   }
    266 
    267   StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) {
    268     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
    269       StackMap<T> stack_map = GetStackMapAt(i);
    270       if (stack_map.GetDexPc() == dex_pc) {
    271         return stack_map;
    272       }
    273     }
    274     LOG(FATAL) << "Unreachable";
    275     return StackMap<T>(MemoryRegion());
    276   }
    277 
    278   StackMap<T> GetStackMapForNativePc(T native_pc) {
    279     // TODO: stack maps are sorted by native pc, we can do a binary search.
    280     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
    281       StackMap<T> stack_map = GetStackMapAt(i);
    282       if (stack_map.GetNativePc() == native_pc) {
    283         return stack_map;
    284       }
    285     }
    286     LOG(FATAL) << "Unreachable";
    287     return StackMap<T>(MemoryRegion());
    288   }
    289 
    290  private:
    291   static constexpr int kNumberOfStackMapsOffset = 0;
    292   static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
    293   static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
    294 
    295   MemoryRegion GetStackMaps() const {
    296     return region_.size() == 0
    297         ? MemoryRegion()
    298         : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
    299   }
    300 
    301   MemoryRegion region_;
    302   template<typename U> friend class StackMapStream;
    303 };
    304 
    305 }  // namespace art
    306 
    307 #endif  // ART_RUNTIME_STACK_MAP_H_
    308