From 7498105ec7497bae2ba9f1a697da9efa0c979654 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Mon, 16 Jan 2017 17:54:09 +0000 Subject: Handle verify-profile and bootclasspath classes in vdex. Two problems: 1) An apk might define a class twice, or define a class that is already in the bootclasspath, or define a class that in the future happens to be in the bootclasspath. 2) verify-profile does not make classes that were not verified as verify-at-runtime for vdex. Fixes: 1) Check that the resolved class is part of the dex file that we are currently looking into. If not, don't update its verification status. 2) Make unverified classes as such when they are not in the profile. bug:34108532 Test: 634-vdex-duplicate Change-Id: I77c5e417c16c91af257b88b6456d07c0e4c2ca93 --- compiler/driver/compiler_driver.cc | 127 +++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 53 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 29502666ad..5da59f3b3d 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1950,66 +1950,82 @@ static void PopulateVerifiedMethods(const DexFile& dex_file, DCHECK(!it.HasNext()); } -void CompilerDriver::Verify(jobject jclass_loader, - const std::vector& dex_files, - TimingLogger* timings) { +bool CompilerDriver::FastVerify(jobject jclass_loader, + const std::vector& dex_files, + 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()); - StackHandleScope<2> hs(soa.Self()); - Handle class_loader( - hs.NewHandle(soa.Decode(jclass_loader))); - MutableHandle cls(hs.NewHandle(nullptr)); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (verifier_deps->ValidateDependencies(class_loader, soa.Self())) { - // We successfully validated the dependencies, now update class status - // of verified classes. Note that the dependencies also record which classes - // could not be fully verified; we could try again, but that would hurt verification - // time. So instead we assume these classes still need to be verified at - // runtime. - for (const DexFile* dex_file : dex_files) { - // Fetch the list of unverified classes and turn it into a set for faster - // lookups. - const std::vector& unverified_classes = - verifier_deps->GetUnverifiedClasses(*dex_file); - std::set 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); - if (set.find(class_def.class_idx_) == set.end()) { - if (!GetCompilerOptions().IsAnyMethodCompilationEnabled()) { - // 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 lock(soa.Self(), cls); - mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self()); - } else { - DCHECK(soa.Self()->IsExceptionPending()); - soa.Self()->ClearException(); - } - // 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 (verifier_deps == nullptr) { + return false; + } + TimingLogger::ScopedTiming t("Fast Verify", timings); + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); + Handle class_loader( + hs.NewHandle(soa.Decode(jclass_loader))); + MutableHandle cls(hs.NewHandle(nullptr)); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + if (!verifier_deps->ValidateDependencies(class_loader, soa.Self())) { + return false; + } + + // We successfully validated the dependencies, now update class status + // of verified classes. Note that the dependencies also record which classes + // could not be fully verified; we could try again, but that would hurt verification + // time. So instead we assume these classes still need to be verified at + // runtime. + for (const DexFile* dex_file : dex_files) { + // Fetch the list of unverified classes and turn it into a set for faster + // lookups. + const std::vector& unverified_classes = + verifier_deps->GetUnverifiedClasses(*dex_file); + std::set 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); + if (set.find(class_def.class_idx_) == set.end()) { + if (!GetCompilerOptions().IsAnyMethodCompilationEnabled()) { + // 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) { + // Check that the class is resolved with the current dex file. We might get + // a boot image class, or a class in a different dex file for multidex, and + // we should not update the status in that case. + if (&cls->GetDexFile() == dex_file) { + ObjectLock lock(soa.Self(), cls); + mirror::Class::SetStatus(cls, mirror::Class::kStatusVerified, soa.Self()); } + } else { + DCHECK(soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); } + // 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_); } } - return; } } + return true; +} + +void CompilerDriver::Verify(jobject jclass_loader, + const std::vector& dex_files, + TimingLogger* timings) { + if (FastVerify(jclass_loader, dex_files, timings)) { + return; + } // 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 @@ -2017,7 +2033,7 @@ void CompilerDriver::Verify(jobject jclass_loader, // Then dex2oat can update the vdex file with these new dependencies. if (!GetCompilerOptions().IsBootImage()) { // Create the main VerifierDeps, and set it to this thread. - verifier_deps = new verifier::VerifierDeps(dex_files); + verifier::VerifierDeps* 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. @@ -2026,6 +2042,7 @@ void CompilerDriver::Verify(jobject jclass_loader, worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files)); } } + // Note: verification should not be pulling in classes anymore when compiling the boot image, // as all should have been resolved before. As such, doing this in parallel should still // be deterministic. @@ -2041,6 +2058,7 @@ void CompilerDriver::Verify(jobject jclass_loader, if (!GetCompilerOptions().IsBootImage()) { // Merge all VerifierDeps into the main one. + verifier::VerifierDeps* verifier_deps = Thread::Current()->GetVerifierDeps(); for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) { verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps(); worker->GetThread()->SetVerifierDeps(nullptr); @@ -2061,7 +2079,10 @@ class VerifyClassVisitor : public CompilationVisitor { ScopedObjectAccess soa(Thread::Current()); const DexFile& dex_file = *manager_->GetDexFile(); if (!manager_->GetCompiler()->ShouldVerifyClassBasedOnProfile(dex_file, class_def_index)) { - // Skip verification since the class is not in the profile. + // Skip verification since the class is not in the profile, and let the VerifierDeps know + // that the class will need to be verified at runtime. + verifier::VerifierDeps::MaybeRecordVerificationStatus( + dex_file, dex::TypeIndex(class_def_index), verifier::MethodVerifier::kSoftFailure); return; } const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); -- cgit v1.2.3-59-g8ed1b