Do not resolve types with vdex.
We don't need to, and it's time expensive.
test: test-art-host, 2x faster vdex compilation time.
bug: 30937355
Change-Id: Ic04ebfee9172ed676fbb38e6901615ed3473352a
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1b1de78..b6b2575 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -423,7 +423,7 @@
// Compile:
// 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
// compilation.
- if (!GetCompilerOptions().VerifyAtRuntime()) {
+ if (!GetCompilerOptions().VerifyAtRuntime() && !GetCompilerOptions().VerifyOnlyProfile()) {
Compile(class_loader, dex_files, timings);
}
if (dump_stats_) {
@@ -492,6 +492,7 @@
// TODO: we unquicken unconditionnally, as we don't know
// if the boot image has changed. How exactly we'll know is under
// experimentation.
+ TimingLogger::ScopedTiming t("Unquicken", timings);
Unquicken(dex_files, vdex_file->GetQuickeningInfo());
Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
@@ -983,8 +984,10 @@
<< "situations. Please check the log.";
}
- InitializeClasses(class_loader, dex_files, timings);
- VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
+ if (!verify_only_profile) {
+ InitializeClasses(class_loader, dex_files, timings);
+ VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false);
+ }
UpdateImageClasses(timings);
VLOG(compiler) << "UpdateImageClasses: " << GetMemoryUsageString(false);
@@ -2060,21 +2063,29 @@
std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
- const char* descriptor = dex_file->GetClassDescriptor(class_def);
- cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
- if (cls.Get() == nullptr) {
- CHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- } else if (set.find(class_def.class_idx_) == set.end()) {
- ObjectLock<mirror::Class> lock(soa.Self(), cls);
- mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
- // Create `VerifiedMethod`s for each methods, the compiler expects one for
- // quickening or compiling.
- // Note that this means:
- // - We're only going to compile methods that did verify.
- // - Quickening will not do checkcast ellision.
- // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
- PopulateVerifiedMethods(*dex_file, i, verification_results_);
+ if (set.find(class_def.class_idx_) == set.end()) {
+ if (GetCompilerOptions().VerifyOnlyProfile()) {
+ // Just update the compiled_classes_ map. The compiler doesn't need to resolve
+ // the type.
+ compiled_classes_.Overwrite(
+ ClassReference(dex_file, i), new CompiledClass(mirror::Class::kStatusVerified));
+ } else {
+ // Resolve the type, so later compilation stages know they don't need to verify
+ // the class.
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader));
+ if (cls.Get() != nullptr) {
+ ObjectLock<mirror::Class> lock(soa.Self(), cls);
+ mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self());
+ }
+ // Create `VerifiedMethod`s for each methods, the compiler expects one for
+ // quickening or compiling.
+ // Note that this means:
+ // - We're only going to compile methods that did verify.
+ // - Quickening will not do checkcast ellision.
+ // TODO(ngeoffray): Reconsider this once we refactor compiler filters.
+ PopulateVerifiedMethods(*dex_file, i, verification_results_);
+ }
}
}
}
@@ -2675,29 +2686,29 @@
}
void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
+ switch (status) {
+ case mirror::Class::kStatusNotReady:
+ case mirror::Class::kStatusError:
+ case mirror::Class::kStatusRetryVerificationAtRuntime:
+ case mirror::Class::kStatusVerified:
+ case mirror::Class::kStatusInitialized:
+ case mirror::Class::kStatusResolved:
+ break; // Expected states.
+ default:
+ LOG(FATAL) << "Unexpected class status for class "
+ << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
+ << " of " << status;
+ }
+
MutexLock mu(Thread::Current(), compiled_classes_lock_);
auto it = compiled_classes_.find(ref);
- if (it == compiled_classes_.end() || it->second->GetStatus() != status) {
- // An entry doesn't exist or the status is lower than the new status.
- if (it != compiled_classes_.end()) {
- CHECK_GT(status, it->second->GetStatus());
- delete it->second;
- }
- switch (status) {
- case mirror::Class::kStatusNotReady:
- case mirror::Class::kStatusError:
- case mirror::Class::kStatusRetryVerificationAtRuntime:
- case mirror::Class::kStatusVerified:
- case mirror::Class::kStatusInitialized:
- case mirror::Class::kStatusResolved:
- break; // Expected states.
- default:
- LOG(FATAL) << "Unexpected class status for class "
- << PrettyDescriptor(ref.first->GetClassDescriptor(ref.first->GetClassDef(ref.second)))
- << " of " << status;
- }
+ if (it == compiled_classes_.end()) {
CompiledClass* compiled_class = new CompiledClass(status);
compiled_classes_.Overwrite(ref, compiled_class);
+ } else if (status > it->second->GetStatus()) {
+ // Update the status if we now have a greater one. This happens with vdex,
+ // which records a class is verified, but does not resolve it.
+ it->second->SetStatus(status);
}
}