summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2021-03-18 22:23:04 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2021-03-25 18:08:51 +0000
commita129d8aef0dfe39edf39b5537852bc2c60496bfa (patch)
treeb5eded46436a3ff1b371a6a706cb7cf8a7e0878b
parentec7b19485ba4af8b0fd0804389c470b556322d13 (diff)
Revamp vdex format for better extensibility.
- Remove class loader context and boot classpath checksum sections. Those are not needed now that VerifierDeps don't depend on them. - Remove remaining quickening encoding. - Introduce sections in a vdex file, which can be extended without requiring a version change. Test: test.py Bug: 160294863 Change-Id: I4e3e25f34d242dc4de37f30ba9d78bcffbc1436d
-rw-r--r--dex2oat/dex2oat.cc16
-rw-r--r--dex2oat/dex2oat_vdex_test.cc2
-rw-r--r--dex2oat/linker/oat_writer.cc84
-rw-r--r--dex2oat/linker/oat_writer_test.cc3
-rw-r--r--oatdump/oatdump.cc25
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc24
-rw-r--r--runtime/oat_file.cc4
-rw-r--r--runtime/oat_file_assistant.cc2
-rw-r--r--runtime/oat_file_manager.cc10
-rw-r--r--runtime/runtime.cc21
-rw-r--r--runtime/vdex_file.cc313
-rw-r--r--runtime/vdex_file.h293
-rw-r--r--test/692-vdex-inmem-loader/src/Main.java8
13 files changed, 201 insertions, 604 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1c63a86971..c8a2cbdcb7 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1287,8 +1287,8 @@ class Dex2Oat final {
// the information to remain valid.
if (update_input_vdex_) {
File* vdex_file = vdex_files_.back().get();
- if (!vdex_file->PwriteFully(&VdexFile::VerifierDepsHeader::kVdexInvalidMagic,
- arraysize(VdexFile::VerifierDepsHeader::kVdexInvalidMagic),
+ if (!vdex_file->PwriteFully(&VdexFile::VdexFileHeader::kVdexInvalidMagic,
+ arraysize(VdexFile::VdexFileHeader::kVdexInvalidMagic),
/*offset=*/ 0u)) {
PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_file->GetPath();
return false;
@@ -1850,18 +1850,6 @@ class Dex2Oat final {
// Setup vdex for compilation.
const std::vector<const DexFile*>& dex_files = compiler_options_->dex_files_for_oat_file_;
- if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) {
- // TODO: we unquicken unconditionally, as we don't know
- // if the boot image has changed. How exactly we'll know is under
- // experimentation.
- TimingLogger::ScopedTiming time_unquicken("Unquicken", timings_);
-
- // We do not decompile a RETURN_VOID_NO_BARRIER into a RETURN_VOID, as the quickening
- // optimization does not depend on the boot image (the optimization relies on not
- // having final fields in a class, which does not change for an app).
- input_vdex_file_->Unquicken(dex_files, /* decompile_return_instruction */ false);
- }
-
// To allow initialization of classes that construct ThreadLocal objects in class initializer,
// re-initialize the ThreadLocal.nextHashCode to a new object that's not in the boot image.
ThreadLocalHashOverride thread_local_hash_override(
diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc
index fd511083e1..d9a555a3ea 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -81,7 +81,7 @@ class Dex2oatVdexTest : public Dex2oatEnvironmentTest {
}
// Verify the deps.
- VdexFile::VerifierDepsHeader vdex_header = vdex->GetVerifierDepsHeader();
+ VdexFile::VdexFileHeader vdex_header = vdex->GetVdexFileHeader();
if (!vdex_header.IsValid()) {
::testing::AssertionFailure() << "Invalid vdex header";
}
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 9070ed2d4f..3e2136089b 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -606,8 +606,9 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
DCHECK(write_state_ == WriteState::kAddingDexFileSources);
DCHECK(vdex_file.HasDexSection());
const uint8_t* current_dex_data = nullptr;
- for (size_t i = 0; i < vdex_file.GetVerifierDepsHeader().GetNumberOfDexFiles(); ++i) {
- current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
+ size_t i = 0;
+ for (; i < vdex_file.GetNumberOfDexFiles(); ++i) {
+ current_dex_data = vdex_file.GetNextDexFileData(current_dex_data, i);
if (current_dex_data == nullptr) {
LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
return false;
@@ -629,7 +630,7 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
header->file_size_);
}
- if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
+ if (vdex_file.GetNextDexFileData(current_dex_data, i) != nullptr) {
LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
return false;
}
@@ -693,9 +694,10 @@ bool OatWriter::WriteAndOpenDexFiles(
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
CHECK(write_state_ == WriteState::kAddingDexFileSources);
- // Reserve space for Vdex header and checksums.
- vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) +
- oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
+ size_vdex_header_ = sizeof(VdexFile::VdexFileHeader) +
+ VdexSection::kNumberOfSections * sizeof(VdexFile::VdexSectionHeader);
+ // Reserve space for Vdex header, sections, and checksums.
+ vdex_size_ = size_vdex_header_ + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
// Write DEX files into VDEX, mmap and open them.
std::vector<MemMap> dex_files_map;
@@ -3133,8 +3135,6 @@ bool OatWriter::WriteDexFiles(File* file,
}
if (extract_dex_files_into_vdex_) {
- // Add the dex section header.
- vdex_size_ += sizeof(VdexFile::DexSectionHeader);
vdex_dex_files_offset_ = vdex_size_;
// Perform dexlayout if requested.
@@ -3155,8 +3155,6 @@ bool OatWriter::WriteDexFiles(File* file,
for (OatDexFile& oat_dex_file : oat_dex_files_) {
// Dex files are required to be 4 byte aligned.
vdex_size_with_dex_files = RoundUp(vdex_size_with_dex_files, 4u);
- // Leave extra room for the quicken table offset.
- vdex_size_with_dex_files += sizeof(VdexFile::QuickeningTableOffsetType);
// Record offset for the dex file.
oat_dex_file.dex_file_offset_ = vdex_size_with_dex_files;
// Add the size of the dex file.
@@ -3236,18 +3234,9 @@ bool OatWriter::WriteDexFiles(File* file,
// Write dex files.
for (OatDexFile& oat_dex_file : oat_dex_files_) {
// Dex files are required to be 4 byte aligned.
- size_t quickening_table_offset_offset = RoundUp(vdex_size_, 4u);
- if (!update_input_vdex) {
- // Clear the padding.
- memset(vdex_begin_ + vdex_size_, 0, quickening_table_offset_offset - vdex_size_);
- // Initialize the quickening table offset to 0.
- auto* quickening_table_offset = reinterpret_cast<VdexFile::QuickeningTableOffsetType*>(
- vdex_begin_ + quickening_table_offset_offset);
- *quickening_table_offset = 0u;
- }
- size_dex_file_alignment_ += quickening_table_offset_offset - vdex_size_;
- size_quickening_table_offset_ += sizeof(VdexFile::QuickeningTableOffsetType);
- vdex_size_ = quickening_table_offset_offset + sizeof(VdexFile::QuickeningTableOffsetType);
+ size_t old_vdex_size = vdex_size_;
+ vdex_size_ = RoundUp(vdex_size_, 4u);
+ size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
// Write the actual dex file.
if (!WriteDexFile(file, &oat_dex_file, update_input_vdex)) {
return false;
@@ -3729,8 +3718,6 @@ bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier
buffer.reserve(64 * KB);
WriteVerifierDeps(verifier_deps, &buffer);
DCHECK_EQ(vdex_size_, old_vdex_size + buffer.size());
- WriteQuickeningInfo(&buffer);
- DCHECK_EQ(vdex_size_, old_vdex_size + buffer.size());
// Resize the vdex file.
if (vdex_file->SetLength(vdex_size_) != 0) {
@@ -3788,7 +3775,7 @@ bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier
}
// Write checksums
- off_t checksums_offset = sizeof(VdexFile::VerifierDepsHeader);
+ off_t checksums_offset = VdexFile::GetChecksumsOffset();
VdexFile::VdexChecksum* checksums_data =
reinterpret_cast<VdexFile::VdexChecksum*>(vdex_begin + checksums_offset);
for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
@@ -3797,24 +3784,29 @@ bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier
size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
}
- // Maybe write dex section header.
- DCHECK_NE(vdex_verifier_deps_offset_, 0u);
- DCHECK_NE(vdex_quickening_info_offset_, 0u);
+ // Write sections.
+ uint8_t* ptr = vdex_begin + sizeof(VdexFile::VdexFileHeader);
- bool has_dex_section = extract_dex_files_into_vdex_;
- if (has_dex_section) {
- DCHECK_NE(vdex_dex_files_offset_, 0u);
- size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_;
- size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_;
- size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
+ // Checksums section.
+ new (ptr) VdexFile::VdexSectionHeader(VdexSection::kChecksumSection,
+ checksums_offset,
+ size_vdex_checksums_);
+ ptr += sizeof(VdexFile::VdexFileHeader);
- void* dex_section_header_storage = checksums_data + oat_dex_files_.size();
- new (dex_section_header_storage) VdexFile::DexSectionHeader(dex_section_size,
- dex_shared_data_size,
- quickening_info_section_size);
- size_vdex_header_ += sizeof(VdexFile::DexSectionHeader);
- }
+ // 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);
+
+ // VerifierDeps section.
+ new (ptr) VdexFile::VdexSectionHeader(VdexSection::kVerifierDepsSection,
+ vdex_verifier_deps_offset_,
+ vdex_size_ - vdex_verifier_deps_offset_);
+ // All the contents (except the header) of the vdex file has been emitted in memory. Flush it
+ // to disk.
{
TimingLogger::ScopedTiming split("VDEX flush contents", timings_);
// Sync the data to the disk while the header is invalid. We do not want to end up with
@@ -3833,14 +3825,10 @@ bool OatWriter::FinishVdexFile(File* vdex_file, verifier::VerifierDeps* verifier
}
}
- // Write header.
- // TODO: Use `size_quickening_info_` instead of `verifier_deps_section_size` which
- // includes `size_quickening_info_alignment_`, adjust code in VdexFile.
- size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
-
- new (vdex_begin) VdexFile::VerifierDepsHeader(
- oat_dex_files_.size(), verifier_deps_section_size, has_dex_section);
- size_vdex_header_ += sizeof(VdexFile::VerifierDepsHeader);
+ // Now that we know all contents have been flushed to disk, we can write
+ // the header which will mke the vdex usable.
+ bool has_dex_section = extract_dex_files_into_vdex_;
+ new (vdex_begin) VdexFile::VdexFileHeader(has_dex_section);
// Note: If `extract_dex_files_into_vdex_`, we passed the ownership of the vdex dex file
// MemMap to the caller, so we need to use msync() for the range explicitly.
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index e77e361570..6cb3ac8dd9 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -291,9 +291,6 @@ class OatTest : public CommonCompilerDriverTest {
dex_file_data->GetHeader().file_size_));
ASSERT_EQ(dex_file_data->GetLocation(), opened_dex_file->GetLocation());
}
- const VdexFile::DexSectionHeader &vdex_header =
- opened_oat_file->GetVdexFile()->GetDexSectionHeader();
- ASSERT_EQ(vdex_header.GetQuickeningInfoSize(), 0u);
int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
ASSERT_GE(actual_vdex_size, 0);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4b381d0016..f389d7858e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -569,7 +569,7 @@ class OatDumper {
if (!options_.dump_header_only_) {
VariableIndentationOutputStream vios(&os);
- VdexFile::VerifierDepsHeader vdex_header = oat_file_.GetVdexFile()->GetVerifierDepsHeader();
+ VdexFile::VdexFileHeader vdex_header = oat_file_.GetVdexFile()->GetVdexFileHeader();
if (vdex_header.IsValid()) {
std::string error_msg;
std::vector<const DexFile*> dex_files;
@@ -590,10 +590,8 @@ class OatDumper {
} else {
os << "UNRECOGNIZED vdex file, magic "
<< vdex_header.GetMagic()
- << ", verifier deps version "
- << vdex_header.GetVerifierDepsVersion()
- << ", dex section version "
- << vdex_header.GetDexSectionVersion()
+ << ", version "
+ << vdex_header.GetVdexVersion()
<< "\n";
}
for (size_t i = 0; i < oat_dex_files_.size(); i++) {
@@ -614,9 +612,9 @@ class OatDumper {
}
DexFileUniqV vdex_dex_files;
- std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
- &vdex_dex_files,
- &error_msg);
+ std::unique_ptr<const VdexFile> vdex_file = OpenVdex(vdex_filename,
+ &vdex_dex_files,
+ &error_msg);
if (vdex_file.get() == nullptr) {
os << "Failed to open vdex file: " << error_msg << "\n";
return false;
@@ -764,10 +762,10 @@ class OatDumper {
}
// Returns nullptr and updates error_msg if the Vdex file cannot be opened, otherwise all Dex
- // files are fully unquickened and stored in dex_files
- std::unique_ptr<const VdexFile> OpenVdexUnquicken(const std::string& vdex_filename,
- /* out */ DexFileUniqV* dex_files,
- /* out */ std::string* error_msg) {
+ // files are stored in dex_files.
+ std::unique_ptr<const VdexFile> OpenVdex(const std::string& vdex_filename,
+ /* out */ DexFileUniqV* dex_files,
+ /* out */ std::string* error_msg) {
std::unique_ptr<const File> file(OS::OpenFileForReading(vdex_filename.c_str()));
if (file == nullptr) {
*error_msg = "Could not open file " + vdex_filename + " for reading.";
@@ -806,9 +804,6 @@ class OatDumper {
return nullptr;
}
- vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
- /* decompile_return_instruction= */ true);
-
*dex_files = std::move(tmp_dex_files);
return vdex_file;
}
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index eefbe41503..4aa81ff47e 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -51,28 +51,6 @@ static void RecomputeDexChecksum(art::DexFile* dex_file) {
dex_file->CalculateChecksum();
}
-static const art::VdexFile* GetVdex(const art::DexFile& original_dex_file) {
- const art::OatDexFile* oat_dex = original_dex_file.GetOatDexFile();
- if (oat_dex == nullptr) {
- return nullptr;
- }
- const art::OatFile* oat_file = oat_dex->GetOatFile();
- if (oat_file == nullptr) {
- return nullptr;
- }
- return oat_file->GetVdexFile();
-}
-
-static void DoDexUnquicken(const art::DexFile& new_dex_file,
- const art::DexFile& original_dex_file) {
- const art::VdexFile* vdex = GetVdex(original_dex_file);
- if (vdex != nullptr) {
- vdex->UnquickenDexFile(new_dex_file,
- original_dex_file,
- /* decompile_return_instruction= */ true);
- }
-}
-
static void DCheckVerifyDexFile(const art::DexFile& dex) {
if (art::kIsDebugBuild) {
std::string error;
@@ -150,8 +128,6 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi
new_dex_file->SetHiddenapiDomain(original.GetHiddenapiDomain());
- DoDexUnquicken(*new_dex_file, original);
-
RecomputeDexChecksum(const_cast<art::DexFile*>(new_dex_file.get()));
DCheckVerifyDexFile(*new_dex_file);
std::unique_ptr<FixedUpDexFile> ret(new FixedUpDexFile(std::move(new_dex_file), std::move(data)));
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index dc311c8b4f..115e0eadfc 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1549,9 +1549,9 @@ class OatFileBackedByVdex final : public OatFileBase {
std::unique_ptr<OatFileBackedByVdex> oat_file(new OatFileBackedByVdex(vdex_file->GetName()));
if (vdex_file->HasDexSection()) {
uint32_t i = 0;
- for (const uint8_t* dex_file_start = vdex_file->GetNextDexFileData(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) {
+ 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());
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 0fee0efa5b..245ae36622 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -337,7 +337,7 @@ bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* er
return true;
}
- uint32_t number_of_dex_files = file.GetVerifierDepsHeader().GetNumberOfDexFiles();
+ uint32_t number_of_dex_files = file.GetNumberOfDexFiles();
if (required_dex_checksums->size() != number_of_dex_files) {
*error_msg = StringPrintf("expected %zu dex files but found %u",
required_dex_checksums->size(),
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 25a24134ba..80afd91312 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -594,15 +594,6 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat_
DCHECK(context->OpenDexFiles())
<< "Context created from already opened dex files should not attempt to open again";
- // Check that we can use the vdex against this boot class path and in this class loader context.
- // Note 1: We do not need a class loader collision check because there is no compiled code.
- // Note 2: If these checks fail, we cannot fast-verify because the vdex does not contain
- // full VerifierDeps.
- if (!vdex_file->MatchesBootClassPathChecksums() ||
- !vdex_file->MatchesClassLoaderContext(*context.get())) {
- return dex_files;
- }
-
// Initialize an OatFile instance backed by the loaded vdex.
std::unique_ptr<OatFile> oat_file(OatFile::OpenFromVdex(MakeNonOwningPointerVector(dex_files),
std::move(vdex_file),
@@ -761,7 +752,6 @@ class BackgroundVerificationTask final : public Task {
if (!VdexFile::WriteToDisk(vdex_path_,
dex_files_,
verifier_deps,
- class_loader_context_,
&error_msg)) {
LOG(ERROR) << "Could not write anonymous vdex " << vdex_path_ << ": " << error_msg;
return;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a4e98f2e2a..6e7167d6e9 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -2958,27 +2958,6 @@ void Runtime::DeoptimizeBootImage() {
jit->GetCodeCache()->TransitionToDebuggable();
}
}
- // Also de-quicken all -quick opcodes. We do this for both BCP and non-bcp so if we are swapping
- // debuggable during startup by a plugin (eg JVMTI) even non-BCP code has its vdex files deopted.
- std::unordered_set<const VdexFile*> vdexs;
- GetClassLinker()->VisitKnownDexFiles(Thread::Current(), [&](const art::DexFile* df) {
- const OatDexFile* odf = df->GetOatDexFile();
- if (odf == nullptr) {
- return;
- }
- const OatFile* of = odf->GetOatFile();
- if (of == nullptr || of->IsDebuggable()) {
- // no Oat or already debuggable so no -quick.
- return;
- }
- vdexs.insert(of->GetVdexFile());
- });
- LOG(INFO) << "Unquickening " << vdexs.size() << " vdex files!";
- for (const VdexFile* vf : vdexs) {
- vf->AllowWriting(true);
- vf->UnquickenInPlace(/*decompile_return_instruction=*/true);
- vf->AllowWriting(false);
- }
}
Runtime::ScopedThreadPoolUsage::ScopedThreadPoolUsage()
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 1f2d4e51bc..02a15634e3 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -45,56 +45,24 @@
namespace art {
-constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexInvalidMagic[4];
-constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexMagic[4];
-constexpr uint8_t VdexFile::VerifierDepsHeader::kVerifierDepsVersion[4];
-constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersion[4];
-constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersionEmpty[4];
+constexpr uint8_t VdexFile::VdexFileHeader::kVdexInvalidMagic[4];
+constexpr uint8_t VdexFile::VdexFileHeader::kVdexMagic[4];
+constexpr uint8_t VdexFile::VdexFileHeader::kVdexVersion[4];
-bool VdexFile::VerifierDepsHeader::IsMagicValid() const {
+bool VdexFile::VdexFileHeader::IsMagicValid() const {
return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
}
-bool VdexFile::VerifierDepsHeader::IsVerifierDepsVersionValid() const {
- return (memcmp(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)) == 0);
+bool VdexFile::VdexFileHeader::IsVdexVersionValid() const {
+ return (memcmp(vdex_version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
}
-bool VdexFile::VerifierDepsHeader::IsDexSectionVersionValid() const {
- return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0) ||
- (memcmp(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)) == 0);
-}
-
-bool VdexFile::VerifierDepsHeader::HasDexSection() const {
- return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0);
-}
-
-VdexFile::VerifierDepsHeader::VerifierDepsHeader(uint32_t number_of_dex_files,
- uint32_t verifier_deps_size,
- bool has_dex_section,
- uint32_t bootclasspath_checksums_size,
- uint32_t class_loader_context_size)
- : number_of_dex_files_(number_of_dex_files),
- verifier_deps_size_(verifier_deps_size),
- bootclasspath_checksums_size_(bootclasspath_checksums_size),
- class_loader_context_size_(class_loader_context_size) {
+VdexFile::VdexFileHeader::VdexFileHeader(bool has_dex_section ATTRIBUTE_UNUSED)
+ : number_of_sections_(static_cast<uint32_t>(VdexSection::kNumberOfSections)) {
memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
- memcpy(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion));
- if (has_dex_section) {
- memcpy(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion));
- } else {
- memcpy(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty));
- }
+ memcpy(vdex_version_, kVdexVersion, sizeof(kVdexVersion));
DCHECK(IsMagicValid());
- DCHECK(IsVerifierDepsVersionValid());
- DCHECK(IsDexSectionVersionValid());
-}
-
-VdexFile::DexSectionHeader::DexSectionHeader(uint32_t dex_size,
- uint32_t dex_shared_data_size,
- uint32_t quickening_info_size)
- : dex_size_(dex_size),
- dex_shared_data_size_(dex_shared_data_size),
- quickening_info_size_(quickening_info_size) {
+ DCHECK(IsVdexVersionValid());
}
std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
@@ -182,66 +150,32 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
return nullptr;
}
- if (unquicken && vdex->HasDexSection()) {
- std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
- if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
- return nullptr;
- }
- // TODO: It would be nice to avoid doing the return-instruction stuff but then we end up not
- // being able to tell if we need dequickening later. Instead just get rid of that too.
- vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
- /* decompile_return_instruction= */ true);
- // Update the quickening info size to pretend there isn't any.
- size_t offset = vdex->GetDexSectionHeaderOffset();
- reinterpret_cast<DexSectionHeader*>(vdex->mmap_.Begin() + offset)->quickening_info_size_ = 0;
- }
-
- if (!writable) {
- vdex->AllowWriting(false);
- Runtime* runtime = Runtime::Current();
- // The runtime might not be available at this point if we're running
- // dex2oat or oatdump.
- if (runtime != nullptr) {
- size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeVdex();
- Runtime::MadviseFileForRange(madvise_size_limit,
- vdex->Size(),
- vdex->Begin(),
- vdex->End(),
- vdex_filename);
- }
- }
-
-
return vdex;
}
-const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const {
+const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const {
DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
if (cursor == nullptr) {
// Beginning of the iteration, return the first dex file if there is one.
- return HasDexSection() ? DexBegin() + sizeof(QuickeningTableOffsetType) : nullptr;
+ return HasDexSection() ? DexBegin() : nullptr;
+ } else if (dex_file_index >= GetNumberOfDexFiles()) {
+ return nullptr;
} else {
// Fetch the next dex file. Return null if there is none.
const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
// Dex files are required to be 4 byte aligned. the OatWriter makes sure they are, see
// OatWriter::SeekToDexFiles.
- data = AlignUp(data, 4);
-
- return (data == DexEnd()) ? nullptr : data + sizeof(QuickeningTableOffsetType);
+ return AlignUp(data, 4);
}
}
-void VdexFile::AllowWriting(bool val) const {
- CHECK(mmap_.Protect(val ? (PROT_READ | PROT_WRITE) : PROT_READ));
-}
-
bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::string* error_msg) const {
const ArtDexFileLoader dex_file_loader;
size_t i = 0;
- for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr);
+ for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr, i);
dex_file_start != nullptr;
- dex_file_start = GetNextDexFileData(dex_file_start), ++i) {
+ dex_file_start = GetNextDexFileData(dex_file_start, ++i)) {
size_t size = reinterpret_cast<const DexFile::Header*>(dex_file_start)->file_size_;
// TODO: Supply the location information for a vdex file.
static constexpr char kVdexLocation[] = "";
@@ -265,128 +199,6 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_
return true;
}
-void VdexFile::UnquickenInPlace(bool decompile_return_instruction) const {
- CHECK_NE(mmap_.GetProtect() & PROT_WRITE, 0)
- << "File not mapped writable. Cannot unquicken! " << mmap_;
- if (HasDexSection()) {
- std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
- std::string error_msg;
- if (!OpenAllDexFiles(&unique_ptr_dex_files, &error_msg)) {
- return;
- }
- Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
- decompile_return_instruction);
- // Update the quickening info size to pretend there isn't any.
- size_t offset = GetDexSectionHeaderOffset();
- reinterpret_cast<DexSectionHeader*>(mmap_.Begin() + offset)->quickening_info_size_ = 0;
- }
-}
-
-void VdexFile::Unquicken(const std::vector<const DexFile*>& target_dex_files,
- bool decompile_return_instruction) const {
- const uint8_t* source_dex = GetNextDexFileData(nullptr);
- for (const DexFile* target_dex : target_dex_files) {
- UnquickenDexFile(*target_dex, source_dex, decompile_return_instruction);
- source_dex = GetNextDexFileData(source_dex);
- }
- DCHECK(source_dex == nullptr);
-}
-
-uint32_t VdexFile::GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const {
- DCHECK_GE(source_dex_begin, DexBegin());
- DCHECK_LT(source_dex_begin, DexEnd());
- return reinterpret_cast<const QuickeningTableOffsetType*>(source_dex_begin)[-1];
-}
-
-CompactOffsetTable::Accessor VdexFile::GetQuickenInfoOffsetTable(
- const uint8_t* source_dex_begin,
- const ArrayRef<const uint8_t>& quickening_info) const {
- // The offset a is in preheader right before the dex file.
- const uint32_t offset = GetQuickeningInfoTableOffset(source_dex_begin);
- return CompactOffsetTable::Accessor(quickening_info.SubArray(offset).data());
-}
-
-CompactOffsetTable::Accessor VdexFile::GetQuickenInfoOffsetTable(
- const DexFile& dex_file,
- const ArrayRef<const uint8_t>& quickening_info) const {
- return GetQuickenInfoOffsetTable(dex_file.Begin(), quickening_info);
-}
-
-static ArrayRef<const uint8_t> GetQuickeningInfoAt(const ArrayRef<const uint8_t>& quickening_info,
- uint32_t quickening_offset) {
- // Subtract offset of one since 0 represents unused and cannot be in the table.
- ArrayRef<const uint8_t> remaining = quickening_info.SubArray(quickening_offset - 1);
- return remaining.SubArray(0u, QuickenInfoTable::SizeInBytes(remaining));
-}
-
-void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
- const DexFile& source_dex_file,
- bool decompile_return_instruction) const {
- UnquickenDexFile(
- target_dex_file, source_dex_file.Begin(), decompile_return_instruction);
-}
-
-void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
- const uint8_t* source_dex_begin,
- bool decompile_return_instruction) const {
- ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
- if (quickening_info.empty()) {
- // Bail early if there is no quickening info and no need to decompile. This means there is also
- // no RETURN_VOID to decompile since the empty table takes a non zero amount of space.
- return;
- }
- // Make sure to not unquicken the same code item multiple times.
- std::unordered_set<const dex::CodeItem*> unquickened_code_item;
- CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin,
- quickening_info));
- for (ClassAccessor class_accessor : target_dex_file.GetClasses()) {
- for (const ClassAccessor::Method& method : class_accessor.GetMethods()) {
- const dex::CodeItem* code_item = method.GetCodeItem();
- if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
- const uint32_t offset = accessor.GetOffset(method.GetIndex());
- // Offset being 0 means not quickened.
- if (offset != 0u) {
- ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset);
- optimizer::ArtDecompileDEX(
- target_dex_file,
- *code_item,
- quicken_data,
- decompile_return_instruction);
- }
- }
- }
- }
-}
-
-ArrayRef<const uint8_t> VdexFile::GetQuickenedInfoOf(const DexFile& dex_file,
- uint32_t dex_method_idx) const {
- ArrayRef<const uint8_t> quickening_info = GetQuickeningInfo();
- if (quickening_info.empty()) {
- return ArrayRef<const uint8_t>();
- }
- CHECK_LT(dex_method_idx, dex_file.NumMethodIds());
- const uint32_t quickening_offset =
- GetQuickenInfoOffsetTable(dex_file, quickening_info).GetOffset(dex_method_idx);
- if (quickening_offset == 0u) {
- return ArrayRef<const uint8_t>();
- }
- return GetQuickeningInfoAt(quickening_info, quickening_offset);
-}
-
-static std::string ComputeBootClassPathChecksumString() {
- Runtime* const runtime = Runtime::Current();
- // Do not include boot image extension checksums, use their dex file checksums instead. Unlike
- // oat files, vdex files do not reference anything in image spaces, so there is no reason why
- // loading or not loading a boot image extension would affect the validity of the vdex file.
- // Note: Update of a boot class path module such as conscrypt invalidates the vdex file anyway.
- ArrayRef<gc::space::ImageSpace* const> image_spaces(runtime->GetHeap()->GetBootImageSpaces());
- size_t boot_image_components =
- image_spaces.empty() ? 0u : image_spaces[0]->GetImageHeader().GetComponentCount();
- return gc::space::ImageSpace::GetBootClassPathChecksums(
- image_spaces.SubArray(/*pos=*/ 0u, boot_image_components),
- ArrayRef<const DexFile* const>(runtime->GetClassLinker()->GetBootClassPath()));
-}
-
static bool CreateDirectories(const std::string& child_path, /* out */ std::string* error_msg) {
size_t last_slash_pos = child_path.find_last_of('/');
CHECK_NE(last_slash_pos, std::string::npos) << "Invalid path: " << child_path;
@@ -407,19 +219,29 @@ static bool CreateDirectories(const std::string& child_path, /* out */ std::stri
bool VdexFile::WriteToDisk(const std::string& path,
const std::vector<const DexFile*>& dex_files,
const verifier::VerifierDeps& verifier_deps,
- const std::string& class_loader_context,
std::string* error_msg) {
std::vector<uint8_t> verifier_deps_data;
verifier_deps.Encode(dex_files, &verifier_deps_data);
- std::string boot_checksum = ComputeBootClassPathChecksumString();
- DCHECK_NE(boot_checksum, "");
+ VdexFile::VdexFileHeader vdex_header(/* has_dex_section= */ false);
+ VdexFile::VdexSectionHeader sections[static_cast<uint32_t>(VdexSection::kNumberOfSections)];
+
+ // Set checksum section.
+ sections[VdexSection::kChecksumSection].section_kind = VdexSection::kChecksumSection;
+ sections[VdexSection::kChecksumSection].section_offset = GetChecksumsOffset();
+ sections[VdexSection::kChecksumSection].section_size =
+ sizeof(VdexFile::VdexChecksum) * dex_files.size();
- VdexFile::VerifierDepsHeader deps_header(dex_files.size(),
- verifier_deps_data.size(),
- /* has_dex_section= */ false,
- boot_checksum.size(),
- class_loader_context.size());
+ // Set dex section.
+ sections[VdexSection::kDexFileSection].section_kind = VdexSection::kDexFileSection;
+ sections[VdexSection::kDexFileSection].section_offset = 0u;
+ sections[VdexSection::kDexFileSection].section_size = 0u;
+
+ // Set VerifierDeps section.
+ 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();
if (!CreateDirectories(path, error_msg)) {
return false;
@@ -431,12 +253,21 @@ bool VdexFile::WriteToDisk(const std::string& path,
return false;
}
- if (!out->WriteFully(reinterpret_cast<const char*>(&deps_header), sizeof(deps_header))) {
+ // Write header.
+ if (!out->WriteFully(reinterpret_cast<const char*>(&vdex_header), sizeof(vdex_header))) {
*error_msg = "Could not write vdex header to " + path;
out->Unlink();
return false;
}
+ // Write section infos.
+ if (!out->WriteFully(reinterpret_cast<const char*>(&sections), sizeof(sections))) {
+ *error_msg = "Could not write vdex sections to " + path;
+ out->Unlink();
+ return false;
+ }
+
+ // Write checksum section.
for (const DexFile* dex_file : dex_files) {
const uint32_t* checksum_ptr = &dex_file->GetHeader().checksum_;
static_assert(sizeof(*checksum_ptr) == sizeof(VdexFile::VdexChecksum));
@@ -444,7 +275,7 @@ bool VdexFile::WriteToDisk(const std::string& path,
sizeof(VdexFile::VdexChecksum))) {
*error_msg = "Could not write dex checksums to " + path;
out->Unlink();
- return false;
+ return false;
}
}
@@ -455,18 +286,6 @@ bool VdexFile::WriteToDisk(const std::string& path,
return false;
}
- if (!out->WriteFully(boot_checksum.c_str(), boot_checksum.size())) {
- *error_msg = "Could not write boot classpath checksum to " + path;
- out->Unlink();
- return false;
- }
-
- if (!out->WriteFully(class_loader_context.c_str(), class_loader_context.size())) {
- *error_msg = "Could not write class loader context to " + path;
- out->Unlink();
- return false;
- }
-
if (out->FlushClose() != 0) {
*error_msg = "Could not flush and close " + path;
out->Unlink();
@@ -478,13 +297,12 @@ bool VdexFile::WriteToDisk(const std::string& path,
bool VdexFile::MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers)
const {
- const VerifierDepsHeader& header = GetVerifierDepsHeader();
- if (dex_headers.size() != header.GetNumberOfDexFiles()) {
+ if (dex_headers.size() != GetNumberOfDexFiles()) {
LOG(WARNING) << "Mismatch of number of dex files in vdex (expected="
- << header.GetNumberOfDexFiles() << ", actual=" << dex_headers.size() << ")";
+ << GetNumberOfDexFiles() << ", actual=" << dex_headers.size() << ")";
return false;
}
- const VdexChecksum* checksums = header.GetDexChecksumsArray();
+ const VdexChecksum* checksums = GetDexChecksumsArray();
for (size_t i = 0; i < dex_headers.size(); ++i) {
if (checksums[i] != dex_headers[i]->checksum_) {
LOG(WARNING) << "Mismatch of dex file checksum in vdex (index=" << i << ")";
@@ -494,32 +312,6 @@ bool VdexFile::MatchesDexFileChecksums(const std::vector<const DexFile::Header*>
return true;
}
-bool VdexFile::MatchesBootClassPathChecksums() const {
- ArrayRef<const uint8_t> data = GetBootClassPathChecksumData();
- std::string vdex(reinterpret_cast<const char*>(data.data()), data.size());
- std::string runtime = ComputeBootClassPathChecksumString();
- if (vdex == runtime) {
- return true;
- } else {
- LOG(WARNING) << "Mismatch of boot class path checksum in vdex (expected="
- << vdex << ", actual=" << runtime << ")";
- return false;
- }
-}
-
-bool VdexFile::MatchesClassLoaderContext(const ClassLoaderContext& context) const {
- ArrayRef<const uint8_t> data = GetClassLoaderContextData();
- std::string spec(reinterpret_cast<const char*>(data.data()), data.size());
- ClassLoaderContext::VerificationResult result = context.VerifyClassLoaderContextMatch(spec);
- if (result != ClassLoaderContext::VerificationResult::kMismatch) {
- return true;
- } else {
- LOG(WARNING) << "Mismatch of class loader context in vdex (expected="
- << spec << ", actual=" << context.EncodeContextForOatFile("") << ")";
- return false;
- }
-}
-
static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker,
Thread* self,
const char* name,
@@ -577,14 +369,15 @@ ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls
// Find which dex file index from within the vdex file.
uint32_t index = 0;
- for (; index < GetVerifierDepsHeader().GetNumberOfDexFiles(); ++index) {
+ for (; index < GetNumberOfDexFiles(); ++index) {
if (dex_file.GetLocationChecksum() == GetLocationChecksum(index)) {
break;
}
}
- DCHECK_NE(index, GetVerifierDepsHeader().GetNumberOfDexFiles());
- const uint8_t* verifier_deps = GetVerifierDepsStart();
+ DCHECK_NE(index, GetNumberOfDexFiles());
+
+ const uint8_t* verifier_deps = GetVerifierDepsData().data();
const uint32_t* dex_file_class_defs = GetDexFileClassDefs(verifier_deps, index);
// Fetch type checks offsets.
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 6e11728061..4dabfd4910 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -49,18 +49,18 @@ class VerifierDeps;
// In the description below, D is the number of dex files.
//
// File format:
-// VdexFile::VerifierDepsHeader fixed-length header
-// Dex file checksums
+// VdexFileHeader fixed-length header
+// VdexSectionHeader[kNumberOfSections]
//
-// Optionally:
-// VdexFile::DexSectionHeader fixed-length header
+// Checksum section
+// VdexChecksum[D]
//
-// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
-// DEX[0] array of the input DEX files, the bytecode may have been quickened.
-// quicken_table_off[1]
-// DEX[1]
-// ...
-// DEX[D-1]
+// Optionally:
+// DexSection
+// DEX[0] array of the input DEX files
+// DEX[1]
+// ...
+// DEX[D-1]
//
// VerifierDeps
// 4-byte alignment
@@ -75,58 +75,45 @@ class VerifierDeps;
// uint32 Number of strings
// uint32[] String data offsets for each string
// uint8[] String data
-//
-//
-// Optionally:
-// QuickeningInfo
-// uint8[D][] quickening data
-// uint32[D][] quickening data offset tables
+
+
+enum VdexSection : uint32_t {
+ kChecksumSection = 0,
+ kDexFileSection = 1,
+ kVerifierDepsSection = 2,
+ kNumberOfSections = 3,
+};
class VdexFile {
public:
using VdexChecksum = uint32_t;
- using QuickeningTableOffsetType = uint32_t;
- struct VerifierDepsHeader {
+ struct VdexSectionHeader {
+ VdexSection section_kind;
+ uint32_t section_offset;
+ uint32_t section_size;
+
+ VdexSectionHeader(VdexSection kind, uint32_t offset, uint32_t size)
+ : section_kind(kind), section_offset(offset), section_size(size) {}
+
+ VdexSectionHeader() {}
+ };
+
+ struct VdexFileHeader {
public:
- VerifierDepsHeader(uint32_t number_of_dex_files_,
- uint32_t verifier_deps_size,
- bool has_dex_section,
- uint32_t bootclasspath_checksums_size = 0,
- uint32_t class_loader_context_size = 0);
+ explicit VdexFileHeader(bool has_dex_section);
const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
- const char* GetVerifierDepsVersion() const {
- return reinterpret_cast<const char*>(verifier_deps_version_);
+ const char* GetVdexVersion() const {
+ return reinterpret_cast<const char*>(vdex_version_);
}
- const char* GetDexSectionVersion() const {
- return reinterpret_cast<const char*>(dex_section_version_);
+ uint32_t GetNumberOfSections() const {
+ return number_of_sections_;
}
bool IsMagicValid() const;
- bool IsVerifierDepsVersionValid() const;
- bool IsDexSectionVersionValid() const;
+ bool IsVdexVersionValid() const;
bool IsValid() const {
- return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
- }
- bool HasDexSection() const;
-
- uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
- uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
- uint32_t GetBootClassPathChecksumStringSize() const { return bootclasspath_checksums_size_; }
- uint32_t GetClassLoaderContextStringSize() const { return class_loader_context_size_; }
-
- size_t GetSizeOfChecksumsSection() const {
- return sizeof(VdexChecksum) * GetNumberOfDexFiles();
- }
-
- const VdexChecksum* GetDexChecksumsArray() const {
- return reinterpret_cast<const VdexChecksum*>(
- reinterpret_cast<const uint8_t*>(this) + sizeof(VerifierDepsHeader));
- }
-
- VdexChecksum GetDexChecksumAtOffset(size_t idx) const {
- DCHECK_LT(idx, GetNumberOfDexFiles());
- return GetDexChecksumsArray()[idx];
+ return IsMagicValid() && IsVdexVersionValid();
}
static constexpr uint8_t kVdexInvalidMagic[] = { 'w', 'd', 'e', 'x' };
@@ -135,65 +122,62 @@ class VdexFile {
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
// The format version of the verifier deps header and the verifier deps.
- // Last update: Fast per-class access.
- static constexpr uint8_t kVerifierDepsVersion[] = { '0', '2', '6', '\0' };
-
- // The format version of the dex section header and the dex section, containing
- // both the dex code and the quickening data.
- // Last update: Add owned section for CompactDex.
- static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '2', '\0' };
-
- // If the .vdex file has no dex section (hence no dex code nor quickening data),
- // we encode this magic version.
- static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
+ // Last update: Introduce vdex sections.
+ static constexpr uint8_t kVdexVersion[] = { '0', '2', '7', '\0' };
uint8_t magic_[4];
- uint8_t verifier_deps_version_[4];
- uint8_t dex_section_version_[4];
- uint32_t number_of_dex_files_;
- uint32_t verifier_deps_size_;
- uint32_t bootclasspath_checksums_size_;
- uint32_t class_loader_context_size_;
+ uint8_t vdex_version_[4];
+ uint32_t number_of_sections_;
};
- struct DexSectionHeader {
- public:
- DexSectionHeader(uint32_t dex_size,
- uint32_t dex_shared_data_size,
- uint32_t quickening_info_size);
-
- uint32_t GetDexSize() const { return dex_size_; }
- uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
- uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
-
- size_t GetDexSectionSize() const {
- return sizeof(DexSectionHeader) +
- GetDexSize() +
- GetDexSharedDataSize();
- }
+ const VdexSectionHeader& GetSectionHeaderAt(uint32_t index) const {
+ DCHECK_LT(index, GetVdexFileHeader().GetNumberOfSections());
+ return *reinterpret_cast<const VdexSectionHeader*>(
+ Begin() + sizeof(VdexFileHeader) + index * sizeof(VdexSectionHeader));
+ }
- private:
- uint32_t dex_size_;
- uint32_t dex_shared_data_size_;
- uint32_t quickening_info_size_;
+ const VdexSectionHeader& GetSectionHeader(VdexSection kind) const {
+ return GetSectionHeaderAt(static_cast<uint32_t>(kind));
+ }
- friend class VdexFile; // For updating quickening_info_size_.
- };
+ static size_t GetChecksumsOffset() {
+ return sizeof(VdexFileHeader) +
+ static_cast<size_t>(VdexSection::kNumberOfSections) * sizeof(VdexSectionHeader);
+ }
size_t GetComputedFileSize() const {
- size_t size = sizeof(VerifierDepsHeader);
- const VerifierDepsHeader& header = GetVerifierDepsHeader();
- size += header.GetVerifierDepsSize();
- size += header.GetSizeOfChecksumsSection();
- if (header.HasDexSection()) {
- size += GetDexSectionHeader().GetDexSectionSize();
- size += GetDexSectionHeader().GetQuickeningInfoSize();
+ const VdexFileHeader& header = GetVdexFileHeader();
+ uint32_t size = sizeof(VdexFileHeader) +
+ header.GetNumberOfSections() * sizeof(VdexSectionHeader);
+ for (uint32_t i = 0; i < header.GetNumberOfSections(); ++i) {
+ size = std::max(size,
+ GetSectionHeaderAt(i).section_offset + GetSectionHeaderAt(i).section_size);
}
- size += header.GetBootClassPathChecksumStringSize();
- size += header.GetClassLoaderContextStringSize();
return size;
}
+ bool IsDexSectionValid() const;
+
+ bool HasDexSection() const {
+ return GetSectionHeader(VdexSection::kDexFileSection).section_size != 0u;
+ }
+ uint32_t GetVerifierDepsSize() const {
+ return GetSectionHeader(VdexSection::kVerifierDepsSection).section_size;
+ }
+ uint32_t GetNumberOfDexFiles() const {
+ return GetSectionHeader(VdexSection::kChecksumSection).section_size / sizeof(VdexChecksum);
+ }
+
+ const VdexChecksum* GetDexChecksumsArray() const {
+ return reinterpret_cast<const VdexChecksum*>(
+ Begin() + GetSectionHeader(VdexSection::kChecksumSection).section_offset);
+ }
+
+ VdexChecksum GetDexChecksumAt(size_t idx) const {
+ DCHECK_LT(idx, GetNumberOfDexFiles());
+ return GetDexChecksumsArray()[idx];
+ }
+
// Note: The file is called "primary" to match the naming with profiles.
static const constexpr char* kVdexNameInDmFile = "primary.vdex";
@@ -263,98 +247,36 @@ class VdexFile {
const uint8_t* End() const { return mmap_.End(); }
size_t Size() const { return mmap_.Size(); }
- const VerifierDepsHeader& GetVerifierDepsHeader() const {
- return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
- }
-
- uint32_t GetDexSectionHeaderOffset() const {
- return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
- }
-
- const DexSectionHeader& GetDexSectionHeader() const {
- DCHECK(GetVerifierDepsHeader().HasDexSection());
- return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
- }
-
- const uint8_t* GetVerifierDepsStart() const {
- const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
- if (GetVerifierDepsHeader().HasDexSection()) {
- // When there is a dex section, the verifier deps are after it, but before the quickening.
- return result + GetDexSectionHeader().GetDexSectionSize();
- } else {
- // When there is no dex section, the verifier deps are just after the header.
- return result;
- }
+ const VdexFileHeader& GetVdexFileHeader() const {
+ return *reinterpret_cast<const VdexFileHeader*>(Begin());
}
ArrayRef<const uint8_t> GetVerifierDepsData() const {
return ArrayRef<const uint8_t>(
- GetVerifierDepsStart(),
- GetVerifierDepsHeader().GetVerifierDepsSize());
- }
-
- ArrayRef<const uint8_t> GetQuickeningInfo() const {
- return ArrayRef<const uint8_t>(
- GetVerifierDepsData().end(),
- GetVerifierDepsHeader().HasDexSection()
- ? GetDexSectionHeader().GetQuickeningInfoSize() : 0);
- }
-
- ArrayRef<const uint8_t> GetBootClassPathChecksumData() const {
- return ArrayRef<const uint8_t>(
- GetQuickeningInfo().end(),
- GetVerifierDepsHeader().GetBootClassPathChecksumStringSize());
- }
-
- ArrayRef<const uint8_t> GetClassLoaderContextData() const {
- return ArrayRef<const uint8_t>(
- GetBootClassPathChecksumData().end(),
- GetVerifierDepsHeader().GetClassLoaderContextStringSize());
+ Begin() + GetSectionHeader(VdexSection::kVerifierDepsSection).section_offset,
+ GetSectionHeader(VdexSection::kVerifierDepsSection).section_size);
}
bool IsValid() const {
- return mmap_.Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
+ return mmap_.Size() >= sizeof(VdexFileHeader) && GetVdexFileHeader().IsValid();
}
// This method is for iterating over the dex files in the vdex. If `cursor` is null,
// the first dex file is returned. If `cursor` is not null, it must point to a dex
// file and this method returns the next dex file if there is one, or null if there
// is none.
- const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
+ const uint8_t* GetNextDexFileData(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, GetVerifierDepsHeader().GetNumberOfDexFiles());
- return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
+ DCHECK_LT(dex_file_index, GetNumberOfDexFiles());
+ return GetDexChecksumAt(dex_file_index);
}
// Open all the dex files contained in this vdex file.
bool OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files,
std::string* error_msg) const;
- // In-place unquicken the given `dex_files` based on `quickening_info`.
- // `decompile_return_instruction` controls if RETURN_VOID_BARRIER instructions are
- // decompiled to RETURN_VOID instructions using the slower ClassAccessor instead of the faster
- // QuickeningInfoIterator.
- // Always unquickens using the vdex dex files as the source for quicken tables.
- void Unquicken(const std::vector<const DexFile*>& target_dex_files,
- bool decompile_return_instruction) const;
-
- void UnquickenInPlace(bool decompile_return_instruction) const;
-
- // Fully unquicken `target_dex_file` based on `quickening_info`.
- void UnquickenDexFile(const DexFile& target_dex_file,
- const DexFile& source_dex_file,
- bool decompile_return_instruction) const;
-
- // Return the quickening info of a given method index (or null if it's empty).
- ArrayRef<const uint8_t> GetQuickenedInfoOf(const DexFile& dex_file,
- uint32_t dex_method_idx) const;
-
- bool HasDexSection() const {
- return GetVerifierDepsHeader().HasDexSection();
- }
-
// Writes a vdex into `path` and returns true on success.
// The vdex will not contain a dex section but will store checksums of `dex_files`,
// encoded `verifier_deps`, as well as the current boot class path cheksum and
@@ -362,7 +284,6 @@ class VdexFile {
static bool WriteToDisk(const std::string& path,
const std::vector<const DexFile*>& dex_files,
const verifier::VerifierDeps& verifier_deps,
- const std::string& class_loader_context,
std::string* error_msg);
// Returns true if the dex file checksums stored in the vdex header match
@@ -370,17 +291,6 @@ class VdexFile {
// order must match too.
bool MatchesDexFileChecksums(const std::vector<const DexFile::Header*>& dex_headers) const;
- // Returns true if the boot class path checksum stored in the vdex matches
- // the checksum of boot class path in the current runtime.
- bool MatchesBootClassPathChecksums() const;
-
- // Returns true if the class loader context stored in the vdex matches `context`.
- bool MatchesClassLoaderContext(const ClassLoaderContext& context) const;
-
- // Make the Vdex file & underlying dex-files RW or RO. Should only be used for in-place
- // dequickening.
- void AllowWriting(bool value) const;
-
ClassStatus ComputeClassStatus(Thread* self, Handle<mirror::Class> cls) const
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -391,35 +301,14 @@ class VdexFile {
}
private:
- uint32_t GetQuickeningInfoTableOffset(const uint8_t* source_dex_begin) const;
-
- // Source dex must be the in the vdex file.
- void UnquickenDexFile(const DexFile& target_dex_file,
- const uint8_t* source_dex_begin,
- bool decompile_return_instruction) const;
-
- CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
- const DexFile& dex_file,
- const ArrayRef<const uint8_t>& quickening_info) const;
-
- CompactOffsetTable::Accessor GetQuickenInfoOffsetTable(
- const uint8_t* source_dex_begin,
- const ArrayRef<const uint8_t>& quickening_info) const;
-
bool ContainsDexFile(const DexFile& dex_file) const;
const uint8_t* DexBegin() const {
DCHECK(HasDexSection());
- return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
- }
-
- const uint8_t* DexEnd() const {
- DCHECK(HasDexSection());
- return DexBegin() + GetDexSectionHeader().GetDexSize();
+ return Begin() + GetSectionHeader(VdexSection::kDexFileSection).section_offset;
}
- // mutable for AllowWriting()
- mutable MemMap mmap_;
+ MemMap mmap_;
DISALLOW_COPY_AND_ASSIGN(VdexFile);
};
diff --git a/test/692-vdex-inmem-loader/src/Main.java b/test/692-vdex-inmem-loader/src/Main.java
index 3ebe2c1cda..d7701fbba1 100644
--- a/test/692-vdex-inmem-loader/src/Main.java
+++ b/test/692-vdex-inmem-loader/src/Main.java
@@ -103,12 +103,14 @@ public class Main {
test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
/*invokeMethod*/ true);
- // Change boot classpath checksum.
+ // Change boot classpath checksum. vdex files can still be loaded.
appendToBootClassLoader(DEX_EXTRA, /*isCorePlatform*/ false);
loaders = multiLoader();
- test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ false);
- test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
+ test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
+ /*invokeMethod*/ false);
+ test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
+ /*invokeMethod*/ true);
loaders = multiLoader();
test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,