Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2015 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 #include "stack_map.h"
     18 
     19 #include <stdint.h>
     20 
     21 namespace art {
     22 
     23 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
     24 constexpr uint32_t StackMap::kNoDexRegisterMap;
     25 constexpr uint32_t StackMap::kNoInlineInfo;
     26 
     27 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number,
     28                                                                   uint16_t number_of_dex_registers,
     29                                                                   const CodeInfo& code_info) const {
     30   DexRegisterLocationCatalog dex_register_location_catalog =
     31       code_info.GetDexRegisterLocationCatalog();
     32   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
     33       dex_register_number,
     34       number_of_dex_registers,
     35       code_info.GetNumberOfDexRegisterLocationCatalogEntries());
     36   return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
     37 }
     38 
     39 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
     40                                                            uint16_t number_of_dex_registers,
     41                                                            const CodeInfo& code_info) const {
     42   DexRegisterLocationCatalog dex_register_location_catalog =
     43       code_info.GetDexRegisterLocationCatalog();
     44   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
     45       dex_register_number,
     46       number_of_dex_registers,
     47       code_info.GetNumberOfDexRegisterLocationCatalogEntries());
     48   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
     49 }
     50 
     51 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
     52 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
     53 static uint32_t LoadAt(MemoryRegion region,
     54                        size_t number_of_bytes,
     55                        size_t offset,
     56                        bool check_max = false) {
     57   if (number_of_bytes == 0u) {
     58     DCHECK(!check_max);
     59     return 0;
     60   } else if (number_of_bytes == 1u) {
     61     uint8_t value = region.LoadUnaligned<uint8_t>(offset);
     62     if (check_max && value == 0xFF) {
     63       return -1;
     64     } else {
     65       return value;
     66     }
     67   } else if (number_of_bytes == 2u) {
     68     uint16_t value = region.LoadUnaligned<uint16_t>(offset);
     69     if (check_max && value == 0xFFFF) {
     70       return -1;
     71     } else {
     72       return value;
     73     }
     74   } else if (number_of_bytes == 3u) {
     75     uint16_t low = region.LoadUnaligned<uint16_t>(offset);
     76     uint16_t high = region.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
     77     uint32_t value = (high << 16) + low;
     78     if (check_max && value == 0xFFFFFF) {
     79       return -1;
     80     } else {
     81       return value;
     82     }
     83   } else {
     84     DCHECK_EQ(number_of_bytes, 4u);
     85     return region.LoadUnaligned<uint32_t>(offset);
     86   }
     87 }
     88 
     89 static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) {
     90   if (number_of_bytes == 0u) {
     91     DCHECK_EQ(value, 0u);
     92   } else if (number_of_bytes == 1u) {
     93     region.StoreUnaligned<uint8_t>(offset, value);
     94   } else if (number_of_bytes == 2u) {
     95     region.StoreUnaligned<uint16_t>(offset, value);
     96   } else if (number_of_bytes == 3u) {
     97     region.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
     98     region.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
     99   } else {
    100     region.StoreUnaligned<uint32_t>(offset, value);
    101     DCHECK_EQ(number_of_bytes, 4u);
    102   }
    103 }
    104 
    105 uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
    106   return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
    107 }
    108 
    109 void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
    110   StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
    111 }
    112 
    113 uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
    114   return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
    115 }
    116 
    117 void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
    118   StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
    119 }
    120 
    121 uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
    122   return LoadAt(region_,
    123                 info.NumberOfBytesForDexRegisterMap(),
    124                 info.ComputeStackMapDexRegisterMapOffset(),
    125                 /* check_max */ true);
    126 }
    127 
    128 void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
    129   StoreAt(region_,
    130           info.NumberOfBytesForDexRegisterMap(),
    131           info.ComputeStackMapDexRegisterMapOffset(),
    132           offset);
    133 }
    134 
    135 uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const {
    136   if (!info.HasInlineInfo()) return kNoInlineInfo;
    137   return LoadAt(region_,
    138                 info.NumberOfBytesForInlineInfo(),
    139                 info.ComputeStackMapInlineInfoOffset(),
    140                 /* check_max */ true);
    141 }
    142 
    143 void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) {
    144   DCHECK(info.HasInlineInfo());
    145   StoreAt(region_,
    146           info.NumberOfBytesForInlineInfo(),
    147           info.ComputeStackMapInlineInfoOffset(),
    148           offset);
    149 }
    150 
    151 uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
    152   return LoadAt(region_,
    153                 info.NumberOfBytesForRegisterMask(),
    154                 info.ComputeStackMapRegisterMaskOffset());
    155 }
    156 
    157 void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
    158   StoreAt(region_,
    159           info.NumberOfBytesForRegisterMask(),
    160           info.ComputeStackMapRegisterMaskOffset(),
    161           mask);
    162 }
    163 
    164 size_t StackMap::ComputeStackMapSizeInternal(size_t stack_mask_size,
    165                                              size_t number_of_bytes_for_inline_info,
    166                                              size_t number_of_bytes_for_dex_map,
    167                                              size_t number_of_bytes_for_dex_pc,
    168                                              size_t number_of_bytes_for_native_pc,
    169                                              size_t number_of_bytes_for_register_mask) {
    170   return stack_mask_size
    171       + number_of_bytes_for_inline_info
    172       + number_of_bytes_for_dex_map
    173       + number_of_bytes_for_dex_pc
    174       + number_of_bytes_for_native_pc
    175       + number_of_bytes_for_register_mask;
    176 }
    177 
    178 size_t StackMap::ComputeStackMapSize(size_t stack_mask_size,
    179                                      size_t inline_info_size,
    180                                      size_t dex_register_map_size,
    181                                      size_t dex_pc_max,
    182                                      size_t native_pc_max,
    183                                      size_t register_mask_max) {
    184   return ComputeStackMapSizeInternal(
    185       stack_mask_size,
    186       inline_info_size == 0
    187           ? 0
    188             // + 1 to also encode kNoInlineInfo.
    189           :  CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1),
    190       // + 1 to also encode kNoDexRegisterMap.
    191       CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1),
    192       CodeInfo::EncodingSizeInBytes(dex_pc_max),
    193       CodeInfo::EncodingSizeInBytes(native_pc_max),
    194       CodeInfo::EncodingSizeInBytes(register_mask_max));
    195 }
    196 
    197 MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
    198   return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
    199 }
    200 
    201 static void DumpRegisterMapping(std::ostream& os,
    202                                 size_t dex_register_num,
    203                                 DexRegisterLocation location,
    204                                 const std::string& prefix = "v",
    205                                 const std::string& suffix = "") {
    206   os << "      " << prefix << dex_register_num << ": "
    207      << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
    208      << " (" << location.GetValue() << ")" << suffix << '\n';
    209 }
    210 
    211 void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
    212   StackMap stack_map = GetStackMapAt(stack_map_num);
    213   os << "    StackMap " << stack_map_num
    214      << std::hex
    215      << " (dex_pc=0x" << stack_map.GetDexPc(*this)
    216      << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
    217      << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
    218      << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
    219      << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
    220      << std::dec
    221      << ", stack_mask=0b";
    222   MemoryRegion stack_mask = stack_map.GetStackMask(*this);
    223   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
    224     os << stack_mask.LoadBit(e - i - 1);
    225   }
    226   os << ")\n";
    227 };
    228 
    229 void CodeInfo::Dump(std::ostream& os, uint16_t number_of_dex_registers) const {
    230   uint32_t code_info_size = GetOverallSize();
    231   size_t number_of_stack_maps = GetNumberOfStackMaps();
    232   os << "  Optimized CodeInfo (size=" << code_info_size
    233      << ", number_of_dex_registers=" << number_of_dex_registers
    234      << ", number_of_stack_maps=" << number_of_stack_maps
    235      << ", has_inline_info=" << HasInlineInfo()
    236      << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
    237      << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
    238      << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
    239      << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
    240      << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
    241      << ")\n";
    242 
    243   // Display the Dex register location catalog.
    244   size_t number_of_location_catalog_entries = GetNumberOfDexRegisterLocationCatalogEntries();
    245   size_t location_catalog_size_in_bytes = GetDexRegisterLocationCatalogSize();
    246   os << "  DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
    247      << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
    248   DexRegisterLocationCatalog dex_register_location_catalog = GetDexRegisterLocationCatalog();
    249   for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
    250     DexRegisterLocation location = dex_register_location_catalog.GetDexRegisterLocation(i);
    251     DumpRegisterMapping(os, i, location, "entry ");
    252   }
    253 
    254   // Display stack maps along with (live) Dex register maps.
    255   for (size_t i = 0; i < number_of_stack_maps; ++i) {
    256     StackMap stack_map = GetStackMapAt(i);
    257     DumpStackMapHeader(os, i);
    258     if (stack_map.HasDexRegisterMap(*this)) {
    259       DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
    260       // TODO: Display the bit mask of live Dex registers.
    261       for (size_t j = 0; j < number_of_dex_registers; ++j) {
    262         if (dex_register_map.IsDexRegisterLive(j)) {
    263           size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex(
    264               j, number_of_dex_registers, number_of_location_catalog_entries);
    265           DexRegisterLocation location =
    266               dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this);
    267           DumpRegisterMapping(
    268               os, j, location, "v",
    269               "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
    270         }
    271       }
    272     }
    273   }
    274   // TODO: Dump the stack map's inline information.
    275 }
    276 
    277 }  // namespace art
    278