ART: Move DexCache arrays to native.

This CL has a companion CL in libcore/
    https://android-review.googlesource.com/162985

Change-Id: Icbc9e20ad1b565e603195b12714762bb446515fa
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index b2c6e4d..10b381d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -817,12 +817,12 @@
   }
 }
 
-inline void Class::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
-  SetFieldObject<false>(DexCacheStringsOffset(), new_dex_cache_strings);
+inline void Class::SetDexCacheStrings(GcRoot<String>* new_dex_cache_strings) {
+  SetFieldPtr<false>(DexCacheStringsOffset(), new_dex_cache_strings);
 }
 
-inline ObjectArray<String>* Class::GetDexCacheStrings() {
-  return GetFieldObject<ObjectArray<String>>(DexCacheStringsOffset());
+inline GcRoot<String>* Class::GetDexCacheStrings() {
+  return GetFieldPtr<GcRoot<String>*>(DexCacheStringsOffset());
 }
 
 template<class Visitor>
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 1420e5b..9422432 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -250,6 +250,14 @@
     SetClassFlags(kClassFlagClassLoader);
   }
 
+  ALWAYS_INLINE bool IsDexCacheClass() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return (GetClassFlags() & kClassFlagDexCache) != 0;
+  }
+
+  ALWAYS_INLINE void SetDexCacheClass() SHARED_REQUIRES(Locks::mutator_lock_) {
+    SetClassFlags(GetClassFlags() | kClassFlagDexCache);
+  }
+
   // Returns true if the class is abstract.
   ALWAYS_INLINE bool IsAbstract() SHARED_REQUIRES(Locks::mutator_lock_) {
     return (GetAccessFlags() & kAccAbstract) != 0;
@@ -1077,8 +1085,8 @@
   bool GetSlowPathEnabled() SHARED_REQUIRES(Locks::mutator_lock_);
   void SetSlowPath(bool enabled) SHARED_REQUIRES(Locks::mutator_lock_);
 
-  ObjectArray<String>* GetDexCacheStrings() SHARED_REQUIRES(Locks::mutator_lock_);
-  void SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings)
+  GcRoot<String>* GetDexCacheStrings() SHARED_REQUIRES(Locks::mutator_lock_);
+  void SetDexCacheStrings(GcRoot<String>* new_dex_cache_strings)
       SHARED_REQUIRES(Locks::mutator_lock_);
   static MemberOffset DexCacheStringsOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_);
@@ -1173,9 +1181,6 @@
   // runtime such as arrays and primitive classes).
   HeapReference<DexCache> dex_cache_;
 
-  // Short cuts to dex_cache_ member for fast compiled code access.
-  HeapReference<ObjectArray<String>> dex_cache_strings_;
-
   // The interface table (iftable_) contains pairs of a interface class and an array of the
   // interface methods. There is one pair per interface supported by this class.  That means one
   // pair for each interface we support directly, indirectly via superclass, or indirectly via a
@@ -1209,9 +1214,8 @@
   // virtual_ methods_ for miranda methods.
   HeapReference<PointerArray> vtable_;
 
-  // Access flags; low 16 bits are defined by VM spec.
-  // Note: Shuffled back.
-  uint32_t access_flags_;
+  // Short cuts to dex_cache_ member for fast compiled code access.
+  uint64_t dex_cache_strings_;
 
   // static, private, and <init> methods. Pointer to an ArtMethod length-prefixed array.
   uint64_t direct_methods_;
@@ -1234,6 +1238,9 @@
   // length-prefixed array.
   uint64_t virtual_methods_;
 
+  // Access flags; low 16 bits are defined by VM spec.
+  uint32_t access_flags_;
+
   // Class flags to help speed up visiting object references.
   uint32_t class_flags_;
 
diff --git a/runtime/mirror/class_flags.h b/runtime/mirror/class_flags.h
index eb2e2eb..139c4cb 100644
--- a/runtime/mirror/class_flags.h
+++ b/runtime/mirror/class_flags.h
@@ -41,17 +41,20 @@
 // Class is ClassLoader or one of its subclasses.
 static constexpr uint32_t kClassFlagClassLoader        = 0x00000020;
 
