ART: Add field offset caching

Add caching to reduce the computational complexity of deriving
field indices. Currently cache the number of interface fields.
In the future, we may also consider the superclass count to
accelerate class visiting.

Bug: 31385354
Test: m test-art-host
Test: m test-art-host-run-test-906-iterate-heap
Test: m test-art-host-run-test-913-heaps
Change-Id: I19da243d1678f9a4a047d849193fb8bac01ed53c
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index d52f0ea..c2495e3 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -25,6 +25,7 @@
 #include "gc_root-inl.h"
 #include "jni_env_ext.h"
 #include "jni_internal.h"
+#include "jvmti_weak_table-inl.h"
 #include "mirror/class.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
@@ -41,6 +42,21 @@
 
 namespace {
 
+struct IndexCache {
+  // The number of interface fields implemented by the class. This is a prefix to all assigned
+  // field indices.
+  size_t interface_fields;
+
+  // It would be nice to also cache the following, but it is complicated to wire up into the
+  // generic visit:
+  // The number of fields in interfaces and superclasses. This is the first index assigned to
+  // fields of the class.
+  // size_t superclass_fields;
+};
+using IndexCachingTable = JvmtiWeakTable<IndexCache>;
+
+static IndexCachingTable gIndexCachingTable;
+
 // Report the contents of a string, if a callback is set.
 jint ReportString(art::ObjPtr<art::mirror::Object> obj,
                   jvmtiEnv* env,
@@ -402,6 +418,12 @@
   // "non-marker" interfaces (= interfaces with methods).
   static size_t CountInterfaceFields(art::ObjPtr<art::mirror::Class> klass)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    // Do we have a cached value?
+    IndexCache tmp;
+    if (gIndexCachingTable.GetTag(klass.Ptr(), &tmp)) {
+      return tmp.interface_fields;
+    }
+
     size_t count = 0;
     auto visitor = [&count](art::ObjPtr<art::mirror::Class> inf_klass)
         REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -410,9 +432,12 @@
       count += inf_klass->NumStaticFields();
     };
     RecursiveInterfaceVisit<decltype(visitor)>::VisitStatic(art::Thread::Current(), klass, visitor);
-    return count;
 
-    // TODO: Implement caching.
+    // Store this into the cache.
+    tmp.interface_fields = count;
+    gIndexCachingTable.Set(klass.Ptr(), tmp);
+
+    return count;
   }
 
   UserData* user_data_;
@@ -618,6 +643,14 @@
 
 }  // namespace
 
+void HeapUtil::Register() {
+  art::Runtime::Current()->AddSystemWeakHolder(&gIndexCachingTable);
+}
+
+void HeapUtil::Unregister() {
+  art::Runtime::Current()->RemoveSystemWeakHolder(&gIndexCachingTable);
+}
+
 struct IterateThroughHeapData {
   IterateThroughHeapData(HeapUtil* _heap_util,
                          jvmtiEnv* _env,
@@ -1004,7 +1037,6 @@
         jvmtiHeapReferenceInfo reference_info;
         memset(&reference_info, 0, sizeof(reference_info));
 
-        // TODO: Implement spec-compliant numbering.
         reference_info.field.index = field_index;
 
         jvmtiHeapReferenceKind kind =