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/class_linker.cc b/runtime/class_linker.cc
index e78914c..fc1127c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -80,6 +80,7 @@
 #include "handle_scope-inl.h"
 #include "thread-inl.h"
 #include "utils.h"
+#include "utils/dex_cache_arrays_layout-inl.h"
 #include "verifier/method_verifier.h"
 #include "well_known_classes.h"
 
@@ -420,6 +421,7 @@
   Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_))));
   SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
+  java_lang_DexCache->SetDexCacheClass();
   java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
   mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self);
 
@@ -1059,6 +1061,26 @@
   }
 }
 
+static void SanityCheckArtMethodPointerArray(
+    ArtMethod** arr,
+    size_t size,
+    size_t pointer_size,
+    gc::space::ImageSpace* space) SHARED_REQUIRES(Locks::mutator_lock_) {
+  CHECK_EQ(arr != nullptr, size != 0u);
+  if (arr != nullptr) {
+    auto offset = reinterpret_cast<uint8_t*>(arr) - space->Begin();
+    CHECK(space->GetImageHeader().GetImageSection(
+        ImageHeader::kSectionDexCacheArrays).Contains(offset));
+  }
+  for (size_t j = 0; j < size; ++j) {
+    ArtMethod* method = mirror::DexCache::GetElementPtrSize(arr, j, pointer_size);
+    // expected_class == null means we are a dex cache.
+    if (method != nullptr) {
+      SanityCheckArtMethod(method, nullptr, space);
+    }
+  }
+}
+
 static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   DCHECK(obj != nullptr);
@@ -1188,8 +1210,10 @@
     }
 
     if (kSanityCheckObjects) {
-      SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(), nullptr,
-                                       image_pointer_size_, space);
+      SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(),
+                                       dex_cache->NumResolvedMethods(),
+                                       image_pointer_size_,
+                                       space);
     }
 
     CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum());
@@ -1476,28 +1500,44 @@
     self->AssertPendingOOMException();
     return nullptr;
   }
-  auto strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds())));
-  if (strings.Get() == nullptr) {
-    self->AssertPendingOOMException();
-    return nullptr;
+  DexCacheArraysLayout layout(image_pointer_size_, &dex_file);
+  uint8_t* raw_arrays = nullptr;
+  if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u ||
+      dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) {
+    // NOTE: We "leak" the raw_arrays because we never destroy the dex cache.
+    DCHECK(image_pointer_size_ == 4u || image_pointer_size_ == 8u);
+    if (sizeof(void*) == 8u && image_pointer_size_ == 4u) {
+      // When cross-compiling for a 32-bit target on a 64-bit host, we need these arrays
+      // in the low 4GiB address space so that we can store pointers in 32-bit fields.
+      // This is conveniently provided by the linear allocator.
+      raw_arrays = reinterpret_cast<uint8_t*>(
+          Runtime::Current()->GetLinearAlloc()->Alloc(self, layout.Size()));  // Zero-initialized.
+    } else {
+      raw_arrays = reinterpret_cast<uint8_t*>(calloc(layout.Size(), 1u));  // Zero-initialized.
+      if (raw_arrays == nullptr) {
+        return nullptr;
+      }
+    }
   }
-  auto types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds())));
-  if (types.Get() == nullptr) {
-    self->AssertPendingOOMException();
-    return nullptr;
-  }
-  auto methods(hs.NewHandle(AllocPointerArray(self, dex_file.NumMethodIds())));
-  if (methods.Get() == nullptr) {
-    self->AssertPendingOOMException();
-    return nullptr;
-  }
-  auto fields(hs.NewHandle(AllocPointerArray(self, dex_file.NumFieldIds())));
-  if (fields.Get() == nullptr) {
-    self->AssertPendingOOMException();
-    return nullptr;
-  }
-  dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(),
-                  fields.Get(), image_pointer_size_);
+  GcRoot<mirror::String>* strings = (dex_file.NumStringIds() == 0u) ? nullptr :
+      reinterpret_cast<GcRoot<mirror::String>*>(raw_arrays + layout.StringsOffset());
+  GcRoot<mirror::Class>* types = (dex_file.NumTypeIds() == 0u) ? nullptr :
+      reinterpret_cast<GcRoot<mirror::Class>*>(raw_arrays + layout.TypesOffset());
+  ArtMethod** methods = (dex_file.NumMethodIds() == 0u) ? nullptr :
+      reinterpret_cast<ArtMethod**>(raw_arrays + layout.MethodsOffset());
+  ArtField** fields = (dex_file.NumFieldIds() == 0u) ? nullptr :
+      reinterpret_cast<ArtField**>(raw_arrays + layout.FieldsOffset());
+  dex_cache->Init(&dex_file,
+                  location.Get(),
+                  strings,
+                  dex_file.NumStringIds(),
+                  types,
+                  dex_file.NumTypeIds(),
+                  methods,
+                  dex_file.NumMethodIds(),
+                  fields,
+                  dex_file.NumFieldIds(),
+                  image_pointer_size_);
   return dex_cache.Get();
 }
 
@@ -2418,8 +2458,8 @@
   dst->SetDeclaringClass(klass.Get());
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
 
-  dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
-  dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
+  dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(), image_pointer_size_);
+  dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes(), image_pointer_size_);
 
   uint32_t access_flags = it.GetMethodAccessFlags();
 
