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 #include "art_method.h"
     22 #include "indenter.h"
     23 #include "scoped_thread_state_change-inl.h"
     24 
     25 namespace art {
     26 
     27 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
     28 constexpr uint32_t StackMap::kNoDexRegisterMap;
     29 constexpr uint32_t StackMap::kNoInlineInfo;
     30 
     31 std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) {
     32   using Kind = DexRegisterLocation::Kind;
     33   switch (kind) {
     34     case Kind::kNone:
     35       return stream << "none";
     36     case Kind::kInStack:
     37       return stream << "in stack";
     38     case Kind::kInRegister:
     39       return stream << "in register";
     40     case Kind::kInRegisterHigh:
     41       return stream << "in register high";
     42     case Kind::kInFpuRegister:
     43       return stream << "in fpu register";
     44     case Kind::kInFpuRegisterHigh:
     45       return stream << "in fpu register high";
     46     case Kind::kConstant:
     47       return stream << "as constant";
     48     case Kind::kInStackLargeOffset:
     49       return stream << "in stack (large offset)";
     50     case Kind::kConstantLargeValue:
     51       return stream << "as constant (large value)";
     52   }
     53   return stream << "Kind<" << static_cast<uint32_t>(kind) << ">";
     54 }
     55 
     56 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(
     57     uint16_t dex_register_number,
     58     uint16_t number_of_dex_registers,
     59     const CodeInfo& code_info,
     60     const CodeInfoEncoding& enc) const {
     61   DexRegisterLocationCatalog dex_register_location_catalog =
     62       code_info.GetDexRegisterLocationCatalog(enc);
     63   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
     64       dex_register_number,
     65       number_of_dex_registers,
     66       code_info.GetNumberOfLocationCatalogEntries(enc));
     67   return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
     68 }
     69 
     70 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
     71                                                            uint16_t number_of_dex_registers,
     72                                                            const CodeInfo& code_info,
     73                                                            const CodeInfoEncoding& enc) const {
     74   DexRegisterLocationCatalog dex_register_location_catalog =
     75       code_info.GetDexRegisterLocationCatalog(enc);
     76   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
     77       dex_register_number,
     78       number_of_dex_registers,
     79       code_info.GetNumberOfLocationCatalogEntries(enc));
     80   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
     81 }
     82 
     83 static void DumpRegisterMapping(std::ostream& os,
     84                                 size_t dex_register_num,
     85                                 DexRegisterLocation location,
     86                                 const std::string& prefix = "v",
     87                                 const std::string& suffix = "") {
     88   os << prefix << dex_register_num << ": "
     89      << location.GetInternalKind()
     90      << " (" << location.GetValue() << ")" << suffix << '\n';
     91 }
     92 
     93 void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const {
     94   vios->Stream()
     95       << "StackMapEncoding"
     96       << " (native_pc_bit_offset=" << static_cast<uint32_t>(kNativePcBitOffset)
     97       << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
     98       << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
     99       << ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_)
    100       << ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_index_bit_offset_)
    101       << ", stack_mask_index_bit_offset=" << static_cast<uint32_t>(stack_mask_index_bit_offset_)
    102       << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
    103       << ")\n";
    104 }
    105 
    106 void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
    107   vios->Stream()
    108       << "InlineInfoEncoding"
    109       << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
    110       << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
    111       << ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_)
    112       << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
    113       << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
    114       << ")\n";
    115 }
    116 
    117 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
    118                     uint32_t code_offset,
    119                     uint16_t number_of_dex_registers,
    120                     bool dump_stack_maps,
    121                     InstructionSet instruction_set,
    122                     const MethodInfo& method_info) const {
    123   CodeInfoEncoding encoding = ExtractEncoding();
    124   size_t number_of_stack_maps = GetNumberOfStackMaps(encoding);
    125   vios->Stream()
    126       << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers
    127       << ", number_of_stack_maps=" << number_of_stack_maps
    128       << ")\n";
    129   ScopedIndentation indent1(vios);
    130   encoding.stack_map.encoding.Dump(vios);
    131   if (HasInlineInfo(encoding)) {
    132     encoding.inline_info.encoding.Dump(vios);
    133   }
    134   // Display the Dex register location catalog.
    135   GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
    136   // Display stack maps along with (live) Dex register maps.
    137   if (dump_stack_maps) {
    138     for (size_t i = 0; i < number_of_stack_maps; ++i) {
    139       StackMap stack_map = GetStackMapAt(i, encoding);
    140       stack_map.Dump(vios,
    141                      *this,
    142                      encoding,
    143                      method_info,
    144                      code_offset,
    145                      number_of_dex_registers,
    146                      instruction_set,
    147                      " " + std::to_string(i));
    148     }
    149   }
    150   // TODO: Dump the stack map's inline information? We need to know more from the caller:
    151   //       we need to know the number of dex registers for each inlined method.
    152 }
    153 
    154 void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
    155                                       const CodeInfo& code_info) {
    156   CodeInfoEncoding encoding = code_info.ExtractEncoding();
    157   size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
    158   size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
    159   vios->Stream()
    160       << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
    161       << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
    162   for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
    163     DexRegisterLocation location = GetDexRegisterLocation(i);
    164     ScopedIndentation indent1(vios);
    165     DumpRegisterMapping(vios->Stream(), i, location, "entry ");
    166   }
    167 }
    168 
    169 void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
    170                           const CodeInfo& code_info,
    171                           uint16_t number_of_dex_registers) const {
    172   CodeInfoEncoding encoding = code_info.ExtractEncoding();
    173   size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding);
    174   // TODO: Display the bit mask of live Dex registers.
    175   for (size_t j = 0; j < number_of_dex_registers; ++j) {
    176     if (IsDexRegisterLive(j)) {
    177       size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
    178           j, number_of_dex_registers, number_of_location_catalog_entries);
    179       DexRegisterLocation location = GetDexRegisterLocation(j,
    180                                                             number_of_dex_registers,
    181                                                             code_info,
    182                                                             encoding);
    183       ScopedIndentation indent1(vios);
    184       DumpRegisterMapping(
    185           vios->Stream(), j, location, "v",
    186           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
    187     }
    188   }
    189 }
    190 
    191 void StackMap::Dump(VariableIndentationOutputStream* vios,
    192                     const CodeInfo& code_info,
    193                     const CodeInfoEncoding& encoding,
    194                     const MethodInfo& method_info,
    195                     uint32_t code_offset,
    196                     uint16_t number_of_dex_registers,
    197                     InstructionSet instruction_set,
    198                     const std::string& header_suffix) const {
    199   StackMapEncoding stack_map_encoding = encoding.stack_map.encoding;
    200   const uint32_t pc_offset = GetNativePcOffset(stack_map_encoding, instruction_set);
    201   vios->Stream()
    202       << "StackMap" << header_suffix
    203       << std::hex
    204       << " [native_pc=0x" << code_offset + pc_offset << "]"
    205       << " [entry_size=0x" << encoding.stack_map.encoding.BitSize() << " bits]"
    206       << " (dex_pc=0x" << GetDexPc(stack_map_encoding)
    207       << ", native_pc_offset=0x" << pc_offset
    208       << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding)
    209       << ", inline_info_offset=0x" << GetInlineInfoIndex(stack_map_encoding)
    210       << ", register_mask=0x" << code_info.GetRegisterMaskOf(encoding, *this)
    211       << std::dec
    212       << ", stack_mask=0b";
    213   BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, *this);
    214   for (size_t i = 0, e = encoding.stack_mask.encoding.BitSize(); i < e; ++i) {
    215     vios->Stream() << stack_mask.LoadBit(e - i - 1);
    216   }
    217   vios->Stream() << ")\n";
    218   if (HasDexRegisterMap(stack_map_encoding)) {
    219     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
    220         *this, encoding, number_of_dex_registers);
    221     dex_register_map.Dump(vios, code_info, number_of_dex_registers);
    222   }
    223   if (HasInlineInfo(stack_map_encoding)) {
    224     InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
    225     // We do not know the length of the dex register maps of inlined frames
    226     // at this level, so we just pass null to `InlineInfo::Dump` to tell
    227     // it not to look at these maps.
    228     inline_info.Dump(vios, code_info, method_info, nullptr);
    229   }
    230 }
    231 
    232 void InlineInfo::Dump(VariableIndentationOutputStream* vios,
    233                       const CodeInfo& code_info,
    234                       const MethodInfo& method_info,
    235                       uint16_t number_of_dex_registers[]) const {
    236   InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info.encoding;
    237   vios->Stream() << "InlineInfo with depth "
    238                  << static_cast<uint32_t>(GetDepth(inline_info_encoding))
    239                  << "\n";
    240 
    241   for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) {
    242     vios->Stream()
    243         << " At depth " << i
    244         << std::hex
    245         << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i);
    246     if (EncodesArtMethodAtDepth(inline_info_encoding, i)) {
    247       ScopedObjectAccess soa(Thread::Current());
    248       vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod();
    249     } else {
    250       vios->Stream()
    251           << std::dec
    252           << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, method_info, i);
    253     }
    254     vios->Stream() << ")\n";
    255     if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
    256       CodeInfoEncoding encoding = code_info.ExtractEncoding();
    257       DexRegisterMap dex_register_map =
    258           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
    259       ScopedIndentation indent1(vios);
    260       dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
    261     }
    262   }
    263 }
    264 
    265 }  // namespace art
    266