Move ArtFields and ArtMethods to be a length prefixed array

Fixes race conditions between changing method and fields arrays
being seen in the wrong order by the GC.

Bug: 22832610
Change-Id: Ia21d6698f73ba207a6392c3d6b9be2658933073f
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 6568487..887e204 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -28,6 +28,7 @@
 #include "dex_file.h"
 #include "gc/heap-inl.h"
 #include "iftable.h"
+#include "length_prefixed_array.h"
 #include "object_array-inl.h"
 #include "read_barrier-inl.h"
 #include "reference-inl.h"
@@ -61,25 +62,28 @@
   return GetFieldObject<DexCache, kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_));
 }
 
-inline ArtMethod* Class::GetDirectMethodsPtr() {
+inline LengthPrefixedArray<ArtMethod>* Class::GetDirectMethodsPtr() {
   DCHECK(IsLoaded() || IsErroneous());
   return GetDirectMethodsPtrUnchecked();
 }
 
-inline ArtMethod* Class::GetDirectMethodsPtrUnchecked() {
-  return reinterpret_cast<ArtMethod*>(GetField64(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_)));
+inline LengthPrefixedArray<ArtMethod>* Class::GetDirectMethodsPtrUnchecked() {
+  return reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
+      GetField64(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_)));
 }
 
-inline ArtMethod* Class::GetVirtualMethodsPtrUnchecked() {
-  return reinterpret_cast<ArtMethod*>(GetField64(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_)));
+inline LengthPrefixedArray<ArtMethod>* Class::GetVirtualMethodsPtrUnchecked() {
+  return reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
+      GetField64(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_)));
 }
 
-inline void Class::SetDirectMethodsPtr(ArtMethod* new_direct_methods) {
+inline void Class::SetDirectMethodsPtr(LengthPrefixedArray<ArtMethod>* new_direct_methods) {
   DCHECK(GetDirectMethodsPtrUnchecked() == nullptr);
   SetDirectMethodsPtrUnchecked(new_direct_methods);
 }
 
-inline void Class::SetDirectMethodsPtrUnchecked(ArtMethod* new_direct_methods) {
+inline void Class::SetDirectMethodsPtrUnchecked(
+    LengthPrefixedArray<ArtMethod>* new_direct_methods) {
   SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
                     reinterpret_cast<uint64_t>(new_direct_methods));
 }
@@ -88,25 +92,23 @@
   CheckPointerSize(pointer_size);
   auto* methods = GetDirectMethodsPtrUnchecked();
   DCHECK(methods != nullptr);
-  return reinterpret_cast<ArtMethod*>(reinterpret_cast<uintptr_t>(methods) +
-      ArtMethod::ObjectSize(pointer_size) * i);
+  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
 }
 
 inline ArtMethod* Class::GetDirectMethod(size_t i, size_t pointer_size) {
   CheckPointerSize(pointer_size);
   auto* methods = GetDirectMethodsPtr();
   DCHECK(methods != nullptr);
-  return reinterpret_cast<ArtMethod*>(reinterpret_cast<uintptr_t>(methods) +
-      ArtMethod::ObjectSize(pointer_size) * i);
+  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
 }
 
 template<VerifyObjectFlags kVerifyFlags>
-inline ArtMethod* Class::GetVirtualMethodsPtr() {
+inline LengthPrefixedArray<ArtMethod>* Class::GetVirtualMethodsPtr() {
   DCHECK(IsLoaded<kVerifyFlags>() || IsErroneous<kVerifyFlags>());
   return GetVirtualMethodsPtrUnchecked();
 }
 
-inline void Class::SetVirtualMethodsPtr(ArtMethod* new_virtual_methods) {
+inline void Class::SetVirtualMethodsPtr(LengthPrefixedArray<ArtMethod>* new_virtual_methods) {
   // TODO: we reassign virtual methods to grow the table for miranda
   // methods.. they should really just be assigned once.
   SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
@@ -129,10 +131,9 @@
 
 inline ArtMethod* Class::GetVirtualMethodUnchecked(size_t i, size_t pointer_size) {
   CheckPointerSize(pointer_size);
-  auto* methods = GetVirtualMethodsPtrUnchecked();
+  LengthPrefixedArray<ArtMethod>* methods = GetVirtualMethodsPtrUnchecked();
   DCHECK(methods != nullptr);
-  return reinterpret_cast<ArtMethod*>(reinterpret_cast<uintptr_t>(methods) +
-      ArtMethod::ObjectSize(pointer_size) * i);
+  return &methods->At(i, ArtMethod::ObjectSize(pointer_size));
 }
 
 inline PointerArray* Class::GetVTable() {
@@ -423,9 +424,9 @@
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable);
 }
 
-inline ArtField* Class::GetIFields() {
+inline LengthPrefixedArray<ArtField>* Class::GetIFieldsPtr() {
   DCHECK(IsLoaded() || IsErroneous());
-  return GetFieldPtr<ArtField*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
+  return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
 }
 
 inline MemberOffset Class::GetFirstReferenceInstanceFieldOffset() {
@@ -458,46 +459,44 @@
   return MemberOffset(base);
 }
 
-inline void Class::SetIFields(ArtField* new_ifields) {
-  DCHECK(GetIFieldsUnchecked() == nullptr);
+inline void Class::SetIFieldsPtr(LengthPrefixedArray<ArtField>* new_ifields) {
+  DCHECK(GetIFieldsPtrUnchecked() == nullptr);
   return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields);
 }
 
-inline void Class::SetIFieldsUnchecked(ArtField* new_ifields) {
+inline void Class::SetIFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_ifields) {
   SetFieldPtr<false, true, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields);
 }
 
-inline ArtField* Class::GetSFieldsUnchecked() {
-  return GetFieldPtr<ArtField*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_));
+inline LengthPrefixedArray<ArtField>* Class::GetSFieldsPtrUnchecked() {
+  return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_));
 }
 