@@ -2895,9 +2935,9 @@
   ClassTable* const class_table = InsertClassTableForClassLoader(nullptr);
   for (int32_t i = 0; i < dex_caches->GetLength(); i++) {
     mirror::DexCache* dex_cache = dex_caches->Get(i);
-    mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
-    for (int32_t j = 0; j < types->GetLength(); j++) {
-      mirror::Class* klass = types->Get(j);
+    GcRoot<mirror::Class>* types = dex_cache->GetResolvedTypes();
+    for (int32_t j = 0, num_types = dex_cache->NumResolvedTypes(); j < num_types; j++) {
+      mirror::Class* klass = types[j].Read();
       if (klass != nullptr) {
         DCHECK(klass->GetClassLoader() == nullptr);
         const char* descriptor = klass->GetDescriptor(&temp);
@@ -3418,7 +3458,8 @@
     for (jobject weak_root : dex_caches_) {
       mirror::DexCache* dex_cache = down_cast<mirror::DexCache*>(self->DecodeJObject(weak_root));
       if (dex_cache != nullptr &&
-          proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) {
+          proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes(),
+                                                     image_pointer_size_)) {
         ArtMethod* resolved_method = dex_cache->GetResolvedMethod(
             proxy_method->GetDexMethodIndex(), image_pointer_size_);
         CHECK(resolved_method != nullptr);
@@ -3491,8 +3532,8 @@
 
   // The proxy method doesn't have its own dex cache or dex file and so it steals those of its
   // interface prototype. The exception to this are Constructors and the Class of the Proxy itself.
-  CHECK(prototype->HasSameDexCacheResolvedMethods(method));
-  CHECK(prototype->HasSameDexCacheResolvedTypes(method));
+  CHECK(prototype->HasSameDexCacheResolvedMethods(method, image_pointer_size_));
+  CHECK(prototype->HasSameDexCacheResolvedTypes(method, image_pointer_size_));
   auto* np = method->GetInterfaceMethodIfProxy(image_pointer_size_);
   CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), np->GetDexCache());
   CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex());
@@ -3500,7 +3541,8 @@
   CHECK_STREQ(np->GetName(), prototype->GetName());
   CHECK_STREQ(np->GetShorty(), prototype->GetShorty());
   // More complex sanity - via dex cache
-  CHECK_EQ(np->GetReturnType(), prototype->GetReturnType());
+  CHECK_EQ(np->GetReturnType(true /* resolve */, image_pointer_size_),
+           prototype->GetReturnType(true /* resolve */, image_pointer_size_));
 }
 
 bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
@@ -3838,6 +3880,7 @@
 }
 
 static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
+                                                      size_t pointer_size,
                                                       Handle<mirror::Class> klass,
                                                       Handle<mirror::Class> super_klass,
                                                       ArtMethod* method1,
@@ -3845,12 +3888,14 @@
     SHARED_REQUIRES(Locks::mutator_lock_) {
   {
     StackHandleScope<1> hs(self);
-    Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType()));
+    Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType(true /* resolve */,
+                                                                          pointer_size)));
     if (UNLIKELY(return_type.Get() == nullptr)) {
       ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1);
       return false;
     }
-    mirror::Class* other_return_type = method2->GetReturnType();
+    mirror::Class* other_return_type = method2->GetReturnType(true /* resolve */,
+                                                              pointer_size);
     if (UNLIKELY(other_return_type == nullptr)) {
       ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2);
       return false;
@@ -3895,7 +3940,7 @@
     StackHandleScope<1> hs(self);
     uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
     Handle<mirror::Class> param_type(hs.NewHandle(
-        method1->GetClassFromTypeIndex(param_type_idx, true)));
+        method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
     if (UNLIKELY(param_type.Get() == nullptr)) {
       ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
                                              method1, i, param_type_idx);
@@ -3903,7 +3948,7 @@
     }
     uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
     mirror::Class* other_param_type =
-        method2->GetClassFromTypeIndex(other_param_type_idx, true);
+        method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
     if (UNLIKELY(other_param_type == nullptr)) {
       ThrowSignatureCheckResolveArgException(klass, super_klass, method1,
                                              method2, i, other_param_type_idx);
@@ -3939,7 +3984,8 @@
       auto* m = klass->GetVTableEntry(i, image_pointer_size_);
       auto* super_m = klass->GetSuperClass()->GetVTableEntry(i, image_pointer_size_);
       if (m != super_m) {
-        if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+        if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
+                                                                klass, super_klass,
                                                                 m, super_m))) {
           self->AssertPendingException();
           return false;
@@ -3956,7 +4002,8 @@
             j, image_pointer_size_);
         auto* super_m = super_klass->GetVirtualMethod(j, image_pointer_size_);
         if (m != super_m) {
-          if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass,
+          if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, image_pointer_size_,
+                                                                  klass, super_klass,
                                                                   m, super_m))) {
             self->AssertPendingException();
             return false;
@@ -5091,8 +5138,8 @@
     // Check that there are no stale methods are in the dex cache array.
     if (kIsDebugBuild) {
       auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods();
-      for (size_t i = 0, count = resolved_methods->GetLength(); i < count; ++i) {
-        auto* m = resolved_methods->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_);
+      for (size_t i = 0, count = klass->GetDexCache()->NumResolvedMethods(); i < count; ++i) {
+        auto* m = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size_);
         CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m);
       }
     }