Change dex caches to be weak roots
Changed dex caches to be weak roots. This is necessary for class
unloading since the resolved types arrays would keep classes live
when they should be unloaded. Currently the dex caches still don't
get freed due to the class loader roots.
Also deleted some unused functionality in image writer.
Bug: 22720414
Change-Id: If22cb3cad7e3baabc8158a77d7f20799faf4c341
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 848c904..5f2caef 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -64,6 +64,7 @@
kJdwpSocketLock,
kRegionSpaceRegionLock,
kTransactionLogLock,
+ kJniWeakGlobalsLock,
kReferenceQueueSoftReferencesLock,
kReferenceQueuePhantomReferencesLock,
kReferenceQueueFinalizerReferencesLock,
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 11901b3..d2dbff6 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -195,12 +195,6 @@
return klass;
}
-inline mirror::DexCache* ClassLinker::GetDexCache(size_t idx) {
- dex_lock_.AssertSharedHeld(Thread::Current());
- DCHECK(idx < dex_caches_.size());
- return dex_caches_[idx].Read();
-}
-
} // namespace art
#endif // ART_RUNTIME_CLASS_LINKER_INL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index dc273d8..667dae2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -273,7 +273,6 @@
array_iftable_(nullptr),
find_array_class_cache_next_victim_(0),
init_done_(false),
- log_new_dex_caches_roots_(false),
log_new_class_table_roots_(false),
intern_table_(intern_table),
quick_resolution_trampoline_(nullptr),
@@ -332,6 +331,12 @@
java_lang_Class->SetSuperClass(java_lang_Object.Get());
mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusLoaded, self);
+ java_lang_Object->SetObjectSize(sizeof(mirror::Object));
+ runtime->SetSentinel(heap->AllocObject<true>(self,
+ java_lang_Object.Get(),
+ java_lang_Object->GetObjectSize(),
+ VoidFunctor()));
+
// Object[] next to hold class roots.
Handle<mirror::Class> object_array_class(hs.NewHandle(
AllocClass(self, java_lang_Class.Get(),
@@ -1139,11 +1144,11 @@
quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge();
+ StackHandleScope<2> hs(self);
mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
- mirror::ObjectArray<mirror::DexCache>* dex_caches =
- dex_caches_object->AsObjectArray<mirror::DexCache>();
+ Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches(
+ hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
- StackHandleScope<1> hs(self);
Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
AsObjectArray<mirror::Class>()));
@@ -1153,6 +1158,13 @@
// as being Strings or not
mirror::String::SetClass(GetClassRoot(kJavaLangString));
+ mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
+ java_lang_Object->SetObjectSize(sizeof(mirror::Object));
+ Runtime::Current()->SetSentinel(Runtime::Current()->GetHeap()->AllocObject<true>(self,
+ java_lang_Object,
+ java_lang_Object->GetObjectSize(),
+ VoidFunctor()));
+
CHECK_EQ(oat_file.GetOatHeader().GetDexFileCount(),
static_cast<uint32_t>(dex_caches->GetLength()));
for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
@@ -1246,7 +1258,6 @@
}
bool ClassLinker::ClassInClassTable(mirror::Class* klass) {
- ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
ClassTable* const class_table = ClassTableForClassLoader(klass->GetClassLoader());
return class_table != nullptr && class_table->Contains(klass);
}
@@ -1303,27 +1314,6 @@
// mapped image.
void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) {
class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
- Thread* const self = Thread::Current();
- {
- ReaderMutexLock mu(self, dex_lock_);
- if ((flags & kVisitRootFlagAllRoots) != 0) {
- for (GcRoot<mirror::DexCache>& dex_cache : dex_caches_) {
- dex_cache.VisitRoot(visitor, RootInfo(kRootVMInternal));
- }
- } else if ((flags & kVisitRootFlagNewRoots) != 0) {
- for (size_t index : new_dex_cache_roots_) {
- dex_caches_[index].VisitRoot(visitor, RootInfo(kRootVMInternal));
- }
- }
- if ((flags & kVisitRootFlagClearRootLog) != 0) {
- new_dex_cache_roots_.clear();
- }
- if ((flags & kVisitRootFlagStartLoggingNewRoots) != 0) {
- log_new_dex_caches_roots_ = true;
- } else if ((flags & kVisitRootFlagStopLoggingNewRoots) != 0) {
- log_new_dex_caches_roots_ = false;
- }
- }
VisitClassRoots(visitor, flags);
array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
for (GcRoot<mirror::Class>& root : find_array_class_cache_) {
@@ -1698,7 +1688,6 @@
long_array->GetWithoutChecks(j)));
const DexFile::ClassDef* dex_class_def = cp_dex_file->FindClassDef(descriptor, hash);
if (dex_class_def != nullptr) {
- RegisterDexFile(*cp_dex_file);
mirror::Class* klass = DefineClass(self, descriptor, hash, class_loader,
*cp_dex_file, *dex_class_def);
if (klass == nullptr) {
@@ -1844,7 +1833,7 @@
CHECK(self->IsExceptionPending()); // Expect an OOME.
return nullptr;
}
- klass->SetDexCache(FindDexCache(dex_file));
+ klass->SetDexCache(RegisterDexFile(dex_file));
SetupClass(dex_file, dex_class_def, klass, class_loader.Get());
@@ -2478,58 +2467,52 @@
RegisterDexFile(dex_file, dex_cache);
}
-bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) {
- dex_lock_.AssertSharedHeld(Thread::Current());
- for (GcRoot<mirror::DexCache>& root : dex_caches_) {
- mirror::DexCache* dex_cache = root.Read();
- if (dex_cache->GetDexFile() == &dex_file) {
- return true;
- }
- }
- return false;
-}
-
-bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) {
- ReaderMutexLock mu(Thread::Current(), dex_lock_);
- return IsDexFileRegisteredLocked(dex_file);
-}
-
void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
Handle<mirror::DexCache> dex_cache) {
- dex_lock_.AssertExclusiveHeld(Thread::Current());
+ Thread* const self = Thread::Current();
+ dex_lock_.AssertExclusiveHeld(self);
CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
<< dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
- dex_caches_.push_back(GcRoot<mirror::DexCache>(dex_cache.Get()));
- dex_cache->SetDexFile(&dex_file);
- if (log_new_dex_caches_roots_) {
- // TODO: This is not safe if we can remove dex caches.
- new_dex_cache_roots_.push_back(dex_caches_.size() - 1);
+ // Clean up pass to remove null dex caches.
+ // Null dex caches can occur due to class unloading and we are lazily removing null entries.
+ JavaVMExt* const vm = self->GetJniEnv()->vm;
+ for (auto it = dex_caches_.begin(); it != dex_caches_.end();) {
+ mirror::Object* dex_cache_root = self->DecodeJObject(*it);
+ if (dex_cache_root == nullptr) {
+ vm->DeleteWeakGlobalRef(self, *it);
+ it = dex_caches_.erase(it);
+ } else {
+ ++it;
+ }
}
+ dex_caches_.push_back(vm->AddWeakGlobalRef(self, dex_cache.Get()));
+ dex_cache->SetDexFile(&dex_file);
}
-void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
+mirror::DexCache* ClassLinker::RegisterDexFile(const DexFile& dex_file) {
Thread* self = Thread::Current();
{
ReaderMutexLock mu(self, dex_lock_);
- if (IsDexFileRegisteredLocked(dex_file)) {
- return;
+ mirror::DexCache* dex_cache = FindDexCacheLocked(dex_file, true);
+ if (dex_cache != nullptr) {
+ return dex_cache;
}
}
// Don't alloc while holding the lock, since allocation may need to
// suspend all threads and another thread may need the dex_lock_ to
// get to a suspend point.
StackHandleScope<1> hs(self);
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
- CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
- << dex_file.GetLocation();
- {
- WriterMutexLock mu(self, dex_lock_);
- if (IsDexFileRegisteredLocked(dex_file)) {
- return;
- }
- RegisterDexFileLocked(dex_file, dex_cache);
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
+ CHECK(h_dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
+ << dex_file.GetLocation();
+ WriterMutexLock mu(self, dex_lock_);
+ mirror::DexCache* dex_cache = FindDexCacheLocked(dex_file, true);
+ if (dex_cache != nullptr) {
+ return dex_cache;
}
+ RegisterDexFileLocked(dex_file, h_dex_cache);
+ return h_dex_cache.Get();
}
void ClassLinker::RegisterDexFile(const DexFile& dex_file,
@@ -2538,36 +2521,44 @@
RegisterDexFileLocked(dex_file, dex_cache);
}
-mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) {
- ReaderMutexLock mu(Thread::Current(), dex_lock_);
+mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file, bool allow_failure) {
+ Thread* const self = Thread::Current();
+ ReaderMutexLock mu(self, dex_lock_);
+ return FindDexCacheLocked(dex_file, allow_failure);
+}
+
+mirror::DexCache* ClassLinker::FindDexCacheLocked(const DexFile& dex_file, bool allow_failure) {
+ Thread* const self = Thread::Current();
// Search assuming unique-ness of dex file.
- for (size_t i = 0; i != dex_caches_.size(); ++i) {
- mirror::DexCache* dex_cache = GetDexCache(i);
- if (dex_cache->GetDexFile() == &dex_file) {
+ for (jobject weak_root : dex_caches_) {
+ mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
+ if (dex_cache != nullptr && dex_cache->GetDexFile() == &dex_file) {
return dex_cache;
}
}
- // Search matching by location name.
+ if (allow_failure) {
+ return nullptr;
+ }
std::string location(dex_file.GetLocation());
- for (size_t i = 0; i != dex_caches_.size(); ++i) {
- mirror::DexCache* dex_cache = GetDexCache(i);
- if (dex_cache->GetDexFile()->GetLocation() == location) {
- return dex_cache;
- }
- }
// Failure, dump diagnostic and abort.
- for (size_t i = 0; i != dex_caches_.size(); ++i) {
- mirror::DexCache* dex_cache = GetDexCache(i);
- LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
+ for (jobject weak_root : dex_caches_) {
+ mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
+ if (dex_cache != nullptr) {
+ LOG(ERROR) << "Registered dex file " << dex_cache->GetDexFile()->GetLocation();
+ }
}
LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
UNREACHABLE();
}
void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) {
- ReaderMutexLock mu(Thread::Current(), dex_lock_);
- for (auto& dex_cache : dex_caches_) {
- dex_cache.Read()->Fixup(resolution_method, image_pointer_size_);
+ Thread* const self = Thread::Current();
+ ReaderMutexLock mu(self, dex_lock_);
+ for (jobject weak_root : dex_caches_) {
+ mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
+ if (dex_cache != nullptr) {
+ dex_cache->Fixup(resolution_method, image_pointer_size_);
+ }
}
}
@@ -3403,11 +3394,13 @@
DCHECK(proxy_class->IsProxyClass());
DCHECK(proxy_method->IsProxyMethod());
{
- ReaderMutexLock mu(Thread::Current(), dex_lock_);
+ Thread* const self = Thread::Current();
+ ReaderMutexLock mu(self, dex_lock_);
// Locate the dex cache of the original interface/Object
- for (const GcRoot<mirror::DexCache>& root : dex_caches_) {
- auto* dex_cache = root.Read();
- if (proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
+ for (jobject weak_root : dex_caches_) {
+ mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
+ if (dex_cache != nullptr &&
+ proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
proxy_method->GetDexMethodIndex(), image_pointer_size_);
CHECK(resolved_method != nullptr);
@@ -5864,11 +5857,6 @@
// We could move the jobject to the callers, but all call-sites do this...
ScopedObjectAccessUnchecked soa(self);
- // Register the dex files.
- for (const DexFile* dex_file : dex_files) {
- RegisterDexFile(*dex_file);
- }
-
// For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
StackHandleScope<10> hs(self);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index fbf4035..cc56e8b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -278,7 +278,7 @@
void RunRootClinits() SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
- void RegisterDexFile(const DexFile& dex_file)
+ mirror::DexCache* RegisterDexFile(const DexFile& dex_file)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -309,9 +309,7 @@
void VisitRoots(RootVisitor* visitor, VisitRootFlags flags)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
- mirror::DexCache* FindDexCache(const DexFile& dex_file)
- REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
- bool IsDexFileRegistered(const DexFile& dex_file)
+ mirror::DexCache* FindDexCache(const DexFile& dex_file, bool allow_failure = false)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
void FixupDexCaches(ArtMethod* resolution_method)
REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -471,7 +469,7 @@
// Used by image writer for checking.
bool ClassInClassTable(mirror::Class* klass)
- REQUIRES(!Locks::classlinker_classes_lock_)
+ REQUIRES(Locks::classlinker_classes_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
ArtMethod* CreateRuntimeMethod();
@@ -561,8 +559,9 @@
void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
REQUIRES(dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_);
- bool IsDexFileRegisteredLocked(const DexFile& dex_file)
- SHARED_REQUIRES(dex_lock_, Locks::mutator_lock_);
+ mirror::DexCache* FindDexCacheLocked(const DexFile& dex_file, bool allow_failure)
+ REQUIRES(dex_lock_)
+ SHARED_REQUIRES(Locks::mutator_lock_);
bool InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_run_clinit,
bool can_init_parents)
@@ -631,7 +630,9 @@
size_t GetDexCacheCount() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) {
return dex_caches_.size();
}
- mirror::DexCache* GetDexCache(size_t idx) SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_);
+ const std::list<jobject>& GetDexCaches() SHARED_REQUIRES(Locks::mutator_lock_, dex_lock_) {
+ return dex_caches_;
+ }
const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
REQUIRES(!dex_lock_);
@@ -702,8 +703,9 @@
std::vector<std::unique_ptr<const DexFile>> opened_dex_files_;
mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- std::vector<size_t> new_dex_cache_roots_ GUARDED_BY(dex_lock_);
- std::vector<GcRoot<mirror::DexCache>> dex_caches_ GUARDED_BY(dex_lock_);
+ // JNI weak globals to allow dex caches to get unloaded. We lazily delete weak globals when we
+ // register new dex files.
+ std::list<jobject> dex_caches_ GUARDED_BY(dex_lock_);
std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
// This contains the class laoders which have class tables. It is populated by
@@ -736,7 +738,6 @@
size_t find_array_class_cache_next_victim_;
bool init_done_;
- bool log_new_dex_caches_roots_ GUARDED_BY(dex_lock_);
bool log_new_class_table_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
InternTable* intern_table_;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 5f9e413..56c5d1a 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -551,7 +551,8 @@
}
Thread* self = Thread::Current();
- jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self, class_path);
+ jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,
+ class_path);
self->SetClassLoaderOverride(class_loader);
return class_loader;
}
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 9d41018..2fd0517 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -373,7 +373,7 @@
globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
libraries_(new Libraries),
unchecked_functions_(&gJniInvokeInterface),
- weak_globals_lock_("JNI weak global reference table lock"),
+ weak_globals_lock_("JNI weak global reference table lock", kJniWeakGlobalsLock),
weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
allow_new_weak_globals_(true),
weak_globals_add_condition_("weak globals add condition", weak_globals_lock_) {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 4f97d20..9bd320c 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -171,7 +171,7 @@
if (array == nullptr) {
ScopedObjectAccess soa(env);
for (auto& dex_file : dex_files) {
- if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+ if (Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file, true) != nullptr) {
dex_file.release();
}
}
@@ -209,7 +209,7 @@
// TODO: The Runtime should support unloading of classes and freeing of the
// dex files for those unloaded classes rather than leaking dex files here.
for (auto& dex_file : *dex_files) {
- if (!Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+ if (Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file, true) == nullptr) {
delete dex_file;
}
}
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 9ea339a..5a9c43b 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -425,14 +425,16 @@
static void PreloadDexCachesStatsFilled(DexCacheStats* filled)
SHARED_REQUIRES(Locks::mutator_lock_) {
if (!kPreloadDexCachesCollectStats) {
- return;
+ return;
}
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
- for (size_t i = 0; i< boot_class_path.size(); i++) {
- const DexFile* dex_file = boot_class_path[i];
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
CHECK(dex_file != nullptr);
- mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
+ mirror::DexCache* const dex_cache = class_linker->FindDexCache(*dex_file, true);
+ // If dex cache was deallocated, just continue.
+ if (dex_cache == nullptr) {
+ continue;
+ }
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
mirror::String* string = dex_cache->GetResolvedString(j);
if (string != nullptr) {
@@ -446,7 +448,7 @@
}
}
for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
- ArtField* field = linker->GetResolvedField(j, dex_cache);
+ ArtField* field = class_linker->GetResolvedField(j, dex_cache);
if (field != nullptr) {
filled->num_fields++;
}
@@ -490,11 +492,11 @@
}
const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
- for (size_t i = 0; i< boot_class_path.size(); i++) {
+ for (size_t i = 0; i < boot_class_path.size(); i++) {
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != nullptr);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file)));
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->RegisterDexFile(*dex_file)));
if (kPreloadDexCachesStrings) {
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 380e72b..bfa8c54 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -20,6 +20,7 @@
#include "runtime.h"
#include "art_method.h"
+#include "class_linker.h"
#include "read_barrier-inl.h"
namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1912314..49451ad 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -791,6 +791,12 @@
return failure_count;
}
+void Runtime::SetSentinel(mirror::Object* sentinel) {
+ CHECK(sentinel_.Read() == nullptr);
+ CHECK(sentinel != nullptr);
+ sentinel_ = GcRoot<mirror::Object>(sentinel);
+}
+
bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
ATRACE_BEGIN("Runtime::Init");
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
@@ -1054,10 +1060,6 @@
CHECK(class_linker_ != nullptr);
- // Initialize the special sentinel_ value early.
- sentinel_ = GcRoot<mirror::Object>(class_linker_->AllocObject(self));
- CHECK(sentinel_.Read() != nullptr);
-
verifier::MethodVerifier::Init();
if (runtime_options.Exists(Opt::MethodTrace)) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4577b75..bd21db1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -568,6 +568,9 @@
return fingerprint_;
}
+ // Called from class linker.
+ void SetSentinel(mirror::Object* sentinel) SHARED_REQUIRES(Locks::mutator_lock_);
+
private:
static void InitPlatformSignalHandlers();
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 4393430..7579d8d 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -640,7 +640,8 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
for (auto& e : seen_methods) {
DexIndexBitSet* bit_set = e.second;
- mirror::DexCache* dex_cache = class_linker->FindDexCache(*e.first);
+ // TODO: Visit trace methods as roots.
+ mirror::DexCache* dex_cache = class_linker->FindDexCache(*e.first, false);
for (uint32_t i = 0; i < bit_set->size(); ++i) {
if ((*bit_set)[i]) {
visited_methods->insert(dex_cache->GetResolvedMethod(i, sizeof(void*)));
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index a506071..1693a85 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3361,6 +3361,7 @@
ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
uint32_t dex_method_idx, MethodType method_type) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
+ // LOG(INFO) << dex_file_->NumTypeIds() << " " << dex_file_->NumClassDefs();
const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
if (klass_type.IsConflict()) {
std::string append(" in attempt to access method ");