-inline ArtField* Class::GetIFieldsUnchecked() {
-  return GetFieldPtr<ArtField*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
+inline LengthPrefixedArray<ArtField>* Class::GetIFieldsPtrUnchecked() {
+  return GetFieldPtr<LengthPrefixedArray<ArtField>*>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_));
 }
 
-inline ArtField* Class::GetSFields() {
+inline LengthPrefixedArray<ArtField>* Class::GetSFieldsPtr() {
   DCHECK(IsLoaded() || IsErroneous()) << GetStatus();
-  return GetSFieldsUnchecked();
+  return GetSFieldsPtrUnchecked();
 }
 
-inline void Class::SetSFields(ArtField* new_sfields) {
+inline void Class::SetSFieldsPtr(LengthPrefixedArray<ArtField>* new_sfields) {
   DCHECK((IsRetired() && new_sfields == nullptr) ||
          GetFieldPtr<ArtField*>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)) == nullptr);
   SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields);
 }
 
-inline void Class::SetSFieldsUnchecked(ArtField* new_sfields) {
+inline void Class::SetSFieldsPtrUnchecked(LengthPrefixedArray<ArtField>* new_sfields) {
   SetFieldPtr<false, true, kVerifyNone>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields);
 }
 
 inline ArtField* Class::GetStaticField(uint32_t i) {
-  DCHECK_LT(i, NumStaticFields());
-  return &GetSFields()[i];
+  return &GetSFieldsPtr()->At(i);
 }
 
 inline ArtField* Class::GetInstanceField(uint32_t i) {
-  DCHECK_LT(i, NumInstanceFields());
-  return &GetIFields()[i];
+  return &GetIFieldsPtr()->At(i);
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -813,85 +812,54 @@
 
 template<class Visitor>
 void mirror::Class::VisitNativeRoots(Visitor& visitor, size_t pointer_size) {
-  ArtField* const sfields = GetSFieldsUnchecked();
-  // Since we visit class roots while we may be writing these fields, check against null.
-  if (sfields != nullptr) {
-    for (size_t i = 0, count = NumStaticFields(); i < count; ++i) {
-      auto* f = &sfields[i];
-      // Visit roots first in case the declaring class gets moved.
-      f->VisitRoots(visitor);
-      if (kIsDebugBuild && IsResolved()) {
-        CHECK_EQ(f->GetDeclaringClass(), this) << GetStatus();
-      }
+  for (ArtField& field : GetSFieldsUnchecked()) {
+    // Visit roots first in case the declaring class gets moved.
+    field.VisitRoots(visitor);
+    if (kIsDebugBuild && IsResolved()) {
+      CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus();
     }
   }
-  ArtField* const ifields = GetIFieldsUnchecked();
-  if (ifields != nullptr) {
-    for (size_t i = 0, count = NumInstanceFields(); i < count; ++i) {
-      auto* f = &ifields[i];
-      // Visit roots first in case the declaring class gets moved.
-      f->VisitRoots(visitor);
-      if (kIsDebugBuild && IsResolved()) {
-        CHECK_EQ(f->GetDeclaringClass(), this) << GetStatus();
-      }
+  for (ArtField& field : GetIFieldsUnchecked()) {
+    // Visit roots first in case the declaring class gets moved.
+    field.VisitRoots(visitor);
+    if (kIsDebugBuild && IsResolved()) {
+      CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus();
     }
   }
-  // We may see GetDirectMethodsPtr() == null with NumDirectMethods() != 0 if the root marking
-  // thread reads a null DirectMethodsBegin() but a non null DirectMethodsBegin() due to a race
-  // SetDirectMethodsPtr from class linking. Same for virtual methods.
-  // In this case, it is safe to avoid marking the roots since we must be either the CC or CMS. If
-  // we are CMS then the roots are already marked through other sources, otherwise the roots are
-  // already marked due to the to-space invariant.
-  // Unchecked versions since we may visit roots of classes that aren't yet loaded.
-  if (GetDirectMethodsPtrUnchecked() != nullptr) {
-    for (auto& m : GetDirectMethods(pointer_size)) {
-      m.VisitRoots(visitor);
-    }
+  for (ArtMethod& method : GetDirectMethods(pointer_size)) {
+    method.VisitRoots(visitor);
   }
-  if (GetVirtualMethodsPtrUnchecked() != nullptr) {
-    for (auto& m : GetVirtualMethods(pointer_size)) {
-      m.VisitRoots(visitor);
-    }
+  for (ArtMethod& method : GetVirtualMethods(pointer_size)) {
+    method.VisitRoots(visitor);
   }
 }
 
-inline StrideIterator<ArtMethod> Class::DirectMethodsBegin(size_t pointer_size)  {
-  CheckPointerSize(pointer_size);
-  auto* methods = GetDirectMethodsPtrUnchecked();
-  auto stride = ArtMethod::ObjectSize(pointer_size);
-  return StrideIterator<ArtMethod>(reinterpret_cast<uintptr_t>(methods), stride);
-}
-
-inline StrideIterator<ArtMethod> Class::DirectMethodsEnd(size_t pointer_size) {
-  CheckPointerSize(pointer_size);
-  auto* methods = GetDirectMethodsPtrUnchecked();
-  auto stride = ArtMethod::ObjectSize(pointer_size);
-  auto count = NumDirectMethods();
-  return StrideIterator<ArtMethod>(reinterpret_cast<uintptr_t>(methods) + stride * count, stride);
-}
-
 inline IterationRange<StrideIterator<ArtMethod>> Class::GetDirectMethods(size_t pointer_size) {
   CheckPointerSize(pointer_size);
-  return MakeIterationRange(DirectMethodsBegin(pointer_size), DirectMethodsEnd(pointer_size));
-}
-
-inline StrideIterator<ArtMethod> Class::VirtualMethodsBegin(size_t pointer_size)  {
-  CheckPointerSize(pointer_size);
-  auto* methods = GetVirtualMethodsPtrUnchecked();
-  auto stride = ArtMethod::ObjectSize(pointer_size);
-  return StrideIterator<ArtMethod>(reinterpret_cast<uintptr_t>(methods), stride);
-}
-
-inline StrideIterator<ArtMethod> Class::VirtualMethodsEnd(size_t pointer_size) {
-  CheckPointerSize(pointer_size);
-  auto* methods = GetVirtualMethodsPtrUnchecked();
-  auto stride = ArtMethod::ObjectSize(pointer_size);
-  auto count = NumVirtualMethods();
-  return StrideIterator<ArtMethod>(reinterpret_cast<uintptr_t>(methods) + stride * count, stride);
+  return MakeIterationRangeFromLengthPrefixedArray(GetDirectMethodsPtrUnchecked(),
+                                                   ArtMethod::ObjectSize(pointer_size));
 }
 
 inline IterationRange<StrideIterator<ArtMethod>> Class::GetVirtualMethods(size_t pointer_size) {
-  return MakeIterationRange(VirtualMethodsBegin(pointer_size), VirtualMethodsEnd(pointer_size));
+  CheckPointerSize(pointer_size);
+  return MakeIterationRangeFromLengthPrefixedArray(GetVirtualMethodsPtrUnchecked(),
+                                                   ArtMethod::ObjectSize(pointer_size));
+}
+
+inline IterationRange<StrideIterator<ArtField>> Class::GetIFields() {
+  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtr(), sizeof(ArtField));
+}
+
+inline IterationRange<StrideIterator<ArtField>> Class::GetSFields() {
+  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtr(), sizeof(ArtField));
+}
+
+inline IterationRange<StrideIterator<ArtField>> Class::GetIFieldsUnchecked() {
+  return MakeIterationRangeFromLengthPrefixedArray(GetIFieldsPtrUnchecked(), sizeof(ArtField));
+}
+
+inline IterationRange<StrideIterator<ArtField>> Class::GetSFieldsUnchecked() {
+  return MakeIterationRangeFromLengthPrefixedArray(GetSFieldsPtrUnchecked(), sizeof(ArtField));
 }
 
 inline MemberOffset Class::EmbeddedImTableOffset(size_t pointer_size) {
@@ -940,6 +908,26 @@
   }
 }
 
+inline uint32_t Class::NumDirectMethods() {
+  LengthPrefixedArray<ArtMethod>* arr = GetDirectMethodsPtrUnchecked();
+  return arr != nullptr ? arr->Length() : 0u;
+}
+
+inline uint32_t Class::NumVirtualMethods() {
+  LengthPrefixedArray<ArtMethod>* arr = GetVirtualMethodsPtrUnchecked();
+  return arr != nullptr ? arr->Length() : 0u;
+}
+
+inline uint32_t Class::NumInstanceFields() {
+  LengthPrefixedArray<ArtField>* arr = GetIFieldsPtrUnchecked();
+  return arr != nullptr ? arr->Length() : 0u;
+}
+
+inline uint32_t Class::NumStaticFields() {
+  LengthPrefixedArray<ArtField>* arr = GetSFieldsPtrUnchecked();
+  return arr != nullptr ? arr->Length() : 0u;
+}
+
 }  // namespace mirror
 }  // namespace art