/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "stack_map.h" #include #include "art_method.h" #include "indenter.h" #include "scoped_thread_state_change-inl.h" namespace art { constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex; constexpr uint32_t StackMap::kNoDexRegisterMap; constexpr uint32_t StackMap::kNoInlineInfo; std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) { using Kind = DexRegisterLocation::Kind; switch (kind) { case Kind::kNone: return stream << "none"; case Kind::kInStack: return stream << "in stack"; case Kind::kInRegister: return stream << "in register"; case Kind::kInRegisterHigh: return stream << "in register high"; case Kind::kInFpuRegister: return stream << "in fpu register"; case Kind::kInFpuRegisterHigh: return stream << "in fpu register high"; case Kind::kConstant: return stream << "as constant"; case Kind::kInStackLargeOffset: return stream << "in stack (large offset)"; case Kind::kConstantLargeValue: return stream << "as constant (large value)"; } return stream << "Kind<" << static_cast(kind) << ">"; } DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind( uint16_t dex_register_number, uint16_t number_of_dex_registers, const CodeInfo& code_info, const CodeInfoEncoding& enc) const { DexRegisterLocationCatalog dex_register_location_catalog = code_info.GetDexRegisterLocationCatalog(enc); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, code_info.GetNumberOfLocationCatalogEntries(enc)); return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index); } DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number, uint16_t number_of_dex_registers, const CodeInfo& code_info, const CodeInfoEncoding& enc) const { DexRegisterLocationCatalog dex_register_location_catalog = code_info.GetDexRegisterLocationCatalog(enc); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, code_info.GetNumberOfLocationCatalogEntries(enc)); return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index); } static void DumpRegisterMapping(std::ostream& os, size_t dex_register_num, DexRegisterLocation location, const std::string& prefix = "v", const std::string& suffix = "") { os << prefix << dex_register_num << ": " << location.GetInternalKind() << " (" << location.GetValue() << ")" << suffix << '\n'; } void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const { vios->Stream() << "StackMapEncoding" << " (native_pc_bit_offset=" << static_cast(kNativePcBitOffset) << ", dex_pc_bit_offset=" << static_cast(dex_pc_bit_offset_) << ", dex_register_map_bit_offset=" << static_cast(dex_register_map_bit_offset_) << ", inline_info_bit_offset=" << static_cast(inline_info_bit_offset_) << ", register_mask_bit_offset=" << static_cast(register_mask_index_bit_offset_) << ", stack_mask_index_bit_offset=" << static_cast(stack_mask_index_bit_offset_) << ", total_bit_size=" << static_cast(total_bit_size_) << ")\n"; } void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const { vios->Stream() << "InlineInfoEncoding" << " (method_index_bit_offset=" << static_cast(kMethodIndexBitOffset) << ", dex_pc_bit_offset=" << static_cast(dex_pc_bit_offset_) << ", extra_data_bit_offset=" << static_cast(extra_data_bit_offset_) << ", dex_register_map_bit_offset=" << static_cast(dex_register_map_bit_offset_) << ", total_bit_size=" << static_cast(total_bit_size_) << ")\n"; } void CodeInfo::Dump(VariableIndentationOutputStream* vios, uint32_t code_offset, uint16_t number_of_dex_registers, bool dump_stack_maps, InstructionSet instruction_set, const MethodInfo& method_info) const { CodeInfoEncoding encoding = ExtractEncoding(); size_t number_of_stack_maps = GetNumberOfStackMaps(encoding); vios->Stream() << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers << ", number_of_stack_maps=" << number_of_stack_maps << ")\n"; ScopedIndentation indent1(vios); encoding.stack_map.encoding.Dump(vios); if (HasInlineInfo(encoding)) { encoding.inline_info.encoding.Dump(vios); } // Display the Dex register location catalog. GetDexRegisterLocationCatalog(encoding).Dump(vios, *this); // Display stack maps along with (live) Dex register maps. if (dump_stack_maps) { for (size_t i = 0; i < number_of_stack_maps; ++i) { StackMap stack_map = GetStackMapAt(i, encoding); stack_map.Dump(vios, *this, encoding, method_info, code_offset, number_of_dex_registers, instruction_set, " " + std::to_string(i)); } } // TODO: Dump the stack map's inline information? We need to know more from the caller: // we need to know the number of dex registers for each inlined method. } void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info) { CodeInfoEncoding encoding = code_info.ExtractEncoding(); size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding); vios->Stream() << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n"; for (size_t i = 0; i < number_of_location_catalog_entries; ++i) { DexRegisterLocation location = GetDexRegisterLocation(i); ScopedIndentation indent1(vios); DumpRegisterMapping(vios->Stream(), i, location, "entry "); } } void DexRegisterMap::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, uint16_t number_of_dex_registers) const { CodeInfoEncoding encoding = code_info.ExtractEncoding(); size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); // TODO: Display the bit mask of live Dex registers. for (size_t j = 0; j < number_of_dex_registers; ++j) { if (IsDexRegisterLive(j)) { size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( j, number_of_dex_registers, number_of_location_catalog_entries); DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, code_info, encoding); ScopedIndentation indent1(vios); DumpRegisterMapping( vios->Stream(), j, location, "v", "\t[entry " + std::to_string(static_cast(location_catalog_entry_index)) + "]"); } } } void StackMap::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, const CodeInfoEncoding& encoding, const MethodInfo& method_info, uint32_t code_offset, uint16_t number_of_dex_registers, InstructionSet instruction_set, const std::string& header_suffix) const { StackMapEncoding stack_map_encoding = encoding.stack_map.encoding; const uint32_t pc_offset = GetNativePcOffset(stack_map_encoding, instruction_set); vios->Stream() << "StackMap" << header_suffix << std::hex << " [native_pc=0x" << code_offset + pc_offset << "]" << " [entry_size=0x" << encoding.stack_map.encoding.BitSize() << " bits]" << " (dex_pc=0x" << GetDexPc(stack_map_encoding) << ", native_pc_offset=0x" << pc_offset << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding) << ", inline_info_offset=0x" << GetInlineInfoIndex(stack_map_encoding) << ", register_mask=0x" << code_info.GetRegisterMaskOf(encoding, *this) << std::dec << ", stack_mask=0b"; BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, *this); for (size_t i = 0, e = encoding.stack_mask.encoding.BitSize(); i < e; ++i) { vios->Stream() << stack_mask.LoadBit(e - i - 1); } vios->Stream() << ")\n"; if (HasDexRegisterMap(stack_map_encoding)) { DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf( *this, encoding, number_of_dex_registers); dex_register_map.Dump(vios, code_info, number_of_dex_registers); } if (HasInlineInfo(stack_map_encoding)) { InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding); // We do not know the length of the dex register maps of inlined frames // at this level, so we just pass null to `InlineInfo::Dump` to tell // it not to look at these maps. inline_info.Dump(vios, code_info, method_info, nullptr); } } void InlineInfo::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, const MethodInfo& method_info, uint16_t number_of_dex_registers[]) const { InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info.encoding; vios->Stream() << "InlineInfo with depth " << static_cast(GetDepth(inline_info_encoding)) << "\n"; for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) { vios->Stream() << " At depth " << i << std::hex << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i); if (EncodesArtMethodAtDepth(inline_info_encoding, i)) { ScopedObjectAccess soa(Thread::Current()); vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod(); } else { vios->Stream() << std::dec << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, method_info, i); } vios->Stream() << ")\n"; if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) { CodeInfoEncoding encoding = code_info.ExtractEncoding(); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]); ScopedIndentation indent1(vios); dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]); } } } } // namespace art