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/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 981ab2c..eb8730c 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -677,10 +677,11 @@
       FALLTHROUGH_INTENDED;
     case 1:  // Get method->dex_cache_resolved_methods_
       if (!use_pc_rel) {
-        cg->LoadRefDisp(arg0_ref,
-                        ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                        arg0_ref,
-                        kNotVolatile);
+        cg->LoadBaseDisp(arg0_ref,
+                         ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value(),
+                         arg0_ref,
+                         k32,
+                         kNotVolatile);
       }
       // Set up direct code if known.
       if (direct_code != 0) {
@@ -702,8 +703,8 @@
       CHECK_EQ(cu->dex_file, target_method.dex_file);
       if (!use_pc_rel) {
         cg->LoadRefDisp(arg0_ref,
-                        mirror::ObjectArray<mirror::Object>::OffsetOfElement(
-                            target_method.dex_method_index).Int32Value(),
+                        cg->GetCachePointerOffset(target_method.dex_method_index,
+                                                  kArmPointerSize),
                         arg0_ref,
                         kNotVolatile);
       } else {
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 83a6aff..036da2e 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -511,10 +511,11 @@
       FALLTHROUGH_INTENDED;
     case 1:  // Get method->dex_cache_resolved_methods_
       if (!use_pc_rel) {
-        cg->LoadRefDisp(arg0_ref,
-                        ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                        arg0_ref,
-                        kNotVolatile);
+        cg->LoadBaseDisp(arg0_ref,
+                         ArtMethod::DexCacheResolvedMethodsOffset(kArm64PointerSize).Int32Value(),
+                         arg0_ref,
+                         k64,
+                         kNotVolatile);
       }
       // Set up direct code if known.
       if (direct_code != 0) {
@@ -536,8 +537,9 @@
       CHECK_EQ(cu->dex_file, target_method.dex_file);
       if (!use_pc_rel) {
         cg->LoadWordDisp(arg0_ref,
-                         mirror::Array::DataOffset(kArm64PointerSize).Uint32Value() +
-                         target_method.dex_method_index * kArm64PointerSize, arg0_ref);
+                         cg->GetCachePointerOffset(target_method.dex_method_index,
+                                                   kArm64PointerSize),
+                         arg0_ref);
       } else {
         size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index);
         cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref, true);
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index af10817..2a1d644 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -88,24 +88,30 @@
                                                        r_result));
 }
 
+void Mir2Lir::LoadTypeFromCache(uint32_t type_index, RegStorage class_reg) {
+  if (CanUseOpPcRelDexCacheArrayLoad()) {
+    uint32_t offset = dex_cache_arrays_layout_.TypeOffset(type_index);
+    OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, class_reg, false);
+  } else {
+    RegStorage r_method = LoadCurrMethodWithHint(class_reg);
+    MemberOffset resolved_types_offset = ArtMethod::DexCacheResolvedTypesOffset(
+        GetInstructionSetPointerSize(cu_->instruction_set));
+    LoadBaseDisp(r_method, resolved_types_offset.Int32Value(), class_reg,
+                 cu_->target64 ? k64 : k32, kNotVolatile);
+    int32_t offset_of_type = GetCacheOffset(type_index);
+    LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
+  }
+}
+
 RegStorage Mir2Lir::GenGetOtherTypeForSgetSput(const MirSFieldLoweringInfo& field_info,
                                                int opt_flags) {
   DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex);
   // May do runtime call so everything to home locations.
   FlushAllRegs();
+  // Using fixed register to sync with possible call to runtime support.
   RegStorage r_base = TargetReg(kArg0, kRef);
   LockTemp(r_base);
