Move the type lookup table to vdex.
The table format has been stable for many releases now, so "promote" it
to .vdex, which remains post-OTA.
Test: test.py
Bug: 112676029
Change-Id: Ie1bbb24b4ab9c7864ae7e69e97db5ee5d1fc9ea1
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 0142c1f..d4104f3 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -396,6 +396,7 @@
vdex_dex_shared_data_offset_(0u),
vdex_verifier_deps_offset_(0u),
vdex_quickening_info_offset_(0u),
+ vdex_lookup_tables_offset_(0u),
oat_checksum_(adler32(0L, Z_NULL, 0)),
code_size_(0u),
oat_size_(0u),
@@ -426,6 +427,8 @@
size_verifier_deps_alignment_(0),
size_quickening_info_(0),
size_quickening_info_alignment_(0),
+ size_vdex_lookup_table_alignment_(0),
+ size_vdex_lookup_table_(0),
size_interpreter_to_interpreter_bridge_(0),
size_interpreter_to_compiled_code_bridge_(0),
size_jni_dlsym_lookup_trampoline_(0),
@@ -459,8 +462,6 @@
size_oat_dex_file_public_type_bss_mapping_offset_(0),
size_oat_dex_file_package_type_bss_mapping_offset_(0),
size_oat_dex_file_string_bss_mapping_offset_(0),
- size_oat_lookup_table_alignment_(0),
- size_oat_lookup_table_(0),
size_oat_class_offsets_alignment_(0),
size_oat_class_offsets_(0),
size_oat_class_type_(0),
@@ -694,6 +695,8 @@
*opened_dex_files_map = std::move(dex_files_map);
*opened_dex_files = std::move(dex_files);
+ // Create type lookup tables to speed up lookups during compilation.
+ InitializeTypeLookupTables(*opened_dex_files);
write_state_ = WriteState::kStartRoData;
return true;
}
@@ -717,11 +720,6 @@
ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, this);
- // Write type lookup tables into the oat file.
- if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
- return false;
- }
-
// Write dex layout sections into the oat file.
if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
return false;
@@ -2626,6 +2624,8 @@
DO_STAT(size_dex_file_);
DO_STAT(size_verifier_deps_);
DO_STAT(size_verifier_deps_alignment_);
+ DO_STAT(size_vdex_lookup_table_);
+ DO_STAT(size_vdex_lookup_table_alignment_);
DO_STAT(size_quickening_info_);
DO_STAT(size_quickening_info_alignment_);
DO_STAT(size_interpreter_to_interpreter_bridge_);
@@ -2661,8 +2661,6 @@
DO_STAT(size_oat_dex_file_public_type_bss_mapping_offset_);
DO_STAT(size_oat_dex_file_package_type_bss_mapping_offset_);
DO_STAT(size_oat_dex_file_string_bss_mapping_offset_);
- DO_STAT(size_oat_lookup_table_alignment_);
- DO_STAT(size_oat_lookup_table_);
DO_STAT(size_oat_class_offsets_alignment_);
DO_STAT(size_oat_class_offsets_);
DO_STAT(size_oat_class_type_);
@@ -3551,86 +3549,29 @@
return true;
}
-bool OatWriter::WriteTypeLookupTables(OutputStream* oat_rodata,
- const std::vector<const DexFile*>& opened_dex_files) {
- TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
-
- uint32_t expected_offset = oat_data_offset_ + oat_size_;
- off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
- if (static_cast<uint32_t>(actual_offset) != expected_offset) {
- PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
- << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
- return false;
- }
-
+void OatWriter::InitializeTypeLookupTables(
+ const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
+ TimingLogger::ScopedTiming split("InitializeTypeLookupTables", timings_);
DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
OatDexFile* oat_dex_file = &oat_dex_files_[i];
DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
- if (oat_dex_file->class_offsets_.empty()) {
- continue;
- }
-
size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
if (table_size == 0u) {
+ // We want a 1:1 mapping between `dex_files_` and `type_lookup_table_oat_dex_files_`,
+ // to simplify `WriteTypeLookupTables`. We push a null entry to notify
+ // that the dex file at index `i` does not have a type lookup table.
+ type_lookup_table_oat_dex_files_.push_back(nullptr);
continue;
}
- // Create the lookup table. When `nullptr` is given as the storage buffer,
- // TypeLookupTable allocates its own and OatDexFile takes ownership.
- // TODO: Create the table in an mmap()ed region of the output file to reduce dirty memory.
- // (We used to do that when dex files were still copied into the oat file.)
- const DexFile& dex_file = *opened_dex_files[i];
- {
- TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
- type_lookup_table_oat_dex_files_.push_back(
- std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
- dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
- }
- const TypeLookupTable& table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
- DCHECK(table.Valid());
-
- // Type tables are required to be 4 byte aligned.
- size_t initial_offset = oat_size_;
- size_t rodata_offset = RoundUp(initial_offset, 4);
- size_t padding_size = rodata_offset - initial_offset;
-
- if (padding_size != 0u) {
- std::vector<uint8_t> buffer(padding_size, 0u);
- if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
- PLOG(ERROR) << "Failed to write lookup table alignment padding."
- << " File: " << oat_dex_file->GetLocation()
- << " Output: " << oat_rodata->GetLocation();
- return false;
- }
- }
-
- DCHECK_EQ(oat_data_offset_ + rodata_offset,
- static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
- DCHECK_EQ(table_size, table.RawDataLength());
-
- if (!oat_rodata->WriteFully(table.RawData(), table_size)) {
- PLOG(ERROR) << "Failed to write lookup table."
- << " File: " << oat_dex_file->GetLocation()
- << " Output: " << oat_rodata->GetLocation();
- return false;
- }
-
- oat_dex_file->lookup_table_offset_ = rodata_offset;
-
- oat_size_ += padding_size + table_size;
- size_oat_lookup_table_ += table_size;
- size_oat_lookup_table_alignment_ += padding_size;
+ const DexFile& dex_file = *opened_dex_files[i].get();
+ TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
+ type_lookup_table_oat_dex_files_.push_back(
+ std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
+ dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
}
-
- if (!oat_rodata->Flush()) {
- PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
- << " File: " << oat_rodata->GetLocation();
- return false;
- }
-
- return true;
}
bool OatWriter::WriteDexLayoutSections(OutputStream* oat_rodata,
@@ -3696,11 +3637,56 @@
return true;
}
+void OatWriter::WriteTypeLookupTables(/*out*/std::vector<uint8_t>* buffer) {
+ TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
+ size_t type_lookup_table_size = 0u;
+ for (const DexFile* dex_file : *dex_files_) {
+ type_lookup_table_size +=
+ sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
+ }
+ // Reserve the space to avoid reallocations later on.
+ buffer->reserve(buffer->size() + type_lookup_table_size);
+
+ // Align the start of the first type lookup table.
+ size_t initial_offset = vdex_size_;
+ size_t table_offset = RoundUp(initial_offset, 4);
+ size_t padding_size = table_offset - initial_offset;
+
+ size_vdex_lookup_table_alignment_ += padding_size;
+ for (uint32_t j = 0; j < padding_size; ++j) {
+ buffer->push_back(0);
+ }
+ vdex_size_ += padding_size;
+ vdex_lookup_tables_offset_ = vdex_size_;
+ for (size_t i = 0, size = type_lookup_table_oat_dex_files_.size(); i != size; ++i) {
+ OatDexFile* oat_dex_file = &oat_dex_files_[i];
+ if (type_lookup_table_oat_dex_files_[i] == nullptr) {
+ buffer->insert(buffer->end(), {0u, 0u, 0u, 0u});
+ size_vdex_lookup_table_ += sizeof(uint32_t);
+ vdex_size_ += sizeof(uint32_t);
+ oat_dex_file->lookup_table_offset_ = 0u;
+ } else {
+ oat_dex_file->lookup_table_offset_ = vdex_size_ + sizeof(uint32_t);
+ const TypeLookupTable& table = type_lookup_table_oat_dex_files_[i]->GetTypeLookupTable();
+ uint32_t table_size = table.RawDataLength();
+ DCHECK_NE(0u, table_size);
+ DCHECK_ALIGNED(table_size, 4);
+ size_t old_buffer_size = buffer->size();
+ buffer->resize(old_buffer_size + table.RawDataLength() + sizeof(uint32_t), 0u);
+ memcpy(buffer->data() + old_buffer_size, &table_size, sizeof(uint32_t));
+ memcpy(buffer->data() + old_buffer_size + sizeof(uint32_t), table.RawData(), table_size);
+ vdex_size_ += table_size + sizeof(uint32_t);
+ size_vdex_lookup_table_ += table_size + sizeof(uint32_t);
+ }
+ }
+}
+
bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier_deps) {
size_t old_vdex_size = vdex_size_;
std::vector<uint8_t> buffer;
buffer.reserve(64 * KB);
WriteVerifierDeps(verifier_deps, &buffer);
+ WriteTypeLookupTables(&buffer);
DCHECK_EQ(vdex_size_, old_vdex_size + buffer.size());
// Resize the vdex file.
@@ -3775,19 +3761,25 @@
new (ptr) VdexFile::VdexSectionHeader(VdexSection::kChecksumSection,
checksums_offset,
size_vdex_checksums_);
- ptr += sizeof(VdexFile::VdexFileHeader);
+ ptr += sizeof(VdexFile::VdexSectionHeader);
// Dex section.
new (ptr) VdexFile::VdexSectionHeader(
VdexSection::kDexFileSection,
extract_dex_files_into_vdex_ ? vdex_dex_files_offset_ : 0u,
extract_dex_files_into_vdex_ ? vdex_verifier_deps_offset_ - vdex_dex_files_offset_ : 0u);
- ptr += sizeof(VdexFile::VdexFileHeader);
+ ptr += sizeof(VdexFile::VdexSectionHeader);
// VerifierDeps section.
new (ptr) VdexFile::VdexSectionHeader(VdexSection::kVerifierDepsSection,
vdex_verifier_deps_offset_,
- vdex_size_ - vdex_verifier_deps_offset_);
+ size_verifier_deps_);
+ ptr += sizeof(VdexFile::VdexSectionHeader);
+
+ // TypeLookupTable section.
+ new (ptr) VdexFile::VdexSectionHeader(VdexSection::kTypeLookupTableSection,
+ vdex_lookup_tables_offset_,
+ vdex_size_ - vdex_lookup_tables_offset_);
// All the contents (except the header) of the vdex file has been emitted in memory. Flush it
// to disk.
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index b26d4ce..5fbc01b 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -297,6 +297,7 @@
/*inout*/ std::vector<MemMap>* opened_dex_files_map,
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
void WriteQuickeningInfo(/*out*/std::vector<uint8_t>* buffer);
+ void WriteTypeLookupTables(/*out*/std::vector<uint8_t>* buffer);
void WriteVerifierDeps(verifier::VerifierDeps* verifier_deps,
/*out*/std::vector<uint8_t>* buffer);
@@ -321,8 +322,8 @@
size_t WriteDataBimgRelRo(OutputStream* out, size_t file_offset, size_t relative_offset);
bool RecordOatDataOffset(OutputStream* out);
- bool WriteTypeLookupTables(OutputStream* oat_rodata,
- const std::vector<const DexFile*>& opened_dex_files);
+ void InitializeTypeLookupTables(
+ const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files);
bool WriteDexLayoutSections(OutputStream* oat_rodata,
const std::vector<const DexFile*>& opened_dex_files);
bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
@@ -392,6 +393,9 @@
// Offset of section holding quickening info inside Vdex.
size_t vdex_quickening_info_offset_;
+ // Offset of type lookup tables inside Vdex.
+ size_t vdex_lookup_tables_offset_;
+
// OAT checksum.
uint32_t oat_checksum_;
@@ -495,6 +499,8 @@
uint32_t size_verifier_deps_alignment_;
uint32_t size_quickening_info_;
uint32_t size_quickening_info_alignment_;
+ uint32_t size_vdex_lookup_table_alignment_;
+ uint32_t size_vdex_lookup_table_;
uint32_t size_interpreter_to_interpreter_bridge_;
uint32_t size_interpreter_to_compiled_code_bridge_;
uint32_t size_jni_dlsym_lookup_trampoline_;
@@ -528,8 +534,6 @@
uint32_t size_oat_dex_file_public_type_bss_mapping_offset_;
uint32_t size_oat_dex_file_package_type_bss_mapping_offset_;
uint32_t size_oat_dex_file_string_bss_mapping_offset_;
- uint32_t size_oat_lookup_table_alignment_;
- uint32_t size_oat_lookup_table_;
uint32_t size_oat_class_offsets_alignment_;
uint32_t size_oat_class_offsets_;
uint32_t size_oat_class_type_;
diff --git a/runtime/oat.h b/runtime/oat.h
index 301e7cf..9d872f9 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: Move code size from OatQuickMethodHeader to CodeInfo.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '2', '\0' } };
+ // Last oat version changed reason: Move TypeLookupTables in .vdex file.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '9', '3', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 857dd3a..1d6fb10 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -476,13 +476,26 @@
}
void OatFileBase::Setup(const std::vector<const DexFile*>& dex_files) {
+ uint32_t i = 0;
+ const uint8_t* type_lookup_table_start = nullptr;
for (const DexFile* dex_file : dex_files) {
+ type_lookup_table_start = vdex_->GetNextTypeLookupTableData(type_lookup_table_start, i++);
std::string dex_location = dex_file->GetLocation();
std::string canonical_location = DexFileLoader::GetDexCanonicalLocation(dex_location.c_str());
+ const uint8_t* type_lookup_table_data = nullptr;
+ if (type_lookup_table_start != nullptr &&
+ (reinterpret_cast<uint32_t*>(type_lookup_table_start[0]) != 0)) {
+ type_lookup_table_data = type_lookup_table_start + sizeof(uint32_t);
+ }
// Create an OatDexFile and add it to the owning container.
- OatDexFile* oat_dex_file =
- new OatDexFile(this, dex_file->Begin(), dex_file->GetLocationChecksum(), dex_location, canonical_location);
+ OatDexFile* oat_dex_file = new OatDexFile(
+ this,
+ dex_file->Begin(),
+ dex_file->GetLocationChecksum(),
+ dex_location,
+ canonical_location,
+ type_lookup_table_data);
dex_file->SetOatDexFile(oat_dex_file);
oat_dex_files_storage_.push_back(oat_dex_file);
@@ -861,11 +874,11 @@
return false;
}
const uint8_t* lookup_table_data = lookup_table_offset != 0u
- ? Begin() + lookup_table_offset
+ ? DexBegin() + lookup_table_offset
: nullptr;
if (lookup_table_offset != 0u &&
- (UNLIKELY(lookup_table_offset > Size()) ||
- UNLIKELY(Size() - lookup_table_offset <
+ (UNLIKELY(lookup_table_offset > DexSize()) ||
+ UNLIKELY(DexSize() - lookup_table_offset <
TypeLookupTable::RawDataLength(header->class_defs_size_)))) {
*error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated "
"type lookup table, offset %u of %zu, class defs %u",
@@ -1543,23 +1556,34 @@
}
static OatFileBackedByVdex* Open(int zip_fd,
- std::unique_ptr<VdexFile>&& vdex_file,
+ std::unique_ptr<VdexFile>&& unique_vdex_file,
const std::string& dex_location,
std::string* error_msg) {
+ VdexFile* vdex_file = unique_vdex_file.get();
std::unique_ptr<OatFileBackedByVdex> oat_file(new OatFileBackedByVdex(vdex_file->GetName()));
+ // SetVdex will take ownership of the VdexFile.
+ oat_file->SetVdex(unique_vdex_file.release());
if (vdex_file->HasDexSection()) {
uint32_t i = 0;
+ const uint8_t* type_lookup_table_start = nullptr;
for (const uint8_t* dex_file_start = vdex_file->GetNextDexFileData(nullptr, i);
dex_file_start != nullptr;
dex_file_start = vdex_file->GetNextDexFileData(dex_file_start, ++i)) {
// Create the OatDexFile and add it to the owning container.
std::string location = DexFileLoader::GetMultiDexLocation(i, dex_location.c_str());
std::string canonical_location = DexFileLoader::GetDexCanonicalLocation(location.c_str());
+ type_lookup_table_start = vdex_file->GetNextTypeLookupTableData(type_lookup_table_start, i);
+ const uint8_t* type_lookup_table_data = nullptr;
+ if (type_lookup_table_start != nullptr &&
+ (reinterpret_cast<uint32_t*>(type_lookup_table_start[0]) != 0)) {
+ type_lookup_table_data = type_lookup_table_start + sizeof(uint32_t);
+ }
OatDexFile* oat_dex_file = new OatDexFile(oat_file.get(),
dex_file_start,
vdex_file->GetLocationChecksum(i),
location,
- canonical_location);
+ canonical_location,
+ type_lookup_table_data);
oat_file->oat_dex_files_storage_.push_back(oat_dex_file);
std::string_view key(oat_dex_file->GetDexFileLocation());
@@ -1597,8 +1621,6 @@
oat_file->Setup(MakeNonOwningPointerVector(oat_file->external_dex_files_));
}
- // SetVdex will take ownership of the VdexFile.
- oat_file->SetVdex(vdex_file.release());
return oat_file.release();
}
@@ -1958,12 +1980,18 @@
oat_class_offsets_pointer_(oat_class_offsets_pointer),
lookup_table_(),
dex_layout_sections_(dex_layout_sections) {
+ InitializeTypeLookupTable();
+ DCHECK(!IsBackedByVdexOnly());
+}
+
+void OatDexFile::InitializeTypeLookupTable() {
// Initialize TypeLookupTable.
if (lookup_table_data_ != nullptr) {
// Peek the number of classes from the DexFile.
const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_);
const uint32_t num_class_defs = dex_header->class_defs_size_;
- if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) > GetOatFile()->End()) {
+ if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) >
+ GetOatFile()->DexEnd()) {
LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
} else {
const uint8_t* dex_data = dex_file_pointer_;
@@ -1974,19 +2002,21 @@
lookup_table_ = TypeLookupTable::Open(dex_data, lookup_table_data_, num_class_defs);
}
}
- DCHECK(!IsBackedByVdexOnly());
}
OatDexFile::OatDexFile(const OatFile* oat_file,
const uint8_t* dex_file_pointer,
uint32_t dex_file_location_checksum,
const std::string& dex_file_location,
- const std::string& canonical_dex_file_location)
+ const std::string& canonical_dex_file_location,
+ const uint8_t* lookup_table_data)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
canonical_dex_file_location_(canonical_dex_file_location),
dex_file_location_checksum_(dex_file_location_checksum),
- dex_file_pointer_(dex_file_pointer) {
+ dex_file_pointer_(dex_file_pointer),
+ lookup_table_data_(lookup_table_data) {
+ InitializeTypeLookupTable();
DCHECK(IsBackedByVdexOnly());
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 7332cc9..4d40584 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -588,9 +588,11 @@
const uint8_t* dex_file_pointer,
uint32_t dex_file_checksum,
const std::string& dex_file_location,
- const std::string& canonical_dex_file_location);
+ const std::string& canonical_dex_file_location,
+ const uint8_t* lookup_table_data);
bool IsBackedByVdexOnly() const;
+ void InitializeTypeLookupTable();
static void AssertAotCompiler();
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 62508f6..7a4ef9c 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -183,6 +183,21 @@
}
}
+const uint8_t* VdexFile::GetNextTypeLookupTableData(const uint8_t* cursor,
+ uint32_t dex_file_index) const {
+ if (cursor == nullptr) {
+ // Beginning of the iteration, return the first dex file if there is one.
+ return HasTypeLookupTableSection() ? TypeLookupTableDataBegin() : nullptr;
+ } else if (dex_file_index >= GetNumberOfDexFiles()) {
+ return nullptr;
+ } else {
+ const uint8_t* data = cursor + sizeof(uint32_t) + reinterpret_cast<const uint32_t*>(cursor)[0];
+ // TypeLookupTables are required to be 4 byte aligned. the OatWriter makes sure they are.
+ CHECK_ALIGNED(data, 4);
+ return data;
+ }
+}
+
bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::string* error_msg) const {
const ArtDexFileLoader dex_file_loader;
@@ -236,6 +251,17 @@
std::string* error_msg) {
std::vector<uint8_t> verifier_deps_data;
verifier_deps.Encode(dex_files, &verifier_deps_data);
+ uint32_t verifier_deps_size = verifier_deps_data.size();
+ // Add padding so the type lookup tables are 4 byte aligned.
+ uint32_t verifier_deps_with_padding_size = RoundUp(verifier_deps_data.size(), 4);
+ DCHECK_GE(verifier_deps_with_padding_size, verifier_deps_data.size());
+ verifier_deps_data.resize(verifier_deps_with_padding_size, 0);
+
+ size_t type_lookup_table_size = 0u;
+ for (const DexFile* dex_file : dex_files) {
+ type_lookup_table_size +=
+ sizeof(uint32_t) + TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
+ }
VdexFile::VdexFileHeader vdex_header(/* has_dex_section= */ false);
VdexFile::VdexSectionHeader sections[static_cast<uint32_t>(VdexSection::kNumberOfSections)];
@@ -255,7 +281,14 @@
sections[VdexSection::kVerifierDepsSection].section_kind = VdexSection::kVerifierDepsSection;
sections[VdexSection::kVerifierDepsSection].section_offset =
GetChecksumsOffset() + sections[kChecksumSection].section_size;
- sections[VdexSection::kVerifierDepsSection].section_size = verifier_deps_data.size();
+ sections[VdexSection::kVerifierDepsSection].section_size = verifier_deps_size;
+
+ // Set TypeLookupTable section.
+ sections[VdexSection::kTypeLookupTableSection].section_kind =
+ VdexSection::kTypeLookupTableSection;
+ sections[VdexSection::kTypeLookupTableSection].section_offset =
+ sections[VdexSection::kVerifierDepsSection].section_offset + verifier_deps_with_padding_size;
+ sections[VdexSection::kTypeLookupTableSection].section_size = type_lookup_table_size;
if (!CreateDirectories(path, error_msg)) {
return false;
@@ -295,12 +328,27 @@
}
if (!out->WriteFully(reinterpret_cast<const char*>(verifier_deps_data.data()),
- verifier_deps_data.size())) {
+ verifier_deps_with_padding_size)) {
*error_msg = "Could not write verifier deps to " + path;
out->Unlink();
return false;
}
+ size_t written_type_lookup_table_size = 0;
+ for (const DexFile* dex_file : dex_files) {
+ TypeLookupTable type_lookup_table = TypeLookupTable::Create(*dex_file);
+ uint32_t size = type_lookup_table.RawDataLength();
+ DCHECK_ALIGNED(size, 4);
+ if (!out->WriteFully(reinterpret_cast<const char*>(&size), sizeof(uint32_t)) ||
+ !out->WriteFully(reinterpret_cast<const char*>(type_lookup_table.RawData()), size)) {
+ *error_msg = "Could not write type lookup table " + path;
+ out->Unlink();
+ return false;
+ }
+ written_type_lookup_table_size += sizeof(uint32_t) + size;
+ }
+ DCHECK_EQ(written_type_lookup_table_size, type_lookup_table_size);
+
if (out->FlushClose() != 0) {
*error_msg = "Could not flush and close " + path;
out->Unlink();
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 4dabfd4..eb8b817 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -81,7 +81,8 @@
kChecksumSection = 0,
kDexFileSection = 1,
kVerifierDepsSection = 2,
- kNumberOfSections = 3,
+ kTypeLookupTableSection = 3,
+ kNumberOfSections = 4,
};
class VdexFile {
@@ -168,6 +169,10 @@
return GetSectionHeader(VdexSection::kChecksumSection).section_size / sizeof(VdexChecksum);
}
+ bool HasTypeLookupTableSection() const {
+ return GetVdexFileHeader().GetNumberOfSections() >= (kTypeLookupTableSection + 1);
+ }
+
const VdexChecksum* GetDexChecksumsArray() const {
return reinterpret_cast<const VdexChecksum*>(
Begin() + GetSectionHeader(VdexSection::kChecksumSection).section_offset);
@@ -267,6 +272,8 @@
// is none.
const uint8_t* GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const;
+ const uint8_t* GetNextTypeLookupTableData(const uint8_t* cursor, uint32_t dex_file_index) const;
+
// Get the location checksum of the dex file number `dex_file_index`.
uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
DCHECK_LT(dex_file_index, GetNumberOfDexFiles());
@@ -308,6 +315,11 @@
return Begin() + GetSectionHeader(VdexSection::kDexFileSection).section_offset;
}
+ const uint8_t* TypeLookupTableDataBegin() const {
+ DCHECK(HasTypeLookupTableSection());
+ return Begin() + GetSectionHeader(VdexSection::kTypeLookupTableSection).section_offset;
+ }
+
MemMap mmap_;
DISALLOW_COPY_AND_ASSIGN(VdexFile);