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