Deduplicate stackmaps at BitTable level.
Make it possible to share BitTables between CodeInfos.
This saves 1% of .oat file size.
Test: test-art-host-gtest
Change-Id: I14172cba6b65e734b94f8c232f24eeee1fc67113
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 62b9f35..e8746bc 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -31,6 +31,24 @@
: CodeInfo(header->GetOptimizedCodeInfoPtr(), flags) {
}
+template<typename Accessor>
+ALWAYS_INLINE static void DecodeTable(BitTable<Accessor>& table,
+ BitMemoryReader& reader,
+ const uint8_t* data) {
+ bool is_deduped = reader.ReadBit();
+ if (is_deduped) {
+ // 'data' points to the start of the reader's data.
+ uint32_t current_bit_offset = reader.GetBitOffset();
+ uint32_t bit_offset_backwards = DecodeVarintBits(reader) - current_bit_offset;
+ uint32_t byte_offset_backwards = BitsToBytesRoundUp(bit_offset_backwards);
+ BitMemoryReader reader2(data - byte_offset_backwards,
+ byte_offset_backwards * kBitsPerByte - bit_offset_backwards);
+ table.Decode(reader2);
+ } else {
+ table.Decode(reader);
+ }
+}
+
void CodeInfo::Decode(const uint8_t* data, DecodeFlags flags) {
const uint8_t* begin = data;
frame_size_in_bytes_ = DecodeUnsignedLeb128(&data);
@@ -38,19 +56,57 @@
fp_spill_mask_ = DecodeUnsignedLeb128(&data);
number_of_dex_registers_ = DecodeUnsignedLeb128(&data);
BitMemoryReader reader(data, /* bit_offset */ 0);
- stack_maps_.Decode(reader);
- inline_infos_.Decode(reader);
+ DecodeTable(stack_maps_, reader, data);
+ DecodeTable(inline_infos_, reader, data);
if (flags & DecodeFlags::InlineInfoOnly) {
return;
}
- register_masks_.Decode(reader);
- stack_masks_.Decode(reader);
- dex_register_masks_.Decode(reader);
- dex_register_maps_.Decode(reader);
- dex_register_catalog_.Decode(reader);
+ DecodeTable(register_masks_, reader, data);
+ DecodeTable(stack_masks_, reader, data);
+ DecodeTable(dex_register_masks_, reader, data);
+ DecodeTable(dex_register_maps_, reader, data);
+ DecodeTable(dex_register_catalog_, reader, data);
size_in_bits_ = (data - begin) * kBitsPerByte + reader.GetBitOffset();
}
+template<typename Accessor>
+ALWAYS_INLINE static void DedupeTable(BitMemoryWriter<std::vector<uint8_t>>& writer,
+ BitMemoryReader& reader,
+ CodeInfo::DedupeMap* dedupe_map) {
+ bool is_deduped = reader.ReadBit();
+ DCHECK(!is_deduped);
+ BitTable<Accessor> bit_table(reader);
+ BitMemoryRegion region = reader.Tail(bit_table.BitSize());
+ auto it = dedupe_map->insert(std::make_pair(region, writer.GetBitOffset() + 1 /* dedupe bit */));
+ if (it.second /* new bit table */ || region.size_in_bits() < 32) {
+ writer.WriteBit(false); // Is not deduped.
+ writer.WriteRegion(region);
+ } else {
+ writer.WriteBit(true); // Is deduped.
+ EncodeVarintBits(writer, writer.GetBitOffset() - it.first->second);
+ }
+}
+
+size_t CodeInfo::Dedupe(std::vector<uint8_t>* out, const uint8_t* in, DedupeMap* dedupe_map) {
+ // Remember the current offset in the output buffer so that we can return it later.
+ const size_t result = out->size();
+ // Copy the header which encodes QuickMethodFrameInfo.
+ EncodeUnsignedLeb128(out, DecodeUnsignedLeb128(&in));
+ EncodeUnsignedLeb128(out, DecodeUnsignedLeb128(&in));
+ EncodeUnsignedLeb128(out, DecodeUnsignedLeb128(&in));
+ EncodeUnsignedLeb128(out, DecodeUnsignedLeb128(&in));
+ BitMemoryReader reader(in, /* bit_offset */ 0);
+ BitMemoryWriter<std::vector<uint8_t>> writer(out, /* bit_offset */ out->size() * kBitsPerByte);
+ DedupeTable<StackMap>(writer, reader, dedupe_map);
+ DedupeTable<InlineInfo>(writer, reader, dedupe_map);
+ DedupeTable<RegisterMask>(writer, reader, dedupe_map);
+ DedupeTable<MaskInfo>(writer, reader, dedupe_map);
+ DedupeTable<MaskInfo>(writer, reader, dedupe_map);
+ DedupeTable<DexRegisterMapInfo>(writer, reader, dedupe_map);
+ DedupeTable<DexRegisterInfo>(writer, reader, dedupe_map);
+ return result;
+}
+
BitTable<StackMap>::const_iterator CodeInfo::BinarySearchNativePc(uint32_t packed_pc) const {
return std::partition_point(
stack_maps_.begin(),
@@ -217,10 +273,7 @@
bool verbose,
InstructionSet instruction_set,
const MethodInfo& method_info) const {
- vios->Stream()
- << "CodeInfo"
- << " BitSize=" << size_in_bits_
- << "\n";
+ vios->Stream() << "CodeInfo\n";
ScopedIndentation indent1(vios);
DumpTable<StackMap>(vios, "StackMaps", stack_maps_, verbose);
DumpTable<RegisterMask>(vios, "RegisterMasks", register_masks_, verbose);