Use efficient encoding for compact dex code item fields
Use a compact format for compact dex code items. In the common case,
there are only 4 bytes worth of fields.
This is accomplished by shrining the fields and adding an optional
preheader before each code item that describes fields that don't fit
in the fast path case. The preheader may use up to 12 extra bytes.
Experiments showed that the preheader is only non empty for ~1% of
code items.
CompactDex code item:
0-12 bytes: Optional preheader
<Code item pointer>
4 bits: register size
4 bits: ins size
4 bits: outs size
4 bits: tries size
11 bits: num code item units
5 bits: preheader flags
[Dex Instructions]
Standard dex code item:
See: https://source.android.com/devices/tech/dalvik/dex-format
<Code item pointer>
16 bits: register size
16 bits: ins size
16 bits: outs size
16 bits: tries size
32 bits: num code item units
[Dex Instructions]
Also change code item alignment to be 2 byte aligned for code items
that don't have payload instructions that require 4 byte alignments.
Results (on golem).
The CL reduces vdex size by an average of 4.3%. Interpreter performance
is 0.3-1% slower, but may be noise.
Test: test-art-host
Bug: 63756964
Change-Id: I836fd098063dd1573a3dfb6ac465a6d33d2cb2c9
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc
index d1dc658..73eb39b 100644
--- a/dexlayout/compact_dex_writer.cc
+++ b/dexlayout/compact_dex_writer.cc
@@ -95,15 +95,45 @@
bool reserve_only) {
DCHECK(code_item != nullptr);
const uint32_t start_offset = offset;
+ // Use 4 byte alignment for now, we need to peek at the bytecode to see if we can 2 byte align
+ // otherwise.
offset = RoundUp(offset, CompactDexFile::CodeItem::kAlignment);
- ProcessOffset(&offset, code_item);
CompactDexFile::CodeItem disk_code_item;
- disk_code_item.registers_size_ = code_item->RegistersSize();
- disk_code_item.ins_size_ = code_item->InsSize();
- disk_code_item.outs_size_ = code_item->OutsSize();
- disk_code_item.tries_size_ = code_item->TriesSize();
- disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
+
+ uint16_t preheader_storage[CompactDexFile::CodeItem::kMaxPreHeaderSize] = {};
+ uint16_t* preheader_end = preheader_storage + CompactDexFile::CodeItem::kMaxPreHeaderSize;
+ const uint16_t* preheader = disk_code_item.Create(
+ code_item->RegistersSize(),
+ code_item->InsSize(),
+ code_item->OutsSize(),
+ code_item->TriesSize(),
+ code_item->InsnsSize(),
+ preheader_end);
+ const size_t preheader_bytes = (preheader_end - preheader) * sizeof(preheader[0]);
+
+ static constexpr size_t kPayloadInstructionRequiredAlignment = 4;
+ const uint32_t current_code_item_start = offset + preheader_bytes;
+ if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment)) {
+ // If the preheader is going to make the code unaligned, consider adding 2 bytes of padding
+ // before if required.
+ for (const DexInstructionPcPair& instruction : code_item->Instructions()) {
+ const Instruction::Code opcode = instruction->Opcode();
+ // Payload instructions possibly require special alignment for their data.
+ if (opcode == Instruction::FILL_ARRAY_DATA ||
+ opcode == Instruction::PACKED_SWITCH ||
+ opcode == Instruction::SPARSE_SWITCH) {
+ offset += RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) -
+ current_code_item_start;
+ break;
+ }
+ }
+ }
+
+ // Write preheader first.
+ offset += Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes, offset);
+ // Registered offset is after the preheader.
+ ProcessOffset(&offset, code_item);
// Avoid using sizeof so that we don't write the fake instruction array at the end of the code
// item.
offset += Write(&disk_code_item,
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 6e1cb62..d26c948 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -512,8 +512,8 @@
bool reserve_only) {
const uint32_t start_offset = offset;
if (code_item->TriesSize() != 0) {
- // Make sure the try items are properly aligned.
- offset = RoundUp(offset, kDexTryItemAlignment);
+ // Align for the try items.
+ offset = RoundUp(offset, DexFile::TryItem::kAlignment);
// Write try items.
for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
DexFile::TryItem disk_try_item;
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index fdeb299..892ea74 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -62,7 +62,6 @@
public:
static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
static constexpr uint32_t kDexSectionWordAlignment = 4;
- static constexpr uint32_t kDexTryItemAlignment = sizeof(uint32_t);
static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
switch (type) {
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index e2b84c5..3d3b121 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1929,6 +1929,8 @@
if (options_.verify_output_) {
std::string error_msg;
std::string location = "memory mapped file for " + std::string(file_name);
+ // Dex file verifier cannot handle compact dex.
+ bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone;
const ArtDexFileLoader dex_file_loader;
std::unique_ptr<const DexFile> output_dex_file(
dex_file_loader.Open(mem_map_->Begin(),
@@ -1936,7 +1938,7 @@
location,
/* checksum */ 0,
/*oat_dex_file*/ nullptr,
- /*verify*/ true,
+ verify,
/*verify_checksum*/ false,
&error_msg));
CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
index aaa86d4..6a99009 100644
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ b/runtime/dex/code_item_accessors-no_art-inl.h
@@ -26,14 +26,25 @@
// The no ART version is used by binaries that don't include the whole runtime.
namespace art {
+inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units,
+ const uint16_t* insns) {
+ insns_size_in_code_units_ = insns_size_in_code_units;
+ insns_ = insns;
+}
+
inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
- insns_ = code_item.insns_;
+ uint32_t insns_size_in_code_units;
+ code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>(
+ &insns_size_in_code_units,
+ /*registers_size*/ nullptr,
+ /*ins_size*/ nullptr,
+ /*outs_size*/ nullptr,
+ /*tries_size*/ nullptr);
+ Init(insns_size_in_code_units, code_item.insns_);
}
inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- insns_size_in_code_units_ = code_item.insns_size_in_code_units_;
- insns_ = code_item.insns_;
+ Init(code_item.insns_size_in_code_units_, code_item.insns_);
}
inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
@@ -72,11 +83,13 @@
}
inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- CodeItemInstructionAccessor::Init(code_item);
- registers_size_ = code_item.registers_size_;
- ins_size_ = code_item.ins_size_;
- outs_size_ = code_item.outs_size_;
- tries_size_ = code_item.tries_size_;
+ uint32_t insns_size_in_code_units;
+ code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&insns_size_in_code_units,
+ ®isters_size_,
+ &ins_size_,
+ &outs_size_,
+ &tries_size_);
+ CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_);
}
inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
diff --git a/runtime/dex/code_item_accessors.h b/runtime/dex/code_item_accessors.h
index 66531f9..08f823c 100644
--- a/runtime/dex/code_item_accessors.h
+++ b/runtime/dex/code_item_accessors.h
@@ -66,6 +66,7 @@
protected:
CodeItemInstructionAccessor() = default;
+ ALWAYS_INLINE void Init(uint32_t insns_size_in_code_units, const uint16_t* insns);
ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
ALWAYS_INLINE void Init(const DexFile& dex_file, const DexFile::CodeItem* code_item);
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
index 2e21956..3380be8 100644
--- a/runtime/dex/code_item_accessors_test.cc
+++ b/runtime/dex/code_item_accessors_test.cc
@@ -62,8 +62,8 @@
ASSERT_TRUE(standard_dex != nullptr);
std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true));
ASSERT_TRUE(compact_dex != nullptr);
- static constexpr uint16_t kRegisterSize = 1;
- static constexpr uint16_t kInsSize = 2;
+ static constexpr uint16_t kRegisterSize = 2;
+ static constexpr uint16_t kInsSize = 1;
static constexpr uint16_t kOutsSize = 3;
static constexpr uint16_t kTriesSize = 4;
// debug_info_off_ is not accessible from the helpers yet.
@@ -97,12 +97,16 @@
verify_code_item(standard_dex.get(), dex_code_item, dex_code_item->insns_);
CompactDexFile::CodeItem* cdex_code_item =
- reinterpret_cast<CompactDexFile::CodeItem*>(const_cast<uint8_t*>(compact_dex->Begin()));
- cdex_code_item->registers_size_ = kRegisterSize;
- cdex_code_item->ins_size_ = kInsSize;
- cdex_code_item->outs_size_ = kOutsSize;
- cdex_code_item->tries_size_ = kTriesSize;
- cdex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
+ reinterpret_cast<CompactDexFile::CodeItem*>(const_cast<uint8_t*>(compact_dex->Begin() +
+ CompactDexFile::CodeItem::kMaxPreHeaderSize * sizeof(uint16_t)));
+ std::vector<uint16_t> preheader;
+ cdex_code_item->Create(kRegisterSize,
+ kInsSize,
+ kOutsSize,
+ kTriesSize,
+ kInsnsSizeInCodeUnits,
+ cdex_code_item->GetPreHeader());
+
verify_code_item(compact_dex.get(), cdex_code_item, cdex_code_item->insns_);
}
diff --git a/runtime/dex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
index af782a9..8dad84d 100644
--- a/runtime/dex/compact_dex_file.h
+++ b/runtime/dex/compact_dex_file.h
@@ -55,27 +55,162 @@
friend class CompactDexWriter;
};
- // Like the standard code item except without a debug info offset.
+ // Like the standard code item except without a debug info offset. Each code item may have a
+ // preheader to encode large methods. In 99% of cases, the preheader is not used. This enables
+ // smaller size with a good fast path case in the accessors.
struct CodeItem : public DexFile::CodeItem {
- static constexpr size_t kAlignment = sizeof(uint32_t);
+ static constexpr size_t kAlignment = sizeof(uint16_t);
+ // Max preheader size in uint16_ts.
+ static constexpr size_t kMaxPreHeaderSize = 6;
private:
CodeItem() = default;
- uint16_t registers_size_; // the number of registers used by this code
- // (locals + parameters)
- uint16_t ins_size_; // the number of words of incoming arguments to the method
- // that this code is for
- uint16_t outs_size_; // the number of words of outgoing argument space required
- // by this code for method invocation
- uint16_t tries_size_; // the number of try_items for this instance. If non-zero,
- // then these appear as the tries array just after the
- // insns in this instance.
+ static constexpr size_t kRegistersSizeShift = 12;
+ static constexpr size_t kInsSizeShift = 8;
+ static constexpr size_t kOutsSizeShift = 4;
+ static constexpr size_t kTriesSizeSizeShift = 0;
+ static constexpr uint16_t kFlagPreHeaderRegisterSize = 0x1 << 0;
+ static constexpr uint16_t kFlagPreHeaderInsSize = 0x1 << 1;
+ static constexpr uint16_t kFlagPreHeaderOutsSize = 0x1 << 2;
+ static constexpr uint16_t kFlagPreHeaderTriesSize = 0x1 << 3;
+ static constexpr uint16_t kFlagPreHeaderInsnsSize = 0x1 << 4;
+ static constexpr size_t kInsnsSizeShift = 5;
+ static constexpr size_t kInsnsSizeBits = sizeof(uint16_t) * kBitsPerByte - kInsnsSizeShift;
- uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units
+ // Combined preheader flags for fast testing if we need to go slow path.
+ static constexpr uint16_t kFlagPreHeaderCombined =
+ kFlagPreHeaderRegisterSize |
+ kFlagPreHeaderInsSize |
+ kFlagPreHeaderOutsSize |
+ kFlagPreHeaderTriesSize |
+ kFlagPreHeaderInsnsSize;
+
+ // Create a code item and associated preheader if required based on field values.
+ // Returns the start of the preheader. The preheader buffer must be at least as large as
+ // kMaxPreHeaderSize;
+ uint16_t* Create(uint16_t registers_size,
+ uint16_t ins_size,
+ uint16_t outs_size,
+ uint16_t tries_size,
+ uint32_t insns_size_in_code_units,
+ uint16_t* out_preheader) {
+ // Dex verification ensures that registers size > ins_size, so we can subtract the registers
+ // size accordingly to reduce how often we need to use the preheader.
+ DCHECK_GE(registers_size, ins_size);
+ registers_size -= ins_size;
+ fields_ = (registers_size & 0xF) << kRegistersSizeShift;
+ fields_ |= (ins_size & 0xF) << kInsSizeShift;
+ fields_ |= (outs_size & 0xF) << kOutsSizeShift;
+ fields_ |= (tries_size & 0xF) << kTriesSizeSizeShift;
+ registers_size &= ~0xF;
+ ins_size &= ~0xF;
+ outs_size &= ~0xF;
+ tries_size &= ~0xF;
+ insns_count_and_flags_ = 0;
+ const size_t masked_count = insns_size_in_code_units & ((1 << kInsnsSizeBits) - 1);
+ insns_count_and_flags_ |= masked_count << kInsnsSizeShift;
+ insns_size_in_code_units -= masked_count;
+
+ // Since the preheader case is rare (1% of code items), use a suboptimally large but fast
+ // decoding format.
+ if (insns_size_in_code_units != 0) {
+ insns_count_and_flags_ |= kFlagPreHeaderInsnsSize;
+ --out_preheader;
+ *out_preheader = static_cast<uint16_t>(insns_size_in_code_units);
+ --out_preheader;
+ *out_preheader = static_cast<uint16_t>(insns_size_in_code_units >> 16);
+ }
+ auto preheader_encode = [&](uint16_t size, uint16_t flag) {
+ if (size != 0) {
+ insns_count_and_flags_ |= flag;
+ --out_preheader;
+ *out_preheader = size;
+ }
+ };
+ preheader_encode(registers_size, kFlagPreHeaderRegisterSize);
+ preheader_encode(ins_size, kFlagPreHeaderInsSize);
+ preheader_encode(outs_size, kFlagPreHeaderOutsSize);
+ preheader_encode(tries_size, kFlagPreHeaderTriesSize);
+ return out_preheader;
+ }
+
+ ALWAYS_INLINE bool HasPreHeader(uint16_t flag) const {
+ return (insns_count_and_flags_ & flag) != 0;
+ }
+
+ // Return true if the code item has any preheaders.
+ ALWAYS_INLINE static bool HasAnyPreHeader(uint16_t insns_count_and_flags) {
+ return (insns_count_and_flags & kFlagPreHeaderCombined) != 0;
+ }
+
+ ALWAYS_INLINE uint16_t* GetPreHeader() {
+ return reinterpret_cast<uint16_t*>(this);
+ }
+
+ ALWAYS_INLINE const uint16_t* GetPreHeader() const {
+ return reinterpret_cast<const uint16_t*>(this);
+ }
+
+ // Decode fields and read the preheader if necessary. If kDecodeOnlyInstructionCount is
+ // specified then only the instruction count is decoded.
+ template <bool kDecodeOnlyInstructionCount>
+ ALWAYS_INLINE void DecodeFields(uint32_t* insns_count,
+ uint16_t* registers_size,
+ uint16_t* ins_size,
+ uint16_t* outs_size,
+ uint16_t* tries_size) const {
+ *insns_count = insns_count_and_flags_ >> kInsnsSizeShift;
+ if (!kDecodeOnlyInstructionCount) {
+ const uint16_t fields = fields_;
+ *registers_size = (fields >> kRegistersSizeShift) & 0xF;
+ *ins_size = (fields >> kInsSizeShift) & 0xF;
+ *outs_size = (fields >> kOutsSizeShift) & 0xF;
+ *tries_size = (fields >> kTriesSizeSizeShift) & 0xF;
+ }
+ if (UNLIKELY(HasAnyPreHeader(insns_count_and_flags_))) {
+ const uint16_t* preheader = GetPreHeader();
+ if (HasPreHeader(kFlagPreHeaderInsnsSize)) {
+ --preheader;
+ *insns_count += static_cast<uint32_t>(*preheader);
+ --preheader;
+ *insns_count += static_cast<uint32_t>(*preheader) << 16;
+ }
+ if (!kDecodeOnlyInstructionCount) {
+ if (HasPreHeader(kFlagPreHeaderRegisterSize)) {
+ --preheader;
+ *registers_size += preheader[0];
+ }
+ if (HasPreHeader(kFlagPreHeaderInsSize)) {
+ --preheader;
+ *ins_size += preheader[0];
+ }
+ if (HasPreHeader(kFlagPreHeaderOutsSize)) {
+ --preheader;
+ *outs_size += preheader[0];
+ }
+ if (HasPreHeader(kFlagPreHeaderTriesSize)) {
+ --preheader;
+ *tries_size += preheader[0];
+ }
+ }
+ }
+ if (!kDecodeOnlyInstructionCount) {
+ *registers_size += *ins_size;
+ }
+ }
+
+ // Packed code item data, 4 bits each: [registers_size, ins_size, outs_size, tries_size]
+ uint16_t fields_;
+
+ // 5 bits for if either of the fields required preheader extension, 11 bits for the number of
+ // instruction code units.
+ uint16_t insns_count_and_flags_;
+
uint16_t insns_[1]; // actual array of bytecode.
ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+ ART_FRIEND_TEST(CompactDexFileTest, CodeItemFields);
friend class CodeItemDataAccessor;
friend class CodeItemDebugInfoAccessor;
friend class CodeItemInstructionAccessor;
diff --git a/runtime/dex/compact_dex_file_test.cc b/runtime/dex/compact_dex_file_test.cc
index d665dc9..517c587 100644
--- a/runtime/dex/compact_dex_file_test.cc
+++ b/runtime/dex/compact_dex_file_test.cc
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include "common_runtime_test.h"
+
#include "compact_dex_file.h"
#include "dex_file_loader.h"
+#include "gtest/gtest.h"
namespace art {
-class CompactDexFileTest : public CommonRuntimeTest {};
-
-TEST_F(CompactDexFileTest, MagicAndVersion) {
+TEST(CompactDexFileTest, MagicAndVersion) {
// Test permutations of valid/invalid headers.
for (size_t i = 0; i < 2; ++i) {
for (size_t j = 0; j < 2; ++j) {
@@ -45,4 +44,58 @@
}
}
+TEST(CompactDexFileTest, CodeItemFields) {
+ auto test_and_write = [&] (uint16_t registers_size,
+ uint16_t ins_size,
+ uint16_t outs_size,
+ uint16_t tries_size,
+ uint32_t insns_size_in_code_units) {
+ ASSERT_GE(registers_size, ins_size);
+ uint16_t buffer[sizeof(CompactDexFile::CodeItem) +
+ CompactDexFile::CodeItem::kMaxPreHeaderSize] = {};
+ CompactDexFile::CodeItem* code_item = reinterpret_cast<CompactDexFile::CodeItem*>(
+ &buffer[CompactDexFile::CodeItem::kMaxPreHeaderSize]);
+ const uint16_t* preheader_ptr = code_item->Create(registers_size,
+ ins_size,
+ outs_size,
+ tries_size,
+ insns_size_in_code_units,
+ code_item->GetPreHeader());
+ ASSERT_GT(preheader_ptr, buffer);
+
+ uint16_t out_registers_size;
+ uint16_t out_ins_size;
+ uint16_t out_outs_size;
+ uint16_t out_tries_size;
+ uint32_t out_insns_size_in_code_units;
+ code_item->DecodeFields</*kDecodeOnlyInstructionCount*/false>(&out_insns_size_in_code_units,
+ &out_registers_size,
+ &out_ins_size,
+ &out_outs_size,
+ &out_tries_size);
+ ASSERT_EQ(registers_size, out_registers_size);
+ ASSERT_EQ(ins_size, out_ins_size);
+ ASSERT_EQ(outs_size, out_outs_size);
+ ASSERT_EQ(tries_size, out_tries_size);
+ ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units);
+
+ ++out_insns_size_in_code_units; // Force value to change.
+ code_item->DecodeFields</*kDecodeOnlyInstructionCount*/true>(&out_insns_size_in_code_units,
+ /*registers_size*/ nullptr,
+ /*ins_size*/ nullptr,
+ /*outs_size*/ nullptr,
+ /*tries_size*/ nullptr);
+ ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units);
+ };
+ static constexpr uint32_t kMax32 = std::numeric_limits<uint32_t>::max();
+ static constexpr uint16_t kMax16 = std::numeric_limits<uint16_t>::max();
+ test_and_write(0, 0, 0, 0, 0);
+ test_and_write(kMax16, kMax16, kMax16, kMax16, kMax32);
+ test_and_write(kMax16 - 1, kMax16 - 2, kMax16 - 3, kMax16 - 4, kMax32 - 5);
+ test_and_write(kMax16 - 4, kMax16 - 5, kMax16 - 3, kMax16 - 2, kMax32 - 1);
+ test_and_write(5, 4, 3, 2, 1);
+ test_and_write(5, 0, 3, 2, 1);
+ test_and_write(kMax16, 0, kMax16 / 2, 1234, kMax32 / 4);
+}
+
} // namespace art
diff --git a/runtime/dex/dex_file-inl.h b/runtime/dex/dex_file-inl.h
index 9b56328..9b14514 100644
--- a/runtime/dex/dex_file-inl.h
+++ b/runtime/dex/dex_file-inl.h
@@ -136,7 +136,7 @@
inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
uint32_t offset) {
return reinterpret_cast<const TryItem*>
- (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), 4)) + offset;
+ (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), TryItem::kAlignment)) + offset;
}
static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h
index 183d84e..9fe0663 100644
--- a/runtime/dex/dex_file.h
+++ b/runtime/dex/dex_file.h
@@ -312,6 +312,8 @@
// Raw try_item.
struct TryItem {
+ static constexpr size_t kAlignment = sizeof(uint32_t);
+
uint32_t start_addr_;
uint16_t insn_count_;
uint16_t handler_off_;
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 4687a39..4e45128 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -84,8 +84,8 @@
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- // Last update: Side table for debug info offsets in compact dex.
- static constexpr uint8_t kVdexVersion[] = { '0', '1', '4', '\0' };
+ // Last update: Use efficient encoding for compact dex code item fields
+ static constexpr uint8_t kVdexVersion[] = { '0', '1', '5', '\0' };
uint8_t magic_[4];
uint8_t version_[4];