Add more read barriers to the class linker.
This change makes it possible to concurrently scan the remaining roots
in the class linker (the non-class-table roots that are visited by
ClassLinker::VisitRoots()) by adding read barriers.
Bug: 12687968
Change-Id: I66fecf7a303eee7537429e018f38da8270b18c67
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ca1239f..6e5f19a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -263,7 +263,11 @@
}
mirror::String* string = obj->AsString();
const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
- for (DexCache* dex_cache : Runtime::Current()->GetClassLinker()->GetDexCaches()) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+ size_t dex_cache_count = class_linker->GetDexCacheCount();
+ for (size_t i = 0; i < dex_cache_count; ++i) {
+ DexCache* dex_cache = class_linker->GetDexCache(i);
const DexFile& dex_file = *dex_cache->GetDexFile();
const DexFile::StringId* string_id;
if (UNLIKELY(string->GetLength() == 0)) {
@@ -316,7 +320,10 @@
// Clear references to removed classes from the DexCaches.
ArtMethod* resolution_method = runtime->GetResolutionMethod();
- for (DexCache* dex_cache : class_linker->GetDexCaches()) {
+ ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+ size_t dex_cache_count = class_linker->GetDexCacheCount();
+ for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+ DexCache* dex_cache = class_linker->GetDexCache(idx);
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
Class* klass = dex_cache->GetResolvedType(i);
if (klass != NULL && !IsImageClass(klass)) {
@@ -408,13 +415,27 @@
Handle<Class> object_array_class(hs.NewHandle(
class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
- // build an Object[] of all the DexCaches used in the source_space_
+ // build an Object[] of all the DexCaches used in the source_space_.
+ // Since we can't hold the dex lock when allocating the dex_caches
+ // ObjectArray, we lock the dex lock twice, first to get the number
+ // of dex caches first and then lock it again to copy the dex
+ // caches. We check that the number of dex caches does not change.
+ size_t dex_cache_count;
+ {
+ ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+ dex_cache_count = class_linker->GetDexCacheCount();
+ }
Handle<ObjectArray<Object>> dex_caches(
hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
- class_linker->GetDexCaches().size())));
- int i = 0;
- for (DexCache* dex_cache : class_linker->GetDexCaches()) {
- dex_caches->Set<false>(i++, dex_cache);
+ dex_cache_count)));
+ CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array.";
+ {
+ ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+ CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
+ << "The number of dex caches changed.";
+ for (size_t i = 0; i < dex_cache_count; ++i) {
+ dex_caches->Set<false>(i, class_linker->GetDexCache(i));
+ }
}
// build an Object[] of the roots needed to restore the runtime