-  if (CanUseOpPcRelDexCacheArrayLoad()) {
-    uint32_t offset = dex_cache_arrays_layout_.TypeOffset(field_info.StorageIndex());
-    OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, r_base, false);
-  } else {
-    // Using fixed register to sync with possible call to runtime support.
-    RegStorage r_method = LoadCurrMethodWithHint(r_base);
-    LoadRefDisp(r_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base,
-                kNotVolatile);
-    int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
-    LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile);
-  }
+  LoadTypeFromCache(field_info.StorageIndex(), r_base);
   // r_base now points at static storage (Class*) or null if the type is not yet resolved.
   LIR* unresolved_branch = nullptr;
   if (!field_info.IsClassInDexCache() && (opt_flags & MIR_CLASS_IS_IN_DEX_CACHE) == 0) {
@@ -1029,19 +1035,7 @@
   } else {
     rl_result = EvalLoc(rl_dest, kRefReg, true);
     // We don't need access checks, load type from dex cache
-    if (CanUseOpPcRelDexCacheArrayLoad()) {
-      size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx);
-      OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, rl_result.reg, false);
-    } else {
-      int32_t dex_cache_offset =
-          ArtMethod::DexCacheResolvedTypesOffset().Int32Value();
-      RegStorage res_reg = AllocTempRef();
-      RegStorage r_method = LoadCurrMethodWithHint(res_reg);
-      LoadRefDisp(r_method, dex_cache_offset, res_reg, kNotVolatile);
-      int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-      LoadRefDisp(res_reg, offset_of_type, rl_result.reg, kNotVolatile);
-      FreeTemp(res_reg);
-    }
+    LoadTypeFromCache(type_idx, rl_result.reg);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file,
         type_idx) || ForceSlowTypePath(cu_)) {
       // Slow path, at runtime test if type is null and if so initialize
@@ -1054,8 +1048,7 @@
 
 void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) {
   /* NOTE: Most strings should be available at compile time */
-  int32_t offset_of_string = mirror::ObjectArray<mirror::String>::OffsetOfElement(string_idx).
-                                                                                      Int32Value();
+  int32_t offset_of_string = GetCacheOffset(string_idx);
   if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache(
       *cu_->dex_file, string_idx) || ForceSlowStringPath(cu_)) {
     // slow path, resolve string if not in dex cache
@@ -1073,7 +1066,8 @@
       RegStorage r_method = LoadCurrMethodWithHint(arg0);
       LoadRefDisp(r_method, ArtMethod::DeclaringClassOffset().Int32Value(), arg0, kNotVolatile);
       // Declaring class to dex cache strings.
-      LoadRefDisp(arg0, mirror::Class::DexCacheStringsOffset().Int32Value(), arg0, kNotVolatile);
+      LoadBaseDisp(arg0, mirror::Class::DexCacheStringsOffset().Int32Value(), arg0,
+                   cu_->target64 ? k64 : k32, kNotVolatile);
 
       LoadRefDisp(arg0, offset_of_string, ret0, kNotVolatile);
     }
@@ -1091,8 +1085,8 @@
       RegStorage res_reg = AllocTempRef();
       LoadRefDisp(rl_method.reg, ArtMethod::DeclaringClassOffset().Int32Value(), res_reg,
                   kNotVolatile);
-      LoadRefDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg,
-                  kNotVolatile);
+      LoadBaseDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg,
+                   cu_->target64 ? k64 : k32, kNotVolatile);
       LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile);
       FreeTemp(res_reg);
     }
@@ -1176,19 +1170,10 @@
                 kNotVolatile);
     LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class,
                 kNotVolatile);
-  } else if (CanUseOpPcRelDexCacheArrayLoad()) {
-    size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx);
-    OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, check_class, false);
-    LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class,
-                kNotVolatile);
   } else {
-    RegStorage r_method = LoadCurrMethodWithHint(check_class);
-    LoadRefDisp(r_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                check_class, kNotVolatile);
+    LoadTypeFromCache(type_idx, check_class);
     LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class,
                 kNotVolatile);
-    int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-    LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
   }
 
   // FIXME: what should we be comparing here? compressed or decompressed references?
@@ -1239,17 +1224,8 @@
       LoadValueDirectFixed(rl_src, ref_reg);  // kArg0 <= ref
     }
 
