diff options
author | 2021-10-18 15:10:41 +0100 | |
---|---|---|
committer | 2021-11-09 11:18:38 +0000 | |
commit | cc76459f5d32d9002d8d0a432ccd6a3ca1f25bd0 (patch) | |
tree | a8122328ac86f383f15d4f3b89d78503b283785e | |
parent | 01f0b8417d75428ed12e4adf19afcbf557651aaa (diff) |
Modified revert of "Add couple DexCache read-barriers."
Remove the DexCache read-barriers again (the revert) since
there is measurable performance difference in app startup (~1%).
It turns out they are on very hot path in the interpreter.
The lazy array initialization made the DexCache fields mutable.
However, instead of the read-barriers, we can just ensure we get
the right to-space object on the array-initialization slow path.
Test: test.py -b -r --host
Change-Id: I3f0123141e9a7875a26f088bff68d50641b66883
-rw-r--r-- | runtime/class_linker-inl.h | 58 | ||||
-rw-r--r-- | runtime/mirror/dex_cache-inl.h | 13 |
2 files changed, 55 insertions, 16 deletions
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 26c422b9eb..e51d5a744d 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -70,7 +70,10 @@ inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string ArtField* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - ObjPtr<mirror::String> resolved = referrer->GetDexCache()->GetResolvedString(string_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); if (resolved == nullptr) { resolved = DoResolveString(string_idx, referrer->GetDexCache()); } @@ -81,7 +84,10 @@ inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string ArtMethod* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - ObjPtr<mirror::String> resolved = referrer->GetDexCache()->GetResolvedString(string_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); if (resolved == nullptr) { resolved = DoResolveString(string_idx, referrer->GetDexCache()); } @@ -116,8 +122,10 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, Thread::Current()->PoisonObjectPointers(); } DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. ObjPtr<mirror::Class> resolved_type = - referrer->GetDexCache<kDefaultVerifyFlags>()->GetResolvedType(type_idx); + referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); if (resolved_type == nullptr) { resolved_type = DoResolveType(type_idx, referrer); } @@ -128,7 +136,10 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> resolved_type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (UNLIKELY(resolved_type == nullptr)) { resolved_type = DoResolveType(type_idx, referrer); } @@ -139,7 +150,10 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> resolved_type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (UNLIKELY(resolved_type == nullptr)) { resolved_type = DoResolveType(type_idx, referrer); } @@ -161,8 +175,10 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) { + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. ObjPtr<mirror::Class> type = - referrer->GetDexCache<kDefaultVerifyFlags>()->GetResolvedType(type_idx); + referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer); } @@ -171,7 +187,10 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx, ArtField* referrer) { - ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } @@ -180,7 +199,10 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx, ArtMethod* referrer) { - ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::Class> type = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } @@ -289,7 +311,10 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* // lookup in the context of the original method from where it steals the code. // However, we delay the GetInterfaceMethodIfProxy() until needed. DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor()); - ArtMethod* resolved_method = referrer->GetDexCache()->GetResolvedMethod(method_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved method + // lookup as both from-space and to-space copies point to the same native resolved methods array. + ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod( + method_idx); if (resolved_method == nullptr) { return nullptr; } @@ -339,7 +364,10 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self, // However, we delay the GetInterfaceMethodIfProxy() until needed. DCHECK(!referrer->IsProxyMethod() || referrer->IsConstructor()); Thread::PoisonObjectPointersIfDebug(); - ArtMethod* resolved_method = referrer->GetDexCache()->GetResolvedMethod(method_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved method + // lookup as both from-space and to-space copies point to the same native resolved methods array. + ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod( + method_idx); DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod()); if (UNLIKELY(resolved_method == nullptr)) { referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); @@ -502,7 +530,10 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, ArtMethod* referrer, bool is_static) { - ArtField* field = referrer->GetDexCache()->GetResolvedField(field_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved field + // lookup as both from-space and to-space copies point to the same native resolved fields array. + ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField( + field_idx); if (field == nullptr) { referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader(); @@ -515,7 +546,10 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static) { Thread::PoisonObjectPointersIfDebug(); - ArtField* resolved_field = referrer->GetDexCache()->GetResolvedField(field_idx); + // We do not need the read barrier for getting the DexCache for the initial resolved field + // lookup as both from-space and to-space copies point to the same native resolved fields array. + ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField( + field_idx); if (UNLIKELY(resolved_field == nullptr)) { StackHandleScope<2> hs(Thread::Current()); referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index a8c2a75a61..31f2bd2d7b 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -54,24 +54,29 @@ static void InitializeArray(GcRoot<T>*) { template<typename T, size_t kMaxCacheSize> T* DexCache::AllocArray(MemberOffset obj_offset, MemberOffset num_offset, size_t num) { - ReadBarrier::AssertToSpaceInvariant(this); num = std::min<size_t>(num, kMaxCacheSize); if (num == 0) { return nullptr; } + mirror::DexCache* dex_cache = this; + if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) { + // Several code paths use DexCache without read-barrier for performance. + // We have to check the "to-space" object here to avoid allocating twice. + dex_cache = reinterpret_cast<DexCache*>(ReadBarrier::Mark(dex_cache)); + } Thread* self = Thread::Current(); ClassLinker* linker = Runtime::Current()->GetClassLinker(); LinearAlloc* alloc = linker->GetOrCreateAllocatorForClassLoader(GetClassLoader()); MutexLock mu(self, *Locks::dex_cache_lock_); // Avoid allocation by multiple threads. - T* array = GetFieldPtr64<T*>(obj_offset); + T* array = dex_cache->GetFieldPtr64<T*>(obj_offset); if (array != nullptr) { DCHECK(alloc->Contains(array)); return array; // Other thread just allocated the array. } array = reinterpret_cast<T*>(alloc->AllocAlign16(self, RoundUp(num * sizeof(T), 16))); InitializeArray(array); // Ensure other threads see the array initialized. - SetField32Volatile<false, false>(num_offset, num); - SetField64Volatile<false, false>(obj_offset, reinterpret_cast64<uint64_t>(array)); + dex_cache->SetField32Volatile<false, false>(num_offset, num); + dex_cache->SetField64Volatile<false, false>(obj_offset, reinterpret_cast64<uint64_t>(array)); return array; } |