diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 180 |
1 files changed, 89 insertions, 91 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 74c04d19b6..1219f6f39f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -370,7 +370,10 @@ ClassLinker::ClassLinker(InternTable* intern_table) quick_imt_conflict_trampoline_(nullptr), quick_generic_jni_trampoline_(nullptr), quick_to_interpreter_bridge_trampoline_(nullptr), - image_pointer_size_(kRuntimePointerSize) { + image_pointer_size_(kRuntimePointerSize), + cha_(Runtime::Current()->IsAotCompiler() ? nullptr : new ClassHierarchyAnalysis()) { + // For CHA disabled during Aot, see b/34193647. + CHECK(intern_table_ != nullptr); static_assert(kFindArrayCacheSize == arraysize(find_array_class_cache_), "Array cache size wrong."); @@ -1138,49 +1141,6 @@ class FixupArtMethodArrayVisitor : public ArtMethodVisitor { const ImageHeader& header_; }; -class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { - public: - explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} - - virtual void Visit(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { - ObjPtr<mirror::Class> klass = method->GetDeclaringClass(); - if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { - CHECK_EQ(table_->LookupByDescriptor(klass), klass) << mirror::Class::PrettyClass(klass); - } - } - - private: - ClassTable* const table_; -}; - -class VerifyDirectInterfacesInTableClassVisitor { - public: - explicit VerifyDirectInterfacesInTableClassVisitor(ObjPtr<mirror::ClassLoader> class_loader) - : class_loader_(class_loader), self_(Thread::Current()) { } - - bool operator()(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) { - if (!klass->IsPrimitive() && klass->GetClassLoader() == class_loader_) { - classes_.push_back(klass); - } - return true; - } - - void Check() const REQUIRES_SHARED(Locks::mutator_lock_) { - for (ObjPtr<mirror::Class> klass : classes_) { - for (uint32_t i = 0, num = klass->NumDirectInterfaces(); i != num; ++i) { - CHECK(klass->GetDirectInterface(self_, klass, i) != nullptr) - << klass->PrettyDescriptor() << " iface #" << i; - } - } - } - - private: - ObjPtr<mirror::ClassLoader> class_loader_; - Thread* self_; - std::vector<ObjPtr<mirror::Class>> classes_; -}; - class VerifyDeclaringClassVisitor : public ArtMethodVisitor { public: VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) @@ -1763,6 +1723,63 @@ class ImageSanityChecks FINAL { std::vector<const ImageSection*> runtime_method_sections_; }; +static void VerifyAppImage(const ImageHeader& header, + const Handle<mirror::ClassLoader>& class_loader, + const Handle<mirror::ObjectArray<mirror::DexCache> >& dex_caches, + ClassTable* class_table, gc::space::ImageSpace* space) + REQUIRES_SHARED(Locks::mutator_lock_) { + { + class VerifyClassInTableArtMethodVisitor : public ArtMethodVisitor { + public: + explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {} + + virtual void Visit(ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) { + ObjPtr<mirror::Class> klass = method->GetDeclaringClass(); + if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) { + CHECK_EQ(table_->LookupByDescriptor(klass), klass) << mirror::Class::PrettyClass(klass); + } + } + + private: + ClassTable* const table_; + }; + VerifyClassInTableArtMethodVisitor visitor(class_table); + header.VisitPackedArtMethods(&visitor, space->Begin(), kRuntimePointerSize); + } + { + // Verify that all direct interfaces of classes in the class table are also resolved. + std::vector<ObjPtr<mirror::Class>> classes; + auto verify_direct_interfaces_in_table = [&](ObjPtr<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_) { + if (!klass->IsPrimitive() && klass->GetClassLoader() == class_loader.Get()) { + classes.push_back(klass); + } + return true; + }; + class_table->Visit(verify_direct_interfaces_in_table); + Thread* self = Thread::Current(); + for (ObjPtr<mirror::Class> klass : classes) { + for (uint32_t i = 0, num = klass->NumDirectInterfaces(); i != num; ++i) { + CHECK(klass->GetDirectInterface(self, klass, i) != nullptr) + << klass->PrettyDescriptor() << " iface #" << i; + } + } + } + // Check that all non-primitive classes in dex caches are also in the class table. + for (int32_t i = 0; i < dex_caches->GetLength(); i++) { + ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i); + mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); + for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { + ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); + if (klass != nullptr && !klass->IsPrimitive()) { + CHECK(class_table->Contains(klass)) + << klass->PrettyDescriptor() << " " << dex_cache->GetDexFile()->GetLocation(); + } + } + } +} + bool ClassLinker::AddImageSpace( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -2016,28 +2033,13 @@ bool ClassLinker::AddImageSpace( WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); class_table->AddClassSet(std::move(temp_set)); } + if (kIsDebugBuild && app_image) { // This verification needs to happen after the classes have been added to the class loader. // Since it ensures classes are in the class table. - VerifyClassInTableArtMethodVisitor visitor2(class_table); - header.VisitPackedArtMethods(&visitor2, space->Begin(), kRuntimePointerSize); - // Verify that all direct interfaces of classes in the class table are also resolved. - VerifyDirectInterfacesInTableClassVisitor visitor(class_loader.Get()); - class_table->Visit(visitor); - visitor.Check(); - // Check that all non-primitive classes in dex caches are also in the class table. - for (int32_t i = 0; i < dex_caches->GetLength(); i++) { - ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i); - mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes(); - for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) { - ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read(); - if (klass != nullptr && !klass->IsPrimitive()) { - CHECK(class_table->Contains(klass)) << klass->PrettyDescriptor() - << " " << dex_cache->GetDexFile()->GetLocation(); - } - } - } + VerifyAppImage(header, class_loader, dex_caches, class_table, space); } + VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time); return true; } @@ -2315,16 +2317,15 @@ void ClassLinker::DeleteClassLoader(Thread* self, const ClassLoaderData& data) { JavaVMExt* const vm = runtime->GetJavaVM(); vm->DeleteWeakGlobalRef(self, data.weak_root); // Notify the JIT that we need to remove the methods and/or profiling info. - ClassHierarchyAnalysis* const cha = runtime->GetClassHierarchyAnalysis(); if (runtime->GetJit() != nullptr) { jit::JitCodeCache* code_cache = runtime->GetJit()->GetCodeCache(); if (code_cache != nullptr) { // For the JIT case, RemoveMethodsIn removes the CHA dependencies. code_cache->RemoveMethodsIn(self, *data.allocator); } - } else { + } else if (cha_ != nullptr) { // If we don't have a JIT, we need to manually remove the CHA dependencies manually. - cha->RemoveDependenciesForLinearAlloc(data.allocator); + cha_->RemoveDependenciesForLinearAlloc(data.allocator); } delete data.allocator; delete data.class_table; @@ -3494,7 +3495,8 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, ObjPtr<mirror::DexCache> dex_cache) { CHECK(dex_cache != nullptr) << dex_file.GetLocation(); boot_class_path_.push_back(&dex_file); - RegisterBootClassPathDexFile(dex_file, dex_cache); + WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_); + RegisterDexFileLocked(dex_file, dex_cache, /* class_loader */ nullptr); } void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, @@ -3553,6 +3555,14 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, data.resolved_methods = dex_cache->GetResolvedMethods(); data.class_table = ClassTableForClassLoader(class_loader); DCHECK(data.class_table != nullptr); + // Make sure to hold the dex cache live in the class table. This case happens for the boot class + // path dex caches without an image. + data.class_table->InsertStrongRoot(dex_cache); + if (class_loader != nullptr) { + // Since we added a strong root to the class table, do the write barrier as required for + // remembered sets and generational GCs. + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); + } dex_caches_.push_back(data); } @@ -3677,12 +3687,6 @@ ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file, return h_dex_cache.Get(); } -void ClassLinker::RegisterBootClassPathDexFile(const DexFile& dex_file, - ObjPtr<mirror::DexCache> dex_cache) { - WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_); - RegisterDexFileLocked(dex_file, dex_cache, /* class_loader */ nullptr); -} - bool ClassLinker::IsDexFileRegistered(Thread* self, const DexFile& dex_file) { ReaderMutexLock mu(self, *Locks::dex_lock_); return DecodeDexCache(self, FindDexCacheDataLocked(dex_file)) != nullptr; @@ -4716,7 +4720,7 @@ void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) cons CHECK_STREQ(np->GetName(), prototype->GetName()); CHECK_STREQ(np->GetShorty(), prototype->GetShorty()); // More complex sanity - via dex cache - CHECK_EQ(np->GetReturnType(true /* resolve */), prototype->GetReturnType(true /* resolve */)); + CHECK_EQ(np->ResolveReturnType(), prototype->ResolveReturnType()); } bool ClassLinker::CanWeInitializeClass(ObjPtr<mirror::Class> klass, bool can_init_statics, @@ -5192,12 +5196,12 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, REQUIRES_SHARED(Locks::mutator_lock_) { { StackHandleScope<1> hs(self); - Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType(true /* resolve */))); + Handle<mirror::Class> return_type(hs.NewHandle(method1->ResolveReturnType())); if (UNLIKELY(return_type == nullptr)) { ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1); return false; } - ObjPtr<mirror::Class> other_return_type = method2->GetReturnType(true /* resolve */); + ObjPtr<mirror::Class> other_return_type = method2->ResolveReturnType(); if (UNLIKELY(other_return_type == nullptr)) { ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2); return false; @@ -5242,7 +5246,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, StackHandleScope<1> hs(self); dex::TypeIndex param_type_idx = types1->GetTypeItem(i).type_idx_; Handle<mirror::Class> param_type(hs.NewHandle( - method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */))); + method1->ResolveClassFromTypeIndex(param_type_idx))); if (UNLIKELY(param_type == nullptr)) { ThrowSignatureCheckResolveArgException(klass, super_klass, method1, method1, i, param_type_idx); @@ -5250,7 +5254,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, } dex::TypeIndex other_param_type_idx = types2->GetTypeItem(i).type_idx_; ObjPtr<mirror::Class> other_param_type = - method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */); + method2->ResolveClassFromTypeIndex(other_param_type_idx); if (UNLIKELY(other_param_type == nullptr)) { ThrowSignatureCheckResolveArgException(klass, super_klass, method1, method2, i, other_param_type_idx); @@ -5487,7 +5491,9 @@ bool ClassLinker::LinkClass(Thread* self, // Update CHA info based on whether we override methods. // Have to do this before setting the class as resolved which allows // instantiation of klass. - Runtime::Current()->GetClassHierarchyAnalysis()->UpdateAfterLoadingOf(klass); + if (cha_ != nullptr) { + cha_->UpdateAfterLoadingOf(klass); + } // This will notify waiters on klass that saw the not yet resolved // class in the class_table_ during EnsureResolved. @@ -5535,7 +5541,9 @@ bool ClassLinker::LinkClass(Thread* self, // Update CHA info based on whether we override methods. // Have to do this before setting the class as resolved which allows // instantiation of klass. - Runtime::Current()->GetClassHierarchyAnalysis()->UpdateAfterLoadingOf(h_new_class); + if (cha_ != nullptr) { + cha_->UpdateAfterLoadingOf(h_new_class); + } // This will notify waiters on temp class that saw the not yet resolved class in the // class_table_ during EnsureResolved. @@ -8510,7 +8518,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod( it.Next(); } - Handle<mirror::Class> return_type = hs.NewHandle(target_method->GetReturnType(true)); + Handle<mirror::Class> return_type = hs.NewHandle(target_method->ResolveReturnType()); if (UNLIKELY(return_type.IsNull())) { DCHECK(self->IsExceptionPending()); return nullptr; @@ -8587,7 +8595,7 @@ void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const { if (!method->IsNative()) { method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); } else { - SetEntryPointsToCompiledCode(method, GetQuickGenericJniStub()); + method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub()); } } @@ -8839,16 +8847,6 @@ void ClassLinker::DropFindArrayClassCache() { find_array_class_cache_next_victim_ = 0; } -void ClassLinker::ClearClassTableStrongRoots() const { - Thread* const self = Thread::Current(); - WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); - for (const ClassLoaderData& data : class_loaders_) { - if (data.class_table != nullptr) { - data.class_table->ClearStrongRoots(); - } - } -} - void ClassLinker::VisitClassLoaders(ClassLoaderVisitor* visitor) const { Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { |