ART: Move CHA to ClassLinker
Move the ClassHierarchyAnalysis singleton to ClassLinker. Hierarchy
analysis is a link-time effort and belongs to class-loading instead
of the global Runtime object.
Also clean up to use a unique_ptr, and add null checks to allow
bypassing the analysis.
Bug: 34193647
Test: m test-art-host
Change-Id: I14ef536e37eb19c0dede372ffd68a826c482cf71
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 74c04d1..e17a259 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -370,7 +370,8 @@
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_(new ClassHierarchyAnalysis()) {
CHECK(intern_table_ != nullptr);
static_assert(kFindArrayCacheSize == arraysize(find_array_class_cache_),
"Array cache size wrong.");
@@ -2315,16 +2316,15 @@
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;
@@ -5487,7 +5487,9 @@
// 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 +5537,9 @@
// 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.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index cb28187..86bfd68 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -60,6 +60,7 @@
using MethodDexCacheType = std::atomic<MethodDexCachePair>;
} // namespace mirror
+class ClassHierarchyAnalysis;
class ClassTable;
template<class T> class Handle;
class ImtConflictTable;
@@ -672,6 +673,10 @@
bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
+ ClassHierarchyAnalysis* GetClassHierarchyAnalysis() {
+ return cha_.get();
+ }
+
struct DexCacheData {
// Construct an invalid data object.
DexCacheData()
@@ -718,7 +723,7 @@
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- static void DeleteClassLoader(Thread* self, const ClassLoaderData& data)
+ void DeleteClassLoader(Thread* self, const ClassLoaderData& data)
REQUIRES_SHARED(Locks::mutator_lock_);
void VisitClassesInternal(ClassVisitor* visitor)
@@ -1268,6 +1273,8 @@
// Image pointer size.
PointerSize image_pointer_size_;
+ std::unique_ptr<ClassHierarchyAnalysis> cha_;
+
class FindVirtualMethodHolderVisitor;
friend class AppImageClassLoadersAndDexCachesHelper;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 2aa2ff2..a030a51 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -642,7 +642,7 @@
// method_headers are expected to be in the executable region.
{
MutexLock mu(Thread::Current(), *Locks::cha_lock_);
- Runtime::Current()->GetClassHierarchyAnalysis()
+ Runtime::Current()->GetClassLinker()->GetClassHierarchyAnalysis()
->RemoveDependentsWithMethodHeaders(method_headers);
}
@@ -977,7 +977,7 @@
<< "Should not be using cha on debuggable apps/runs!";
for (ArtMethod* single_impl : cha_single_implementation_list) {
- Runtime::Current()->GetClassHierarchyAnalysis()->AddDependency(
+ Runtime::Current()->GetClassLinker()->GetClassHierarchyAnalysis()->AddDependency(
single_impl, method, method_header);
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2712419..6fbf64b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -63,7 +63,6 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
-#include "cha.h"
#include "class_linker-inl.h"
#include "compiler_callbacks.h"
#include "debugger.h"
@@ -259,8 +258,7 @@
pruned_dalvik_cache_(false),
// Initially assume we perceive jank in case the process state is never updated.
process_state_(kProcessStateJankPerceptible),
- zygote_no_threads_(false),
- cha_(nullptr) {
+ zygote_no_threads_(false) {
static_assert(Runtime::kCalleeSaveSize ==
static_cast<uint32_t>(CalleeSaveType::kLastCalleeSaveType), "Unexpected size");
@@ -382,7 +380,6 @@
delete monitor_list_;
delete monitor_pool_;
delete class_linker_;
- delete cha_;
delete heap_;
delete intern_table_;
delete oat_file_manager_;
@@ -1287,7 +1284,6 @@
CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
class_linker_ = new ClassLinker(intern_table_);
- cha_ = new ClassHierarchyAnalysis;
if (GetHeap()->HasBootImageSpace()) {
bool result = class_linker_->InitFromBootImage(&error_msg);
if (!result) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 9424596..7e4b896 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -73,7 +73,6 @@
class ArenaPool;
class ArtMethod;
enum class CalleeSaveType: uint32_t;
-class ClassHierarchyAnalysis;
class ClassLinker;
class CompilerCallbacks;
class DexFile;
@@ -650,10 +649,6 @@
void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
- ClassHierarchyAnalysis* GetClassHierarchyAnalysis() {
- return cha_;
- }
-
void AttachAgent(const std::string& agent_arg);
const std::list<ti::Agent>& GetAgents() const {
@@ -944,8 +939,6 @@
// Generic system-weak holders.
std::vector<gc::AbstractSystemWeakHolder*> system_weak_holders_;
- ClassHierarchyAnalysis* cha_;
-
std::unique_ptr<RuntimeCallbacks> callbacks_;
std::atomic<uint32_t> deoptimization_counts_[