Merge "Cleanup BitMemoryReader/Writer api."
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index a281bb3..d28f09f 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -750,9 +750,9 @@
ScopedArenaVector<uint8_t> memory = stream.Encode();
std::vector<uint8_t> out;
- CodeInfo::DedupeMap dedupe_map;
- size_t deduped1 = CodeInfo::Dedupe(&out, memory.data(), &dedupe_map);
- size_t deduped2 = CodeInfo::Dedupe(&out, memory.data(), &dedupe_map);
+ CodeInfo::Deduper deduper(&out);
+ size_t deduped1 = deduper.Dedupe(memory.data());
+ size_t deduped2 = deduper.Dedupe(memory.data());
for (size_t deduped : { deduped1, deduped2 }) {
CodeInfo code_info(out.data() + deduped);
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 28942da..8bac720 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -1438,10 +1438,10 @@
class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
public:
- static constexpr bool kDebugVerifyDedupedCodeInfo = false;
-
InitMapMethodVisitor(OatWriter* writer, size_t offset)
- : OatDexMethodVisitor(writer, offset) {}
+ : OatDexMethodVisitor(writer, offset),
+ dedupe_bit_table_(&writer_->code_info_data_) {
+ }
bool VisitMethod(size_t class_def_method_index,
const ClassAccessor::Method& method ATTRIBUTE_UNUSED)
@@ -1455,21 +1455,9 @@
ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
if (map.size() != 0u) {
- // Deduplicate the inner bittables within the CodeInfo.
- std::vector<uint8_t>* data = &writer_->code_info_data_;
size_t offset = dedupe_code_info_.GetOrCreate(map.data(), [=]() {
- size_t deduped_offset = CodeInfo::Dedupe(data, map.data(), &dedupe_bit_table_);
- if (kDebugVerifyDedupedCodeInfo) {
- InstructionSet isa = writer_->GetCompilerOptions().GetInstructionSet();
- std::stringstream old_code_info;
- VariableIndentationOutputStream old_vios(&old_code_info);
- std::stringstream new_code_info;
- VariableIndentationOutputStream new_vios(&new_code_info);
- CodeInfo(map.data()).Dump(&old_vios, 0, true, isa);
- CodeInfo(data->data() + deduped_offset).Dump(&new_vios, 0, true, isa);
- DCHECK_EQ(old_code_info.str(), new_code_info.str());
- }
- return offset_ + deduped_offset;
+ // Deduplicate the inner BitTable<>s within the CodeInfo.
+ return offset_ + dedupe_bit_table_.Dedupe(map.data());
});
// Code offset is not initialized yet, so set the map offset to 0u-offset.
DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
@@ -1487,8 +1475,8 @@
// The compiler already deduplicated the pointers but it did not dedupe the tables.
SafeMap<const uint8_t*, size_t> dedupe_code_info_;
- // Deduplicate at BitTable level. The value is bit offset within code_info_data_.
- std::map<BitMemoryRegion, uint32_t, BitMemoryRegion::Less> dedupe_bit_table_;
+ // Deduplicate at BitTable level.
+ CodeInfo::Deduper dedupe_bit_table_;
};
class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
@@ -2082,6 +2070,7 @@
InitMapMethodVisitor visitor(this, offset);
bool success = VisitDexMethods(&visitor);
DCHECK(success);
+ code_info_data_.shrink_to_fit();
offset += code_info_data_.size();
}
return offset;
diff --git a/libartbase/base/bit_memory_region.h b/libartbase/base/bit_memory_region.h
index 7d8de39..f9b643e 100644
--- a/libartbase/base/bit_memory_region.h
+++ b/libartbase/base/bit_memory_region.h
@@ -29,39 +29,26 @@
class BitMemoryRegion FINAL : public ValueObject {
public:
struct Less {
- constexpr bool operator()(const BitMemoryRegion& lhs, const BitMemoryRegion& rhs) const {
- if (lhs.size_in_bits() != rhs.size_in_bits()) {
- return lhs.size_in_bits() < rhs.size_in_bits();
- }
- size_t bit = 0;
- constexpr size_t kNumBits = BitSizeOf<uint32_t>();
- for (; bit + kNumBits <= lhs.size_in_bits(); bit += kNumBits) {
- uint32_t lhs_bits = lhs.LoadBits(bit, kNumBits);
- uint32_t rhs_bits = rhs.LoadBits(bit, kNumBits);
- if (lhs_bits != rhs_bits) {
- return lhs_bits < rhs_bits;
- }
- }
- size_t num_bits = lhs.size_in_bits() - bit;
- return lhs.LoadBits(bit, num_bits) < rhs.LoadBits(bit, num_bits);
+ bool operator()(const BitMemoryRegion& lhs, const BitMemoryRegion& rhs) const {
+ return Compare(lhs, rhs) < 0;
}
};
BitMemoryRegion() = default;
- ALWAYS_INLINE BitMemoryRegion(void* data, size_t bit_start, size_t bit_size)
- : data_(reinterpret_cast<uintptr_t*>(AlignDown(data, sizeof(uintptr_t)))),
- bit_start_(bit_start + 8 * (reinterpret_cast<uintptr_t>(data) % sizeof(uintptr_t))),
- bit_size_(bit_size) {
+ ALWAYS_INLINE BitMemoryRegion(uint8_t* data, ssize_t bit_start, size_t bit_size) {
+ // Normalize the data pointer. Note that bit_start may be negative.
+ uint8_t* aligned_data = AlignDown(data + (bit_start >> kBitsPerByteLog2), sizeof(uintptr_t));
+ data_ = reinterpret_cast<uintptr_t*>(aligned_data);
+ bit_start_ = bit_start + kBitsPerByte * (data - aligned_data);
+ bit_size_ = bit_size;
+ DCHECK_LT(bit_start_, static_cast<size_t>(kBitsPerIntPtrT));
}
ALWAYS_INLINE explicit BitMemoryRegion(MemoryRegion region)
: BitMemoryRegion(region.begin(), /* bit_start */ 0, region.size_in_bits()) {
}
ALWAYS_INLINE BitMemoryRegion(MemoryRegion region, size_t bit_offset, size_t bit_length)
: BitMemoryRegion(region) {
- DCHECK_LE(bit_offset, bit_size_);
- DCHECK_LE(bit_length, bit_size_ - bit_offset);
- bit_start_ += bit_offset;
- bit_size_ = bit_length;
+ *this = Subregion(bit_offset, bit_length);
}
ALWAYS_INLINE bool IsValid() const { return data_ != nullptr; }
@@ -70,6 +57,10 @@
return bit_size_;
}
+ void Resize(size_t bit_size) {
+ bit_size_ = bit_size;
+ }
+
ALWAYS_INLINE BitMemoryRegion Subregion(size_t bit_offset, size_t bit_length) const {
DCHECK_LE(bit_offset, bit_size_);
DCHECK_LE(bit_length, bit_size_ - bit_offset);
@@ -79,12 +70,11 @@
return result;
}
- // Increase the size of the region and return the newly added range (starting at the old end).
- ALWAYS_INLINE BitMemoryRegion Extend(size_t bit_length) {
+ ALWAYS_INLINE BitMemoryRegion Subregion(size_t bit_offset) const {
+ DCHECK_LE(bit_offset, bit_size_);
BitMemoryRegion result = *this;
- result.bit_start_ += result.bit_size_;
- result.bit_size_ = bit_length;
- bit_size_ += bit_length;
+ result.bit_start_ += bit_offset;
+ result.bit_size_ -= bit_offset;
return result;
}
@@ -183,10 +173,26 @@
return count;
}
- ALWAYS_INLINE bool Equals(const BitMemoryRegion& other) const {
- return data_ == other.data_ &&
- bit_start_ == other.bit_start_ &&
- bit_size_ == other.bit_size_;
+ static int Compare(const BitMemoryRegion& lhs, const BitMemoryRegion& rhs) {
+ if (lhs.size_in_bits() != rhs.size_in_bits()) {
+ return (lhs.size_in_bits() < rhs.size_in_bits()) ? -1 : 1;
+ }
+ size_t bit = 0;
+ constexpr size_t kNumBits = BitSizeOf<uint32_t>();
+ for (; bit + kNumBits <= lhs.size_in_bits(); bit += kNumBits) {
+ uint32_t lhs_bits = lhs.LoadBits(bit, kNumBits);
+ uint32_t rhs_bits = rhs.LoadBits(bit, kNumBits);
+ if (lhs_bits != rhs_bits) {
+ return (lhs_bits < rhs_bits) ? -1 : 1;
+ }
+ }
+ size_t num_bits = lhs.size_in_bits() - bit;
+ uint32_t lhs_bits = lhs.LoadBits(bit, num_bits);
+ uint32_t rhs_bits = rhs.LoadBits(bit, num_bits);
+ if (lhs_bits != rhs_bits) {
+ return (lhs_bits < rhs_bits) ? -1 : 1;
+ }
+ return 0;
}
private:
@@ -198,28 +204,30 @@
class BitMemoryReader {
public:
- explicit BitMemoryReader(const uint8_t* data, size_t bit_offset = 0)
- : finished_region_(const_cast<uint8_t*>(data), /* bit_start */ 0, bit_offset) {
- DCHECK_EQ(GetBitOffset(), bit_offset);
+ BitMemoryReader(BitMemoryReader&&) = default;
+ explicit BitMemoryReader(BitMemoryRegion data)
+ : finished_region_(data.Subregion(0, 0) /* set the length to zero */ ) {
+ }
+ explicit BitMemoryReader(const uint8_t* data, ssize_t bit_offset = 0)
+ : finished_region_(const_cast<uint8_t*>(data), bit_offset, /* bit_length */ 0) {
}
- size_t GetBitOffset() const { return finished_region_.size_in_bits(); }
+ BitMemoryRegion GetReadRegion() const { return finished_region_; }
- ALWAYS_INLINE BitMemoryRegion Skip(size_t bit_length) {
- return finished_region_.Extend(bit_length);
- }
+ size_t NumberOfReadBits() const { return finished_region_.size_in_bits(); }
- // Get the most recently read bits.
- ALWAYS_INLINE BitMemoryRegion Tail(size_t bit_length) {
- return finished_region_.Subregion(finished_region_.size_in_bits() - bit_length, bit_length);
+ ALWAYS_INLINE BitMemoryRegion ReadRegion(size_t bit_length) {
+ size_t bit_offset = finished_region_.size_in_bits();
+ finished_region_.Resize(bit_offset + bit_length);
+ return finished_region_.Subregion(bit_offset, bit_length);
}
ALWAYS_INLINE uint32_t ReadBits(size_t bit_length) {
- return finished_region_.Extend(bit_length).LoadBits(0, bit_length);
+ return ReadRegion(bit_length).LoadBits(/* bit_offset */ 0, bit_length);
}
ALWAYS_INLINE bool ReadBit() {
- return finished_region_.Extend(1).LoadBit(0);
+ return ReadRegion(/* bit_length */ 1).LoadBit(/* bit_offset */ 0);
}
private:
@@ -234,36 +242,46 @@
class BitMemoryWriter {
public:
explicit BitMemoryWriter(Vector* out, size_t bit_offset = 0)
- : out_(out), bit_offset_(bit_offset) {
- DCHECK_EQ(GetBitOffset(), bit_offset);
+ : out_(out), bit_start_(bit_offset), bit_offset_(bit_offset) {
+ DCHECK_EQ(NumberOfWrittenBits(), 0u);
+ }
+
+ BitMemoryRegion GetWrittenRegion() const {
+ return BitMemoryRegion(out_->data(), bit_start_, bit_offset_ - bit_start_);
}
const uint8_t* data() const { return out_->data(); }
- size_t GetBitOffset() const { return bit_offset_; }
+ size_t NumberOfWrittenBits() const { return bit_offset_ - bit_start_; }
ALWAYS_INLINE BitMemoryRegion Allocate(size_t bit_length) {
out_->resize(BitsToBytesRoundUp(bit_offset_ + bit_length));
- BitMemoryRegion region(MemoryRegion(out_->data(), out_->size()), bit_offset_, bit_length);
+ BitMemoryRegion region(out_->data(), bit_offset_, bit_length);
DCHECK_LE(bit_length, std::numeric_limits<size_t>::max() - bit_offset_) << "Overflow";
bit_offset_ += bit_length;
return region;
}
+ ALWAYS_INLINE void WriteRegion(const BitMemoryRegion& region) {
+ Allocate(region.size_in_bits()).StoreBits(/* bit_offset */ 0, region, region.size_in_bits());
+ }
+
ALWAYS_INLINE void WriteBits(uint32_t value, size_t bit_length) {
- Allocate(bit_length).StoreBits(0, value, bit_length);
+ Allocate(bit_length).StoreBits(/* bit_offset */ 0, value, bit_length);
}
ALWAYS_INLINE void WriteBit(bool value) {
- Allocate(1).StoreBit(0, value);
+ Allocate(1).StoreBit(/* bit_offset */ 0, value);
}
- ALWAYS_INLINE void WriteRegion(const BitMemoryRegion& region) {
- Allocate(region.size_in_bits()).StoreBits(0, region, region.size_in_bits());
+ ALWAYS_INLINE void ByteAlign() {
+ size_t end = bit_start_ + bit_offset_;
+ bit_offset_ += RoundUp(end, kBitsPerByte) - end;
}
private:
Vector* out_;
+ size_t bit_start_;
size_t bit_offset_;
DISALLOW_COPY_AND_ASSIGN(BitMemoryWriter);
diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h
index 1c7614b..18de3d3 100644
--- a/libartbase/base/bit_table.h
+++ b/libartbase/base/bit_table.h
@@ -77,7 +77,7 @@
ALWAYS_INLINE void Decode(BitMemoryReader& reader) {
// Decode row count and column sizes from the table header.
- size_t initial_bit_offset = reader.GetBitOffset();
+ size_t initial_bit_offset = reader.NumberOfReadBits();
num_rows_ = DecodeVarintBits(reader);
if (num_rows_ != 0) {
column_offset_[0] = 0;
@@ -86,10 +86,10 @@
column_offset_[i + 1] = dchecked_integral_cast<uint16_t>(column_end);
}
}
- header_bit_size_ = reader.GetBitOffset() - initial_bit_offset;
+ header_bit_size_ = reader.NumberOfReadBits() - initial_bit_offset;
// Record the region which contains the table data and skip past it.
- table_data_ = reader.Skip(num_rows_ * NumRowBits());
+ table_data_ = reader.ReadRegion(num_rows_ * NumRowBits());
}
ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column = 0) const {
@@ -122,6 +122,12 @@
size_t BitSize() const { return header_bit_size_ + table_data_.size_in_bits(); }
+ bool Equals(const BitTableBase& other) const {
+ return num_rows_ == other.num_rows_ &&
+ std::equal(column_offset_, column_offset_ + kNumColumns, other.column_offset_) &&
+ BitMemoryRegion::Compare(table_data_, other.table_data_) == 0;
+ }
+
protected:
BitMemoryRegion table_data_;
size_t num_rows_ = 0;
@@ -376,7 +382,7 @@
// Encode the stored data into a BitTable.
template<typename Vector>
void Encode(BitMemoryWriter<Vector>& out) const {
- size_t initial_bit_offset = out.GetBitOffset();
+ size_t initial_bit_offset = out.NumberOfWrittenBits();
std::array<uint32_t, kNumColumns> column_bits;
Measure(&column_bits);
@@ -398,7 +404,7 @@
// Verify the written data.
if (kIsDebugBuild) {
BitTableBase<kNumColumns> table;
- BitMemoryReader reader(out.data(), initial_bit_offset);
+ BitMemoryReader reader(out.GetWrittenRegion().Subregion(initial_bit_offset));
table.Decode(reader);
DCHECK_EQ(size(), table.NumRows());
for (uint32_t c = 0; c < kNumColumns; c++) {
@@ -467,7 +473,7 @@
// Encode the stored data into a BitTable.
template<typename Vector>
void Encode(BitMemoryWriter<Vector>& out) const {
- size_t initial_bit_offset = out.GetBitOffset();
+ size_t initial_bit_offset = out.NumberOfWrittenBits();
EncodeVarintBits(out, size());
if (size() != 0) {
@@ -484,7 +490,7 @@
// Verify the written data.
if (kIsDebugBuild) {
BitTableBase<1> table;
- BitMemoryReader reader(out.data(), initial_bit_offset);
+ BitMemoryReader reader(out.GetWrittenRegion().Subregion(initial_bit_offset));
table.Decode(reader);
DCHECK_EQ(size(), table.NumRows());
DCHECK_EQ(max_num_bits_, table.NumColumnBits(0));
diff --git a/libartbase/base/bit_table_test.cc b/libartbase/base/bit_table_test.cc
index 2fd9052..4f25730 100644
--- a/libartbase/base/bit_table_test.cc
+++ b/libartbase/base/bit_table_test.cc
@@ -36,7 +36,7 @@
BitMemoryReader reader(buffer.data(), start_bit_offset);
uint32_t result = DecodeVarintBits(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
EXPECT_EQ(value, result);
}
}
@@ -54,7 +54,7 @@
BitMemoryReader reader(buffer.data());
BitTableBase<1> table(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
EXPECT_EQ(0u, table.NumRows());
}
@@ -75,7 +75,7 @@
BitMemoryReader reader(buffer.data());
BitTableBase<1> table(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
EXPECT_EQ(4u, table.NumRows());
EXPECT_EQ(42u, table.Get(0));
EXPECT_EQ(kNoValue, table.Get(1));
@@ -98,7 +98,7 @@
BitMemoryReader reader(buffer.data(), start_bit_offset);
BitTableBase<1> table(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
EXPECT_EQ(1u, table.NumRows());
EXPECT_EQ(42u, table.Get(0));
}
@@ -119,7 +119,7 @@
BitMemoryReader reader(buffer.data());
BitTableBase<4> table(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
EXPECT_EQ(2u, table.NumRows());
EXPECT_EQ(42u, table.Get(0, 0));
EXPECT_EQ(kNoValue, table.Get(0, 1));
@@ -169,7 +169,7 @@
BitMemoryReader reader(buffer.data());
BitTableBase<1> table(reader);
- EXPECT_EQ(writer.GetBitOffset(), reader.GetBitOffset());
+ EXPECT_EQ(writer.NumberOfWrittenBits(), reader.NumberOfReadBits());
for (auto it : indicies) {
uint64_t expected = it.first;
BitMemoryRegion actual = table.GetBitMemoryRegion(it.second);
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index d1000c5..b0c59a6 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -34,15 +34,10 @@
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);
+ const uint8_t* reader_data) {
+ if (reader.ReadBit() /* is_deduped */) {
+ ssize_t bit_offset = reader.NumberOfReadBits() - DecodeVarintBits(reader);
+ BitMemoryReader reader2(reader_data, bit_offset); // The offset is negative.
table.Decode(reader2);
} else {
table.Decode(reader);
@@ -69,45 +64,63 @@
DecodeTable(dex_register_masks_, reader, data);
DecodeTable(dex_register_maps_, reader, data);
DecodeTable(dex_register_catalog_, reader, data);
- size_in_bits_ = reader.GetBitOffset();
+ size_in_bits_ = reader.NumberOfReadBits();
}
template<typename Accessor>
-ALWAYS_INLINE static void DedupeTable(BitMemoryWriter<std::vector<uint8_t>>& writer,
- BitMemoryReader& reader,
- CodeInfo::DedupeMap* dedupe_map) {
+ALWAYS_INLINE void CodeInfo::Deduper::DedupeTable(BitMemoryReader& reader) {
bool is_deduped = reader.ReadBit();
DCHECK(!is_deduped);
+ size_t bit_table_start = reader.NumberOfReadBits();
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 */));
+ BitMemoryRegion region = reader.GetReadRegion().Subregion(bit_table_start);
+ auto it = dedupe_map_.insert(std::make_pair(region, /* placeholder */ 0));
if (it.second /* new bit table */ || region.size_in_bits() < 32) {
- writer.WriteBit(false); // Is not deduped.
- writer.WriteRegion(region);
+ writer_.WriteBit(false); // Is not deduped.
+ it.first->second = writer_.NumberOfWrittenBits();
+ writer_.WriteRegion(region);
} else {
- writer.WriteBit(true); // Is deduped.
- EncodeVarintBits(writer, writer.GetBitOffset() - it.first->second);
+ writer_.WriteBit(true); // Is deduped.
+ size_t bit_offset = writer_.NumberOfWrittenBits();
+ EncodeVarintBits(writer_, bit_offset - 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();
- BitMemoryReader reader(in);
- BitMemoryWriter<std::vector<uint8_t>> writer(out, /* bit_offset */ out->size() * kBitsPerByte);
- EncodeVarintBits(writer, DecodeVarintBits(reader)); // packed_frame_size_.
- EncodeVarintBits(writer, DecodeVarintBits(reader)); // core_spill_mask_.
- EncodeVarintBits(writer, DecodeVarintBits(reader)); // fp_spill_mask_.
- EncodeVarintBits(writer, DecodeVarintBits(reader)); // number_of_dex_registers_.
- DedupeTable<StackMap>(writer, reader, dedupe_map);
- DedupeTable<RegisterMask>(writer, reader, dedupe_map);
- DedupeTable<MaskInfo>(writer, reader, dedupe_map);
- DedupeTable<InlineInfo>(writer, reader, dedupe_map);
- DedupeTable<MethodInfo>(writer, reader, dedupe_map);
- DedupeTable<MaskInfo>(writer, reader, dedupe_map);
- DedupeTable<DexRegisterMapInfo>(writer, reader, dedupe_map);
- DedupeTable<DexRegisterInfo>(writer, reader, dedupe_map);
- return result;
+size_t CodeInfo::Deduper::Dedupe(const uint8_t* code_info) {
+ writer_.ByteAlign();
+ size_t deduped_offset = writer_.NumberOfWrittenBits() / kBitsPerByte;
+ BitMemoryReader reader(code_info);
+ EncodeVarintBits(writer_, DecodeVarintBits(reader)); // packed_frame_size_.
+ EncodeVarintBits(writer_, DecodeVarintBits(reader)); // core_spill_mask_.
+ EncodeVarintBits(writer_, DecodeVarintBits(reader)); // fp_spill_mask_.
+ EncodeVarintBits(writer_, DecodeVarintBits(reader)); // number_of_dex_registers_.
+ DedupeTable<StackMap>(reader);
+ DedupeTable<RegisterMask>(reader);
+ DedupeTable<MaskInfo>(reader);
+ DedupeTable<InlineInfo>(reader);
+ DedupeTable<MethodInfo>(reader);
+ DedupeTable<MaskInfo>(reader);
+ DedupeTable<DexRegisterMapInfo>(reader);
+ DedupeTable<DexRegisterInfo>(reader);
+
+ if (kIsDebugBuild) {
+ CodeInfo old_code_info(code_info);
+ CodeInfo new_code_info(writer_.data() + deduped_offset);
+ DCHECK_EQ(old_code_info.packed_frame_size_, new_code_info.packed_frame_size_);
+ DCHECK_EQ(old_code_info.core_spill_mask_, new_code_info.core_spill_mask_);
+ DCHECK_EQ(old_code_info.fp_spill_mask_, new_code_info.fp_spill_mask_);
+ DCHECK_EQ(old_code_info.number_of_dex_registers_, new_code_info.number_of_dex_registers_);
+ DCHECK(old_code_info.stack_maps_.Equals(new_code_info.stack_maps_));
+ DCHECK(old_code_info.register_masks_.Equals(new_code_info.register_masks_));
+ DCHECK(old_code_info.stack_masks_.Equals(new_code_info.stack_masks_));
+ DCHECK(old_code_info.inline_infos_.Equals(new_code_info.inline_infos_));
+ DCHECK(old_code_info.method_infos_.Equals(new_code_info.method_infos_));
+ DCHECK(old_code_info.dex_register_masks_.Equals(new_code_info.dex_register_masks_));
+ DCHECK(old_code_info.dex_register_maps_.Equals(new_code_info.dex_register_maps_));
+ DCHECK(old_code_info.dex_register_catalog_.Equals(new_code_info.dex_register_catalog_));
+ }
+
+ return deduped_offset;
}
BitTable<StackMap>::const_iterator CodeInfo::BinarySearchNativePc(uint32_t packed_pc) const {
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index d6db05a..cde08f3 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -269,6 +269,26 @@
*/
class CodeInfo {
public:
+ class Deduper {
+ public:
+ explicit Deduper(std::vector<uint8_t>* output) : writer_(output) {
+ DCHECK_EQ(output->size(), 0u);
+ }
+
+ // Copy CodeInfo into output while de-duplicating the internal bit tables.
+ // It returns the byte offset of the copied CodeInfo within the output.
+ size_t Dedupe(const uint8_t* code_info);
+
+ private:
+ template<typename Accessor>
+ void DedupeTable(BitMemoryReader& reader);
+
+ BitMemoryWriter<std::vector<uint8_t>> writer_;
+
+ // Deduplicate at BitTable level. The value is bit offset within the output.
+ std::map<BitMemoryRegion, uint32_t, BitMemoryRegion::Less> dedupe_map_;
+ };
+
enum DecodeFlags {
Default = 0,
// Limits the decoding only to the data needed by GC.
@@ -421,16 +441,6 @@
DecodeVarintBits(reader)); // fp_spill_mask_.
}
- typedef std::map<BitMemoryRegion, uint32_t, BitMemoryRegion::Less> DedupeMap;
-
- // Copy CodeInfo data while de-duplicating the internal bit tables.
- // The 'out' vector must be reused between Dedupe calls (it does not have to be empty).
- // The 'dedupe_map' stores the bit offsets of bit tables within the 'out' vector.
- // It returns the byte offset of the copied CodeInfo within the 'out' vector.
- static size_t Dedupe(std::vector<uint8_t>* out,
- const uint8_t* in,
- /*inout*/ DedupeMap* dedupe_map);
-
private:
// Returns lower bound (fist stack map which has pc greater or equal than the desired one).
// It ignores catch stack maps at the end (it is the same as if they had maximum pc value).