+// Class is DexCache.
+static constexpr uint32_t kClassFlagDexCache           = 0x00000040;
+
 // Class is a soft/weak/phantom class.
-static constexpr uint32_t kClassFlagSoftReference      = 0x00000040;
+static constexpr uint32_t kClassFlagSoftReference      = 0x00000080;
 
 // Class is a weak reference class.
-static constexpr uint32_t kClassFlagWeakReference      = 0x00000080;
+static constexpr uint32_t kClassFlagWeakReference      = 0x00000100;
 
 // Class is a finalizer reference class.
-static constexpr uint32_t kClassFlagFinalizerReference = 0x00000100;
+static constexpr uint32_t kClassFlagFinalizerReference = 0x00000200;
 
 // Class is the phantom reference class.
-static constexpr uint32_t kClassFlagPhantomReference   = 0x00000200;
+static constexpr uint32_t kClassFlagPhantomReference   = 0x00000400;
 
 // Combination of flags to figure out if the class is either the weak/soft/phantom/finalizer
 // reference class.
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 4b5063a..f8ccfb1 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -21,6 +21,7 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/casts.h"
 #include "base/logging.h"
 #include "mirror/class.h"
 #include "runtime.h"
@@ -33,29 +34,53 @@
   return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0, pointer_size);
 }
 
-inline void DexCache::SetResolvedType(uint32_t type_idx, Class* resolved) {
-  // TODO default transaction support.
-  DCHECK(resolved == nullptr || !resolved->IsErroneous());
-  GetResolvedTypes()->Set(type_idx, resolved);
+inline String* DexCache::GetResolvedString(uint32_t string_idx) {
+  DCHECK_LT(string_idx, NumStrings());
+  return GetStrings()[string_idx].Read();
 }
 
-inline ArtField* DexCache::GetResolvedField(uint32_t idx, size_t ptr_size) {
+inline void DexCache::SetResolvedString(uint32_t string_idx, String* resolved) {
+  DCHECK_LT(string_idx, NumStrings());
+  // TODO default transaction support.
+  GetStrings()[string_idx] = GcRoot<String>(resolved);
+  // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
+  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
+}
+
+inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
+  DCHECK_LT(type_idx, NumResolvedTypes());
+  return GetResolvedTypes()[type_idx].Read();
+}
+
+inline void DexCache::SetResolvedType(uint32_t type_idx, Class* resolved) {
+  DCHECK_LT(type_idx, NumResolvedTypes());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+  // TODO default transaction support.
+  DCHECK(resolved == nullptr || !resolved->IsErroneous());
+  GetResolvedTypes()[type_idx] = GcRoot<Class>(resolved);
+  // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
+  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
+}
+
+inline ArtField* DexCache::GetResolvedField(uint32_t field_idx, size_t ptr_size) {
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), ptr_size);
-  auto* field = GetResolvedFields()->GetElementPtrSize<ArtField*>(idx, ptr_size);
+  DCHECK_LT(field_idx, NumResolvedFields());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+  ArtField* field = GetElementPtrSize(GetResolvedFields(), field_idx, ptr_size);
   if (field == nullptr || field->GetDeclaringClass()->IsErroneous()) {
     return nullptr;
   }
   return field;
 }
 
-inline void DexCache::SetResolvedField(uint32_t idx, ArtField* field, size_t ptr_size) {
+inline void DexCache::SetResolvedField(uint32_t field_idx, ArtField* field, size_t ptr_size) {
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), ptr_size);
-  GetResolvedFields()->SetElementPtrSize(idx, field, ptr_size);
+  DCHECK_LT(field_idx, NumResolvedFields());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+  SetElementPtrSize(GetResolvedFields(), field_idx, field, ptr_size);
 }
 
 inline ArtMethod* DexCache::GetResolvedMethod(uint32_t method_idx, size_t ptr_size) {
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), ptr_size);
-  auto* method = GetResolvedMethods()->GetElementPtrSize<ArtMethod*>(method_idx, ptr_size);
+  DCHECK_LT(method_idx, NumResolvedMethods());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+  ArtMethod* method = GetElementPtrSize<ArtMethod*>(GetResolvedMethods(), method_idx, ptr_size);
   // Hide resolution trampoline methods from the caller
   if (method != nullptr && method->IsRuntimeMethod()) {
     DCHECK_EQ(method, Runtime::Current()->GetResolutionMethod());
@@ -64,9 +89,52 @@
   return method;
 }
 
