Show stack maps and Dex register maps in oatdump's assembly code.
Stack maps and Dex register maps are not longer displayed
in CodeInfo sections, unless `--dump:code_info_stack_maps'
is passed to oatdump.
Change-Id: Id82adb406d7e56cda27df8e5a8bd328a88b9ee11
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 04f5a6a..0c3061a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -304,6 +304,7 @@
OatDumperOptions(bool dump_raw_mapping_table,
bool dump_raw_gc_map,
bool dump_vmap,
+ bool dump_code_info_stack_maps,
bool disassemble_code,
bool absolute_addresses,
const char* class_filter,
@@ -315,6 +316,7 @@
: dump_raw_mapping_table_(dump_raw_mapping_table),
dump_raw_gc_map_(dump_raw_gc_map),
dump_vmap_(dump_vmap),
+ dump_code_info_stack_maps_(dump_code_info_stack_maps),
disassemble_code_(disassemble_code),
absolute_addresses_(absolute_addresses),
class_filter_(class_filter),
@@ -328,6 +330,7 @@
const bool dump_raw_mapping_table_;
const bool dump_raw_gc_map_;
const bool dump_vmap_;
+ const bool dump_code_info_stack_maps_;
const bool disassemble_code_;
const bool absolute_addresses_;
const char* const class_filter_;
@@ -1011,15 +1014,13 @@
void DumpVmapData(std::ostream& os,
const OatFile::OatMethod& oat_method,
const DexFile::CodeItem* code_item) {
- if (oat_method.GetGcMap() == nullptr) {
- // If the native GC map is null, then this method has been
- // compiled with the optimizing compiler. The optimizing
- // compiler currently outputs its stack maps in the vmap table.
+ if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+ // The optimizing compiler outputs its CodeInfo data in the vmap table.
const void* raw_code_info = oat_method.GetVmapTable();
if (raw_code_info != nullptr) {
CodeInfo code_info(raw_code_info);
DCHECK(code_item != nullptr);
- DumpCodeInfo(os, code_info, *code_item);
+ DumpCodeInfo(os, code_info, oat_method, *code_item);
}
} else {
// Otherwise, display the vmap table.
@@ -1034,8 +1035,12 @@
// Display a CodeInfo object emitted by the optimizing compiler.
void DumpCodeInfo(std::ostream& os,
const CodeInfo& code_info,
+ const OatFile::OatMethod& oat_method,
const DexFile::CodeItem& code_item) {
- code_info.Dump(os, code_item.registers_size_, true);
+ code_info.Dump(os,
+ oat_method.GetCodeOffset(),
+ code_item.registers_size_,
+ options_.dump_code_info_stack_maps_);
}
// Display a vmap table.
@@ -1198,6 +1203,23 @@
}
}
+ uint32_t DumpInformationAtOffset(std::ostream& os,
+ const OatFile::OatMethod& oat_method,
+ const DexFile::CodeItem* code_item,
+ size_t offset,
+ bool suspend_point_mapping) {
+ if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+ if (suspend_point_mapping) {
+ DumpDexRegisterMapAtOffset(os, oat_method, code_item, offset);
+ }
+ // The return value is not used in the case of a method compiled
+ // with the optimizing compiler.
+ return DexFile::kDexNoIndex;
+ } else {
+ return DumpMappingAtOffset(os, oat_method, offset, suspend_point_mapping);
+ }
+ }
+
uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
size_t offset, bool suspend_point_mapping) {
MappingTable table(oat_method.GetMappingTable());
@@ -1300,6 +1322,35 @@
}
}
+ // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
+ // the optimizing compiler?
+ static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
+ const DexFile::CodeItem* code_item) {
+ // If the native GC map is null and the Dex `code_item` is not
+ // null, then this method has been compiled with the optimizing
+ // compiler.
+ return oat_method.GetGcMap() == nullptr && code_item != nullptr;
+ }
+
+ void DumpDexRegisterMapAtOffset(std::ostream& os,
+ const OatFile::OatMethod& oat_method,
+ const DexFile::CodeItem* code_item,
+ size_t offset) {
+ // This method is only relevant for oat methods compiled with the
+ // optimizing compiler.
+ DCHECK(IsMethodGeneratedByOptimizingCompiler(oat_method, code_item));
+
+ // The optimizing compiler outputs its CodeInfo data in the vmap table.
+ const void* raw_code_info = oat_method.GetVmapTable();
+ if (raw_code_info != nullptr) {
+ CodeInfo code_info(raw_code_info);
+ StackMap stack_map = code_info.GetStackMapForNativePcOffset(offset);
+ if (stack_map.IsValid()) {
+ stack_map.Dump(os, code_info, oat_method.GetCodeOffset(), code_item->registers_size_);
+ }
+ }
+ }
+
verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
const DexFile* dex_file,
const DexFile::ClassDef& class_def,
@@ -1338,11 +1389,11 @@
size_t offset = 0;
while (offset < code_size) {
if (!bad_input) {
- DumpMappingAtOffset(os, oat_method, offset, false);
+ DumpInformationAtOffset(os, oat_method, code_item, offset, false);
}
offset += disassembler_->Dump(os, quick_native_pc + offset);
if (!bad_input) {
- uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
+ uint32_t dex_pc = DumpInformationAtOffset(os, oat_method, code_item, offset, true);
if (dex_pc != DexFile::kDexNoIndex) {
DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
if (verifier != nullptr) {
@@ -2229,6 +2280,8 @@
dump_raw_gc_map_ = true;
} else if (option == "--no-dump:vmap") {
dump_vmap_ = false;
+ } else if (option =="--dump:code_info_stack_maps") {
+ dump_code_info_stack_maps_ = true;
} else if (option == "--no-disassemble") {
disassemble_code_ = false;
} else if (option.starts_with("--symbolize=")) {
@@ -2308,6 +2361,9 @@
" --no-dump:vmap may be used to disable vmap dumping.\n"
" Example: --no-dump:vmap\n"
"\n"
+ " --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
+ " Example: --dump:code_info_stack_maps\n"
+ "\n"
" --no-disassemble may be used to disable disassembly.\n"
" Example: --no-disassemble\n"
"\n"
@@ -2348,6 +2404,7 @@
bool dump_raw_mapping_table_ = false;
bool dump_raw_gc_map_ = false;
bool dump_vmap_ = true;
+ bool dump_code_info_stack_maps_ = false;
bool disassemble_code_ = true;
bool symbolize_ = false;
bool list_classes_ = false;
@@ -2367,6 +2424,7 @@
args_->dump_raw_mapping_table_,
args_->dump_raw_gc_map_,
args_->dump_vmap_,
+ args_->dump_code_info_stack_maps_,
args_->disassemble_code_,
absolute_addresses,
args_->class_filter_,
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index c36ee05..a64071f 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -212,38 +212,8 @@
<< " (" << location.GetValue() << ")" << suffix << '\n';
}
-void CodeInfo::DumpStackMap(std::ostream& os,
- size_t stack_map_num,
- uint16_t number_of_dex_registers) const {
- StackMap stack_map = GetStackMapAt(stack_map_num);
- DumpStackMapHeader(os, stack_map_num);
- if (stack_map.HasDexRegisterMap(*this)) {
- DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
- dex_register_map.Dump(os, *this, number_of_dex_registers);
- }
-}
-
-void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
- StackMap stack_map = GetStackMapAt(stack_map_num);
- Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
- std::ostream indented_os(&indent_filter);
- indented_os << "StackMap " << stack_map_num
- << std::hex
- << " (dex_pc=0x" << stack_map.GetDexPc(*this)
- << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
- << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
- << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
- << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
- << std::dec
- << ", stack_mask=0b";
- MemoryRegion stack_mask = stack_map.GetStackMask(*this);
- for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
- indented_os << stack_mask.LoadBit(e - i - 1);
- }
- indented_os << ")\n";
-};
-
void CodeInfo::Dump(std::ostream& os,
+ uint32_t code_offset,
uint16_t number_of_dex_registers,
bool dump_stack_maps) const {
uint32_t code_info_size = GetOverallSize();
@@ -265,7 +235,9 @@
// Display stack maps along with (live) Dex register maps.
if (dump_stack_maps) {
for (size_t i = 0; i < number_of_stack_maps; ++i) {
- DumpStackMap(indented_os, i, number_of_dex_registers);
+ StackMap stack_map = GetStackMapAt(i);
+ stack_map.Dump(
+ indented_os, *this, code_offset, number_of_dex_registers, " " + std::to_string(i));
}
}
// TODO: Dump the stack map's inline information? We need to know more from the caller:
@@ -307,6 +279,34 @@
}
}
+void StackMap::Dump(std::ostream& os,
+ const CodeInfo& code_info,
+ uint32_t code_offset,
+ uint16_t number_of_dex_registers,
+ const std::string& header_suffix) const {
+ Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+ std::ostream indented_os(&indent_filter);
+ indented_os << "StackMap" << header_suffix
+ << std::hex
+ << " [native_pc=0x" << code_offset + GetNativePcOffset(code_info) << "]"
+ << " (dex_pc=0x" << GetDexPc(code_info)
+ << ", native_pc_offset=0x" << GetNativePcOffset(code_info)
+ << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(code_info)
+ << ", inline_info_offset=0x" << GetInlineDescriptorOffset(code_info)
+ << ", register_mask=0x" << GetRegisterMask(code_info)
+ << std::dec
+ << ", stack_mask=0b";
+ MemoryRegion stack_mask = GetStackMask(code_info);
+ for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
+ indented_os << stack_mask.LoadBit(e - i - 1);
+ }
+ indented_os << ")\n";
+ if (HasDexRegisterMap(code_info)) {
+ DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(*this, number_of_dex_registers);
+ dex_register_map.Dump(os, code_info, number_of_dex_registers);
+ }
+}
+
void InlineInfo::Dump(std::ostream& os,
const CodeInfo& code_info,
uint16_t number_of_dex_registers[]) const {
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index eefdaa7..f17fe1b 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -696,6 +696,12 @@
size_t native_pc_max,
size_t register_mask_max);
+ void Dump(std::ostream& os,
+ const CodeInfo& code_info,
+ uint32_t code_offset,
+ uint16_t number_of_dex_registers,
+ const std::string& header_suffix = "") const;
+
// Special (invalid) offset for the DexRegisterMapOffset field meaning
// that there is no Dex register map for this stack map.
static constexpr uint32_t kNoDexRegisterMap = -1;
@@ -1048,16 +1054,15 @@
return StackMap();
}
- // Dump this CodeInfo object on `os`. If `dump_stack_maps` is true,
- // also dump the stack maps and the associated Dex register maps.
- void Dump(std::ostream& os, uint16_t number_of_dex_registers, bool dump_stack_maps) const;
-
- // Dump stack map number `stack_map_num` as well as associated data on `os`,
- // such as Dex register locations.
- void DumpStackMap(std::ostream& os, size_t stack_map_num, uint16_t number_of_dex_registers) const;
- // Dump the header of stack map number `stack_map_num` on `os`, without
- // associated data.
- void DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const;
+ // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
+ // native PC of the compiled method and `number_of_dex_registers` the
+ // number of Dex virtual registers used in this method. If
+ // `dump_stack_maps` is true, also dump the stack maps and the
+ // associated Dex register maps.
+ void Dump(std::ostream& os,
+ uint32_t code_offset,
+ uint16_t number_of_dex_registers,
+ bool dump_stack_maps) const;
private:
// TODO: Instead of plain types such as "uint32_t", introduce