265 lines
12 KiB
C++
265 lines
12 KiB
C++
/*
|
|
* 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 <stdint.h>
|
|
|
|
#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<uint32_t>(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<uint32_t>(kNativePcBitOffset)
|
|
<< ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
|
|
<< ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
|
|
<< ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_)
|
|
<< ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_index_bit_offset_)
|
|
<< ", stack_mask_index_bit_offset=" << static_cast<uint32_t>(stack_mask_index_bit_offset_)
|
|
<< ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
|
|
<< ")\n";
|
|
}
|
|
|
|
void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
|
|
vios->Stream()
|
|
<< "InlineInfoEncoding"
|
|
<< " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
|
|
<< ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
|
|
<< ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_)
|
|
<< ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
|
|
<< ", total_bit_size=" << static_cast<uint32_t>(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<int>(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<uint32_t>(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
|