summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/class_linker_test.cc6
-rw-r--r--runtime/mirror/dex_cache-inl.h136
-rw-r--r--runtime/mirror/dex_cache.cc43
-rw-r--r--runtime/mirror/dex_cache.h164
-rw-r--r--runtime/mirror/dex_cache_test.cc15
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);
}