-inline void DexCache::SetResolvedMethod(uint32_t idx, ArtMethod* method, size_t ptr_size) {
+inline void DexCache::SetResolvedMethod(uint32_t method_idx, ArtMethod* method, size_t ptr_size) {
   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), ptr_size);
-  GetResolvedMethods()->SetElementPtrSize(idx, method, ptr_size);
+  DCHECK_LT(method_idx, NumResolvedMethods());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+  SetElementPtrSize(GetResolvedMethods(), method_idx, method, ptr_size);
+}
+
+template <typename PtrType>
+inline PtrType DexCache::GetElementPtrSize(PtrType* ptr_array, size_t idx, size_t ptr_size) {
+  if (ptr_size == 8u) {
+    uint64_t element = reinterpret_cast<const uint64_t*>(ptr_array)[idx];
+    return reinterpret_cast<PtrType>(dchecked_integral_cast<uintptr_t>(element));
+  } else {
+    DCHECK_EQ(ptr_size, 4u);
+    uint32_t element = reinterpret_cast<const uint32_t*>(ptr_array)[idx];
+    return reinterpret_cast<PtrType>(dchecked_integral_cast<uintptr_t>(element));
+  }
+}
+
+template <typename PtrType>
+inline void DexCache::SetElementPtrSize(PtrType* ptr_array,
+                                        size_t idx,
+                                        PtrType ptr,
+                                        size_t ptr_size) {
+  if (ptr_size == 8u) {
+    reinterpret_cast<uint64_t*>(ptr_array)[idx] =
+        dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr));
+  } else {
+    DCHECK_EQ(ptr_size, 4u);
+    reinterpret_cast<uint32_t*>(ptr_array)[idx] =
+        dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr));
+  }
+}
+
+template <VerifyObjectFlags kVerifyFlags, typename Visitor>
+inline void DexCache::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
+  // Visit instance fields first.
+  VisitInstanceFieldsReferences(klass, visitor);
+  // Visit arrays after.
+  GcRoot<mirror::String>* strings = GetStrings();
+  for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) {
+    visitor.VisitRootIfNonNull(strings[i].AddressWithoutBarrier());
+  }
+  GcRoot<mirror::Class>* resolved_types = GetResolvedTypes();
+  for (size_t i = 0, num_types = NumResolvedTypes(); i != num_types; ++i) {
+    visitor.VisitRootIfNonNull(resolved_types[i].AddressWithoutBarrier());
+  }
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 630faee..349a319 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "dex_cache.h"
+#include "dex_cache-inl.h"
 
 #include "art_method-inl.h"
 #include "base/logging.h"
