diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 127 |
1 files changed, 84 insertions, 43 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 32ad422158..706059369c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -50,7 +50,7 @@ #include "experimental_flags.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" -#include "gc/accounting/heap_bitmap.h" +#include "gc/accounting/heap_bitmap-inl.h" #include "gc/heap.h" #include "gc/space/image_space.h" #include "handle_scope-inl.h" @@ -96,6 +96,7 @@ namespace art { static constexpr bool kSanityCheckObjects = kIsDebugBuild; +static constexpr bool kVerifyArtMethodDeclaringClasses = kIsDebugBuild; static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) @@ -1197,6 +1198,23 @@ class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { ClassTable* const table_; }; +class VerifyDeclaringClassVisitor : public ArtMethodVisitor { + public: + VerifyDeclaringClassVisitor() SHARED_REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_) + : live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {} + + virtual void Visit(ArtMethod* method) + SHARED_REQUIRES(Locks::mutator_lock_, Locks::heap_bitmap_lock_) { + mirror::Class* klass = method->GetDeclaringClassUnchecked(); + if (klass != nullptr) { + CHECK(live_bitmap_->Test(klass)) << "Image method has unmarked declaring class"; + } + } + + private: + gc::accounting::HeapBitmap* const live_bitmap_; +}; + bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -1416,15 +1434,24 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( } } } - if (*out_forward_dex_cache_array) { - ScopedTrace timing("Fixup ArtMethod dex cache arrays"); - FixupArtMethodArrayVisitor visitor(header); - header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( - &visitor, - space->Begin(), - sizeof(void*)); - Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); - } + } + if (*out_forward_dex_cache_array) { + ScopedTrace timing("Fixup ArtMethod dex cache arrays"); + FixupArtMethodArrayVisitor visitor(header); + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor, + space->Begin(), + sizeof(void*)); + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get()); + } + if (kVerifyArtMethodDeclaringClasses) { + ScopedTrace timing("Verify declaring classes"); + ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_); + VerifyDeclaringClassVisitor visitor; + header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( + &visitor, + space->Begin(), + sizeof(void*)); } return true; } @@ -3715,10 +3742,6 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, DCHECK(klass.Get() != nullptr); DCHECK(supertype.Get() != nullptr); - StackHandleScope<1> hs(self); - // Acquire lock to prevent races on verifying the super class. - ObjectLock<mirror::Class> super_lock(self, supertype); - if (!supertype->IsVerified() && !supertype->IsErroneous()) { VerifyClass(self, supertype); } @@ -3732,6 +3755,7 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, PrettyDescriptor(klass.Get()).c_str(), PrettyDescriptor(supertype.Get()).c_str()); LOG(WARNING) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); + StackHandleScope<1> hs(self); Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException())); if (cause.Get() != nullptr) { // Set during VerifyClass call (if at all). @@ -3746,44 +3770,57 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, if (Runtime::Current()->IsAotCompiler()) { Runtime::Current()->GetCompilerCallbacks()->ClassRejected(ref); } + // Need to grab the lock to change status. + ObjectLock<mirror::Class> super_lock(self, klass); mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); return false; } void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass, LogSeverity log_level) { - // TODO: assert that the monitor on the Class is held - ObjectLock<mirror::Class> lock(self, klass); + { + // TODO: assert that the monitor on the Class is held + ObjectLock<mirror::Class> lock(self, klass); - // Don't attempt to re-verify if already sufficiently verified. - if (klass->IsVerified()) { - EnsureSkipAccessChecksMethods(klass); - return; - } - if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { - return; - } + // Is somebody verifying this now? + mirror::Class::Status old_status = klass->GetStatus(); + while (old_status == mirror::Class::kStatusVerifying || + old_status == mirror::Class::kStatusVerifyingAtRuntime) { + lock.WaitIgnoringInterrupts(); + CHECK_GT(klass->GetStatus(), old_status); + old_status = klass->GetStatus(); + } - // The class might already be erroneous, for example at compile time if we attempted to verify - // this class as a parent to another. - if (klass->IsErroneous()) { - ThrowEarlierClassFailure(klass.Get()); - return; - } + // The class might already be erroneous, for example at compile time if we attempted to verify + // this class as a parent to another. + if (klass->IsErroneous()) { + ThrowEarlierClassFailure(klass.Get()); + return; + } - if (klass->GetStatus() == mirror::Class::kStatusResolved) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self); - } else { - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) - << PrettyClass(klass.Get()); - CHECK(!Runtime::Current()->IsAotCompiler()); - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self); - } + // Don't attempt to re-verify if already sufficiently verified. + if (klass->IsVerified()) { + EnsureSkipAccessChecksMethods(klass); + return; + } + if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) { + return; + } - // Skip verification if disabled. - if (!Runtime::Current()->IsVerificationEnabled()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); - EnsureSkipAccessChecksMethods(klass); - return; + if (klass->GetStatus() == mirror::Class::kStatusResolved) { + mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifying, self); + } else { + CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) + << PrettyClass(klass.Get()); + CHECK(!Runtime::Current()->IsAotCompiler()); + mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self); + } + + // Skip verification if disabled. + if (!Runtime::Current()->IsVerificationEnabled()) { + mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self); + EnsureSkipAccessChecksMethods(klass); + return; + } } // Verify super class. @@ -3856,6 +3893,10 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass, LogSeve log_level, &error_msg); } + + // Verification is done, grab the lock again. + ObjectLock<mirror::Class> lock(self, klass); + if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.Get()) |