-    if (CanUseOpPcRelDexCacheArrayLoad()) {
-      size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx);
-      OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, class_reg, false);
-    } else {
-      RegStorage r_method = LoadCurrMethodWithHint(class_reg);
-      // Load dex cache entry into class_reg (kArg2)
-      LoadRefDisp(r_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                  class_reg, kNotVolatile);
-      int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-      LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
-    }
+    // Load dex cache entry into class_reg (kArg2)
+    LoadTypeFromCache(type_idx, class_reg);
     if (!can_assume_type_is_in_dex_cache) {
       GenIfNullUseHelperImm(class_reg, kQuickInitializeType, type_idx);
 
@@ -1370,17 +1346,7 @@
                 class_reg, kNotVolatile);
   } else {
     // Load dex cache entry into class_reg (kArg2)
-    if (CanUseOpPcRelDexCacheArrayLoad()) {
-      size_t offset = dex_cache_arrays_layout_.TypeOffset(type_idx);
-      OpPcRelDexCacheArrayLoad(cu_->dex_file, offset, class_reg, false);
-    } else {
-      RegStorage r_method = LoadCurrMethodWithHint(class_reg);
-
-      LoadRefDisp(r_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                  class_reg, kNotVolatile);
-      int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
-      LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile);
-    }
+    LoadTypeFromCache(type_idx, class_reg);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
       // Need to test presence of type in dex cache at runtime
       GenIfNullUseHelperImm(class_reg, kQuickInitializeType, type_idx);
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 853980d..8863c05 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -415,10 +415,11 @@
  * Bit of a hack here - in the absence of a real scheduling pass,
  * emit the next instruction in static & direct invoke sequences.
  */
-static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state,
-                          const MethodReference& target_method, uint32_t, uintptr_t direct_code,
-                          uintptr_t direct_method, InvokeType type) {
-  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
+int MipsMir2Lir::MipsNextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state,
+                                    const MethodReference& target_method, uint32_t,
+                                    uintptr_t direct_code, uintptr_t direct_method,
+                                    InvokeType type) {
+  MipsMir2Lir* cg = static_cast<MipsMir2Lir*>(cu->cg.get());
   if (info->string_init_offset != 0) {
     RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
     switch (state) {
@@ -469,10 +470,12 @@
         cg->LoadCurrMethodDirect(arg0_ref);
         break;
       case 1:  // Get method->dex_cache_resolved_methods_
-        cg->LoadRefDisp(arg0_ref,
-                        ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                        arg0_ref,
-                        kNotVolatile);
+        cg->LoadBaseDisp(arg0_ref,
+                         ArtMethod::DexCacheResolvedMethodsOffset(
+                             cu->target64 ? kMips64PointerSize : kMipsPointerSize).Int32Value(),
+                         arg0_ref,
+                         cu->target64 ? k64 : k32,
+                         kNotVolatile);
         // Set up direct code if known.
         if (direct_code != 0) {
           if (direct_code != static_cast<uintptr_t>(-1)) {
@@ -492,8 +495,9 @@
         CHECK_EQ(cu->dex_file, target_method.dex_file);
         const size_t pointer_size = GetInstructionSetPointerSize(cu->instruction_set);
         cg->LoadWordDisp(arg0_ref,
-                         mirror::Array::DataOffset(pointer_size).Uint32Value() +
-                         target_method.dex_method_index * pointer_size, arg0_ref);
+                         cg->GetCachePointerOffset(target_method.dex_method_index,
+                                                   pointer_size),
+                         arg0_ref);
         break;
       }
       case 3:  // Grab the code from the method*
@@ -512,7 +516,7 @@
 }
 
 NextCallInsn MipsMir2Lir::GetNextSDCallInsn() {
-  return NextSDCallInsn;
+  return MipsNextSDCallInsn;
 }
 
 LIR* MipsMir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info ATTRIBUTE_UNUSED) {
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 2173253..378b9a0 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -269,6 +269,11 @@
   const bool fpuIs32Bit_;
 
  private:
+  static int MipsNextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state,
+                                const MethodReference& target_method, uint32_t,
+                                uintptr_t direct_code, uintptr_t direct_method,
+                                InvokeType type);
+
   void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
   void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
   void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h
index 767fe25..f96816c 100644
--- a/compiler/dex/quick/mir_to_lir-inl.h
+++ b/compiler/dex/quick/mir_to_lir-inl.h
@@ -21,6 +21,7 @@
 
 #include "base/logging.h"
 #include "dex/compiler_ir.h"
+#include "gc_root.h"
 #include "utils.h"
 
 namespace art {
@@ -278,6 +279,14 @@
   }
 }
 
