ART: Use proxy ArtMethod's data_ to store the interface method.
This immensely simplifies the interface method retrieval
and removes one dependency on dex_cache_resolved_methods_.
We may later consider removing that member if we deem the
memory savings worth the performance impact.
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --host --jit
Change-Id: Id76349c69e4c4dea4e3b297bd504db8f98f1b7cc
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 50e9144..9780522 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -388,17 +388,8 @@
if (LIKELY(!IsProxyMethod())) {
return this;
}
- uint32_t method_index = GetDexMethodIndex();
- uint32_t slot_idx = method_index % mirror::DexCache::kDexCacheMethodCacheSize;
- mirror::MethodDexCachePair pair = mirror::DexCache::GetNativePairPtrSize(
- GetDexCacheResolvedMethods(pointer_size), slot_idx, pointer_size);
- ArtMethod* interface_method = pair.GetObjectForIndex(method_index);
- if (LIKELY(interface_method != nullptr)) {
- DCHECK_EQ(interface_method, Runtime::Current()->GetClassLinker()->FindMethodForProxy(this));
- } else {
- interface_method = Runtime::Current()->GetClassLinker()->FindMethodForProxy(this);
- DCHECK(interface_method != nullptr);
- }
+ ArtMethod* interface_method = reinterpret_cast<ArtMethod*>(GetDataPtrSize(pointer_size));
+ DCHECK(interface_method->GetDeclaringClass()->IsAssignableFrom(GetDeclaringClass()));
return interface_method;
}
diff --git a/runtime/art_method.h b/runtime/art_method.h
index cac40e0..7ffd585 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -458,12 +458,15 @@
SetDataPtrSize(table, pointer_size);
}
- ProfilingInfo* GetProfilingInfo(PointerSize pointer_size) {
+ ProfilingInfo* GetProfilingInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_) {
// Don't do a read barrier in the DCHECK, as GetProfilingInfo is called in places
// where the declaring class is treated as a weak reference (accessing it with
// a read barrier would either prevent unloading the class, or crash the runtime if
// the GC wants to unload it).
DCHECK(!IsNative<kWithoutReadBarrier>());
+ if (UNLIKELY(IsProxyMethod())) {
+ return nullptr;
+ }
return reinterpret_cast<ProfilingInfo*>(GetDataPtrSize(pointer_size));
}
@@ -726,9 +729,13 @@
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
mirror::MethodDexCacheType* dex_cache_resolved_methods_;
- // Pointer to JNI function registered to this method, or a function to resolve the JNI function,
- // or the profiling data for non-native methods, or an ImtConflictTable, or the
- // single-implementation of an abstract/interface method.
+ // Depending on the method type, the data is
+ // - native method: pointer to the JNI function registered to this method
+ // or a function to resolve the JNI function,
+ // - conflict method: ImtConflictTable,
+ // - abstract/interface method: the single-implementation if any,
+ // - proxy method: the original interface method or constructor,
+ // - other methods: the profiling data.
void* data_;
// Method dispatch from quick compiled code invokes this pointer which may cause bridging into
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 845bd6d..0efc004 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3552,7 +3552,6 @@
DexCacheData data;
data.weak_root = dex_cache_jweak;
data.dex_file = dex_cache->GetDexFile();
- data.resolved_methods = dex_cache->GetResolvedMethods();
data.class_table = ClassTableForClassLoader(class_loader);
DCHECK(data.class_table != nullptr);
// Make sure to hold the dex cache live in the class table. This case happens for the boot class
@@ -4668,6 +4667,9 @@
kAccPublic |
kAccCompileDontBother);
out->SetDeclaringClass(klass.Get());
+
+ // Set the original constructor method.
+ out->SetDataPtrSize(proxy_constructor, image_pointer_size_);
}
void ClassLinker::CheckProxyConstructor(ArtMethod* constructor) const {
@@ -4708,6 +4710,9 @@
// method they copy might (if it's a default method).
out->SetCodeItemOffset(0);
+ // Set the original interface method.
+ out->SetDataPtrSize(prototype, image_pointer_size_);
+
// At runtime the method looks like a reference and argument saving method, clone the code
// related parameters from this method.
out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
@@ -9031,53 +9036,6 @@
ifcount * mirror::IfTable::kMax));
}
-ArtMethod* ClassLinker::FindMethodForProxy(ArtMethod* proxy_method) {
- DCHECK(proxy_method->IsProxyMethod());
- {
- uint32_t method_index = proxy_method->GetDexMethodIndex();
- PointerSize pointer_size = image_pointer_size_;
- Thread* const self = Thread::Current();
- ReaderMutexLock mu(self, *Locks::dex_lock_);
- // Locate the dex cache of the original interface/Object
- for (const DexCacheData& data : dex_caches_) {
- if (!self->IsJWeakCleared(data.weak_root) &&
- proxy_method->HasSameDexCacheResolvedMethods(data.resolved_methods, pointer_size)) {
- ObjPtr<mirror::DexCache> dex_cache =
- ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
- if (dex_cache != nullptr) {
- // Lookup up the method. Instead of going through LookupResolvedMethod()
- // and thus LookupResolvedType(), use the ClassTable from the DexCacheData.
- ArtMethod* resolved_method = dex_cache->GetResolvedMethod(method_index, pointer_size);
- if (resolved_method == nullptr) {
- const DexFile::MethodId& method_id = data.dex_file->GetMethodId(method_index);
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(method_id.class_idx_);
- if (klass == nullptr) {
- const char* descriptor = data.dex_file->StringByTypeIdx(method_id.class_idx_);
- klass = data.class_table->Lookup(descriptor, ComputeModifiedUtf8Hash(descriptor));
- DCHECK(klass != nullptr);
- dex_cache->SetResolvedType(method_id.class_idx_, klass);
- }
- if (klass->IsInterface()) {
- resolved_method = klass->FindInterfaceMethod(dex_cache, method_index, pointer_size);
- } else {
- DCHECK(
- klass == WellKnownClasses::ToClass(WellKnownClasses::java_lang_reflect_Proxy) ||
- klass == WellKnownClasses::ToClass(WellKnownClasses::java_lang_Object));
- resolved_method = klass->FindClassMethod(dex_cache, method_index, pointer_size);
- }
- CHECK(resolved_method != nullptr);
- dex_cache->SetResolvedMethod(method_index, resolved_method, pointer_size);
- }
- return resolved_method;
- }
- }
- }
- }
- // Note: Do not use proxy_method->PrettyMethod() as it can call back here.
- LOG(FATAL) << "Didn't find dex cache for " << proxy_method->GetDeclaringClass()->PrettyClass();
- UNREACHABLE();
-}
-
// Instantiate ResolveMethod.
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
const DexFile& dex_file,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 66bcbe0..783ec74 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -479,9 +479,6 @@
REQUIRES_SHARED(Locks::mutator_lock_);
std::string GetDescriptorForProxy(ObjPtr<mirror::Class> proxy_class)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindMethodForProxy(ArtMethod* proxy_method)
- REQUIRES(!Locks::dex_lock_)
- REQUIRES_SHARED(Locks::mutator_lock_);
// Get the oat code for a method when its class isn't yet initialized.
const void* GetQuickOatCodeFor(ArtMethod* method)
@@ -675,7 +672,6 @@
DexCacheData()
: weak_root(nullptr),
dex_file(nullptr),
- resolved_methods(nullptr),
class_table(nullptr) { }
// Check if the data is valid.
@@ -686,11 +682,9 @@
// Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may
// not work properly.
jweak weak_root;
- // The following two fields are caches to the DexCache's fields and here to avoid unnecessary
- // jweak decode that triggers read barriers (and mark them alive unnecessarily and mess with
- // class unloading.)
+ // The following field caches the DexCache's field here to avoid unnecessary jweak decode that
+ // triggers read barriers (and marks them alive unnecessarily and messes with class unloading.)
const DexFile* dex_file;
- mirror::MethodDexCacheType* resolved_methods;
// Identify the associated class loader's class table. This is used to make sure that
// the Java call to native DexCache.setResolvedType() inserts the resolved type in that
// class table. It is also used to make sure we don't register the same dex cache with
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 47ace7f..40a5212 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -1169,7 +1169,6 @@
RemoveUnmarkedCode(self);
if (collect_profiling_info) {
- ScopedThreadSuspension sts(self, kSuspended);
MutexLock mu(self, lock_);
// Free all profiling infos of methods not compiled nor being compiled.
auto profiling_kept_end = std::remove_if(profiling_infos_.begin(), profiling_infos_.end(),
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index daa1d61..9790e3a 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -323,7 +323,8 @@
REQUIRES_SHARED(Locks::mutator_lock_);
bool CheckLiveCompiledCodeHasProfilingInfo()
- REQUIRES(lock_);
+ REQUIRES(lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
void FreeCode(uint8_t* code) REQUIRES(lock_);
uint8_t* AllocateCode(size_t code_size) REQUIRES(lock_);