diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 112 |
1 files changed, 71 insertions, 41 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 8220ba4910..448b4600cc 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -351,7 +351,7 @@ ClassLinker::ClassLinker(InternTable* intern_table) array_iftable_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), - log_new_class_table_roots_(false), + log_new_roots_(false), intern_table_(intern_table), quick_resolution_trampoline_(nullptr), quick_imt_conflict_trampoline_(nullptr), @@ -1865,12 +1865,10 @@ bool ClassLinker::AddImageSpace( << reinterpret_cast<const void*>(section_end); } } - if (!oat_file->GetBssGcRoots().empty()) { - // Insert oat file to class table for visiting .bss GC roots. - class_table->InsertOatFile(oat_file); - } - } else { - DCHECK(oat_file->GetBssGcRoots().empty()); + } + if (!oat_file->GetBssGcRoots().empty()) { + // Insert oat file to class table for visiting .bss GC roots. + class_table->InsertOatFile(oat_file); } if (added_class_table) { WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); @@ -1934,14 +1932,27 @@ void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { // Concurrent moving GC marked new roots through the to-space invariant. CHECK_EQ(new_ref, old_ref); } + for (const OatFile* oat_file : new_bss_roots_boot_oat_files_) { + for (GcRoot<mirror::Object>& root : oat_file->GetBssGcRoots()) { + ObjPtr<mirror::Object> old_ref = root.Read<kWithoutReadBarrier>(); + if (old_ref != nullptr) { + DCHECK(old_ref->IsClass()); + root.VisitRoot(visitor, RootInfo(kRootStickyClass)); + ObjPtr<mirror::Object> new_ref = root.Read<kWithoutReadBarrier>(); + // Concurrent moving GC marked new roots through the to-space invariant. + CHECK_EQ(new_ref, old_ref); + } + } + } } if ((flags & kVisitRootFlagClearRootLog) != 0) { new_class_roots_.clear(); + new_bss_roots_boot_oat_files_.clear(); } if ((flags & kVisitRootFlagStartLoggingNewRoots) != 0) { - log_new_class_table_roots_ = true; + log_new_roots_ = true; } else if ((flags & kVisitRootFlagStopLoggingNewRoots) != 0) { - log_new_class_table_roots_ = false; + log_new_roots_ = false; } // We deliberately ignore the class roots in the image since we // handle image roots by using the MS/CMS rescanning of dirty cards. @@ -3303,6 +3314,7 @@ mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file, ReaderMutexLock mu(self, *Locks::dex_lock_); ObjPtr<mirror::DexCache> dex_cache = FindDexCacheLocked(self, dex_file, true); if (dex_cache != nullptr) { + // TODO: Check if the dex file was registered with the same class loader. Bug: 34193123 return dex_cache.Ptr(); } } @@ -3647,7 +3659,7 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, ObjPtr<mirror::C // This is necessary because we need to have the card dirtied for remembered sets. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); } - if (log_new_class_table_roots_) { + if (log_new_roots_) { new_class_roots_.push_back(GcRoot<mirror::Class>(klass)); } } @@ -3660,6 +3672,14 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, ObjPtr<mirror::C return nullptr; } +void ClassLinker::WriteBarrierForBootOatFileBssRoots(const OatFile* oat_file) { + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + DCHECK(!oat_file->GetBssGcRoots().empty()) << oat_file->GetLocation(); + if (log_new_roots_ && !ContainsElement(new_bss_roots_boot_oat_files_, oat_file)) { + new_bss_roots_boot_oat_files_.push_back(oat_file); + } +} + // TODO This should really be in mirror::Class. void ClassLinker::UpdateClassMethods(ObjPtr<mirror::Class> klass, LengthPrefixedArray<ArtMethod>* new_methods) { @@ -5157,7 +5177,7 @@ bool ClassLinker::LinkClass(Thread* self, Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); } CHECK_EQ(existing, klass.Get()); - if (log_new_class_table_roots_) { + if (log_new_roots_) { new_class_roots_.push_back(GcRoot<mirror::Class>(h_new_class.Get())); } } @@ -6929,7 +6949,7 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { method_alignment_); const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0; auto* methods = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>( - class_linker_->GetAllocatorForClassLoader(klass_->GetClassLoader())->Realloc( + Runtime::Current()->GetLinearAlloc()->Realloc( self_, old_methods, old_methods_ptr_size, new_size)); CHECK(methods != nullptr); // Native allocation failure aborts. @@ -6949,13 +6969,19 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { StrideIterator<ArtMethod> out(methods->begin(method_size_, method_alignment_) + old_method_count); // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and // we want the roots of the miranda methods to get visited. - for (ArtMethod* mir_method : miranda_methods_) { + for (size_t i = 0; i < miranda_methods_.size(); ++i) { + ArtMethod* mir_method = miranda_methods_[i]; ArtMethod& new_method = *out; new_method.CopyFrom(mir_method, pointer_size); new_method.SetAccessFlags(new_method.GetAccessFlags() | kAccMiranda | kAccCopied); DCHECK_NE(new_method.GetAccessFlags() & kAccAbstract, 0u) << "Miranda method should be abstract!"; move_table_.emplace(mir_method, &new_method); + // Update the entry in the method array, as the array will be used for future lookups, + // where thread suspension is allowed. + // As such, the array should not contain locally allocated ArtMethod, otherwise the GC + // would not see them. + miranda_methods_[i] = &new_method; ++out; } // We need to copy the default methods into our own method table since the runtime requires that @@ -6964,9 +6990,10 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { // interface but will have different ArtMethod*s for them. This also means we cannot compare a // default method found on a class with one found on the declaring interface directly and must // look at the declaring class to determine if they are the same. - for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_methods_, - overriding_default_methods_}) { - for (ArtMethod* def_method : methods_vec) { + for (ScopedArenaVector<ArtMethod*>* methods_vec : {&default_methods_, + &overriding_default_methods_}) { + for (size_t i = 0; i < methods_vec->size(); ++i) { + ArtMethod* def_method = (*methods_vec)[i]; ArtMethod& new_method = *out; new_method.CopyFrom(def_method, pointer_size); // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been @@ -6977,12 +7004,18 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks; new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); move_table_.emplace(def_method, &new_method); + // Update the entry in the method array, as the array will be used for future lookups, + // where thread suspension is allowed. + // As such, the array should not contain locally allocated ArtMethod, otherwise the GC + // would not see them. + (*methods_vec)[i] = &new_method; ++out; } } - for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_conflict_methods_, - overriding_default_conflict_methods_}) { - for (ArtMethod* conf_method : methods_vec) { + for (ScopedArenaVector<ArtMethod*>* methods_vec : {&default_conflict_methods_, + &overriding_default_conflict_methods_}) { + for (size_t i = 0; i < methods_vec->size(); ++i) { + ArtMethod* conf_method = (*methods_vec)[i]; ArtMethod& new_method = *out; new_method.CopyFrom(conf_method, pointer_size); // This is a type of default method (there are default method impls, just a conflict) so @@ -6998,6 +7031,11 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { // that the compiler will not invoke the implementation of whatever method we copied from. EnsureThrowsInvocationError(class_linker_, &new_method); move_table_.emplace(conf_method, &new_method); + // Update the entry in the method array, as the array will be used for future lookups, + // where thread suspension is allowed. + // As such, the array should not contain locally allocated ArtMethod, otherwise the GC + // would not see them. + (*methods_vec)[i] = &new_method; ++out; } } @@ -7030,12 +7068,7 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab default_conflict_methods_, miranda_methods_}) { // These are the functions that are not already in the vtable! - for (ArtMethod* new_method : methods_vec) { - auto translated_method_it = move_table_.find(new_method); - CHECK(translated_method_it != move_table_.end()) - << "We must have a translation for methods added to the classes methods_ array! We " - << "could not find the ArtMethod added for " << ArtMethod::PrettyMethod(new_method); - ArtMethod* new_vtable_method = translated_method_it->second; + for (ArtMethod* new_vtable_method : methods_vec) { // Leave the declaring class alone the method's dex_code_item_offset_ and dex_method_index_ // fields are references into the dex file the method was defined in. Since the ArtMethod // does not store that information it uses declaring_class_->dex_cache_. @@ -7052,7 +7085,6 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size); // Try and find what we need to change this method to. auto translation_it = default_translations.find(i); - bool found_translation = false; if (translation_it != default_translations.end()) { if (translation_it->second.IsInConflict()) { // Find which conflict method we are to use for this method. @@ -7076,30 +7108,28 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkInterfaceMethodsHelper::UpdateVtab // Normal default method (changed from an older default or abstract interface method). DCHECK(translation_it->second.IsTranslation()); translated_method = translation_it->second.GetTranslation(); + auto it = move_table_.find(translated_method); + DCHECK(it != move_table_.end()); + translated_method = it->second; } - found_translation = true; + } else { + auto it = move_table_.find(translated_method); + translated_method = (it != move_table_.end()) ? it->second : nullptr; } - DCHECK(translated_method != nullptr); - auto it = move_table_.find(translated_method); - if (it != move_table_.end()) { - auto* new_method = it->second; - DCHECK(new_method != nullptr); + + if (translated_method != nullptr) { // Make sure the new_methods index is set. - if (new_method->GetMethodIndexDuringLinking() != i) { + if (translated_method->GetMethodIndexDuringLinking() != i) { if (kIsDebugBuild) { auto* methods = klass_->GetMethodsPtr(); CHECK_LE(reinterpret_cast<uintptr_t>(&*methods->begin(method_size_, method_alignment_)), - reinterpret_cast<uintptr_t>(new_method)); - CHECK_LT(reinterpret_cast<uintptr_t>(new_method), + reinterpret_cast<uintptr_t>(translated_method)); + CHECK_LT(reinterpret_cast<uintptr_t>(translated_method), reinterpret_cast<uintptr_t>(&*methods->end(method_size_, method_alignment_))); } - new_method->SetMethodIndex(0xFFFF & i); + translated_method->SetMethodIndex(0xFFFF & i); } - vtable->SetElementPtrSize(i, new_method, pointer_size); - } else { - // If it was not going to be updated we wouldn't have put it into the default_translations - // map. - CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail."; + vtable->SetElementPtrSize(i, translated_method, pointer_size); } } klass_->SetVTable(vtable.Ptr()); |