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);