diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 221 |
1 files changed, 124 insertions, 97 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b8ed530981..edd6e3b522 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -19,6 +19,7 @@ #include <algorithm> #include <deque> #include <iostream> +#include <map> #include <memory> #include <queue> #include <string> @@ -1340,7 +1341,7 @@ bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches( // The image space is not yet added to the heap, avoid read barriers. ObjPtr<mirror::Class> klass = types[j].Read(); if (space->HasAddress(klass.Ptr())) { - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); + DCHECK(!klass->IsErroneous()) << klass->GetStatus(); auto it = new_class_set->Find(ClassTable::TableSlot(klass)); DCHECK(it != new_class_set->end()); DCHECK_EQ(it->Read(), klass); @@ -1703,7 +1704,7 @@ bool ClassLinker::AddImageSpace( for (int32_t j = 0, num_types = h_dex_cache->NumResolvedTypes(); j < num_types; j++) { ObjPtr<mirror::Class> klass = types[j].Read(); if (klass != nullptr) { - DCHECK_NE(klass->GetStatus(), mirror::Class::kStatusError); + DCHECK(!klass->IsErroneous()) << klass->GetStatus(); } } } else { @@ -2232,7 +2233,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, // For temporary classes we must wait for them to be retired. if (init_done_ && klass->IsTemp()) { CHECK(!klass->IsResolved()); - if (klass->IsErroneous()) { + if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } @@ -2240,10 +2241,10 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, Handle<mirror::Class> h_class(hs.NewHandle(klass)); ObjectLock<mirror::Class> lock(self, h_class); // Loop and wait for the resolving thread to retire this class. - while (!h_class->IsRetired() && !h_class->IsErroneous()) { + while (!h_class->IsRetired() && !h_class->IsErroneousUnresolved()) { lock.WaitIgnoringInterrupts(); } - if (h_class->IsErroneous()) { + if (h_class->IsErroneousUnresolved()) { ThrowEarlierClassFailure(h_class.Get()); return nullptr; } @@ -2258,7 +2259,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, static const size_t kNumYieldIterations = 1000; // How long each sleep is in us. static const size_t kSleepDurationUS = 1000; // 1 ms. - while (!klass->IsResolved() && !klass->IsErroneous()) { + while (!klass->IsResolved() && !klass->IsErroneousUnresolved()) { StackHandleScope<1> hs(self); HandleWrapperObjPtr<mirror::Class> h_class(hs.NewHandleWrapper(&klass)); { @@ -2269,7 +2270,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, // Check for circular dependencies between classes, the lock is required for SetStatus. if (!h_class->IsResolved() && h_class->GetClinitThreadId() == self->GetTid()) { ThrowClassCircularityError(h_class.Get()); - mirror::Class::SetStatus(h_class, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(h_class, mirror::Class::kStatusErrorUnresolved, self); return nullptr; } } @@ -2286,7 +2287,7 @@ mirror::Class* ClassLinker::EnsureResolved(Thread* self, ++index; } - if (klass->IsErroneous()) { + if (klass->IsErroneousUnresolved()) { ThrowEarlierClassFailure(klass); return nullptr; } @@ -2649,6 +2650,10 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, dex_class_def, &new_dex_file, &new_class_def); + // Check to see if an exception happened during runtime callbacks. Return if so. + if (self->IsExceptionPending()) { + return nullptr; + } ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get()); if (dex_cache == nullptr) { self->AssertPendingOOMException(); @@ -2687,7 +2692,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, // An exception occured during load, set status to erroneous while holding klass' lock in case // notification is necessary. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); } return nullptr; } @@ -2697,7 +2702,7 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, if (!LoadSuperAndInterfaces(klass, *new_dex_file)) { // Loading failed. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); } return nullptr; } @@ -2716,13 +2721,13 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) { // Linking failed. if (!klass->IsErroneous()) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); } return nullptr; } self->AssertNoPendingException(); CHECK(h_new_class.Get() != nullptr) << descriptor; - CHECK(h_new_class->IsResolved()) << descriptor; + CHECK(h_new_class->IsResolved() && !h_new_class->IsErroneousResolved()) << descriptor; // Instrumentation may have updated entrypoints for all methods of all // classes. However it could not update methods of this class while we @@ -2857,9 +2862,12 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* return true; } - if (runtime->IsFullyDeoptable()) { - // We need to be able to deoptimize at any time so we should always just ignore precompiled - // code and go to the interpreter assuming we don't already have jitted code. + if (runtime->IsJavaDebuggable()) { + // For simplicity, we ignore precompiled code and go to the interpreter + // assuming we don't already have jitted code. + // We could look at the oat file where `quick_code` is being defined, + // and check whether it's been compiled debuggable, but we decided to + // only rely on the JIT for debuggable apps. jit::Jit* jit = Runtime::Current()->GetJit(); return (jit == nullptr) || !jit->GetCodeCache()->ContainsPc(quick_code); } @@ -2867,18 +2875,13 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* if (runtime->IsNativeDebuggable()) { DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse()); // If we are doing native debugging, ignore application's AOT code, - // since we want to JIT it with extra stackmaps for native debugging. - // On the other hand, keep all AOT code from the boot image, since the - // blocking JIT would results in non-negligible performance impact. + // since we want to JIT it (at first use) with extra stackmaps for native + // debugging. We keep however all AOT code from the boot image, + // since the JIT-at-first-use is blocking and would result in non-negligible + // startup performance impact. return !runtime->GetHeap()->IsInBootImageOatFile(quick_code); } - if (Dbg::IsDebuggerActive()) { - // Boot image classes may be AOT-compiled as non-debuggable. - // This is not suitable for the Java debugger, so ignore the AOT code. - return runtime->GetHeap()->IsInBootImageOatFile(quick_code); - } - return false; } @@ -3817,7 +3820,7 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self, } // Need to grab the lock to change status. ObjectLock<mirror::Class> super_lock(self, klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } @@ -3939,8 +3942,8 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( bool preverified = VerifyClassUsingOatFile(dex_file, klass.Get(), oat_file_class_status); // If the oat file says the class had an error, re-run the verifier. That way we will get a // precise error message. To ensure a rerun, test: - // oat_file_class_status == mirror::Class::kStatusError => !preverified - DCHECK(!(oat_file_class_status == mirror::Class::kStatusError) || !preverified); + // mirror::Class::IsErroneous(oat_file_class_status) => !preverified + DCHECK(!mirror::Class::IsErroneous(oat_file_class_status) || !preverified); std::string error_msg; verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; @@ -3998,7 +4001,7 @@ verifier::MethodVerifier::FailureKind ClassLinker::VerifyClass( << " because: " << error_msg; self->AssertNoPendingException(); ThrowVerifyError(klass.Get(), "%s", error_msg.c_str()); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); } if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) { // Class is verified so we don't need to do any access check on its methods. @@ -4089,7 +4092,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, // at compile time). return false; } - if (oat_file_class_status == mirror::Class::kStatusError) { + if (mirror::Class::IsErroneous(oat_file_class_status)) { // Compile time verification failed with a hard error. This is caused by invalid instructions // in the class. These errors are unrecoverable. return false; @@ -4248,7 +4251,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& Handle<mirror::ObjectArray<mirror::Class>> h_interfaces( hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces))); if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); return nullptr; } } @@ -4463,7 +4466,8 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, return false; } - CHECK(klass->IsResolved()) << klass->PrettyClass() << ": state=" << klass->GetStatus(); + CHECK(klass->IsResolved() && !klass->IsErroneousResolved()) + << klass->PrettyClass() << ": state=" << klass->GetStatus(); if (!klass->IsVerified()) { VerifyClass(self, klass); @@ -4498,7 +4502,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, // A separate thread could have moved us all the way to initialized. A "simple" example // involves a subclass of the current class being initialized at the same time (which // will implicitly initialize the superclass, if scheduled that way). b/28254258 - DCHECK_NE(mirror::Class::kStatusError, klass->GetStatus()); + DCHECK(!klass->IsErroneous()) << klass->GetStatus(); if (klass->IsInitialized()) { return true; } @@ -4525,7 +4529,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, } if (!ValidateSuperClassDescriptors(klass)) { - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } self->AllowThreadSuspension(); @@ -4561,7 +4565,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, << (self->GetException() != nullptr ? self->GetException()->Dump() : ""); ObjectLock<mirror::Class> lock(self, klass); // Initialization failed because the super-class is erroneous. - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } } @@ -4592,7 +4596,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (!iface_initialized) { ObjectLock<mirror::Class> lock(self, klass); // Initialization failed because one of our interfaces with default methods is erroneous. - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } } @@ -4665,7 +4669,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, if (self->IsExceptionPending()) { WrapExceptionInInitializer(klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); success = false; } else if (Runtime::Current()->IsTransactionAborted()) { // The exception thrown when the transaction aborted has been caught and cleared @@ -4674,7 +4678,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, << mirror::Class::PrettyDescriptor(klass.Get()) << " without exception while transaction was aborted: re-throw it now."; Runtime::Current()->ThrowTransactionAbortError(self); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); success = false; } else { RuntimeStats* global_stats = Runtime::Current()->GetStats(); @@ -4758,7 +4762,7 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, // we were not using WaitIgnoringInterrupts), bail out. if (self->IsExceptionPending()) { WrapExceptionInInitializer(klass); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self); return false; } // Spurious wakeup? Go back to waiting. @@ -5169,7 +5173,7 @@ bool ClassLinker::LinkClass(Thread* self, klass->SetIFieldsPtrUnchecked(nullptr); if (UNLIKELY(h_new_class.Get() == nullptr)) { self->AssertPendingOOMException(); - mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); + mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorUnresolved, self); return false; } @@ -7781,7 +7785,7 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, } } } - DCHECK((resolved == nullptr) || resolved->IsResolved() || resolved->IsErroneous()) + DCHECK((resolved == nullptr) || resolved->IsResolved()) << resolved->PrettyDescriptor() << " " << resolved->GetStatus(); return resolved.Ptr(); } @@ -8478,71 +8482,94 @@ void ClassLinker::CleanupClassLoaders() { } } -std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { - ScopedTrace trace(__PRETTY_FUNCTION__); - ScopedObjectAccess soa(Thread::Current()); - ScopedAssertNoThreadSuspension ants(__FUNCTION__); - std::set<DexCacheResolvedClasses> ret; - VLOG(class_linker) << "Collecting resolved classes"; - const uint64_t start_time = NanoTime(); - ReaderMutexLock mu(soa.Self(), *Locks::dex_lock_); - // Loop through all the dex caches and inspect resolved classes. - for (const ClassLinker::DexCacheData& data : GetDexCachesData()) { - if (soa.Self()->IsJWeakCleared(data.weak_root)) { - continue; - } - ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(data.weak_root); - if (dex_cache == nullptr) { - continue; - } - const DexFile* dex_file = dex_cache->GetDexFile(); - const std::string& location = dex_file->GetLocation(); - const size_t num_class_defs = dex_file->NumClassDefs(); - // Use the resolved types, this will miss array classes. - const size_t num_types = dex_file->NumTypeIds(); - VLOG(class_linker) << "Collecting class profile for dex file " << location - << " types=" << num_types << " class_defs=" << num_class_defs; - DexCacheResolvedClasses resolved_classes(dex_file->GetLocation(), - dex_file->GetBaseLocation(), - dex_file->GetLocationChecksum()); - size_t num_resolved = 0; - std::unordered_set<dex::TypeIndex> class_set; - CHECK_EQ(num_types, dex_cache->NumResolvedTypes()); - for (size_t i = 0; i < num_types; ++i) { - ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(i)); - // Filter out null class loader since that is the boot class loader. - if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) { - continue; - } - ++num_resolved; - DCHECK(!klass->IsProxyClass()); - if (!klass->IsResolved()) { - DCHECK(klass->IsErroneous()); - continue; +class GetResolvedClassesVisitor : public ClassVisitor { + public: + GetResolvedClassesVisitor(std::set<DexCacheResolvedClasses>* result, bool ignore_boot_classes) + : result_(result), + ignore_boot_classes_(ignore_boot_classes), + last_resolved_classes_(result->end()), + last_dex_file_(nullptr), + vlog_is_on_(VLOG_IS_ON(class_linker)), + extra_stats_(), + last_extra_stats_(extra_stats_.end()) { } + + bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { + if (!klass->IsProxyClass() && + !klass->IsArrayClass() && + klass->IsResolved() && + !klass->IsErroneousResolved() && + (!ignore_boot_classes_ || klass->GetClassLoader() != nullptr)) { + const DexFile& dex_file = klass->GetDexFile(); + if (&dex_file != last_dex_file_) { + last_dex_file_ = &dex_file; + DexCacheResolvedClasses resolved_classes(dex_file.GetLocation(), + dex_file.GetBaseLocation(), + dex_file.GetLocationChecksum()); + last_resolved_classes_ = result_->find(resolved_classes); + if (last_resolved_classes_ == result_->end()) { + last_resolved_classes_ = result_->insert(resolved_classes).first; + } } - ObjPtr<mirror::DexCache> klass_dex_cache = klass->GetDexCache(); - if (klass_dex_cache == dex_cache) { - DCHECK(klass->IsResolved()); - CHECK_LT(klass->GetDexClassDefIndex(), num_class_defs); - class_set.insert(klass->GetDexTypeIndex()); + bool added = last_resolved_classes_->AddClass(klass->GetDexTypeIndex()); + if (UNLIKELY(vlog_is_on_) && added) { + const DexCacheResolvedClasses* resolved_classes = std::addressof(*last_resolved_classes_); + if (last_extra_stats_ == extra_stats_.end() || + last_extra_stats_->first != resolved_classes) { + last_extra_stats_ = extra_stats_.find(resolved_classes); + if (last_extra_stats_ == extra_stats_.end()) { + last_extra_stats_ = + extra_stats_.emplace(resolved_classes, ExtraStats(dex_file.NumClassDefs())).first; + } + } } } + return true; + } - if (!class_set.empty()) { - auto it = ret.find(resolved_classes); - if (it != ret.end()) { - // Already have the key, union the class type indexes. - it->AddClasses(class_set.begin(), class_set.end()); - } else { - resolved_classes.AddClasses(class_set.begin(), class_set.end()); - ret.insert(resolved_classes); + void PrintStatistics() const { + if (vlog_is_on_) { + for (const DexCacheResolvedClasses& resolved_classes : *result_) { + auto it = extra_stats_.find(std::addressof(resolved_classes)); + DCHECK(it != extra_stats_.end()); + const ExtraStats& extra_stats = it->second; + LOG(INFO) << "Dex location " << resolved_classes.GetDexLocation() + << " has " << resolved_classes.GetClasses().size() << " / " + << extra_stats.number_of_class_defs_ << " resolved classes"; } } + } + + private: + struct ExtraStats { + explicit ExtraStats(uint32_t number_of_class_defs) + : number_of_class_defs_(number_of_class_defs) {} + uint32_t number_of_class_defs_; + }; + + std::set<DexCacheResolvedClasses>* result_; + bool ignore_boot_classes_; + std::set<DexCacheResolvedClasses>::iterator last_resolved_classes_; + const DexFile* last_dex_file_; - VLOG(class_linker) << "Dex location " << location << " has " << num_resolved << " / " - << num_class_defs << " resolved classes"; + // Statistics. + bool vlog_is_on_; + std::map<const DexCacheResolvedClasses*, ExtraStats> extra_stats_; + std::map<const DexCacheResolvedClasses*, ExtraStats>::iterator last_extra_stats_; +}; + +std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) { + ScopedTrace trace(__PRETTY_FUNCTION__); + ScopedObjectAccess soa(Thread::Current()); + ScopedAssertNoThreadSuspension ants(__FUNCTION__); + std::set<DexCacheResolvedClasses> ret; + VLOG(class_linker) << "Collecting resolved classes"; + const uint64_t start_time = NanoTime(); + GetResolvedClassesVisitor visitor(&ret, ignore_boot_classes); + VisitClasses(&visitor); + if (VLOG_IS_ON(class_linker)) { + visitor.PrintStatistics(); + LOG(INFO) << "Collecting class profile took " << PrettyDuration(NanoTime() - start_time); } - VLOG(class_linker) << "Collecting class profile took " << PrettyDuration(NanoTime() - start_time); return ret; } |