From 0a27fd0e1177c58a344e7321fcae716c94c127eb Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Wed, 25 Jan 2017 16:18:54 +0000 Subject: Preserve verification invariant after compile-time verification. After the verification step of the compiler, all classes in the dex file that are being compiled should be either erroneous, verified, or verify at runtime. vdex used to break that invariant by only setting the status of verified classes. bug: 34691602 bug: 34691854 test: 634-vdex-duplicate, which breaks for the newly added EnsureVerifiedOrVerifyAtRuntime check. Change-Id: I67bd57880ed3238525f36fde484e36ca535ae5d5 --- compiler/driver/compiler_driver.cc | 85 ++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 18 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index b00d083c28..320304873d 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -940,6 +940,31 @@ inline void CompilerDriver::CheckThreadPools() { DCHECK(single_thread_pool_ != nullptr); } +static void EnsureVerifiedOrVerifyAtRuntime(jobject jclass_loader, + const std::vector& dex_files) { + 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(); + + 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 char* descriptor = dex_file->GetClassDescriptor(class_def); + cls.Assign(class_linker->FindClass(soa.Self(), descriptor, class_loader)); + if (cls.Get() == nullptr) { + soa.Self()->ClearException(); + } else if (&cls->GetDexFile() == dex_file) { + DCHECK(cls->IsErroneous() || cls->IsVerified() || cls->IsCompileTimeVerified()) + << cls->PrettyClass() + << " " << cls->GetStatus(); + } + } + } +} + void CompilerDriver::PreCompile(jobject class_loader, const std::vector& dex_files, TimingLogger* timings) { @@ -984,6 +1009,9 @@ void CompilerDriver::PreCompile(jobject class_loader, } if (compiler_options_->IsAnyMethodCompilationEnabled()) { + if (kIsDebugBuild) { + EnsureVerifiedOrVerifyAtRuntime(class_loader, dex_files); + } InitializeClasses(class_loader, dex_files, timings); VLOG(compiler) << "InitializeClasses: " << GetMemoryUsageString(false); } @@ -1949,6 +1977,31 @@ static void PopulateVerifiedMethods(const DexFile& dex_file, DCHECK(!it.HasNext()); } +static void LoadAndUpdateStatus(const DexFile& dex_file, + const DexFile::ClassDef& class_def, + mirror::Class::Status status, + Handle class_loader, + Thread* self) + REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<1> hs(self); + const char* descriptor = dex_file.GetClassDescriptor(class_def); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Handle cls(hs.NewHandle( + class_linker->FindClass(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(self, cls); + mirror::Class::SetStatus(cls, status, self); + } + } else { + DCHECK(self->IsExceptionPending()); + self->ClearException(); + } +} + bool CompilerDriver::FastVerify(jobject jclass_loader, const std::vector& dex_files, TimingLogger* timings) { @@ -1963,12 +2016,12 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, 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; } + bool compiler_only_verifies = !GetCompilerOptions().IsAnyMethodCompilationEnabled(); + // 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 @@ -1983,28 +2036,16 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, 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()) { + if (compiler_only_verifies) { // 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 + // Update the class status, 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(); - } + LoadAndUpdateStatus( + *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self()); // Create `VerifiedMethod`s for each methods, the compiler expects one for // quickening or compiling. // Note that this means: @@ -2013,6 +2054,14 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // TODO(ngeoffray): Reconsider this once we refactor compiler filters. PopulateVerifiedMethods(*dex_file, i, verification_results_); } + } else if (!compiler_only_verifies) { + // Make sure later compilation stages know they should not try to verify + // this class again. + LoadAndUpdateStatus(*dex_file, + class_def, + mirror::Class::kStatusRetryVerificationAtRuntime, + class_loader, + soa.Self()); } } } -- cgit v1.2.3-59-g8ed1b