@@ -31,22 +31,34 @@
 namespace art {
 namespace mirror {
 
-void DexCache::Init(const DexFile* dex_file, String* location, ObjectArray<String>* strings,
-                    ObjectArray<Class>* resolved_types, PointerArray* resolved_methods,
-                    PointerArray* resolved_fields, size_t pointer_size) {
+void DexCache::Init(const DexFile* dex_file,
+                    String* location,
+                    GcRoot<String>* strings,
+                    uint32_t num_strings,
+                    GcRoot<Class>* resolved_types,
+                    uint32_t num_resolved_types,
+                    ArtMethod** resolved_methods,
+                    uint32_t num_resolved_methods,
+                    ArtField** resolved_fields,
+                    uint32_t num_resolved_fields,
+                    size_t pointer_size) {
   CHECK(dex_file != nullptr);
   CHECK(location != nullptr);
-  CHECK(strings != nullptr);
-  CHECK(resolved_types != nullptr);
-  CHECK(resolved_methods != nullptr);
-  CHECK(resolved_fields != nullptr);
+  CHECK_EQ(num_strings != 0u, strings != nullptr);
+  CHECK_EQ(num_resolved_types != 0u, resolved_types != nullptr);
+  CHECK_EQ(num_resolved_methods != 0u, resolved_methods != nullptr);
+  CHECK_EQ(num_resolved_fields != 0u, resolved_fields != nullptr);
 
   SetDexFile(dex_file);
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
-  SetFieldObject<false>(StringsOffset(), strings);
-  SetFieldObject<false>(ResolvedFieldsOffset(), resolved_fields);
-  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types);
-  SetFieldObject<false>(ResolvedMethodsOffset(), resolved_methods);
+  SetField64<false>(StringsOffset(), reinterpret_cast<uintptr_t>(strings));
+  SetField64<false>(ResolvedTypesOffset(), reinterpret_cast<uintptr_t>(resolved_types));
+  SetField64<false>(ResolvedMethodsOffset(), reinterpret_cast<uintptr_t>(resolved_methods));
+  SetField64<false>(ResolvedFieldsOffset(), reinterpret_cast<uintptr_t>(resolved_fields));
+  SetField32<false>(NumStringsOffset(), num_strings);
+  SetField32<false>(NumResolvedTypesOffset(), num_resolved_types);
+  SetField32<false>(NumResolvedMethodsOffset(), num_resolved_methods);
+  SetField32<false>(NumResolvedFieldsOffset(), num_resolved_fields);
 
   Runtime* const runtime = Runtime::Current();
   if (runtime->HasResolutionMethod()) {
@@ -60,9 +72,9 @@
   CHECK(trampoline != nullptr);
   CHECK(trampoline->IsRuntimeMethod());
   auto* resolved_methods = GetResolvedMethods();
-  for (size_t i = 0, length = resolved_methods->GetLength(); i < length; i++) {
-    if (resolved_methods->GetElementPtrSize<ArtMethod*>(i, pointer_size) == nullptr) {
-      resolved_methods->SetElementPtrSize(i, trampoline, pointer_size);
+  for (size_t i = 0, length = NumResolvedMethods(); i < length; i++) {
+    if (GetElementPtrSize<ArtMethod*>(resolved_methods, i, pointer_size) == nullptr) {
+      SetElementPtrSize(resolved_methods, i, trampoline, pointer_size);
     }
   }
 }
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index ba49a15..3144553 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -46,8 +46,16 @@
     return sizeof(DexCache);
   }
 
-  void Init(const DexFile* dex_file, String* location, ObjectArray<String>* strings,
-            ObjectArray<Class>* types, PointerArray* methods, PointerArray* fields,
+  void Init(const DexFile* dex_file,
+            String* location,
+            GcRoot<String>* strings,
+            uint32_t num_strings,
+            GcRoot<Class>* resolved_types,
+            uint32_t num_resolved_types,
+            ArtMethod** resolved_methods,
+            uint32_t num_resolved_methods,
+            ArtField** resolved_fields,
+            uint32_t num_resolved_fields,
             size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_);
 
   void Fixup(ArtMethod* trampoline, size_t pointer_size)
@@ -65,6 +73,10 @@
     return OFFSET_OF_OBJECT_MEMBER(DexCache, strings_);
   }
 
+  static MemberOffset ResolvedTypesOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_);
+  }
+
   static MemberOffset ResolvedFieldsOffset() {
     return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_fields_);
   }
@@ -73,40 +85,32 @@
     return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_methods_);
   }
 
-  size_t NumStrings() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetStrings()->GetLength();
+  static MemberOffset NumStringsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, num_strings_);
   }
 
-  size_t NumResolvedTypes() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetResolvedTypes()->GetLength();
+  static MemberOffset NumResolvedTypesOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_types_);
   }
 
-  size_t NumResolvedMethods() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetResolvedMethods()->GetLength();
+  static MemberOffset NumResolvedFieldsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_fields_);
   }
 
-  size_t NumResolvedFields() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetResolvedFields()->GetLength();
+  static MemberOffset NumResolvedMethodsOffset() {
+    return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_methods_);
   }
 
-  String* GetResolvedString(uint32_t string_idx) SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetStrings()->Get(string_idx);
-  }
+  String* GetResolvedString(uint32_t string_idx) ALWAYS_INLINE
+      SHARED_REQUIRES(Locks::mutator_lock_);
 
   void SetResolvedString(uint32_t string_idx, String* resolved) ALWAYS_INLINE
