Optimistically update field and method cache on type update.
To save on future lookups, update the method and field caches as soon as
we update the type cache, when the type has the same dex cache, and the
dex cache is using full arrays.
This saves the number of lookup of maps startup by ~30% (2100 -> 1500).
Test: test.py
Change-Id: I4cb708a04fb491fe65a75412bb2a8b9306e81f78
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index b79f3f5..8f3692d 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -476,6 +476,11 @@
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
}
+ // Look for the method again in case the type resolution updated the cache.
+ resolved = dex_cache->GetResolvedMethod(method_idx);
+ if (kResolveMode == ResolveMode::kNoChecks && resolved != nullptr) {
+ return resolved;
+ }
}
// Check if the invoke type matches the class type.
@@ -584,6 +589,12 @@
return nullptr;
}
+ // Look for the field again in case the type resolution updated the cache.
+ resolved = dex_cache->GetResolvedField(field_idx);
+ if (resolved != nullptr) {
+ return resolved;
+ }
+
resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
if (resolved == nullptr) {
const char* name = dex_file.GetFieldName(field_id);
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 5a44fff..3452f17 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -164,18 +164,6 @@
return GetResolvedTypesEntry(type_idx.index_);
}
-inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
- DCHECK(resolved != nullptr);
- DCHECK(resolved->IsResolved()) << resolved->GetStatus();
- // 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.
- 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();
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 5e6138c..b0b6012 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -215,5 +215,46 @@
UnlinkResolvedMethodTypesArrayIfStartup();
}
+void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
+ DCHECK(resolved != nullptr);
+ DCHECK(resolved->IsResolved()) << resolved->GetStatus();
+ // 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.
+ 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);
+
+ if (this == resolved->GetDexCache()) {
+ // If we're updating the dex cache of the class, optimistically update the cache for methods and
+ // fields if the caches are full arrays.
+ auto* resolved_methods = GetResolvedMethodsArray();
+ if (resolved_methods != nullptr) {
+ PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+ // Because there could be duplicate method entries, we make sure we only
+ // update the cache with the first one found to be consistent with method
+ // resolution.
+ uint32_t previous_method_index = dex::kDexNoIndex;
+ for (ArtMethod& current_method : resolved->GetDeclaredMethods(pointer_size)) {
+ uint32_t new_index = current_method.GetDexMethodIndex();
+ if (new_index != previous_method_index) {
+ resolved_methods->Set(new_index, ¤t_method);
+ previous_method_index = new_index;
+ }
+ }
+ }
+ auto* resolved_fields = GetResolvedFieldsArray();
+ if (resolved_fields != nullptr) {
+ for (ArtField& current_field : resolved->GetSFields()) {
+ resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field);
+ }
+ for (ArtField& current_field : resolved->GetIFields()) {
+ resolved_fields->Set(current_field.GetDexFieldIndex(), ¤t_field);
+ }
+ }
+ }
+}
+
} // namespace mirror
} // namespace art