summaryrefslogtreecommitdiff
path: root/compiler/driver/compiler_driver.cc
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2017-01-25 16:18:54 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2017-01-25 16:21:29 +0000
commit0a27fd0e1177c58a344e7321fcae716c94c127eb (patch)
tree2f2601f3fa11d295c653c898c867da4efadcfa98 /compiler/driver/compiler_driver.cc
parent8116003cc9dd1e74fac1682eec547b8bb0afb061 (diff)
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
Diffstat (limited to 'compiler/driver/compiler_driver.cc')
-rw-r--r--compiler/driver/compiler_driver.cc85
1 files changed, 67 insertions, 18 deletions
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<const DexFile*>& dex_files) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
+ MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(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<const DexFile*>& 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<mirror::ClassLoader> 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<mirror::Class> cls(hs.NewHandle<mirror::Class>(
+ 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<mirror::Class> lock(self, cls);
+ mirror::Class::SetStatus(cls, status, self);
+ }
+ } else {
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ }
+}
+
bool CompilerDriver::FastVerify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings) {
@@ -1963,12 +2016,12 @@ bool CompilerDriver::FastVerify(jobject jclass_loader,
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
- MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(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<mirror::Class> 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());
}
}
}