Use input-vdex-fd, or input-vdex in dex2oat.
input-vdex-fd is used by installd
input-vdex is used by run-tests, and (will be used by) go/lem
This change copies the contents of the passed vdex to the new one,
unquicken the new vdex, and run the fast verification on the new
vdex.
bug:30937355
Test: device boots, apps get updated faster with vdex
Test: set TEST_VDEX to true in run-test-jar, run all tests
Test: 628-vdex
Change-Id: Idfbac4de411cebcf8ea7a6af7a417d7c7908dd72
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index e155e10..ad75ec4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -45,6 +45,7 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
+#include "dex/dex_to_dex_decompiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "driver/compiler_options.h"
@@ -72,6 +73,7 @@
#include "transaction.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "utils/swap_space.h"
+#include "vdex_file.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
#include "verifier/verifier_log_mode.h"
@@ -394,7 +396,6 @@
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
@@ -406,7 +407,7 @@
// 2) Resolve all classes
// 3) Attempt to verify all classes
// 4) Attempt to initialize image classes, and trivially initialized classes
- PreCompile(class_loader, dex_files, verifier_deps, timings);
+ PreCompile(class_loader, dex_files, timings);
if (GetCompilerOptions().IsBootImage()) {
// We don't need to setup the intrinsics for non boot image compilation, as
// those compilations will pick up a boot image that have the ArtMethod already
@@ -433,6 +434,72 @@
FreeThreadPools();
}
+// In-place unquicken the given `dex_files` based on `quickening_info`.
+static void Unquicken(const std::vector<const DexFile*>& dex_files,
+ const ArrayRef<const uint8_t>& quickening_info) {
+ const uint8_t* quickening_info_ptr = quickening_info.data();
+ const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
+ for (const DexFile* dex_file : dex_files) {
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ ClassDataItemIterator it(*dex_file, class_data);
+ // Skip fields
+ while (it.HasNextStaticField()) {
+ it.Next();
+ }
+ while (it.HasNextInstanceField()) {
+ it.Next();
+ }
+
+ // Unquicken each method.
+ while (it.HasNextDirectMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(
+ *code_item, ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size));
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+
+ while (it.HasNextVirtualMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(
+ *code_item, ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size));
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
+ }
+ DCHECK_EQ(quickening_info_ptr, quickening_info_end) << "Failed to use all quickening info";
+}
+
+void CompilerDriver::CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ VdexFile* vdex_file,
+ TimingLogger* timings) {
+ if (vdex_file != nullptr) {
+ // TODO: we unquicken unconditionnally, as we don't know
+ // if the boot image has changed. How exactly we'll know is under
+ // experimentation.
+ Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+ Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
+ new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
+ }
+ CompileAll(class_loader, dex_files, timings);
+}
+
static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file, const DexFile::ClassDef& class_def)
@@ -673,7 +740,7 @@
InitializeThreadPools();
- PreCompile(jclass_loader, dex_files, /* verifier_deps */ nullptr, timings);
+ PreCompile(jclass_loader, dex_files, timings);
// Can we run DEX-to-DEX compiler on this class ?
optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
@@ -870,7 +937,6 @@
void CompilerDriver::PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
CheckThreadPools();
@@ -904,7 +970,7 @@
VLOG(compiler) << "Resolve const-strings: " << GetMemoryUsageString(false);
}
- Verify(class_loader, dex_files, verifier_deps, timings);
+ Verify(class_loader, dex_files, timings);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
@@ -1936,8 +2002,10 @@
void CompilerDriver::Verify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
+ verifier::VerifierDeps* verifier_deps =
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
+ // If there is an existing `VerifierDeps`, try to use it for fast verification.
if (verifier_deps != nullptr) {
TimingLogger::ScopedTiming t("Fast Verify", timings);
ScopedObjectAccess soa(Thread::Current());
@@ -1975,16 +2043,15 @@
}
}
- // If there is no passed `verifier_deps` (because of non-existing vdex), or
- // the passed `verifier_deps` is not valid anymore, create a new one for
+ // If there is no existing `verifier_deps` (because of non-existing vdex), or
+ // the existing `verifier_deps` is not valid anymore, create a new one for
// non boot image compilation. The verifier will need it to record the new dependencies.
// Then dex2oat can update the vdex file with these new dependencies.
if (!GetCompilerOptions().IsBootImage()) {
// Create the main VerifierDeps, and set it to this thread.
- Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
- new verifier::VerifierDeps(dex_files));
- Thread::Current()->SetVerifierDeps(
- Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps());
+ verifier_deps = new verifier::VerifierDeps(dex_files);
+ Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(verifier_deps);
+ Thread::Current()->SetVerifierDeps(verifier_deps);
// Create per-thread VerifierDeps to avoid contention on the main one.
// We will merge them after verification.
for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
@@ -2005,13 +2072,11 @@
}
if (!GetCompilerOptions().IsBootImage()) {
- verifier::VerifierDeps* main_deps =
- Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
// Merge all VerifierDeps into the main one.
for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
worker->GetThread()->SetVerifierDeps(nullptr);
- main_deps->MergeWith(*thread_deps, dex_files);;
+ verifier_deps->MergeWith(*thread_deps, dex_files);;
delete thread_deps;
}
Thread::Current()->SetVerifierDeps(nullptr);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c7719fb..7418b00 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -51,7 +51,6 @@
namespace verifier {
class MethodVerifier;
-class VerifierDeps;
class VerifierDepsTest;
} // namespace verifier
@@ -69,6 +68,7 @@
using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>;
template<class T> class Handle;
class TimingLogger;
+class VdexFile;
class VerificationResults;
class VerifiedMethod;
@@ -119,7 +119,12 @@
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
+ TimingLogger* timings)
+ REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
+
+ void CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ VdexFile* vdex_file,
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
@@ -420,7 +425,6 @@
private:
void PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
@@ -443,7 +447,6 @@
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings);
void VerifyDexFile(jobject class_loader,
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index eed9d11..153aff4 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -403,6 +403,35 @@
return true;
}
+// Add dex file source(s) from a vdex file specified by a file handle.
+bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
+ const char* location,
+ CreateTypeLookupTable create_type_lookup_table) {
+ DCHECK(write_state_ == WriteState::kAddingDexFileSources);
+ const uint8_t* current_dex_data = nullptr;
+ for (size_t i = 0; ; ++i) {
+ current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
+ if (current_dex_data == nullptr) {
+ break;
+ }
+ if (!DexFile::IsMagicValid(current_dex_data)) {
+ LOG(ERROR) << "Invalid magic in vdex file created from " << location;
+ return false;
+ }
+ // We used `zipped_dex_file_locations_` to keep the strings in memory.
+ zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+ const char* full_location = zipped_dex_file_locations_.back().c_str();
+ oat_dex_files_.emplace_back(full_location,
+ DexFileSource(current_dex_data),
+ create_type_lookup_table);
+ }
+ if (oat_dex_files_.empty()) {
+ LOG(ERROR) << "No dex files in vdex file created from " << location;
+ return false;
+ }
+ return true;
+}
+
// Add dex file source from raw memory.
bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
const char* location,
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index f9671d7..0dcf79e 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -42,6 +42,7 @@
class OutputStream;
class TimingLogger;
class TypeLookupTable;
+class VdexFile;
class ZipEntry;
namespace debug {
@@ -116,7 +117,8 @@
// To produce a valid oat file, the user must first add sources with any combination of
// - AddDexFileSource(),
// - AddZippedDexFilesSource(),
- // - AddRawDexFileSource().
+ // - AddRawDexFileSource(),
+ // - AddVdexDexFilesSource().
// Then the user must call in order
// - WriteAndOpenDexFiles()
// - Initialize()
@@ -145,6 +147,11 @@
const char* location,
uint32_t location_checksum,
CreateTypeLookupTable create_type_lookup_table = CreateTypeLookupTable::kDefault);
+ // Add dex file source(s) from a vdex file.
+ bool AddVdexDexFilesSource(
+ const VdexFile& vdex_file,
+ const char* location,
+ CreateTypeLookupTable create_type_lookup_table = CreateTypeLookupTable::kDefault);
dchecked_vector<const char*> GetSourceLocations() const;
// Write raw dex files to the vdex file, mmap the file and open the dex files from it.
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index dcf3619..525a2ee 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -83,10 +83,13 @@
// The compiler driver handles the verifier deps in the callbacks, so
// remove what this class did for unit testing.
verifier_deps_.reset(nullptr);
- callbacks_->SetVerifierDeps(nullptr);
- compiler_driver_->Verify(class_loader_, dex_files_, deps, &timings);
+ callbacks_->SetVerifierDeps(deps);
+ compiler_driver_->Verify(class_loader_, dex_files_, &timings);
// The compiler driver may have updated the VerifierDeps in the callback object.
- verifier_deps_.reset(callbacks_->GetVerifierDeps());
+ if (callbacks_->GetVerifierDeps() != deps) {
+ verifier_deps_.reset(callbacks_->GetVerifierDeps());
+ }
+ callbacks_->SetVerifierDeps(nullptr);
}
void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) {