Pack stack map entries on bit level to save space.
Use only the minimum number of bits required to store stack map data.
For example, if native_pc needs 5 bits and dex_pc needs 3 bits, they
will share the first byte of the stack map entry.
The header is changed to store bit offsets of the fields rather than
byte sizes. Offsets also make it easier to access later fields without
calculating sum of all previous sizes.
All of the header fields are byte sized or encoded as ULEB128 instead
of the previous fixed size encoding. This shrinks it by about half.
It saves 3.6 MB from non-debuggable boot.oat (AOSP).
It saves 3.1 MB from debuggable boot.oat (AOSP).
It saves 2.8 MB (of 99.4 MB) from /system/framework/arm/ (GOOG).
It saves 1.0 MB (of 27.8 MB) from /system/framework/oat/arm/ (GOOG).
Field loads from stackmaps seem to get around 10% faster.
(based on the time it takes to load all stackmap entries from boot.oat)
Bug: 27640410
Change-Id: I8bf0996b4eb24300c1b0dfc6e9d99fe85d04a1b7
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index 4712d47..9645643 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -98,12 +98,12 @@
// Get stack maps sorted by pc (they might not be sorted internally).
// TODO(dsrbecky) Remove this once stackmaps get sorted by pc.
const CodeInfo code_info(method_info->code_info);
- const StackMapEncoding encoding = code_info.ExtractEncoding();
+ const CodeInfoEncoding encoding = code_info.ExtractEncoding();
std::map<uint32_t, uint32_t> stack_maps; // low_pc -> stack_map_index.
- for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+ for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); s++) {
StackMap stack_map = code_info.GetStackMapAt(s, encoding);
DCHECK(stack_map.IsValid());
- if (!stack_map.HasDexRegisterMap(encoding)) {
+ if (!stack_map.HasDexRegisterMap(encoding.stack_map_encoding)) {
// The compiler creates stackmaps without register maps at the start of
// basic blocks in order to keep instruction-accurate line number mapping.
// However, we never stop at those (breakpoint locations always have map).
@@ -111,7 +111,7 @@
// The main reason for this is to save space by avoiding undefined gaps.
continue;
}
- const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding);
+ const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding.stack_map_encoding);
DCHECK_LE(pc_offset, method_info->code_size);
DCHECK_LE(compilation_unit_code_address, method_info->code_address);
const uint32_t low_pc = dchecked_integral_cast<uint32_t>(
@@ -135,7 +135,7 @@
}
// Check that the stack map is in the requested range.
- uint32_t dex_pc = stack_map.GetDexPc(encoding);
+ uint32_t dex_pc = stack_map.GetDexPc(encoding.stack_map_encoding);
if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
// The variable is not in scope at this PC. Therefore omit the entry.
// Note that this is different to None() entry which means in scope, but unknown location.