Rewrite dex register map encoding in stackmaps.
Simplify code by encoding dex register maps using BitTables.
The overall design is unchanged (bitmask+indices+catalogue).
This CL saves ~0.4% of .oat file size.
The dex register map decoding is factor of 3 faster now
(based on the time to verify the register maps on Arm).
This is not too surprising as the old version was O(n^2).
It also reduces compiler arena memory usage by 11% since the
BitTableBuilder is more memory efficient, we store less
intermediate data, and we deduplicate most data on the fly.
Test: test-art-host-gtest-stack_map_test
Change-Id: Ib703a5ddf7f581280522d589e4a2bfebe53c26a9
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 61fe2e7..923bb35 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -16,6 +16,7 @@
#include "stack_map.h"
+#include <iomanip>
#include <stdint.h>
#include "art_method.h"
@@ -24,149 +25,102 @@
namespace art {
-constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
-
-std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) {
+std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg) {
using Kind = DexRegisterLocation::Kind;
- switch (kind) {
+ switch (reg.GetKind()) {
case Kind::kNone:
- return stream << "none";
+ return stream << "None";
case Kind::kInStack:
- return stream << "in stack";
+ return stream << "sp+" << reg.GetValue();
case Kind::kInRegister:
- return stream << "in register";
+ return stream << "r" << reg.GetValue();
case Kind::kInRegisterHigh:
- return stream << "in register high";
+ return stream << "r" << reg.GetValue() << "/hi";
case Kind::kInFpuRegister:
- return stream << "in fpu register";
+ return stream << "f" << reg.GetValue();
case Kind::kInFpuRegisterHigh:
- return stream << "in fpu register high";
+ return stream << "f" << reg.GetValue() << "/hi";
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 << "#" << reg.GetValue();
+ default:
+ return stream << "DexRegisterLocation(" << static_cast<uint32_t>(reg.GetKind())
+ << "," << reg.GetValue() << ")";
}
- return stream << "Kind<" << static_cast<uint32_t>(kind) << ">";
}
-DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(
- uint16_t dex_register_number) const {
- DexRegisterLocationCatalog dex_register_location_catalog =
- code_info_.GetDexRegisterLocationCatalog();
- size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
- dex_register_number,
- code_info_.GetNumberOfLocationCatalogEntries());
- return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index);
+static void DumpDexRegisterMap(VariableIndentationOutputStream* vios,
+ const DexRegisterMap& map) {
+ if (map.IsValid()) {
+ ScopedIndentation indent1(vios);
+ for (size_t i = 0; i < map.size(); ++i) {
+ if (map.IsDexRegisterLive(i)) {
+ vios->Stream() << "v" << i << ":" << map.Get(i) << " ";
+ }
+ }
+ vios->Stream() << "\n";
+ }
}
-DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number) const {
- DexRegisterLocationCatalog dex_register_location_catalog =
- code_info_.GetDexRegisterLocationCatalog();
- size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
- dex_register_number,
- code_info_.GetNumberOfLocationCatalogEntries());
- 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 StackMap::DumpEncoding(const BitTable<6>& table,
- VariableIndentationOutputStream* vios) {
- vios->Stream()
- << "StackMapEncoding"
- << " (PackedNativePcBits=" << table.NumColumnBits(kPackedNativePc)
- << ", DexPcBits=" << table.NumColumnBits(kDexPc)
- << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset)
- << ", InlineInfoIndexBits=" << table.NumColumnBits(kInlineInfoIndex)
- << ", RegisterMaskIndexBits=" << table.NumColumnBits(kRegisterMaskIndex)
- << ", StackMaskIndexBits=" << table.NumColumnBits(kStackMaskIndex)
- << ")\n";
-}
-
-void InlineInfo::DumpEncoding(const BitTable<5>& table,
- VariableIndentationOutputStream* vios) {
- vios->Stream()
- << "InlineInfoEncoding"
- << " (IsLastBits=" << table.NumColumnBits(kIsLast)
- << ", MethodIndexIdxBits=" << table.NumColumnBits(kMethodIndexIdx)
- << ", DexPcBits=" << table.NumColumnBits(kDexPc)
- << ", ExtraDataBits=" << table.NumColumnBits(kExtraData)
- << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset)
- << ")\n";
+template<uint32_t kNumColumns>
+static void DumpTable(VariableIndentationOutputStream* vios,
+ const char* table_name,
+ const BitTable<kNumColumns>& table,
+ bool verbose,
+ bool is_mask = false) {
+ if (table.NumRows() != 0) {
+ vios->Stream() << table_name << " BitSize=" << table.NumRows() * table.NumRowBits();
+ vios->Stream() << " Rows=" << table.NumRows() << " Bits={";
+ for (size_t c = 0; c < table.NumColumns(); c++) {
+ vios->Stream() << (c != 0 ? " " : "");
+ vios->Stream() << table.NumColumnBits(c);
+ }
+ vios->Stream() << "}\n";
+ if (verbose) {
+ ScopedIndentation indent1(vios);
+ for (size_t r = 0; r < table.NumRows(); r++) {
+ vios->Stream() << "[" << std::right << std::setw(3) << r << "]={";
+ for (size_t c = 0; c < table.NumColumns(); c++) {
+ vios->Stream() << (c != 0 ? " " : "");
+ if (is_mask) {
+ BitMemoryRegion bits = table.GetBitMemoryRegion(r, c);
+ for (size_t b = 0, e = bits.size_in_bits(); b < e; b++) {
+ vios->Stream() << bits.LoadBit(e - b - 1);
+ }
+ } else {
+ vios->Stream() << std::right << std::setw(8) << static_cast<int32_t>(table.Get(r, c));
+ }
+ }
+ vios->Stream() << "}\n";
+ }
+ }
+ }
}
void CodeInfo::Dump(VariableIndentationOutputStream* vios,
uint32_t code_offset,
- uint16_t number_of_dex_registers,
- bool dump_stack_maps,
+ uint16_t num_dex_registers,
+ bool verbose,
InstructionSet instruction_set,
const MethodInfo& method_info) const {
- size_t number_of_stack_maps = GetNumberOfStackMaps();
vios->Stream()
- << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers
- << ", number_of_stack_maps=" << number_of_stack_maps
- << ")\n";
+ << "CodeInfo"
+ << " BitSize=" << size_ * kBitsPerByte
+ << "\n";
ScopedIndentation indent1(vios);
- StackMap::DumpEncoding(stack_maps_, vios);
- if (HasInlineInfo()) {
- InlineInfo::DumpEncoding(inline_infos_, vios);
- }
- // Display the Dex register location catalog.
- GetDexRegisterLocationCatalog().Dump(vios, *this);
+ DumpTable(vios, "StackMaps", stack_maps_, verbose);
+ DumpTable(vios, "RegisterMasks", register_masks_, verbose);
+ DumpTable(vios, "StackMasks", stack_masks_, verbose, true /* is_mask */);
+ DumpTable(vios, "InvokeInfos", invoke_infos_, verbose);
+ DumpTable(vios, "InlineInfos", inline_infos_, verbose);
+ DumpTable(vios, "DexRegisterMasks", dex_register_masks_, verbose, true /* is_mask */);
+ DumpTable(vios, "DexRegisterMaps", dex_register_maps_, verbose);
+ DumpTable(vios, "DexRegisterCatalog", dex_register_catalog_, verbose);
+
// Display stack maps along with (live) Dex register maps.
- if (dump_stack_maps) {
- for (size_t i = 0; i < number_of_stack_maps; ++i) {
+ if (verbose) {
+ for (size_t i = 0; i < GetNumberOfStackMaps(); ++i) {
StackMap stack_map = GetStackMapAt(i);
- stack_map.Dump(vios,
- *this,
- 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) {
- size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries();
- size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize();
- 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 {
- size_t number_of_location_catalog_entries = code_info_.GetNumberOfLocationCatalogEntries();
- // 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_location_catalog_entries);
- DexRegisterLocation location = GetDexRegisterLocation(j);
- ScopedIndentation indent1(vios);
- DumpRegisterMapping(
- vios->Stream(), j, location, "v",
- "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
+ stack_map.Dump(vios, *this, method_info, code_offset, num_dex_registers, instruction_set);
}
}
}
@@ -176,17 +130,13 @@
const MethodInfo& method_info,
uint32_t code_offset,
uint16_t number_of_dex_registers,
- InstructionSet instruction_set,
- const std::string& header_suffix) const {
+ InstructionSet instruction_set) const {
const uint32_t pc_offset = GetNativePcOffset(instruction_set);
vios->Stream()
- << "StackMap" << header_suffix
+ << "StackMap[" << Row() << "]"
<< std::hex
- << " [native_pc=0x" << code_offset + pc_offset << "]"
- << " (dex_pc=0x" << GetDexPc()
- << ", native_pc_offset=0x" << pc_offset
- << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset()
- << ", inline_info_offset=0x" << GetInlineInfoIndex()
+ << " (native_pc=0x" << code_offset + pc_offset
+ << ", dex_pc=0x" << GetDexPc()
<< ", register_mask=0x" << code_info.GetRegisterMaskOf(*this)
<< std::dec
<< ", stack_mask=0b";
@@ -195,11 +145,7 @@
vios->Stream() << stack_mask.LoadBit(e - i - 1);
}
vios->Stream() << ")\n";
- if (HasDexRegisterMap()) {
- DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
- *this, number_of_dex_registers);
- dex_register_map.Dump(vios);
- }
+ DumpDexRegisterMap(vios, code_info.GetDexRegisterMapOf(*this, number_of_dex_registers));
if (HasInlineInfo()) {
InlineInfo inline_info = code_info.GetInlineInfoOf(*this);
// We do not know the length of the dex register maps of inlined frames
@@ -213,15 +159,12 @@
const CodeInfo& code_info,
const MethodInfo& method_info,
uint16_t number_of_dex_registers[]) const {
- vios->Stream() << "InlineInfo with depth "
- << static_cast<uint32_t>(GetDepth())
- << "\n";
-
for (size_t i = 0; i < GetDepth(); ++i) {
vios->Stream()
- << " At depth " << i
+ << "InlineInfo[" << Row() + i << "]"
+ << " (depth=" << i
<< std::hex
- << " (dex_pc=0x" << GetDexPcAtDepth(i);
+ << ", dex_pc=0x" << GetDexPcAtDepth(i);
if (EncodesArtMethodAtDepth(i)) {
ScopedObjectAccess soa(Thread::Current());
vios->Stream() << ", method=" << GetArtMethodAtDepth(i)->PrettyMethod();
@@ -231,11 +174,9 @@
<< ", method_index=" << GetMethodIndexAtDepth(method_info, i);
}
vios->Stream() << ")\n";
- if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
- DexRegisterMap dex_register_map =
- code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]);
- ScopedIndentation indent1(vios);
- dex_register_map.Dump(vios);
+ if (number_of_dex_registers != nullptr) {
+ uint16_t vregs = number_of_dex_registers[i];
+ DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(i, *this, vregs));
}
}
}