-      SHARED_REQUIRES(Locks::mutator_lock_) {
-    // TODO default transaction support.
-    GetStrings()->Set(string_idx, resolved);
-  }
-
-  Class* GetResolvedType(uint32_t type_idx) ALWAYS_INLINE
-      SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetResolvedTypes()->Get(type_idx);
-  }
-
-  void SetResolvedType(uint32_t type_idx, Class* resolved)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  Class* GetResolvedType(uint32_t type_idx) SHARED_REQUIRES(Locks::mutator_lock_);
+
+  void SetResolvedType(uint32_t type_idx, Class* resolved) SHARED_REQUIRES(Locks::mutator_lock_);
+
   ALWAYS_INLINE ArtMethod* GetResolvedMethod(uint32_t method_idx, size_t ptr_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -121,21 +125,36 @@
   ALWAYS_INLINE void SetResolvedField(uint32_t idx, ArtField* field, size_t ptr_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  ObjectArray<String>* GetStrings() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetFieldObject<ObjectArray<String>>(StringsOffset());
+  GcRoot<String>* GetStrings() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetFieldPtr<GcRoot<String>*>(StringsOffset());
   }
 
-  ObjectArray<Class>* GetResolvedTypes() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetFieldObject<ObjectArray<Class>>(
-        OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_));
+  GcRoot<Class>* GetResolvedTypes() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetFieldPtr<GcRoot<Class>*>(ResolvedTypesOffset());
   }
 
-  PointerArray* GetResolvedMethods() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetFieldObject<PointerArray>(ResolvedMethodsOffset());
+  ArtMethod** GetResolvedMethods() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetFieldPtr<ArtMethod**>(ResolvedMethodsOffset());
   }
 
-  PointerArray* GetResolvedFields() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
-    return GetFieldObject<PointerArray>(ResolvedFieldsOffset());
+  ArtField** GetResolvedFields() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetFieldPtr<ArtField**>(ResolvedFieldsOffset());
+  }
+
+  size_t NumStrings() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32(NumStringsOffset());
+  }
+
+  size_t NumResolvedTypes() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32(NumResolvedTypesOffset());
+  }
+
+  size_t NumResolvedMethods() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32(NumResolvedMethodsOffset());
+  }
+
+  size_t NumResolvedFields() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return GetField32(NumResolvedFieldsOffset());
   }
 
   const DexFile* GetDexFile() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_) {
@@ -147,17 +166,36 @@
     return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file);
   }
 
+  // NOTE: Get/SetElementPtrSize() are intended for working with ArtMethod** and ArtField**
+  // provided by GetResolvedMethods/Fields() and ArtMethod::GetDexCacheResolvedMethods(),
+  // so they need to be public.
+
+  template <typename PtrType>
+  static PtrType GetElementPtrSize(PtrType* ptr_array, size_t idx, size_t ptr_size);
+
+  template <typename PtrType>
+  static void SetElementPtrSize(PtrType* ptr_array, size_t idx, PtrType ptr, size_t ptr_size);
+
  private:
+  // Visit instance fields of the dex cache as well as its associated arrays.
+  template <VerifyObjectFlags kVerifyFlags, typename Visitor>
+  void VisitReferences(mirror::Class* klass, const Visitor& visitor)
+      SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
+
   HeapReference<Object> dex_;
   HeapReference<String> location_;
-  // Either an int array or long array based on runtime ISA since these arrays hold pointers.
-  HeapReference<PointerArray> resolved_fields_;
-  HeapReference<PointerArray> resolved_methods_;
-  HeapReference<ObjectArray<Class>> resolved_types_;
-  HeapReference<ObjectArray<String>> strings_;
-  uint64_t dex_file_;
+  uint64_t dex_file_;           // const DexFile*
+  uint64_t resolved_fields_;    // ArtField*, array with num_resolved_fields_ elements.
+  uint64_t resolved_methods_;   // ArtMethod*, array with num_resolved_methods_ elements.
+  uint64_t resolved_types_;     // GcRoot<Class>*, array with num_resolved_types_ elements.
+  uint64_t strings_;            // GcRoot<String>*, array with num_strings_ elements.
+  uint32_t num_resolved_fields_;    // Number of elements in the resolved_fields_ array.
+  uint32_t num_resolved_methods_;   // Number of elements in the resolved_methods_ array.
+  uint32_t num_resolved_types_;     // Number of elements in the resolved_types_ array.
+  uint32_t num_strings_;            // Number of elements in the strings_ array.
 
   friend struct art::DexCacheOffsets;  // for verifying offset information