+inline size_t Mir2Lir::GetCacheOffset(uint32_t index) {
+  return sizeof(GcRoot<mirror::Object>) * index;
+}
+
+inline size_t Mir2Lir::GetCachePointerOffset(uint32_t index, size_t pointer_size) {
+  return pointer_size * index;
+}
+
 inline Mir2Lir::ShortyIterator::ShortyIterator(const char* shorty, bool is_static)
     : cur_(shorty + 1), pending_this_(!is_static), initialized_(false) {
   DCHECK(shorty != nullptr);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 73787e9..4e3aab2 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1771,6 +1771,11 @@
       return (core_spill_mask_ & (1u << reg)) != 0;
     }
 
+    size_t GetCacheOffset(uint32_t index);
+    size_t GetCachePointerOffset(uint32_t index, size_t pointer_size);
+
+    void LoadTypeFromCache(uint32_t type_index, RegStorage class_reg);
+
   public:
     // TODO: add accessors for these.
     LIR* literal_list_;                        // Constants.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 43167a1..9cb45a4 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -394,18 +394,19 @@
       cg->LoadCurrMethodDirect(arg0_ref);
       break;
     case 1:  // Get method->dex_cache_resolved_methods_
-      cg->LoadRefDisp(arg0_ref,
-                      ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
-                      arg0_ref,
-                      kNotVolatile);
+      cg->LoadBaseDisp(arg0_ref,
+                       ArtMethod::DexCacheResolvedMethodsOffset(
+                           cu->target64 ? kX86_64PointerSize : kX86PointerSize).Int32Value(),
+                       arg0_ref,
+                       cu->target64 ? k64 : k32,
+                       kNotVolatile);
       break;
     case 2: {
       // Grab target method*
       CHECK_EQ(cu->dex_file, target_method.dex_file);
       const size_t pointer_size = GetInstructionSetPointerSize(cu->instruction_set);
       cg->LoadWordDisp(arg0_ref,
-                       mirror::Array::DataOffset(pointer_size).Uint32Value() +
-                       target_method.dex_method_index * pointer_size,
+                       cg->GetCachePointerOffset(target_method.dex_method_index, pointer_size),
                        arg0_ref);
       break;
     }
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index d1fe167..ecd23e9 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -3031,31 +3031,12 @@
   // The LoadRefDisp(s) below will work normally, even in 64 bit mode.
   RegStorage check_class = AllocTemp();
 
-  // If Method* is already in a register, we can save a copy.
-  RegLocation rl_method = mir_graph_->GetMethodLoc();
-  int32_t offset_of_type = mirror::Array::DataOffset(
-      sizeof(mirror::HeapReference<mirror::Class*>)).Int32Value() +
-      (sizeof(mirror::HeapReference<mirror::Class*>) * type_idx);
-
-  if (rl_method.location == kLocPhysReg) {
-    if (use_declaring_class) {
-      LoadRefDisp(rl_method.reg, ArtMethod::DeclaringClassOffset().Int32Value(),
-                  check_class, kNotVolatile);
-    } else {
-      LoadRefDisp(rl_method.reg, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                  check_class, kNotVolatile);
-      LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
-    }
+  if (use_declaring_class) {
+    RegStorage r_method = LoadCurrMethodWithHint(check_class);
+    LoadRefDisp(r_method, ArtMethod::DeclaringClassOffset().Int32Value(),
+                check_class, kNotVolatile);
   } else {
-    LoadCurrMethodDirect(check_class);
-    if (use_declaring_class) {
-      LoadRefDisp(check_class, ArtMethod::DeclaringClassOffset().Int32Value(),
-                  check_class, kNotVolatile);
-    } else {
-      LoadRefDisp(check_class, ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
-                  check_class, kNotVolatile);
-      LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile);
-    }
+    LoadTypeFromCache(type_idx, check_class);
   }
 
   // Compare the computed class to the class in the object.