diff options
-rw-r--r-- | runtime/class_linker_test.cc | 6 | ||||
-rw-r--r-- | runtime/mirror/dex_cache-inl.h | 136 | ||||
-rw-r--r-- | runtime/mirror/dex_cache.cc | 43 | ||||
-rw-r--r-- | runtime/mirror/dex_cache.h | 164 | ||||
-rw-r--r-- | runtime/mirror/dex_cache_test.cc | 15 |
5 files changed, 252 insertions, 112 deletions
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index bd654bb73b..e7e5554d7a 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -684,10 +684,16 @@ struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> { addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_call_sites_), "resolvedCallSites"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_array_), "resolvedFieldsArray"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_method_types_), "resolvedMethodTypes"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_method_types_array_), + "resolvedMethodTypesArray"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_array_), "resolvedMethodsArray"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_array_), "resolvedTypesArray"); addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_array_), "stringsArray"); } }; diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 3cbfb40253..0b6bb1433b 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -49,23 +49,20 @@ static void InitializeArray(std::atomic<DexCachePair>* array) { } template<typename T> -static void InitializeArray(GcRoot<T>*) { - // No special initialization is needed. +static void InitializeArray(T*) { + // Nothing to do. } -template<typename T, size_t kMaxCacheSize> +template<typename T> T* DexCache::AllocArray(MemberOffset obj_offset, size_t num, LinearAllocKind kind) { - num = std::min<size_t>(num, kMaxCacheSize); - if (num == 0) { - return nullptr; - } + Thread* self = Thread::Current(); mirror::DexCache* dex_cache = this; - if (gUseReadBarrier && Thread::Current()->GetIsGcMarking()) { + if (gUseReadBarrier && self->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)); + dex_cache = reinterpret_cast<DexCache*>(ReadBarrier::Mark(this)); } - Thread* self = Thread::Current(); + // DON'T USE 'this' from now on. ClassLinker* linker = Runtime::Current()->GetClassLinker(); LinearAlloc* alloc = linker->GetOrCreateAllocatorForClassLoader(GetClassLoader()); MutexLock mu(self, *Locks::dex_cache_lock_); // Avoid allocation by multiple threads. @@ -112,26 +109,29 @@ inline void NativeDexCachePair<T>::Initialize(std::atomic<NativeDexCachePair<T>> AtomicPairStoreRelease(&array[0], v); } +template <typename T> +inline void GcRootArray<T>::Set(uint32_t index, T* value) { + GcRoot<T> root(value); + entries_[index] = root; +} + +template <typename T> +inline T* GcRootArray<T>::Get(uint32_t index) { + return entries_[index].Read(); +} + inline uint32_t DexCache::ClassSize(PointerSize pointer_size) { const uint32_t vtable_entries = Object::kVTableLength; return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0, pointer_size); } inline String* DexCache::GetResolvedString(dex::StringIndex string_idx) { - auto* strings = GetStrings(); - if (UNLIKELY(strings == nullptr)) { - return nullptr; - } - return strings->Get(string_idx.index_); + return GetStringsEntry(string_idx.index_); } inline void DexCache::SetResolvedString(dex::StringIndex string_idx, ObjPtr<String> resolved) { DCHECK(resolved != nullptr); - auto* strings = GetStrings(); - if (UNLIKELY(strings == nullptr)) { - strings = AllocateStrings(); - } - strings->Set(string_idx.index_, resolved.Ptr()); + SetStringsEntry(string_idx.index_, resolved.Ptr()); Runtime* const runtime = Runtime::Current(); if (UNLIKELY(runtime->IsActiveTransaction())) { DCHECK(runtime->IsAotCompiler()); @@ -143,6 +143,10 @@ inline void DexCache::SetResolvedString(dex::StringIndex string_idx, ObjPtr<Stri inline void DexCache::ClearString(dex::StringIndex string_idx) { DCHECK(Runtime::Current()->IsAotCompiler()); + auto* array = GetStringsArray(); + if (array != nullptr) { + array->Set(string_idx.index_, nullptr); + } auto* strings = GetStrings(); if (UNLIKELY(strings == nullptr)) { return; @@ -151,33 +155,27 @@ inline void DexCache::ClearString(dex::StringIndex string_idx) { } inline Class* DexCache::GetResolvedType(dex::TypeIndex type_idx) { - // It is theorized that a load acquire is not required since obtaining the resolved class will - // always have an address dependency or a lock. - auto* resolved_types = GetResolvedTypes(); - if (UNLIKELY(resolved_types == nullptr)) { - return nullptr; - } - return resolved_types->Get(type_idx.index_); + return GetResolvedTypesEntry(type_idx.index_); } inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) { DCHECK(resolved != nullptr); DCHECK(resolved->IsResolved()) << resolved->GetStatus(); - auto* resolved_types = GetResolvedTypes(); - if (UNLIKELY(resolved_types == nullptr)) { - resolved_types = AllocateResolvedTypes(); - } // TODO default transaction support. // Use a release store for SetResolvedType. This is done to prevent other threads from seeing a // class but not necessarily seeing the loaded members like the static fields array. // See b/32075261. - resolved_types->Set(type_idx.index_, resolved.Ptr()); + SetResolvedTypesEntry(type_idx.index_, resolved.Ptr()); // TODO: Fine-grained marking, so that we don't need to go through all arrays in full. WriteBarrier::ForEveryFieldWrite(this); } inline void DexCache::ClearResolvedType(dex::TypeIndex type_idx) { DCHECK(Runtime::Current()->IsAotCompiler()); + auto* array = GetResolvedTypesArray(); + if (array != nullptr) { + array->Set(type_idx.index_, nullptr); + } auto* resolved_types = GetResolvedTypes(); if (UNLIKELY(resolved_types == nullptr)) { return; @@ -186,20 +184,13 @@ inline void DexCache::ClearResolvedType(dex::TypeIndex type_idx) { } inline MethodType* DexCache::GetResolvedMethodType(dex::ProtoIndex proto_idx) { - auto* methods = GetResolvedMethodTypes(); - if (UNLIKELY(methods == nullptr)) { - return nullptr; - } - return methods->Get(proto_idx.index_); + return GetResolvedMethodTypesEntry(proto_idx.index_); } inline void DexCache::SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodType* resolved) { DCHECK(resolved != nullptr); - auto* methods = GetResolvedMethodTypes(); - if (UNLIKELY(methods == nullptr)) { - methods = AllocateResolvedMethodTypes(); - } - methods->Set(proto_idx.index_, resolved); + SetResolvedMethodTypesEntry(proto_idx.index_, resolved); + Runtime* const runtime = Runtime::Current(); if (UNLIKELY(runtime->IsActiveTransaction())) { DCHECK(runtime->IsAotCompiler()); @@ -211,6 +202,10 @@ inline void DexCache::SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodTyp inline void DexCache::ClearMethodType(dex::ProtoIndex proto_idx) { DCHECK(Runtime::Current()->IsAotCompiler()); + auto* array = GetResolvedMethodTypesArray(); + if (array != nullptr) { + array->Set(proto_idx.index_, nullptr); + } auto* methods = GetResolvedMethodTypes(); if (methods == nullptr) { return; @@ -221,11 +216,11 @@ inline void DexCache::ClearMethodType(dex::ProtoIndex proto_idx) { inline CallSite* DexCache::GetResolvedCallSite(uint32_t call_site_idx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); DCHECK_LT(call_site_idx, GetDexFile()->NumCallSiteIds()); - GcRoot<CallSite>* call_sites = GetResolvedCallSites(); + GcRootArray<CallSite>* call_sites = GetResolvedCallSites(); if (UNLIKELY(call_sites == nullptr)) { return nullptr; } - GcRoot<mirror::CallSite>& target = call_sites[call_site_idx]; + GcRoot<mirror::CallSite>& target = call_sites->GetGcRoot(call_site_idx); Atomic<GcRoot<mirror::CallSite>>& ref = reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target); return ref.load(std::memory_order_seq_cst).Read(); @@ -238,11 +233,11 @@ inline ObjPtr<CallSite> DexCache::SetResolvedCallSite(uint32_t call_site_idx, GcRoot<mirror::CallSite> null_call_site(nullptr); GcRoot<mirror::CallSite> candidate(call_site); - GcRoot<CallSite>* call_sites = GetResolvedCallSites(); + GcRootArray<CallSite>* call_sites = GetResolvedCallSites(); if (UNLIKELY(call_sites == nullptr)) { call_sites = AllocateResolvedCallSites(); } - GcRoot<mirror::CallSite>& target = call_sites[call_site_idx]; + GcRoot<mirror::CallSite>& target = call_sites->GetGcRoot(call_site_idx); // The first assignment for a given call site wins. Atomic<GcRoot<mirror::CallSite>>& ref = @@ -257,37 +252,19 @@ inline ObjPtr<CallSite> DexCache::SetResolvedCallSite(uint32_t call_site_idx, } inline ArtField* DexCache::GetResolvedField(uint32_t field_idx) { - auto* fields = GetResolvedFields(); - if (UNLIKELY(fields == nullptr)) { - return nullptr; - } - return fields->Get(field_idx); + return GetResolvedFieldsEntry(field_idx); } inline void DexCache::SetResolvedField(uint32_t field_idx, ArtField* field) { - DCHECK(field != nullptr); - auto* fields = GetResolvedFields(); - if (UNLIKELY(fields == nullptr)) { - fields = AllocateResolvedFields(); - } - fields->Set(field_idx, field); + SetResolvedFieldsEntry(field_idx, field); } inline ArtMethod* DexCache::GetResolvedMethod(uint32_t method_idx) { - auto* methods = GetResolvedMethods(); - if (UNLIKELY(methods == nullptr)) { - return nullptr; - } - return methods->Get(method_idx); + return GetResolvedMethodsEntry(method_idx); } inline void DexCache::SetResolvedMethod(uint32_t method_idx, ArtMethod* method) { - DCHECK(method != nullptr); - auto* methods = GetResolvedMethods(); - if (UNLIKELY(methods == nullptr)) { - methods = AllocateResolvedMethods(); - } - methods->Set(method_idx, method); + SetResolvedMethodsEntry(method_idx, method); } template <ReadBarrierOption kReadBarrierOption, @@ -349,10 +326,29 @@ inline void DexCache::VisitNativeRoots(const Visitor& visitor) { VisitDexCachePairs<kReadBarrierOption, Visitor>( GetResolvedMethodTypes<kVerifyFlags>(), NumResolvedMethodTypes<kVerifyFlags>(), visitor); - GcRoot<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites<kVerifyFlags>(); + GcRootArray<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites<kVerifyFlags>(); size_t num_call_sites = NumResolvedCallSites<kVerifyFlags>(); for (size_t i = 0; resolved_call_sites != nullptr && i != num_call_sites; ++i) { - visitor.VisitRootIfNonNull(resolved_call_sites[i].AddressWithoutBarrier()); + visitor.VisitRootIfNonNull(resolved_call_sites->GetGcRoot(i).AddressWithoutBarrier()); + } + + GcRootArray<mirror::Class>* resolved_types = GetResolvedTypesArray<kVerifyFlags>(); + size_t num_resolved_types = NumResolvedTypesArray<kVerifyFlags>(); + for (size_t i = 0; resolved_types != nullptr && i != num_resolved_types; ++i) { + visitor.VisitRootIfNonNull(resolved_types->GetGcRoot(i).AddressWithoutBarrier()); + } + + GcRootArray<mirror::String>* resolved_strings = GetStringsArray<kVerifyFlags>(); + size_t num_resolved_strings = NumStringsArray<kVerifyFlags>(); + for (size_t i = 0; resolved_strings != nullptr && i != num_resolved_strings; ++i) { + visitor.VisitRootIfNonNull(resolved_strings->GetGcRoot(i).AddressWithoutBarrier()); + } + + GcRootArray<mirror::MethodType>* resolved_method_types = + GetResolvedMethodTypesArray<kVerifyFlags>(); + size_t num_resolved_method_types = NumResolvedMethodTypesArray<kVerifyFlags>(); + for (size_t i = 0; resolved_method_types != nullptr && i != num_resolved_method_types; ++i) { + visitor.VisitRootIfNonNull(resolved_method_types->GetGcRoot(i).AddressWithoutBarrier()); } } diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index 1d9fecdd11..7d0c97ffda 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -44,6 +44,12 @@ void DexCache::Initialize(const DexFile* dex_file, ObjPtr<ClassLoader> class_loa DCHECK(GetResolvedMethodTypes() == nullptr); DCHECK(GetResolvedCallSites() == nullptr); + DCHECK(GetStringsArray() == nullptr); + DCHECK(GetResolvedTypesArray() == nullptr); + DCHECK(GetResolvedMethodsArray() == nullptr); + DCHECK(GetResolvedFieldsArray() == nullptr); + DCHECK(GetResolvedMethodTypesArray() == nullptr); + ScopedAssertNoThreadSuspension sants(__FUNCTION__); SetDexFile(dex_file); @@ -96,6 +102,37 @@ void DexCache::VisitReflectiveTargets(ReflectiveValueVisitor* visitor) { wrote = true; } } + + auto* fields_array = GetResolvedFieldsArray(); + num_fields = NumResolvedFieldsArray(); + for (size_t i = 0; fields_array != nullptr && i < num_fields; i++) { + ArtField* old_val = fields_array->Get(i); + if (old_val == nullptr) { + continue; + } + ArtField* new_val = visitor->VisitField( + old_val, DexCacheSourceInfo(kSourceDexCacheResolvedField, i, this)); + if (new_val != old_val) { + fields_array->Set(i, new_val); + wrote = true; + } + } + + auto* methods_array = GetResolvedMethodsArray(); + num_methods = NumResolvedMethodsArray(); + for (size_t i = 0; methods_array != nullptr && i < num_methods; i++) { + ArtMethod* old_val = methods_array->Get(i); + if (old_val == nullptr) { + continue; + } + ArtMethod* new_val = visitor->VisitMethod( + old_val, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, i, this)); + if (new_val != old_val) { + methods_array->Set(i, new_val); + wrote = true; + } + } + if (wrote) { WriteBarrier::ForEveryFieldWrite(this); } @@ -108,6 +145,12 @@ void DexCache::ResetNativeArrays() { SetResolvedFields(nullptr); SetResolvedMethodTypes(nullptr); SetResolvedCallSites(nullptr); + + SetStringsArray(nullptr); + SetResolvedTypesArray(nullptr); + SetResolvedMethodsArray(nullptr); + SetResolvedFieldsArray(nullptr); + SetResolvedMethodTypesArray(nullptr); } void DexCache::SetLocation(ObjPtr<mirror::String> location) { diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 7af0fa2e87..4c0c35db18 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -205,6 +205,38 @@ template <typename T, size_t size> class DexCachePairArray { DexCachePairArray& operator=(const DexCachePairArray<T, size>&) = delete; }; +template <typename T> class GcRootArray { + public: + GcRootArray() {} + + T* Get(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_); + + GcRoot<T>& GetGcRoot(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) { + return entries_[index]; + } + + void Set(uint32_t index, T* value) REQUIRES_SHARED(Locks::mutator_lock_); + + private: + GcRoot<T> entries_[0]; +}; + +template <typename T> class NativeArray { + public: + NativeArray() {} + + T* Get(uint32_t index) { + return entries_[index]; + } + + void Set(uint32_t index, T* value) { + entries_[index] = value; + } + + private: + T* entries_[0]; +}; + // C++ mirror of java.lang.DexCache. class MANAGED DexCache final : public Object { public: @@ -333,107 +365,164 @@ class MANAGED DexCache final : public Object { void VisitNativeRoots(const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); - // NOLINTBEGIN(bugprone-macro-parentheses) -#define DEFINE_PAIR_ARRAY(name, pair_kind, getter_setter, type, size, ids, alloc_kind) \ +// NOLINTBEGIN(bugprone-macro-parentheses) +#define DEFINE_ARRAY(name, array_kind, getter_setter, type, ids, alloc_kind) \ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> \ - pair_kind ##Array<type, size>* Get ##getter_setter() \ + array_kind* Get ##getter_setter() \ ALWAYS_INLINE \ REQUIRES_SHARED(Locks::mutator_lock_) { \ - return GetFieldPtr<pair_kind ##Array<type, size>*, kVerifyFlags>(getter_setter ##Offset()); \ + return GetFieldPtr<array_kind*, kVerifyFlags>(getter_setter ##Offset()); \ } \ - void Set ##getter_setter(pair_kind ##Array<type, size>* value) \ + void Set ##getter_setter(array_kind* value) \ REQUIRES_SHARED(Locks::mutator_lock_) { \ SetFieldPtr<false>(getter_setter ##Offset(), value); \ } \ static constexpr MemberOffset getter_setter ##Offset() { \ return OFFSET_OF_OBJECT_MEMBER(DexCache, name); \ } \ - pair_kind ##Array<type, size>* Allocate ##getter_setter() \ + array_kind* Allocate ##getter_setter() \ REQUIRES_SHARED(Locks::mutator_lock_) { \ - return reinterpret_cast<pair_kind ##Array<type, size>*>( \ - AllocArray<std::atomic<pair_kind<type>>, size>( \ - getter_setter ##Offset(), GetDexFile()->ids(), alloc_kind)); \ + return reinterpret_cast<array_kind*>(AllocArray<type>( \ + getter_setter ##Offset(), GetDexFile()->ids(), alloc_kind)); \ } \ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> \ size_t Num ##getter_setter() REQUIRES_SHARED(Locks::mutator_lock_) { \ - return Get ##getter_setter() == nullptr ? 0u : std::min<size_t>(GetDexFile()->ids(), size); \ + return Get ##getter_setter() == nullptr ? 0u : GetDexFile()->ids(); \ } \ -#define DEFINE_ARRAY(name, getter_setter, type, ids, alloc_kind) \ +#define DEFINE_PAIR_ARRAY(name, pair_kind, getter_setter, type, size, alloc_kind) \ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> \ - type* Get ##getter_setter() \ + pair_kind ##Array<type, size>* Get ##getter_setter() \ ALWAYS_INLINE \ REQUIRES_SHARED(Locks::mutator_lock_) { \ - return GetFieldPtr<type*, kVerifyFlags>(getter_setter ##Offset()); \ + return GetFieldPtr<pair_kind ##Array<type, size>*, kVerifyFlags>(getter_setter ##Offset()); \ } \ - void Set ##getter_setter(type* value) \ + void Set ##getter_setter(pair_kind ##Array<type, size>* value) \ REQUIRES_SHARED(Locks::mutator_lock_) { \ SetFieldPtr<false>(getter_setter ##Offset(), value); \ } \ static constexpr MemberOffset getter_setter ##Offset() { \ return OFFSET_OF_OBJECT_MEMBER(DexCache, name); \ } \ - type* Allocate ##getter_setter() \ + pair_kind ##Array<type, size>* Allocate ##getter_setter() \ REQUIRES_SHARED(Locks::mutator_lock_) { \ - return reinterpret_cast<type*>(AllocArray<type, std::numeric_limits<size_t>::max()>( \ - getter_setter ##Offset(), GetDexFile()->ids(), alloc_kind)); \ + return reinterpret_cast<pair_kind ##Array<type, size>*>( \ + AllocArray<std::atomic<pair_kind<type>>>( \ + getter_setter ##Offset(), size, alloc_kind)); \ } \ template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> \ size_t Num ##getter_setter() REQUIRES_SHARED(Locks::mutator_lock_) { \ - return GetDexFile()->ids(); \ + return Get ##getter_setter() == nullptr ? 0u : size; \ } \ +#define DEFINE_DUAL_CACHE( \ + name, pair_kind, getter_setter, type, pair_size, alloc_pair_kind, \ + array_kind, component_type, ids, alloc_array_kind) \ + DEFINE_PAIR_ARRAY( \ + name, pair_kind, getter_setter, type, pair_size, alloc_pair_kind) \ + DEFINE_ARRAY( \ + name ##array_, array_kind, getter_setter ##Array, component_type, ids, alloc_array_kind) \ + type* Get ##getter_setter ##Entry(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) { \ + DCHECK_LT(index, GetDexFile()->ids()); \ + auto* array = Get ##getter_setter ##Array(); \ + if (array != nullptr) { \ + return array->Get(index); \ + } \ + auto* pairs = Get ##getter_setter(); \ + if (pairs != nullptr) { \ + return pairs->Get(index); \ + } \ + return nullptr; \ + } \ + void Set ##getter_setter ##Entry(uint32_t index, type* resolved) \ + REQUIRES_SHARED(Locks::mutator_lock_) { \ + DCHECK_LT(index, GetDexFile()->ids()); \ + auto* array = Get ##getter_setter ##Array(); \ + if (array != nullptr) { \ + array->Set(index, resolved); \ + } else { \ + auto* pairs = Get ##getter_setter(); \ + if (pairs == nullptr) { \ + if (GetDexFile()->ids() <= pair_size) { \ + array = Allocate ##getter_setter ##Array(); \ + array->Set(index, resolved); \ + } else { \ + pairs = Allocate ##getter_setter(); \ + pairs->Set(index, resolved); \ + } \ + } else { \ + pairs->Set(index, resolved); \ + } \ + } \ + } + DEFINE_ARRAY(resolved_call_sites_, + GcRootArray<CallSite>, ResolvedCallSites, GcRoot<CallSite>, NumCallSiteIds, LinearAllocKind::kGCRootArray) - DEFINE_PAIR_ARRAY(resolved_fields_, + DEFINE_DUAL_CACHE(resolved_fields_, NativeDexCachePair, ResolvedFields, ArtField, kDexCacheFieldCacheSize, + LinearAllocKind::kNoGCRoots, + NativeArray<ArtField>, + ArtField, NumFieldIds, LinearAllocKind::kNoGCRoots) - DEFINE_PAIR_ARRAY(resolved_method_types_, + DEFINE_DUAL_CACHE(resolved_method_types_, DexCachePair, ResolvedMethodTypes, mirror::MethodType, kDexCacheMethodTypeCacheSize, + LinearAllocKind::kDexCacheArray, + GcRootArray<mirror::MethodType>, + GcRoot<mirror::MethodType>, NumProtoIds, - LinearAllocKind::kDexCacheArray); + LinearAllocKind::kGCRootArray); - DEFINE_PAIR_ARRAY(resolved_methods_, + DEFINE_DUAL_CACHE(resolved_methods_, NativeDexCachePair, ResolvedMethods, ArtMethod, kDexCacheMethodCacheSize, + LinearAllocKind::kNoGCRoots, + NativeArray<ArtMethod>, + ArtMethod, NumMethodIds, LinearAllocKind::kNoGCRoots) - DEFINE_PAIR_ARRAY(resolved_types_, + DEFINE_DUAL_CACHE(resolved_types_, DexCachePair, ResolvedTypes, mirror::Class, kDexCacheTypeCacheSize, + LinearAllocKind::kDexCacheArray, + GcRootArray<mirror::Class>, + GcRoot<mirror::Class>, NumTypeIds, - LinearAllocKind::kDexCacheArray); + LinearAllocKind::kGCRootArray); - DEFINE_PAIR_ARRAY(strings_, + DEFINE_DUAL_CACHE(strings_, DexCachePair, Strings, mirror::String, kDexCacheStringCacheSize, + LinearAllocKind::kDexCacheArray, + GcRootArray<mirror::String>, + GcRoot<mirror::String>, NumStringIds, - LinearAllocKind::kDexCacheArray); + LinearAllocKind::kGCRootArray); // NOLINTEND(bugprone-macro-parentheses) private: // Allocate new array in linear alloc and save it in the given fields. - template<typename T, size_t kMaxCacheSize> + template<typename T> T* AllocArray(MemberOffset obj_offset, size_t num, LinearAllocKind kind) REQUIRES_SHARED(Locks::mutator_lock_); @@ -448,14 +537,19 @@ class MANAGED DexCache final : public Object { HeapReference<ClassLoader> class_loader_; HeapReference<String> location_; - uint64_t dex_file_; // const DexFile* - - uint64_t resolved_call_sites_; // Array of call sites - uint64_t resolved_fields_; // NativeDexCacheArray holding ArtField's - uint64_t resolved_method_types_; // DexCacheArray holding mirror::MethodType's - uint64_t resolved_methods_; // NativeDexCacheArray holding ArtMethod's - uint64_t resolved_types_; // DexCacheArray holding mirror::Class's - uint64_t strings_; // DexCacheArray holding mirror::String's + uint64_t dex_file_; // const DexFile* + // + uint64_t resolved_call_sites_; // Array of call sites + uint64_t resolved_fields_; // NativeDexCacheArray holding ArtField's + uint64_t resolved_fields_array_; // Array of ArtField's. + uint64_t resolved_method_types_; // DexCacheArray holding mirror::MethodType's + uint64_t resolved_method_types_array_; // Array of mirror::MethodType's + uint64_t resolved_methods_; // NativeDexCacheArray holding ArtMethod's + uint64_t resolved_methods_array_; // Array of ArtMethod's + uint64_t resolved_types_; // DexCacheArray holding mirror::Class's + uint64_t resolved_types_array_; // Array of resolved types. + uint64_t strings_; // DexCacheArray holding mirror::String's + uint64_t strings_array_; // Array of String's. friend struct art::DexCacheOffsets; // for verifying offset information friend class linker::ImageWriter; diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index bc695fad92..bc521f5604 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -146,15 +146,16 @@ TEST_F(DexCacheMethodHandlesTest, TestResolvedMethodTypes) { // The MethodTypes dex file contains a single interface with two abstract // methods. It must therefore contain precisely two method IDs. ASSERT_EQ(2u, dex_file.NumProtoIds()); - ASSERT_EQ(dex_file.NumProtoIds(), dex_cache->NumResolvedMethodTypes()); - auto* method_types_cache = dex_cache->GetResolvedMethodTypes(); + ASSERT_EQ(dex_file.NumProtoIds(), dex_cache->NumResolvedMethodTypesArray()); + ASSERT_EQ(0u, dex_cache->NumResolvedMethodTypes()); + auto* method_types_cache = dex_cache->GetResolvedMethodTypesArray(); for (size_t i = 0; i < dex_file.NumProtoIds(); ++i) { - const DexCachePair<MethodType> pair = method_types_cache->GetPair(i); - if (dex::ProtoIndex(pair.index) == method1_id.proto_idx_) { - ASSERT_EQ(method1_type.Get(), pair.object.Read()); - } else if (dex::ProtoIndex(pair.index) == method2_id.proto_idx_) { - ASSERT_EQ(method2_type.Get(), pair.object.Read()); + auto* method_type = method_types_cache->Get(i); + if (dex::ProtoIndex(i) == method1_id.proto_idx_) { + ASSERT_EQ(method1_type.Get(), method_type); + } else if (dex::ProtoIndex(i) == method2_id.proto_idx_) { + ASSERT_EQ(method2_type.Get(), method_type); } else { ASSERT_TRUE(false); } |