+  friend class Object;  // For VisitReferences
   DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache);
 };
 
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 228fce5..8fb860f 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -43,19 +43,6 @@
   EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),   dex_cache->NumResolvedTypes());
   EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumResolvedMethods());
   EXPECT_EQ(java_lang_dex_file_->NumFieldIds(),  dex_cache->NumResolvedFields());
-
-  EXPECT_LE(0, dex_cache->GetStrings()->GetLength());
-  EXPECT_LE(0, dex_cache->GetResolvedTypes()->GetLength());
-  EXPECT_LE(0, dex_cache->GetResolvedMethods()->GetLength());
-  EXPECT_LE(0u, dex_cache->NumResolvedFields());
-
-  EXPECT_EQ(java_lang_dex_file_->NumStringIds(),
-            static_cast<uint32_t>(dex_cache->GetStrings()->GetLength()));
-  EXPECT_EQ(java_lang_dex_file_->NumTypeIds(),
-            static_cast<uint32_t>(dex_cache->GetResolvedTypes()->GetLength()));
-  EXPECT_EQ(java_lang_dex_file_->NumMethodIds(),
-            static_cast<uint32_t>(dex_cache->GetResolvedMethods()->GetLength()));
-  EXPECT_EQ(java_lang_dex_file_->NumFieldIds(), dex_cache->NumResolvedFields());
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index e35ddcc..90180c5 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -27,6 +27,7 @@
 #include "class_flags.h"
 #include "class_linker.h"
 #include "class_loader-inl.h"
+#include "dex_cache-inl.h"
 #include "lock_word-inl.h"
 #include "monitor.h"
 #include "object_array-inl.h"
@@ -1006,6 +1007,17 @@
   return down_cast<mirror::ClassLoader*>(this);
 }
 
+template<VerifyObjectFlags kVerifyFlags>
+inline bool Object::IsDexCache() {
+  return GetClass<kVerifyFlags>()->IsDexCacheClass();
+}
+
+template<VerifyObjectFlags kVerifyFlags>
+inline mirror::DexCache* Object::AsDexCache() {
+  DCHECK(IsDexCache<kVerifyFlags>());
+  return down_cast<mirror::DexCache*>(this);
+}
+
 template <VerifyObjectFlags kVerifyFlags, typename Visitor, typename JavaLangRefVisitor>
 inline void Object::VisitReferences(const Visitor& visitor,
                                     const JavaLangRefVisitor& ref_visitor) {
@@ -1031,6 +1043,9 @@
       } else if ((class_flags & kClassFlagReference) != 0) {
         VisitInstanceFieldsReferences(klass, visitor);
         ref_visitor(klass, AsReference());
+      } else if (class_flags == kClassFlagDexCache) {
+        mirror::DexCache* const dex_cache = AsDexCache<kVerifyFlags>();
+        dex_cache->VisitReferences<kVerifyFlags>(klass, visitor);
       } else {
         mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags>();
         class_loader->VisitReferences<kVerifyFlags>(klass, visitor);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 3cec29c..50490bb 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -38,6 +38,7 @@
 class Array;
 class Class;
 class ClassLoader;
+class DexCache;
 class FinalizerReference;
 template<class T> class ObjectArray;
 template<class T> class PrimitiveArray;
@@ -162,6 +163,11 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ClassLoader* AsClassLoader() SHARED_REQUIRES(Locks::mutator_lock_);
 
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  bool IsDexCache() SHARED_REQUIRES(Locks::mutator_lock_);
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  DexCache* AsDexCache() SHARED_REQUIRES(Locks::mutator_lock_);
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   bool IsArrayInstance() SHARED_REQUIRES(Locks::mutator_lock_);