summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc112
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());