Use ArtMethod* .bss entries for HInvokeStaticOrDirect.

Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --target
Test: Nexus 6P boots.
Test: Build aosp_mips64-userdebug.
Bug: 30627598
Change-Id: I0e54fdd2e91e983d475b7a04d40815ba89ae3d4f
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 307a42c..a1269dc 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -110,7 +110,6 @@
                 "optimizing/code_generator_vector_arm.cc",
                 "optimizing/code_generator_arm_vixl.cc",
                 "optimizing/code_generator_vector_arm_vixl.cc",
-                "optimizing/dex_cache_array_fixups_arm.cc",
                 "optimizing/instruction_simplifier_arm.cc",
                 "optimizing/instruction_simplifier_shared.cc",
                 "optimizing/intrinsics_arm.cc",
@@ -145,7 +144,6 @@
                 "linker/mips/relative_patcher_mips.cc",
                 "optimizing/code_generator_mips.cc",
                 "optimizing/code_generator_vector_mips.cc",
-                "optimizing/dex_cache_array_fixups_mips.cc",
                 "optimizing/intrinsics_mips.cc",
                 "optimizing/pc_relative_fixups_mips.cc",
                 "utils/mips/assembler_mips.cc",
@@ -342,6 +340,7 @@
         "image_test.cc",
         "image_write_read_test.cc",
         "jni/jni_compiler_test.cc",
+        "linker/method_bss_mapping_encoder_test.cc",
         "linker/multi_oat_relative_patcher_test.cc",
         "linker/output_stream_test.cc",
         "oat_test.cc",
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 0ca23a5..761e9e1 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -120,13 +120,13 @@
   // patch_type_ as an uintN_t and do explicit static_cast<>s.
   enum class Type : uint8_t {
     kMethodRelative,          // NOTE: Actual patching is instruction_set-dependent.
+    kMethodBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
     kCall,
     kCallRelative,            // NOTE: Actual patching is instruction_set-dependent.
     kTypeRelative,            // NOTE: Actual patching is instruction_set-dependent.
     kTypeBssEntry,            // NOTE: Actual patching is instruction_set-dependent.
     kStringRelative,          // NOTE: Actual patching is instruction_set-dependent.
     kStringBssEntry,          // NOTE: Actual patching is instruction_set-dependent.
-    kDexCacheArray,           // NOTE: Actual patching is instruction_set-dependent.
     kBakerReadBarrierBranch,  // NOTE: Actual patching is instruction_set-dependent.
   };
 
@@ -140,6 +140,16 @@
     return patch;
   }
 
+  static LinkerPatch MethodBssEntryPatch(size_t literal_offset,
+                                         const DexFile* target_dex_file,
+                                         uint32_t pc_insn_offset,
+                                         uint32_t target_method_idx) {
+    LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file);
+    patch.method_idx_ = target_method_idx;
+    patch.pc_insn_offset_ = pc_insn_offset;
+    return patch;
+  }
+
   static LinkerPatch CodePatch(size_t literal_offset,
                                const DexFile* target_dex_file,
                                uint32_t target_method_idx) {
@@ -196,16 +206,6 @@
     return patch;
   }
 
-  static LinkerPatch DexCacheArrayPatch(size_t literal_offset,
-                                        const DexFile* target_dex_file,
-                                        uint32_t pc_insn_offset,
-                                        uint32_t element_offset) {
-    LinkerPatch patch(literal_offset, Type::kDexCacheArray, target_dex_file);
-    patch.pc_insn_offset_ = pc_insn_offset;
-    patch.element_offset_ = element_offset;
-    return patch;
-  }
-
   static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset,
                                                  uint32_t custom_value1 = 0u,
                                                  uint32_t custom_value2 = 0u) {
@@ -229,12 +229,12 @@
   bool IsPcRelative() const {
     switch (GetType()) {
       case Type::kMethodRelative:
+      case Type::kMethodBssEntry:
       case Type::kCallRelative:
       case Type::kTypeRelative:
       case Type::kTypeBssEntry:
       case Type::kStringRelative:
       case Type::kStringBssEntry:
-      case Type::kDexCacheArray:
       case Type::kBakerReadBarrierBranch:
         return true;
       default:
@@ -244,6 +244,7 @@
 
   MethodReference TargetMethod() const {
     DCHECK(patch_type_ == Type::kMethodRelative ||
+           patch_type_ == Type::kMethodBssEntry ||
            patch_type_ == Type::kCall ||
            patch_type_ == Type::kCallRelative);
     return MethodReference(target_dex_file_, method_idx_);
@@ -273,23 +274,13 @@
     return dex::StringIndex(string_idx_);
   }
 
-  const DexFile* TargetDexCacheDexFile() const {
-    DCHECK(patch_type_ == Type::kDexCacheArray);
-    return target_dex_file_;
-  }
-
-  size_t TargetDexCacheElementOffset() const {
-    DCHECK(patch_type_ == Type::kDexCacheArray);
-    return element_offset_;
-  }
-
   uint32_t PcInsnOffset() const {
     DCHECK(patch_type_ == Type::kMethodRelative ||
+           patch_type_ == Type::kMethodBssEntry ||
            patch_type_ == Type::kTypeRelative ||
            patch_type_ == Type::kTypeBssEntry ||
            patch_type_ == Type::kStringRelative ||
-           patch_type_ == Type::kStringBssEntry ||
-           patch_type_ == Type::kDexCacheArray);
+           patch_type_ == Type::kStringBssEntry);
     return pc_insn_offset_;
   }
 
@@ -324,12 +315,10 @@
     uint32_t method_idx_;       // Method index for Call/Method patches.
     uint32_t type_idx_;         // Type index for Type patches.
     uint32_t string_idx_;       // String index for String patches.
-    uint32_t element_offset_;   // Element offset in the dex cache arrays.
     uint32_t baker_custom_value1_;
     static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
     static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
     static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
-    static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators");
     static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
   };
   union {
diff --git a/compiler/compiled_method_test.cc b/compiler/compiled_method_test.cc
index 72b2282..f4a72cf 100644
--- a/compiler/compiled_method_test.cc
+++ b/compiler/compiled_method_test.cc
@@ -58,6 +58,14 @@
       LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1000u),
       LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3000u, 1001u),
       LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1001u),
       LinkerPatch::CodePatch(16u, dex_file1, 1000u),
       LinkerPatch::CodePatch(16u, dex_file1, 1001u),
       LinkerPatch::CodePatch(16u, dex_file2, 1000u),
@@ -98,14 +106,6 @@
       LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1000u),
       LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3000u, 1001u),
       LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1001u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2001u),
       LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 0u),
       LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 1u),
       LinkerPatch::BakerReadBarrierBranchPatch(16u, 1u, 0u),
@@ -119,6 +119,14 @@
       LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1000u),
       LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3000u, 1001u),
       LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1000u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1001u),
+      LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1001u),
       LinkerPatch::CodePatch(32u, dex_file1, 1000u),
       LinkerPatch::CodePatch(32u, dex_file1, 1001u),
       LinkerPatch::CodePatch(32u, dex_file2, 1000u),
@@ -159,14 +167,6 @@
       LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1000u),
       LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3000u, 1001u),
       LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1001u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2000u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2001u),
-      LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2001u),
       LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 0u),
       LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 1u),
       LinkerPatch::BakerReadBarrierBranchPatch(32u, 1u, 0u),
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 7c02384..2ef9fa1 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -670,6 +670,7 @@
                              Elf_Word rodata_size,
                              Elf_Word text_size,
                              Elf_Word bss_size,
+                             Elf_Word bss_methods_offset,
                              Elf_Word bss_roots_offset) {
     std::string soname(elf_file_path);
     size_t directory_separator_pos = soname.rfind('/');
@@ -715,9 +716,18 @@
       Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u);
       Elf_Word oatbss = dynstr_.Add("oatbss");
       dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT);
+      DCHECK_LE(bss_methods_offset, bss_roots_offset);
+      DCHECK_LE(bss_roots_offset, bss_size);
+      // Add a symbol marking the start of the methods part of the .bss, if not empty.
+      if (bss_methods_offset != bss_roots_offset) {
+        Elf_Word bss_methods_address = bss_address + bss_methods_offset;
+        Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset;
+        Elf_Word oatbssroots = dynstr_.Add("oatbssmethods");
+        dynsym_.Add(
+            oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT);
+      }
       // Add a symbol marking the start of the GC roots part of the .bss, if not empty.
       if (bss_roots_offset != bss_size) {
-        DCHECK_LT(bss_roots_offset, bss_size);
         Elf_Word bss_roots_address = bss_address + bss_roots_offset;
         Elf_Word bss_roots_size = bss_size - bss_roots_offset;
         Elf_Word oatbssroots = dynstr_.Add("oatbssroots");
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 7baae52..a8a5bc3 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -55,6 +55,7 @@
   virtual void PrepareDynamicSection(size_t rodata_size,
                                      size_t text_size,
                                      size_t bss_size,
+                                     size_t bss_methods_offset,
                                      size_t bss_roots_offset) = 0;
   virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual OutputStream* StartRoData() = 0;
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 738f5a2..38bd9be 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -97,6 +97,7 @@
   void PrepareDynamicSection(size_t rodata_size,
                              size_t text_size,
                              size_t bss_size,
+                             size_t bss_methods_offset,
                              size_t bss_roots_offset) OVERRIDE;
   void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   OutputStream* StartRoData() OVERRIDE;
@@ -178,6 +179,7 @@
 void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
                                                      size_t text_size,
                                                      size_t bss_size,
+                                                     size_t bss_methods_offset,
                                                      size_t bss_roots_offset) {
   DCHECK_EQ(rodata_size_, 0u);
   rodata_size_ = rodata_size;
@@ -189,6 +191,7 @@
                                   rodata_size_,
                                   text_size_,
                                   bss_size_,
+                                  bss_methods_offset,
                                   bss_roots_offset);
 }
 
diff --git a/compiler/image_test.h b/compiler/image_test.h
index 2f15ff4..394b7f1 100644
--- a/compiler/image_test.h
+++ b/compiler/image_test.h
@@ -311,6 +311,7 @@
         elf_writer->PrepareDynamicSection(rodata_size,
                                           text_size,
                                           oat_writer->GetBssSize(),
+                                          oat_writer->GetBssMethodsOffset(),
                                           oat_writer->GetBssRootsOffset());
 
         writer->UpdateOatFileLayout(i,
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 2283b39..3db4fab 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -106,19 +106,6 @@
 
   ArtMethod* GetImageMethodAddress(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  template <typename PtrType>
-  PtrType GetDexCacheArrayElementImageAddress(const DexFile* dex_file, uint32_t offset)
-      const REQUIRES_SHARED(Locks::mutator_lock_) {
-    auto oat_it = dex_file_oat_index_map_.find(dex_file);
-    DCHECK(oat_it != dex_file_oat_index_map_.end());
-    const ImageInfo& image_info = GetImageInfo(oat_it->second);
-    auto it = image_info.dex_cache_array_starts_.find(dex_file);
-    DCHECK(it != image_info.dex_cache_array_starts_.end());
-    return reinterpret_cast<PtrType>(
-        image_info.image_begin_ + image_info.bin_slot_offsets_[kBinDexCacheArray] +
-            it->second + offset);
-  }
-
   size_t GetOatFileOffset(size_t oat_index) const {
     return GetImageInfo(oat_index).oat_offset_;
   }
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 117684a..bc21607 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -59,11 +59,11 @@
     case LinkerPatch::Type::kBakerReadBarrierBranch:
       return false;
     case LinkerPatch::Type::kMethodRelative:
+    case LinkerPatch::Type::kMethodBssEntry:
     case LinkerPatch::Type::kTypeRelative:
     case LinkerPatch::Type::kTypeBssEntry:
     case LinkerPatch::Type::kStringRelative:
     case LinkerPatch::Type::kStringBssEntry:
-    case LinkerPatch::Type::kDexCacheArray:
       return patch.LiteralOffset() == patch.PcInsnOffset();
   }
 }
@@ -251,20 +251,20 @@
       // ADD immediate, 64-bit with imm12 == 0 (unset).
       if (!kEmitCompilerReadBarrier) {
         DCHECK(patch.GetType() == LinkerPatch::Type::kMethodRelative ||
-               patch.GetType() == LinkerPatch::Type::kStringRelative ||
-               patch.GetType() == LinkerPatch::Type::kTypeRelative) << patch.GetType();
+               patch.GetType() == LinkerPatch::Type::kTypeRelative ||
+               patch.GetType() == LinkerPatch::Type::kStringRelative) << patch.GetType();
       } else {
         // With the read barrier (non-Baker) enabled, it could be kStringBssEntry or kTypeBssEntry.
         DCHECK(patch.GetType() == LinkerPatch::Type::kMethodRelative ||
-               patch.GetType() == LinkerPatch::Type::kStringRelative ||
                patch.GetType() == LinkerPatch::Type::kTypeRelative ||
-               patch.GetType() == LinkerPatch::Type::kStringBssEntry ||
-               patch.GetType() == LinkerPatch::Type::kTypeBssEntry) << patch.GetType();
+               patch.GetType() == LinkerPatch::Type::kStringRelative ||
+               patch.GetType() == LinkerPatch::Type::kTypeBssEntry ||
+               patch.GetType() == LinkerPatch::Type::kStringBssEntry) << patch.GetType();
       }
       shift = 0u;  // No shift for ADD.
     } else {
       // LDR/STR 32-bit or 64-bit with imm12 == 0 (unset).
-      DCHECK(patch.GetType() == LinkerPatch::Type::kDexCacheArray ||
+      DCHECK(patch.GetType() == LinkerPatch::Type::kMethodBssEntry ||
              patch.GetType() == LinkerPatch::Type::kTypeBssEntry ||
              patch.GetType() == LinkerPatch::Type::kStringBssEntry) << patch.GetType();
       DCHECK_EQ(insn & 0xbfbffc00, 0xb9000000) << std::hex << insn;
diff --git a/compiler/linker/method_bss_mapping_encoder.h b/compiler/linker/method_bss_mapping_encoder.h
new file mode 100644
index 0000000..b2922ec
--- /dev/null
+++ b/compiler/linker/method_bss_mapping_encoder.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_
+#define ART_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_
+
+#include "base/enums.h"
+#include "base/logging.h"
+#include "dex_file.h"
+#include "method_bss_mapping.h"
+
+namespace art {
+namespace linker {
+
+// Helper class for encoding compressed MethodBssMapping.
+class MethodBssMappingEncoder {
+ public:
+  explicit MethodBssMappingEncoder(PointerSize pointer_size)
+      : pointer_size_(static_cast<size_t>(pointer_size)) {
+    entry_.method_index = DexFile::kDexNoIndex16;
+    entry_.index_mask = 0u;
+    entry_.bss_offset = static_cast<uint32_t>(-1);
+  }
+
+  // Try to merge the next method_index -> bss_offset mapping into the current entry.
+  // Return true on success, false on failure.
+  bool TryMerge(uint32_t method_index, uint32_t bss_offset) {
+    DCHECK_NE(method_index, entry_.method_index);
+    if (entry_.bss_offset + pointer_size_ != bss_offset) {
+      return false;
+    }
+    uint32_t diff = method_index - entry_.method_index;
+    if (diff > 16u) {
+      return false;
+    }
+    if ((entry_.index_mask & ~(static_cast<uint32_t>(-1) << diff)) != 0u) {
+      return false;
+    }
+    entry_.method_index = method_index;
+    // Insert the bit indicating the method index we've just overwritten
+    // and shift bits indicating method indexes before that.
+    entry_.index_mask = dchecked_integral_cast<uint16_t>(
+        (static_cast<uint32_t>(entry_.index_mask) | 0x10000u) >> diff);
+    entry_.bss_offset = bss_offset;
+    return true;
+  }
+
+  void Reset(uint32_t method_index, uint32_t bss_offset) {
+    entry_.method_index = method_index;
+    entry_.index_mask = 0u;
+    entry_.bss_offset = bss_offset;
+  }
+
+  MethodBssMappingEntry GetEntry() {
+    return entry_;
+  }
+
+ private:
+  size_t pointer_size_;
+  MethodBssMappingEntry entry_;
+};
+
+}  // namespace linker
+}  // namespace art
+
+#endif  // ART_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_
diff --git a/compiler/linker/method_bss_mapping_encoder_test.cc b/compiler/linker/method_bss_mapping_encoder_test.cc
new file mode 100644
index 0000000..1240389
--- /dev/null
+++ b/compiler/linker/method_bss_mapping_encoder_test.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_bss_mapping_encoder.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+namespace linker {
+
+TEST(MethodBssMappingEncoder, TryMerge) {
+  for (PointerSize pointer_size : {PointerSize::k32, PointerSize::k64}) {
+    size_t raw_pointer_size = static_cast<size_t>(pointer_size);
+    MethodBssMappingEncoder encoder(pointer_size);
+    encoder.Reset(1u, 0u);
+    ASSERT_FALSE(encoder.TryMerge(5u, raw_pointer_size + 1));       // Wrong bss_offset difference.
+    ASSERT_FALSE(encoder.TryMerge(18u, raw_pointer_size));          // Method index out of range.
+    ASSERT_TRUE(encoder.TryMerge(5u, raw_pointer_size));
+    ASSERT_TRUE(encoder.GetEntry().CoversIndex(1u));
+    ASSERT_TRUE(encoder.GetEntry().CoversIndex(5u));
+    ASSERT_FALSE(encoder.GetEntry().CoversIndex(17u));
+    ASSERT_FALSE(encoder.TryMerge(17u, 2 * raw_pointer_size + 1));  // Wrong bss_offset difference.
+    ASSERT_FALSE(encoder.TryMerge(18u, 2 * raw_pointer_size));      // Method index out of range.
+    ASSERT_TRUE(encoder.TryMerge(17u, 2 * raw_pointer_size));
+    ASSERT_TRUE(encoder.GetEntry().CoversIndex(1u));
+    ASSERT_TRUE(encoder.GetEntry().CoversIndex(5u));
+    ASSERT_TRUE(encoder.GetEntry().CoversIndex(17u));
+    ASSERT_EQ(0u, encoder.GetEntry().GetBssOffset(1u, raw_pointer_size));
+    ASSERT_EQ(raw_pointer_size, encoder.GetEntry().GetBssOffset(5u, raw_pointer_size));
+    ASSERT_EQ(2 * raw_pointer_size, encoder.GetEntry().GetBssOffset(17u, raw_pointer_size));
+    ASSERT_EQ(0x0011u, encoder.GetEntry().index_mask);
+    ASSERT_FALSE(encoder.TryMerge(18u, 2 * raw_pointer_size));      // Method index out of range.
+  }
+}
+
+}  // namespace linker
+}  // namespace art
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index 8da530f..d99d237 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -50,7 +50,6 @@
   uint32_t anchor_literal_offset = patch.PcInsnOffset();
   uint32_t literal_offset = patch.LiteralOffset();
   uint32_t literal_low_offset;
-  bool dex_cache_array = (patch.GetType() == LinkerPatch::Type::kDexCacheArray);
 
   // Perform basic sanity checks and initialize `literal_low_offset` to point
   // to the instruction containing the 16 least significant bits of the
@@ -72,16 +71,8 @@
     DCHECK_GE(code->size(), 16u);
     DCHECK_LE(literal_offset, code->size() - 12u);
     DCHECK_GE(literal_offset, 4u);
-    // The NAL instruction may not precede immediately as the PC+0 value may
-    // come from HMipsComputeBaseMethodAddress.
-    if (dex_cache_array) {
-      DCHECK_EQ(literal_offset + 4u, anchor_literal_offset);
-      // NAL
-      DCHECK_EQ((*code)[literal_offset - 4], 0x00);
-      DCHECK_EQ((*code)[literal_offset - 3], 0x00);
-      DCHECK_EQ((*code)[literal_offset - 2], 0x10);
-      DCHECK_EQ((*code)[literal_offset - 1], 0x04);
-    }
+    // The NAL instruction does not precede immediately as the PC+0
+    // comes from HMipsComputeBaseMethodAddress.
     // LUI reg, offset_high
     DCHECK_EQ((*code)[literal_offset + 0], 0x34);
     DCHECK_EQ((*code)[literal_offset + 1], 0x12);
@@ -90,10 +81,6 @@
     // ADDU reg, reg, reg2
     DCHECK_EQ((*code)[literal_offset + 4], 0x21);
     DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
-    if (dex_cache_array) {
-      // reg2 is either RA or from HMipsComputeBaseMethodAddress.
-      DCHECK_EQ(((*code)[literal_offset + 6] & 0x1F), 0x1F);
-    }
     DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
     // instr reg(s), offset_low
     DCHECK_EQ((*code)[literal_offset + 8], 0x78);
@@ -104,9 +91,6 @@
   // Apply patch.
   uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
   uint32_t diff = target_offset - anchor_offset;
-  if (dex_cache_array && !is_r6) {
-    diff += kDexCacheArrayLwOffset;
-  }
   diff += (diff & 0x8000) << 1;  // Account for sign extension in "instr reg(s), offset_low".
 
   // LUI reg, offset_high / AUIPC reg, offset_high
diff --git a/compiler/linker/mips/relative_patcher_mips.h b/compiler/linker/mips/relative_patcher_mips.h
index 852a345..0b74bd3 100644
--- a/compiler/linker/mips/relative_patcher_mips.h
+++ b/compiler/linker/mips/relative_patcher_mips.h
@@ -46,9 +46,6 @@
                                    uint32_t patch_offset) OVERRIDE;
 
  private:
-  // We'll maximize the range of a single load instruction for dex cache array accesses
-  // by aligning offset -32768 with the offset of the first used element.
-  static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000;
   bool is_r6;
 
   DISALLOW_COPY_AND_ASSIGN(MipsRelativePatcher);
diff --git a/compiler/linker/mips/relative_patcher_mips_test.cc b/compiler/linker/mips/relative_patcher_mips_test.cc
index 961b312..49af7c6 100644
--- a/compiler/linker/mips/relative_patcher_mips_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips_test.cc
@@ -61,7 +61,6 @@
   ASSERT_TRUE(result.first);
 
   uint32_t diff = target_offset - (result.second + kAnchorOffset);
-  CHECK_NE(patches[0].GetType(), LinkerPatch::Type::kDexCacheArray);
   diff += (diff & 0x8000) << 1;  // Account for sign extension in addiu.
 
   const uint8_t expected_code[] = {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 1578c0c..fdb21e4 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -220,6 +220,7 @@
     elf_writer->PrepareDynamicSection(rodata_size,
                                       text_size,
                                       oat_writer.GetBssSize(),
+                                      oat_writer.GetBssMethodsOffset(),
                                       oat_writer.GetBssRootsOffset());
 
     if (kIsVdexEnabled) {
@@ -483,7 +484,7 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(72U, sizeof(OatHeader));
+  EXPECT_EQ(76U, sizeof(OatHeader));
   EXPECT_EQ(4U, sizeof(OatMethodOffsets));
   EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
   EXPECT_EQ(161 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index fed2d34..581b1ee 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -22,7 +22,7 @@
 #include "arch/arm64/instruction_set_features_arm64.h"
 #include "art_method-inl.h"
 #include "base/allocator.h"
-#include "base/bit_vector.h"
+#include "base/bit_vector-inl.h"
 #include "base/enums.h"
 #include "base/file_magic.h"
 #include "base/stl_util.h"
@@ -41,6 +41,7 @@
 #include "image_writer.h"
 #include "linker/buffered_output_stream.h"
 #include "linker/file_output_stream.h"
+#include "linker/method_bss_mapping_encoder.h"
 #include "linker/multi_oat_relative_patcher.h"
 #include "linker/output_stream.h"
 #include "mirror/array.h"
@@ -230,12 +231,14 @@
     return dex_file_location_data_;
   }
 
-  void ReserveClassOffsets(OatWriter* oat_writer);
-
   size_t SizeOf() const;
   bool Write(OatWriter* oat_writer, OutputStream* out) const;
   bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
 
+  size_t GetClassOffsetsRawSize() const {
+    return class_offsets_.size() * sizeof(class_offsets_[0]);
+  }
+
   // The source of the dex file.
   DexFileSource source_;
 
@@ -256,15 +259,12 @@
   uint32_t dex_file_offset_;
   uint32_t class_offsets_offset_;
   uint32_t lookup_table_offset_;
+  uint32_t method_bss_mapping_offset_;
 
   // Data to write to a separate section.
   dchecked_vector<uint32_t> class_offsets_;
 
  private:
-  size_t GetClassOffsetsRawSize() const {
-    return class_offsets_.size() * sizeof(class_offsets_[0]);
-  }
-
   DISALLOW_COPY_AND_ASSIGN(OatDexFile);
 };
 
@@ -294,7 +294,10 @@
     oat_size_(0u),
     bss_start_(0u),
     bss_size_(0u),
+    bss_methods_offset_(0u),
     bss_roots_offset_(0u),
+    bss_method_entry_references_(),
+    bss_method_entries_(),
     bss_type_entries_(),
     bss_string_entries_(),
     oat_data_offset_(0u),
@@ -331,6 +334,7 @@
     size_oat_dex_file_offset_(0),
     size_oat_dex_file_class_offsets_offset_(0),
     size_oat_dex_file_lookup_table_offset_(0),
+    size_oat_dex_file_method_bss_mapping_offset_(0),
     size_oat_lookup_table_alignment_(0),
     size_oat_lookup_table_(0),
     size_oat_class_offsets_alignment_(0),
@@ -339,6 +343,7 @@
     size_oat_class_status_(0),
     size_oat_class_method_bitmaps_(0),
     size_oat_class_method_offsets_(0),
+    size_method_bss_mappings_(0u),
     relative_patcher_(nullptr),
     absolute_patch_locations_(),
     profile_compilation_info_(info) {
@@ -502,11 +507,10 @@
     // Reserve space for Vdex header and checksums.
     vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
   }
-  size_t oat_data_offset = InitOatHeader(instruction_set,
-                                        instruction_set_features,
-                                        dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
-                                        key_value_store);
-  oat_size_ = InitOatDexFiles(oat_data_offset);
+  oat_size_ = InitOatHeader(instruction_set,
+                            instruction_set_features,
+                            dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
+                            key_value_store);
 
   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
 
@@ -539,16 +543,6 @@
     return false;
   }
 
-  // Reserve space for class offsets in OAT and update class_offsets_offset_.
-  for (OatDexFile& oat_dex_file : oat_dex_files_) {
-    oat_dex_file.ReserveClassOffsets(this);
-  }
-
-  // Write OatDexFiles into OAT. Needs to be done last, once offsets are collected.
-  if (!WriteOatDexFiles(&checksum_updating_rodata)) {
-    return false;
-  }
-
   *opened_dex_files_map = std::move(dex_files_map);
   *opened_dex_files = std::move(dex_files);
   write_state_ = WriteState::kPrepareLayout;
@@ -567,16 +561,34 @@
   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
 
+  {
+    TimingLogger::ScopedTiming split("InitBssLayout", timings_);
+    InitBssLayout(instruction_set);
+  }
+
   uint32_t offset = oat_size_;
   {
+    TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
+    offset = InitClassOffsets(offset);
+  }
+  {
     TimingLogger::ScopedTiming split("InitOatClasses", timings_);
     offset = InitOatClasses(offset);
   }
   {
+    TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
+    offset = InitMethodBssMappings(offset);
+  }
+  {
     TimingLogger::ScopedTiming split("InitOatMaps", timings_);
     offset = InitOatMaps(offset);
   }
   {
+    TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
+    oat_header_->SetOatDexFilesOffset(offset);
+    offset = InitOatDexFiles(offset);
+  }
+  {
     TimingLogger::ScopedTiming split("InitOatCode", timings_);
     offset = InitOatCode(offset);
   }
@@ -585,11 +597,7 @@
     offset = InitOatCodeDexFiles(offset);
   }
   oat_size_ = offset;
-
-  {
-    TimingLogger::ScopedTiming split("InitBssLayout", timings_);
-    InitBssLayout(instruction_set);
-  }
+  bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
   if (compiling_boot_image_) {
@@ -606,11 +614,10 @@
 class OatWriter::DexMethodVisitor {
  public:
   DexMethodVisitor(OatWriter* writer, size_t offset)
-    : writer_(writer),
-      offset_(offset),
-      dex_file_(nullptr),
-      class_def_index_(DexFile::kDexNoIndex) {
-  }
+      : writer_(writer),
+        offset_(offset),
+        dex_file_(nullptr),
+        class_def_index_(DexFile::kDexNoIndex) {}
 
   virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
     DCHECK(dex_file_ == nullptr);
@@ -650,19 +657,18 @@
 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
  public:
   OatDexMethodVisitor(OatWriter* writer, size_t offset)
-    : DexMethodVisitor(writer, offset),
-      oat_class_index_(0u),
-      method_offsets_index_(0u) {
-  }
+      : DexMethodVisitor(writer, offset),
+        oat_class_index_(0u),
+        method_offsets_index_(0u) {}
 
-  bool StartClass(const DexFile* dex_file, size_t class_def_index) {
+  bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
     DexMethodVisitor::StartClass(dex_file, class_def_index);
     DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
     method_offsets_index_ = 0u;
     return true;
   }
 
-  bool EndClass() {
+  bool EndClass() OVERRIDE {
     ++oat_class_index_;
     return DexMethodVisitor::EndClass();
   }
@@ -672,21 +678,61 @@
   size_t method_offsets_index_;
 };
 
+class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
+ public:
+  explicit InitBssLayoutMethodVisitor(OatWriter* writer)
+      : DexMethodVisitor(writer, /* offset */ 0u) {}
+
+  bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
+                   const ClassDataItemIterator& it) OVERRIDE {
+    // Look for patches with .bss references and prepare maps with placeholders for their offsets.
+    CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
+        MethodReference(dex_file_, it.GetMemberIndex()));
+    if (compiled_method != nullptr) {
+      for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+        if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
+          MethodReference target_method = patch.TargetMethod();
+          auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
+          if (refs_it == writer_->bss_method_entry_references_.end()) {
+            refs_it = writer_->bss_method_entry_references_.Put(
+                target_method.dex_file,
+                BitVector(target_method.dex_file->NumMethodIds(),
+                          /* expandable */ false,
+                          Allocator::GetMallocAllocator()));
+            refs_it->second.ClearAllBits();
+          }
+          refs_it->second.SetBit(target_method.dex_method_index);
+          writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
+        } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
+          TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
+          writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
+        } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
+          StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
+          writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
+        }
+      }
+    }
+    return true;
+  }
+};
+
 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
  public:
   InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
-    : DexMethodVisitor(writer, offset),
-      compiled_methods_(),
-      num_non_null_compiled_methods_(0u) {
+      : DexMethodVisitor(writer, offset),
+        compiled_methods_(),
+        num_non_null_compiled_methods_(0u) {
     size_t num_classes = 0u;
     for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
       num_classes += oat_dex_file.class_offsets_.size();
     }
     writer_->oat_classes_.reserve(num_classes);
     compiled_methods_.reserve(256u);
+    // If there are any classes, the class offsets allocation aligns the offset.
+    DCHECK(num_classes == 0u || IsAligned<4u>(offset));
   }
 
-  bool StartClass(const DexFile* dex_file, size_t class_def_index) {
+  bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
     DexMethodVisitor::StartClass(dex_file, class_def_index);
     compiled_methods_.clear();
     num_non_null_compiled_methods_ = 0u;
@@ -694,7 +740,7 @@
   }
 
   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
-                   const ClassDataItemIterator& it) {
+                   const ClassDataItemIterator& it) OVERRIDE {
     // Fill in the compiled_methods_ array for methods that have a
     // CompiledMethod. We track the number of non-null entries in
     // num_non_null_compiled_methods_ since we only want to allocate
@@ -704,12 +750,12 @@
         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
     compiled_methods_.push_back(compiled_method);
     if (compiled_method != nullptr) {
-        ++num_non_null_compiled_methods_;
+      ++num_non_null_compiled_methods_;
     }
     return true;
   }
 
-  bool EndClass() {
+  bool EndClass() OVERRIDE {
     ClassReference class_ref(dex_file_, class_def_index_);
     mirror::Class::Status status;
     bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
@@ -740,14 +786,14 @@
 class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
  public:
   InitCodeMethodVisitor(OatWriter* writer, size_t offset, size_t quickening_info_offset)
-    : OatDexMethodVisitor(writer, offset),
-      debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()),
-      current_quickening_info_offset_(quickening_info_offset) {
+      : OatDexMethodVisitor(writer, offset),
+        debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()),
+        current_quickening_info_offset_(quickening_info_offset) {
     writer_->absolute_patch_locations_.reserve(
         writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
   }
 
-  bool EndClass() {
+  bool EndClass() OVERRIDE {
     OatDexMethodVisitor::EndClass();
     if (oat_class_index_ == writer_->oat_classes_.size()) {
       offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
@@ -755,7 +801,7 @@
     return true;
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
@@ -858,14 +904,6 @@
             if (!patch.IsPcRelative()) {
               writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
             }
-            if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
-              TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
-              writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
-            }
-            if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
-              StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
-              writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
-            }
           }
         }
       }
@@ -950,11 +988,10 @@
 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
  public:
   InitMapMethodVisitor(OatWriter* writer, size_t offset)
-    : OatDexMethodVisitor(writer, offset) {
-  }
+      : OatDexMethodVisitor(writer, offset) {}
 
   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
@@ -997,7 +1034,7 @@
   InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
 
   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
+      OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
@@ -1035,18 +1072,17 @@
   InitImageMethodVisitor(OatWriter* writer,
                          size_t offset,
                          const std::vector<const DexFile*>* dex_files)
-    : OatDexMethodVisitor(writer, offset),
-      pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
-      dex_files_(dex_files),
-      class_linker_(Runtime::Current()->GetClassLinker()) {
-    }
+      : OatDexMethodVisitor(writer, offset),
+        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
+        dex_files_(dex_files),
+        class_linker_(Runtime::Current()->GetClassLinker()) {}
 
   // Handle copied methods here. Copy pointer to quick code from
   // an origin method to a copied method only if they are
   // in the same oat file. If the origin and the copied methods are
   // in different oat files don't touch the copied method.
   // References to other oat files are not supported yet.
-  bool StartClass(const DexFile* dex_file, size_t class_def_index)
+  bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
     // Skip classes that are not in the image.
@@ -1085,7 +1121,7 @@
     return true;
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     // Skip methods that are not in the image.
     if (!IsImageClass()) {
@@ -1131,8 +1167,7 @@
       // Should already have been resolved by the compiler, just peek into the dex cache.
       // It may not be resolved if the class failed to verify, in this case, don't set the
       // entrypoint. This is not fatal since the dex cache will contain a resolution method.
-      method = dex_cache->GetResolvedMethod(it.GetMemberIndex(),
-          class_linker_->GetImagePointerSize());
+      method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), pointer_size_);
     }
     if (method != nullptr &&
         compiled_method != nullptr &&
@@ -1171,7 +1206,7 @@
     }
   }
 
- protected:
+ private:
   const PointerSize pointer_size_;
   const std::vector<const DexFile*>* dex_files_;
   ClassLinker* const class_linker_;
@@ -1182,14 +1217,15 @@
  public:
   WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
                          size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
-    : OatDexMethodVisitor(writer, relative_offset),
-      class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
-      out_(out),
-      file_offset_(file_offset),
-      soa_(Thread::Current()),
-      no_thread_suspension_("OatWriter patching"),
-      class_linker_(Runtime::Current()->GetClassLinker()),
-      dex_cache_(nullptr) {
+      : OatDexMethodVisitor(writer, relative_offset),
+        pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
+        class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
+        out_(out),
+        file_offset_(file_offset),
+        soa_(Thread::Current()),
+        no_thread_suspension_("OatWriter patching"),
+        class_linker_(Runtime::Current()->GetClassLinker()),
+        dex_cache_(nullptr) {
     patched_code_.reserve(16 * KB);
     if (writer_->HasBootImage()) {
       // If we're creating the image, the address space must be ready so that we can apply patches.
@@ -1200,7 +1236,7 @@
   ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
   }
 
-  bool StartClass(const DexFile* dex_file, size_t class_def_index)
+  bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
     if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
@@ -1210,7 +1246,7 @@
     return true;
   }
 
-  bool EndClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     bool result = OatDexMethodVisitor::EndClass();
     if (oat_class_index_ == writer_->oat_classes_.size()) {
       DCHECK(result);  // OatDexMethodVisitor::EndClass() never fails.
@@ -1223,7 +1259,7 @@
     return result;
   }
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
       REQUIRES_SHARED(Locks::mutator_lock_) {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
@@ -1275,6 +1311,15 @@
           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
             uint32_t literal_offset = patch.LiteralOffset();
             switch (patch.GetType()) {
+              case LinkerPatch::Type::kMethodBssEntry: {
+                uint32_t target_offset =
+                    writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
+                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+                                                                     patch,
+                                                                     offset_ + literal_offset,
+                                                                     target_offset);
+                break;
+              }
               case LinkerPatch::Type::kCallRelative: {
                 // NOTE: Relative calls across oat files are not supported.
                 uint32_t target_offset = GetTargetOffset(patch);
@@ -1284,14 +1329,6 @@
                                                       target_offset);
                 break;
               }
-              case LinkerPatch::Type::kDexCacheArray: {
-                uint32_t target_offset = GetDexCacheOffset(patch);
-                writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
-                                                                     patch,
-                                                                     offset_ + literal_offset,
-                                                                     target_offset);
-                break;
-              }
               case LinkerPatch::Type::kStringRelative: {
                 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
@@ -1302,7 +1339,8 @@
               }
               case LinkerPatch::Type::kStringBssEntry: {
                 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
-                uint32_t target_offset = writer_->bss_string_entries_.Get(ref);
+                uint32_t target_offset =
+                    writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
                                                                      patch,
                                                                      offset_ + literal_offset,
@@ -1319,7 +1357,7 @@
               }
               case LinkerPatch::Type::kTypeBssEntry: {
                 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
-                uint32_t target_offset = writer_->bss_type_entries_.Get(ref);
+                uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
                                                                      patch,
                                                                      offset_ + literal_offset,
@@ -1368,6 +1406,7 @@
   }
 
  private:
+  const PointerSize pointer_size_;
   ObjPtr<mirror::ClassLoader> class_loader_;
   OutputStream* const out_;
   const size_t file_offset_;
@@ -1388,8 +1427,7 @@
     ObjPtr<mirror::DexCache> dex_cache =
         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
             Thread::Current(), *ref.dex_file);
-    ArtMethod* method = dex_cache->GetResolvedMethod(
-        ref.dex_method_index, class_linker_->GetImagePointerSize());
+    ArtMethod* method = dex_cache->GetResolvedMethod(ref.dex_method_index, pointer_size_);
     CHECK(method != nullptr);
     return method;
   }
@@ -1401,9 +1439,8 @@
     if (UNLIKELY(target_offset == 0)) {
       ArtMethod* target = GetTargetMethod(patch);
       DCHECK(target != nullptr);
-      PointerSize size =
-          GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet());
-      const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(size);
+      const void* oat_code_offset =
+          target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
       if (oat_code_offset != 0) {
         DCHECK(!writer_->HasBootImage());
         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
@@ -1447,19 +1484,6 @@
     return string;
   }
 
-  uint32_t GetDexCacheOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (writer_->HasBootImage()) {
-      uintptr_t element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<uintptr_t>(
-          patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
-      size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
-      uintptr_t oat_data = writer_->image_writer_->GetOatDataBegin(oat_index);
-      return element - oat_data;
-    } else {
-      size_t start = writer_->dex_cache_arrays_offsets_.Get(patch.TargetDexCacheDexFile());
-      return start + patch.TargetDexCacheElementOffset();
-    }
-  }
-
   uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK(writer_->HasBootImage());
     method = writer_->image_writer_->GetImageMethodAddress(method);
@@ -1525,12 +1549,11 @@
                         OutputStream* out,
                         const size_t file_offset,
                         size_t relative_offset)
-    : OatDexMethodVisitor(writer, relative_offset),
-      out_(out),
-      file_offset_(file_offset) {
-  }
+      : OatDexMethodVisitor(writer, relative_offset),
+        out_(out),
+        file_offset_(file_offset) {}
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
@@ -1589,11 +1612,11 @@
                          OutputStream* out,
                          const size_t file_offset,
                          size_t relative_offset)
-    : OatDexMethodVisitor(writer, relative_offset),
-      out_(out),
-      file_offset_(file_offset) {}
+      : OatDexMethodVisitor(writer, relative_offset),
+        out_(out),
+        file_offset_(file_offset) {}
 
-  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
+  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
@@ -1698,12 +1721,17 @@
   return oat_header_->GetHeaderSize();
 }
 
-size_t OatWriter::InitOatDexFiles(size_t offset) {
-  TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
-  // Initialize offsets of dex files.
+size_t OatWriter::InitClassOffsets(size_t offset) {
+  // Reserve space for class offsets in OAT and update class_offsets_offset_.
   for (OatDexFile& oat_dex_file : oat_dex_files_) {
-    oat_dex_file.offset_ = offset;
-    offset += oat_dex_file.SizeOf();
+    DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
+    if (!oat_dex_file.class_offsets_.empty()) {
+      // Class offsets are required to be 4 byte aligned.
+      offset = RoundUp(offset, 4u);
+      oat_dex_file.class_offsets_offset_ = offset;
+      offset += oat_dex_file.GetClassOffsetsRawSize();
+      DCHECK_ALIGNED(offset, 4u);
+    }
   }
   return offset;
 }
@@ -1748,6 +1776,50 @@
   return offset;
 }
 
+size_t OatWriter::InitMethodBssMappings(size_t offset) {
+  size_t number_of_dex_files = 0u;
+  for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    auto it = bss_method_entry_references_.find(dex_file);
+    if (it != bss_method_entry_references_.end()) {
+      const BitVector& method_indexes = it->second;
+      ++number_of_dex_files;
+      // If there are any classes, the class offsets allocation aligns the offset
+      // and we cannot have method bss mappings without class offsets.
+      static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
+      DCHECK_ALIGNED(offset, 4u);
+      oat_dex_files_[i].method_bss_mapping_offset_ = offset;
+
+      linker::MethodBssMappingEncoder encoder(
+          GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
+      size_t number_of_entries = 0u;
+      bool first_index = true;
+      for (uint32_t method_index : method_indexes.Indexes()) {
+        uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
+        if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
+          encoder.Reset(method_index, bss_offset);
+          ++number_of_entries;
+          first_index = false;
+        }
+      }
+      DCHECK_NE(number_of_entries, 0u);
+      offset += MethodBssMapping::ComputeSize(number_of_entries);
+    }
+  }
+  // Check that all dex files targeted by method bss entries are in `*dex_files_`.
+  CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
+  return offset;
+}
+
+size_t OatWriter::InitOatDexFiles(size_t offset) {
+  // Initialize offsets of oat dex files.
+  for (OatDexFile& oat_dex_file : oat_dex_files_) {
+    oat_dex_file.offset_ = offset;
+    offset += oat_dex_file.SizeOf();
+  }
+  return offset;
+}
+
 size_t OatWriter::InitOatCode(size_t offset) {
   // calculate the offsets within OatHeader to executable code
   size_t old_offset = offset;
@@ -1806,38 +1878,51 @@
 }
 
 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
+  {
+    InitBssLayoutMethodVisitor visitor(this);
+    bool success = VisitDexMethods(&visitor);
+    DCHECK(success);
+  }
+
+  DCHECK_EQ(bss_size_, 0u);
   if (HasBootImage()) {
     DCHECK(bss_string_entries_.empty());
-    if (bss_type_entries_.empty()) {
+    if (bss_method_entries_.empty() && bss_type_entries_.empty()) {
       // Nothing to put to the .bss section.
       return;
     }
   }
 
   // Allocate space for app dex cache arrays in the .bss section.
-  bss_start_ = RoundUp(oat_size_, kPageSize);
-  bss_size_ = 0u;
+  PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
   if (!HasBootImage()) {
-    PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
     for (const DexFile* dex_file : *dex_files_) {
-      dex_cache_arrays_offsets_.Put(dex_file, bss_start_ + bss_size_);
       DexCacheArraysLayout layout(pointer_size, dex_file);
       bss_size_ += layout.Size();
     }
   }
 
+  bss_methods_offset_ = bss_size_;
+
+  // Prepare offsets for .bss ArtMethod entries.
+  for (auto& entry : bss_method_entries_) {
+    DCHECK_EQ(entry.second, 0u);
+    entry.second = bss_size_;
+    bss_size_ += static_cast<size_t>(pointer_size);
+  }
+
   bss_roots_offset_ = bss_size_;
 
   // Prepare offsets for .bss Class entries.
   for (auto& entry : bss_type_entries_) {
     DCHECK_EQ(entry.second, 0u);
-    entry.second = bss_start_ + bss_size_;
+    entry.second = bss_size_;
     bss_size_ += sizeof(GcRoot<mirror::Class>);
   }
   // Prepare offsets for .bss String entries.
   for (auto& entry : bss_string_entries_) {
     DCHECK_EQ(entry.second, 0u);
-    entry.second = bss_start_ + bss_size_;
+    entry.second = bss_size_;
     bss_size_ += sizeof(GcRoot<mirror::String>);
   }
 }
@@ -1845,30 +1930,45 @@
 bool OatWriter::WriteRodata(OutputStream* out) {
   CHECK(write_state_ == WriteState::kWriteRoData);
 
+  size_t file_offset = oat_data_offset_;
+  off_t current_offset = out->Seek(0, kSeekCurrent);
+  if (current_offset == static_cast<off_t>(-1)) {
+    PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
+  }
+  DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
+  size_t relative_offset = current_offset - file_offset;
+
   // Wrap out to update checksum with each write.
   ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
   out = &checksum_updating_out;
 
-  if (!WriteClassOffsets(out)) {
-    LOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
+  relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
+  if (relative_offset == 0) {
+    PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
     return false;
   }
 
-  if (!WriteClasses(out)) {
-    LOG(ERROR) << "Failed to write classes to " << out->GetLocation();
+  relative_offset = WriteClasses(out, file_offset, relative_offset);
+  if (relative_offset == 0) {
+    PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
     return false;
   }
 
-  off_t tables_end_offset = out->Seek(0, kSeekCurrent);
-  if (tables_end_offset == static_cast<off_t>(-1)) {
-    LOG(ERROR) << "Failed to get oat code position in " << out->GetLocation();
+  relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
+  if (relative_offset == 0) {
+    PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
     return false;
   }
-  size_t file_offset = oat_data_offset_;
-  size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset;
+
   relative_offset = WriteMaps(out, file_offset, relative_offset);
   if (relative_offset == 0) {
-    LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
+    PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
+    return false;
+  }
+
+  relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
+  if (relative_offset == 0) {
+    PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
     return false;
   }
 
@@ -1891,12 +1991,12 @@
 class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
  public:
   WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out, uint32_t offset)
-    : DexMethodVisitor(writer, offset),
-      out_(out),
-      written_bytes_(0u) {}
+      : DexMethodVisitor(writer, offset),
+        out_(out),
+        written_bytes_(0u) {}
 
   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
-                   const ClassDataItemIterator& it) {
+                   const ClassDataItemIterator& it) OVERRIDE {
     if (it.GetMethodCodeItem() == nullptr) {
       // No CodeItem. Native or abstract method.
       return true;
@@ -2092,6 +2192,7 @@
     DO_STAT(size_oat_dex_file_offset_);
     DO_STAT(size_oat_dex_file_class_offsets_offset_);
     DO_STAT(size_oat_dex_file_lookup_table_offset_);
+    DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
     DO_STAT(size_oat_lookup_table_alignment_);
     DO_STAT(size_oat_lookup_table_);
     DO_STAT(size_oat_class_offsets_alignment_);
@@ -2100,6 +2201,7 @@
     DO_STAT(size_oat_class_status_);
     DO_STAT(size_oat_class_method_bitmaps_);
     DO_STAT(size_oat_class_method_offsets_);
+    DO_STAT(size_method_bss_mappings_);
     #undef DO_STAT
 
     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
@@ -2172,35 +2274,41 @@
   return true;
 }
 
-bool OatWriter::WriteClassOffsets(OutputStream* out) {
+size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
   for (OatDexFile& oat_dex_file : oat_dex_files_) {
     if (oat_dex_file.class_offsets_offset_ != 0u) {
-      uint32_t expected_offset = oat_data_offset_ + oat_dex_file.class_offsets_offset_;
-      off_t actual_offset = out->Seek(expected_offset, kSeekSet);
-      if (static_cast<uint32_t>(actual_offset) != expected_offset) {
-        PLOG(ERROR) << "Failed to seek to oat class offsets section. Actual: " << actual_offset
-                    << " Expected: " << expected_offset << " File: " << oat_dex_file.GetLocation();
-        return false;
+      // Class offsets are required to be 4 byte aligned.
+      if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
+        size_t padding_size =  RoundUp(relative_offset, 4u) - relative_offset;
+        if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
+          return 0u;
+        }
+        relative_offset += padding_size;
       }
+      DCHECK_OFFSET();
       if (!oat_dex_file.WriteClassOffsets(this, out)) {
-        return false;
+        return 0u;
       }
+      relative_offset += oat_dex_file.GetClassOffsetsRawSize();
     }
   }
-  return true;
+  return relative_offset;
 }
 
-bool OatWriter::WriteClasses(OutputStream* out) {
+size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
   for (OatClass& oat_class : oat_classes_) {
+    // If there are any classes, the class offsets allocation aligns the offset.
+    DCHECK_ALIGNED(relative_offset, 4u);
+    DCHECK_OFFSET();
     if (!oat_class.Write(this, out, oat_data_offset_)) {
-      PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
-      return false;
+      return 0u;
     }
+    relative_offset += oat_class.SizeOf();
   }
-  return true;
+  return relative_offset;
 }
 
-size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
+size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
   {
     size_t vmap_tables_offset = relative_offset;
     WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
@@ -2223,7 +2331,87 @@
   return relative_offset;
 }
 
-size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
+size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
+                                         size_t file_offset,
+                                         size_t relative_offset) {
+  TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
+
+  for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
+    const DexFile* dex_file = (*dex_files_)[i];
+    OatDexFile* oat_dex_file = &oat_dex_files_[i];
+    auto it = bss_method_entry_references_.find(dex_file);
+    if (it != bss_method_entry_references_.end()) {
+      const BitVector& method_indexes = it->second;
+      // If there are any classes, the class offsets allocation aligns the offset
+      // and we cannot have method bss mappings without class offsets.
+      static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
+                    "MethodBssMapping alignment check.");
+      DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
+
+      linker::MethodBssMappingEncoder encoder(
+          GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
+      // Allocate a sufficiently large MethodBssMapping.
+      size_t number_of_method_indexes = method_indexes.NumSetBits();
+      DCHECK_NE(number_of_method_indexes, 0u);
+      size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
+      DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
+      std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
+      MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
+      mappings->ClearPadding();
+      // Encode the MethodBssMapping.
+      auto init_it = mappings->begin();
+      bool first_index = true;
+      for (uint32_t method_index : method_indexes.Indexes()) {
+        size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
+        if (first_index) {
+          first_index = false;
+          encoder.Reset(method_index, bss_offset);
+        } else if (!encoder.TryMerge(method_index, bss_offset)) {
+          *init_it = encoder.GetEntry();
+          ++init_it;
+          encoder.Reset(method_index, bss_offset);
+        }
+      }
+      // Store the last entry and shrink the mapping to the actual size.
+      *init_it = encoder.GetEntry();
+      ++init_it;
+      DCHECK(init_it <= mappings->end());
+      mappings->SetSize(std::distance(mappings->begin(), init_it));
+      size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
+
+      DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
+      DCHECK_OFFSET();
+      if (!out->WriteFully(storage.get(), mappings_size)) {
+        return 0u;
+      }
+      size_method_bss_mappings_ += mappings_size;
+      relative_offset += mappings_size;
+    } else {
+      DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
+    }
+  }
+  return relative_offset;
+}
+
+size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
+  TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
+
+  for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
+    OatDexFile* oat_dex_file = &oat_dex_files_[i];
+    DCHECK_EQ(relative_offset, oat_dex_file->offset_);
+    DCHECK_OFFSET();
+
+    // Write OatDexFile.
+    if (!oat_dex_file->Write(this, out)) {
+      return 0u;
+    }
+    relative_offset += oat_dex_file->SizeOf();
+  }
+
+  return relative_offset;
+}
+
+size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
 
@@ -2253,7 +2441,7 @@
 }
 
 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
-                                    const size_t file_offset,
+                                    size_t file_offset,
                                     size_t relative_offset) {
   #define VISIT(VisitorType)                                              \
     do {                                                                  \
@@ -2667,50 +2855,6 @@
   return true;
 }
 
-bool OatWriter::WriteOatDexFiles(OutputStream* rodata) {
-  TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
-
-  off_t initial_offset = rodata->Seek(0, kSeekCurrent);
-  if (initial_offset == static_cast<off_t>(-1)) {
-    LOG(ERROR) << "Failed to get current position in " << rodata->GetLocation();
-    return false;
-  }
-
-  // Seek to the start of OatDexFiles, i.e. to the end of the OatHeader.  If there are
-  // no OatDexFiles, no data is actually written to .rodata before WriteHeader() and
-  // this Seek() ensures that we reserve the space for OatHeader in .rodata.
-  DCHECK(oat_dex_files_.empty() || oat_dex_files_[0u].offset_ == oat_header_->GetHeaderSize());
-  uint32_t expected_offset = oat_data_offset_ + oat_header_->GetHeaderSize();
-  off_t actual_offset = rodata->Seek(expected_offset, kSeekSet);
-  if (static_cast<uint32_t>(actual_offset) != expected_offset) {
-    PLOG(ERROR) << "Failed to seek to OatDexFile table section. Actual: " << actual_offset
-                << " Expected: " << expected_offset << " File: " << rodata->GetLocation();
-    return false;
-  }
-
-  for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
-    OatDexFile* oat_dex_file = &oat_dex_files_[i];
-
-    DCHECK_EQ(oat_data_offset_ + oat_dex_file->offset_,
-              static_cast<size_t>(rodata->Seek(0, kSeekCurrent)));
-
-    // Write OatDexFile.
-    if (!oat_dex_file->Write(this, rodata)) {
-      PLOG(ERROR) << "Failed to write oat dex information to " << rodata->GetLocation();
-      return false;
-    }
-  }
-
-  // Seek back to the initial position.
-  if (rodata->Seek(initial_offset, kSeekSet) != initial_offset) {
-    PLOG(ERROR) << "Failed to seek to initial position. Actual: " << actual_offset
-                << " Expected: " << initial_offset << " File: " << rodata->GetLocation();
-    return false;
-  }
-
-  return true;
-}
-
 bool OatWriter::OpenDexFiles(
     File* file,
     bool verify,
@@ -2929,14 +3073,18 @@
 }
 
 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
+  return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
+}
+
+bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
   static const uint8_t kPadding[] = {
       0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
   };
-  DCHECK_LE(aligned_code_delta, sizeof(kPadding));
-  if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) {
+  DCHECK_LE(size, sizeof(kPadding));
+  if (UNLIKELY(!out->WriteFully(kPadding, size))) {
     return false;
   }
-  size_code_alignment_ += aligned_code_delta;
+  *stat += size;
   return true;
 }
 
@@ -2965,6 +3113,7 @@
       dex_file_offset_(0u),
       class_offsets_offset_(0u),
       lookup_table_offset_(0u),
+      method_bss_mapping_offset_(0u),
       class_offsets_() {
 }
 
@@ -2974,19 +3123,8 @@
           + sizeof(dex_file_location_checksum_)
           + sizeof(dex_file_offset_)
           + sizeof(class_offsets_offset_)
-          + sizeof(lookup_table_offset_);
-}
-
-void OatWriter::OatDexFile::ReserveClassOffsets(OatWriter* oat_writer) {
-  DCHECK_EQ(class_offsets_offset_, 0u);
-  if (!class_offsets_.empty()) {
-    // Class offsets are required to be 4 byte aligned.
-    size_t initial_offset = oat_writer->oat_size_;
-    size_t offset = RoundUp(initial_offset, 4);
-    oat_writer->size_oat_class_offsets_alignment_ += offset - initial_offset;
-    class_offsets_offset_ = offset;
-    oat_writer->oat_size_ = offset + GetClassOffsetsRawSize();
-  }
+          + sizeof(lookup_table_offset_)
+          + sizeof(method_bss_mapping_offset_);
 }
 
 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
@@ -3029,6 +3167,12 @@
   }
   oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
 
+  if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
+    PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
+    return false;
+  }
+  oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
+
   return true;
 }
 
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 66b70ad..9217701 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -60,11 +60,6 @@
 
 // OatHeader         variable length with count of D OatDexFiles
 //
-// OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
-// OatDexFile[1]
-// ...
-// OatDexFile[D]
-//
 // TypeLookupTable[0] one descriptor to class def index hash table for each OatDexFile.
 // TypeLookupTable[1]
 // ...
@@ -80,20 +75,25 @@
 // ...
 // OatClass[C]
 //
-// GcMap             one variable sized blob with GC map.
-// GcMap             GC maps are deduplicated.
+// MethodBssMapping  one variable sized MethodBssMapping for each dex file, optional.
+// MethodBssMapping
 // ...
-// GcMap
+// MethodBssMapping
 //
-// VmapTable         one variable sized VmapTable blob (quick compiler only).
+// VmapTable         one variable sized VmapTable blob (CodeInfo or QuickeningInfo).
 // VmapTable         VmapTables are deduplicated.
 // ...
 // VmapTable
 //
-// MappingTable      one variable sized blob with MappingTable (quick compiler only).
-// MappingTable      MappingTables are deduplicated.
+// MethodInfo        one variable sized blob with MethodInfo.
+// MethodInfo        MethodInfos are deduplicated.
 // ...
-// MappingTable
+// MethodInfo
+//
+// OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
+// OatDexFile[1]
+// ...
+// OatDexFile[D]
 //
 // padding           if necessary so that the following code will be page aligned
 //
@@ -217,6 +217,10 @@
     return bss_size_;
   }
 
+  size_t GetBssMethodsOffset() const {
+    return bss_methods_offset_;
+  }
+
   size_t GetBssRootsOffset() const {
     return bss_roots_offset_;
   }
@@ -251,6 +255,7 @@
   // to actually write it.
   class DexMethodVisitor;
   class OatDexMethodVisitor;
+  class InitBssLayoutMethodVisitor;
   class InitOatClassesMethodVisitor;
   class InitCodeMethodVisitor;
   class InitMapMethodVisitor;
@@ -295,26 +300,30 @@
                        const InstructionSetFeatures* instruction_set_features,
                        uint32_t num_dex_files,
                        SafeMap<std::string, std::string>* key_value_store);
-  size_t InitOatDexFiles(size_t offset);
+  size_t InitClassOffsets(size_t offset);
   size_t InitOatClasses(size_t offset);
   size_t InitOatMaps(size_t offset);
+  size_t InitMethodBssMappings(size_t offset);
+  size_t InitOatDexFiles(size_t offset);
   size_t InitOatCode(size_t offset);
   size_t InitOatCodeDexFiles(size_t offset);
   void InitBssLayout(InstructionSet instruction_set);
 
-  bool WriteClassOffsets(OutputStream* out);
-  bool WriteClasses(OutputStream* out);
-  size_t WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset);
-  size_t WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset);
-  size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset);
+  size_t WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteMethodBssMappings(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset);
+  size_t WriteCodeDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset);
 
   bool RecordOatDataOffset(OutputStream* out);
   bool ReadDexFileHeader(File* oat_file, OatDexFile* oat_dex_file);
   bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location);
-  bool WriteOatDexFiles(OutputStream* oat_rodata);
   bool WriteTypeLookupTables(OutputStream* oat_rodata,
                              const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files);
   bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
+  bool WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat);
   void SetMultiOatRelativePatcherAdjustment();
   void CloseSources();
 
@@ -368,9 +377,20 @@
   // The size of the required .bss section holding the DexCache data and GC roots.
   size_t bss_size_;
 
+  // The offset of the methods in .bss section.
+  size_t bss_methods_offset_;
+
   // The offset of the GC roots in .bss section.
   size_t bss_roots_offset_;
 
+  // Map for recording references to ArtMethod entries in .bss.
+  SafeMap<const DexFile*, BitVector> bss_method_entry_references_;
+
+  // Map for allocating ArtMethod entries in .bss. Indexed by MethodReference for the target
+  // method in the dex file with the "method reference value comparator" for deduplication.
+  // The value is the target offset for patching, starting at `bss_start_ + bss_methods_offset_`.
+  SafeMap<MethodReference, size_t, MethodReferenceValueComparator> bss_method_entries_;
+
   // Map for allocating Class entries in .bss. Indexed by TypeReference for the source
   // type in the dex file with the "type value comparator" for deduplication. The value
   // is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`.
@@ -381,10 +401,6 @@
   // is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`.
   SafeMap<StringReference, size_t, StringReferenceValueComparator> bss_string_entries_;
 
-  // Offsets of the dex cache arrays for each app dex file. For the
-  // boot image, this information is provided by the ImageWriter.
-  SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_;  // DexFiles not owned.
-
   // Offset of the oat data from the start of the mmapped region of the elf file.
   size_t oat_data_offset_;
 
@@ -434,6 +450,7 @@
   uint32_t size_oat_dex_file_offset_;
   uint32_t size_oat_dex_file_class_offsets_offset_;
   uint32_t size_oat_dex_file_lookup_table_offset_;
+  uint32_t size_oat_dex_file_method_bss_mapping_offset_;
   uint32_t size_oat_lookup_table_alignment_;
   uint32_t size_oat_lookup_table_;
   uint32_t size_oat_class_offsets_alignment_;
@@ -442,6 +459,7 @@
   uint32_t size_oat_class_status_;
   uint32_t size_oat_class_method_bitmaps_;
   uint32_t size_oat_class_method_offsets_;
+  uint32_t size_method_bss_mappings_;
 
   // The helper for processing relative patches is external so that we can patch across oat files.
   linker::MultiOatRelativePatcher* relative_patcher_;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 8300f81..804bc0f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2395,8 +2395,8 @@
       isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -3553,18 +3553,10 @@
 
   IntrinsicLocationsBuilderARM intrinsic(codegen_);
   if (intrinsic.TryDispatch(invoke)) {
-    if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
-      invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
-    }
     return;
   }
 
   HandleInvoke(invoke);
-
-  // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
-  if (invoke->HasPcRelativeDexCache()) {
-    invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
-  }
 }
 
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
@@ -8981,13 +8973,17 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress());
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
-      HArmDexCacheArraysBase* base =
-          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
-      Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
-                                                                temp.AsRegister<Register>());
-      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
-      __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
+      Register temp_reg = temp.AsRegister<Register>();
+      PcRelativePatchInfo* labels = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
+      __ BindTrackedLabel(&labels->movw_label);
+      __ movw(temp_reg, /* placeholder */ 0u);
+      __ BindTrackedLabel(&labels->movt_label);
+      __ movt(temp_reg, /* placeholder */ 0u);
+      __ BindTrackedLabel(&labels->add_pc_label);
+      __ add(temp_reg, temp_reg, ShifterOperand(PC));
+      __ LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset */ 0);
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -9056,6 +9052,13 @@
                             &pc_relative_method_patches_);
 }
 
+CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewMethodBssEntryPatch(
+    MethodReference target_method) {
+  return NewPcRelativePatch(*target_method.dex_file,
+                            target_method.dex_method_index,
+                            &method_bss_entry_patches_);
+}
+
 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
   return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
@@ -9071,11 +9074,6 @@
   return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
 }
 
-CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
-    const DexFile& dex_file, uint32_t element_offset) {
-  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
-}
-
 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch(
     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   patches->emplace_back(dex_file, offset_or_index);
@@ -9134,15 +9132,13 @@
 void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() +
+      /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
                                                                   linker_patches);
@@ -9156,6 +9152,8 @@
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
                                                                   linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
@@ -9292,23 +9290,6 @@
   }
 }
 
-void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
-  locations->SetOut(Location::RequiresRegister());
-}
-
-void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
-  Register base_reg = base->GetLocations()->Out().AsRegister<Register>();
-  CodeGeneratorARM::PcRelativePatchInfo* labels =
-      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
-  __ BindTrackedLabel(&labels->movw_label);
-  __ movw(base_reg, /* placeholder */ 0u);
-  __ BindTrackedLabel(&labels->movt_label);
-  __ movt(base_reg, /* placeholder */ 0u);
-  __ BindTrackedLabel(&labels->add_pc_label);
-  __ add(base_reg, base_reg, ShifterOperand(PC));
-}
-
 void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) {
   if (!trg.IsValid()) {
     DCHECK_EQ(type, Primitive::kPrimVoid);
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 398b6ed..9280e63 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -483,12 +483,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
   PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
                                                 dex::StringIndex string_index);
-  PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
-                                                       uint32_t element_offset);
 
   // Add a new baker read barrier patch and return the label to be bound
   // before the BNE instruction.
@@ -669,10 +668,10 @@
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
-  // PC-relative patch info for each HArmDexCacheArraysBase.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
   // PC-relative type patch info for kBssEntry.
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a84f8f3..9ba38e5 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1448,8 +1448,8 @@
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -4526,15 +4526,14 @@
       // Load method address from literal pool.
       __ Ldr(XRegisterFrom(temp), DeduplicateUint64Literal(invoke->GetMethodAddress()));
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
       // Add ADRP with its PC-relative DexCache access patch.
-      const DexFile& dex_file = invoke->GetDexFileForPcRelativeDexCache();
-      uint32_t element_offset = invoke->GetDexCacheArrayOffset();
-      vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
+      MethodReference target_method(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex());
+      vixl::aarch64::Label* adrp_label = NewMethodBssEntryPatch(target_method);
       EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
       // Add LDR with its PC-relative DexCache access patch.
       vixl::aarch64::Label* ldr_label =
-          NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label);
+          NewMethodBssEntryPatch(target_method, adrp_label);
       EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp));
       break;
     }
@@ -4635,6 +4634,15 @@
                             &pc_relative_method_patches_);
 }
 
+vixl::aarch64::Label* CodeGeneratorARM64::NewMethodBssEntryPatch(
+    MethodReference target_method,
+    vixl::aarch64::Label* adrp_label) {
+  return NewPcRelativePatch(*target_method.dex_file,
+                            target_method.dex_method_index,
+                            adrp_label,
+                            &method_bss_entry_patches_);
+}
+
 vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(
     const DexFile& dex_file,
     dex::TypeIndex type_index,
@@ -4657,13 +4665,6 @@
       NewPcRelativePatch(dex_file, string_index.index_, adrp_label, &pc_relative_string_patches_);
 }
 
-vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch(
-    const DexFile& dex_file,
-    uint32_t element_offset,
-    vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(dex_file, element_offset, adrp_label, &pc_relative_dex_cache_patches_);
-}
-
 vixl::aarch64::Label* CodeGeneratorARM64::NewBakerReadBarrierPatch(uint32_t custom_data) {
   baker_read_barrier_patches_.emplace_back(custom_data);
   return &baker_read_barrier_patches_.back().label;
@@ -4685,7 +4686,7 @@
 
 vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateBootImageAddressLiteral(
     uint64_t address) {
-  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
+  return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address));
 }
 
 vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateJitStringLiteral(
@@ -4748,19 +4749,13 @@
 void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_dex_cache_patches_.size() +
       pc_relative_method_patches_.size() +
+      method_bss_entry_patches_.size() +
       pc_relative_type_patches_.size() +
       type_bss_entry_patches_.size() +
       pc_relative_string_patches_.size() +
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
-  for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
-    linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(info.label.GetLocation(),
-                                                              &info.target_dex_file,
-                                                              info.pc_insn_label->GetLocation(),
-                                                              info.offset_or_index));
-  }
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
                                                                   linker_patches);
@@ -4774,6 +4769,8 @@
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
                                                                   linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
@@ -4783,9 +4780,8 @@
   DCHECK_EQ(size, linker_patches->size());
 }
 
-vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateUint32Literal(uint32_t value,
-                                                                      Uint32ToLiteralMap* map) {
-  return map->GetOrCreate(
+vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateUint32Literal(uint32_t value) {
+  return uint32_literals_.GetOrCreate(
       value,
       [this, value]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(value); });
 }
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 5bb2ab5..d9c49d1 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -557,6 +557,13 @@
   vixl::aarch64::Label* NewPcRelativeMethodPatch(MethodReference target_method,
                                                  vixl::aarch64::Label* adrp_label = nullptr);
 
+  // Add a new .bss entry method patch for an instruction and return
+  // the label to be bound before the instruction. The instruction will be
+  // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label`
+  // pointing to the associated ADRP patch label).
+  vixl::aarch64::Label* NewMethodBssEntryPatch(MethodReference target_method,
+                                               vixl::aarch64::Label* adrp_label = nullptr);
+
   // Add a new PC-relative type patch for an instruction and return the label
   // to be bound before the instruction. The instruction will be either the
   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
@@ -581,15 +588,6 @@
                                                  dex::StringIndex string_index,
                                                  vixl::aarch64::Label* adrp_label = nullptr);
 
-  // Add a new PC-relative dex cache array patch for an instruction and return
-  // the label to be bound before the instruction. The instruction will be
-  // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label`
-  // pointing to the associated ADRP patch label).
-  vixl::aarch64::Label* NewPcRelativeDexCacheArrayPatch(
-      const DexFile& dex_file,
-      uint32_t element_offset,
-      vixl::aarch64::Label* adrp_label = nullptr);
-
   // Add a new baker read barrier patch and return the label to be bound
   // before the CBNZ instruction.
   vixl::aarch64::Label* NewBakerReadBarrierPatch(uint32_t custom_data);
@@ -741,8 +739,7 @@
                                         vixl::aarch64::Literal<uint32_t>*,
                                         TypeReferenceValueComparator>;
 
-  vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value,
-                                                             Uint32ToLiteralMap* map);
+  vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value);
   vixl::aarch64::Literal<uint64_t>* DeduplicateUint64Literal(uint64_t value);
 
   // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
@@ -793,10 +790,10 @@
   Uint32ToLiteralMap uint32_literals_;
   // Deduplication map for 64-bit literals, used for non-patchable method address or method code.
   Uint64ToLiteralMap uint64_literals_;
-  // PC-relative DexCache access info.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
   // PC-relative type patch info for kBssEntry.
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index d5e3723..9cd7761 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -2499,8 +2499,8 @@
       isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -3642,18 +3642,10 @@
 
   IntrinsicLocationsBuilderARMVIXL intrinsic(codegen_);
   if (intrinsic.TryDispatch(invoke)) {
-    if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) {
-      invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
-    }
     return;
   }
 
   HandleInvoke(invoke);
-
-  // For PC-relative dex cache the invoke has an extra input, the PC-relative address base.
-  if (invoke->HasPcRelativeDexCache()) {
-    invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
-  }
 }
 
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARMVIXL* codegen) {
@@ -9140,12 +9132,12 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       __ Mov(RegisterFrom(temp), Operand::From(invoke->GetMethodAddress()));
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
-      HArmDexCacheArraysBase* base =
-          invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase();
-      vixl32::Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke, RegisterFrom(temp));
-      int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset();
-      GetAssembler()->LoadFromOffset(kLoadWord, RegisterFrom(temp), base_reg, offset);
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
+      PcRelativePatchInfo* labels = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
+      vixl32::Register temp_reg = RegisterFrom(temp);
+      EmitMovwMovtPlaceholder(labels, temp_reg);
+      GetAssembler()->LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset*/ 0);
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -9244,6 +9236,13 @@
                             &pc_relative_method_patches_);
 }
 
+CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewMethodBssEntryPatch(
+    MethodReference target_method) {
+  return NewPcRelativePatch(*target_method.dex_file,
+                            target_method.dex_method_index,
+                            &method_bss_entry_patches_);
+}
+
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeTypePatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
   return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
@@ -9259,11 +9258,6 @@
   return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
 }
 
-CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeDexCacheArrayPatch(
-    const DexFile& dex_file, uint32_t element_offset) {
-  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
-}
-
 CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativePatch(
     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   patches->emplace_back(dex_file, offset_or_index);
@@ -9327,15 +9321,13 @@
 void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() +
+      /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() +
       /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
       baker_read_barrier_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
                                                                   linker_patches);
@@ -9349,6 +9341,8 @@
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
                                                                   linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) {
@@ -9498,17 +9492,6 @@
     }
   }
 }
-void LocationsBuilderARMVIXL::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
-  locations->SetOut(Location::RequiresRegister());
-}
-
-void InstructionCodeGeneratorARMVIXL::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) {
-  vixl32::Register base_reg = OutputRegister(base);
-  CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
-      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
-  codegen_->EmitMovwMovtPlaceholder(labels, base_reg);
-}
 
 // Copy the result of a call into the given target.
 void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 5320f71..805a3f4 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -566,12 +566,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
   PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
                                                 dex::StringIndex string_index);
-  PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
-                                                       uint32_t element_offset);
 
   // Add a new baker read barrier patch and return the label to be bound
   // before the BNE instruction.
@@ -766,10 +765,10 @@
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
-  // PC-relative patch info for each HArmDexCacheArraysBase.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
   // PC-relative type patch info for kBssEntry.
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 8560e3e..b39d412 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -40,10 +40,6 @@
 static constexpr int kCurrentMethodStackOffset = 0;
 static constexpr Register kMethodRegisterArgument = A0;
 
-// We'll maximize the range of a single load instruction for dex cache array accesses
-// by aligning offset -32768 with the offset of the first used element.
-static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000;
-
 Location MipsReturnLocation(Primitive::Type return_type) {
   switch (return_type) {
     case Primitive::kPrimBoolean:
@@ -1060,8 +1056,8 @@
       isa_features_(isa_features),
       uint32_literals_(std::less<uint32_t>(),
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -1602,14 +1598,12 @@
 void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_dex_cache_patches_.size() +
       pc_relative_method_patches_.size() +
+      method_bss_entry_patches_.size() +
       pc_relative_type_patches_.size() +
       type_bss_entry_patches_.size() +
       pc_relative_string_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
                                                                   linker_patches);
@@ -1623,6 +1617,8 @@
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
                                                                   linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   DCHECK_EQ(size, linker_patches->size());
@@ -1635,6 +1631,13 @@
                             &pc_relative_method_patches_);
 }
 
+CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
+    MethodReference target_method) {
+  return NewPcRelativePatch(*target_method.dex_file,
+                            target_method.dex_method_index,
+                            &method_bss_entry_patches_);
+}
+
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
   return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
@@ -1650,11 +1653,6 @@
   return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
 }
 
-CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
-    const DexFile& dex_file, uint32_t element_offset) {
-  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
-}
-
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   patches->emplace_back(dex_file, offset_or_index);
@@ -7000,7 +6998,7 @@
     HLoadString::LoadKind desired_string_load_kind) {
   // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
   // is incompatible with it.
-  // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
+  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
   // with irreducible loops.
   bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
   bool is_r6 = GetInstructionSetFeatures().IsR6();
@@ -7030,6 +7028,8 @@
     HLoadClass::LoadKind desired_class_load_kind) {
   // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
   // is incompatible with it.
+  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
+  // with irreducible loops.
   bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
   bool is_r6 = GetInstructionSetFeatures().IsR6();
   bool fallback_load = has_irreducible_loops && !is_r6;
@@ -7093,12 +7093,14 @@
   HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
   // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
   // is incompatible with it.
+  // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods
+  // with irreducible loops.
   bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
   bool is_r6 = GetInstructionSetFeatures().IsR6();
   bool fallback_load = has_irreducible_loops && !is_r6;
   switch (dispatch_info.method_load_kind) {
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative:
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry:
       break;
     default:
       fallback_load = false;
@@ -7149,23 +7151,16 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
-      if (is_r6) {
-        uint32_t offset = invoke->GetDexCacheArrayOffset();
-        CodeGeneratorMIPS::PcRelativePatchInfo* info =
-            NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
-        bool reordering = __ SetReorder(false);
-        EmitPcRelativeAddressPlaceholderHigh(info, TMP, ZERO);
-        __ Lw(temp.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
-        __ SetReorder(reordering);
-      } else {
-        HMipsDexCacheArraysBase* base =
-            invoke->InputAt(invoke->GetSpecialInputIndex())->AsMipsDexCacheArraysBase();
-        int32_t offset =
-            invoke->GetDexCacheArrayOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset;
-        __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
-      }
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
+      PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
+      Register temp_reg = temp.AsRegister<Register>();
+      bool reordering = __ SetReorder(false);
+      EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+      __ Lw(temp_reg, TMP, /* placeholder */ 0x5678);
+      __ SetReorder(reordering);
       break;
+    }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
       GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
       return;  // No code pointer retrieval; the runtime performs the call directly.
@@ -8711,29 +8706,11 @@
   __ Nal();
   // Grab the return address off RA.
   __ Move(reg, RA);
-  // TODO: Can we share this code with that of VisitMipsDexCacheArraysBase()?
 
   // Remember this offset (the obtained PC value) for later use with constant area.
   __ BindPcRelBaseLabel();
 }
 
-void LocationsBuilderMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
-  locations->SetOut(Location::RequiresRegister());
-}
-
-void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
-  Register reg = base->GetLocations()->Out().AsRegister<Register>();
-  CodeGeneratorMIPS::PcRelativePatchInfo* info =
-      codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
-  CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
-  bool reordering = __ SetReorder(false);
-  // TODO: Reuse MipsComputeBaseMethodAddress on R2 instead of passing ZERO to force emitting NAL.
-  codegen_->EmitPcRelativeAddressPlaceholderHigh(info, reg, ZERO);
-  __ Addiu(reg, reg, /* placeholder */ 0x5678);
-  __ SetReorder(reordering);
-}
-
 void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
   // The trampoline uses the same calling convention as dex calling conventions,
   // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index d774219..e72e838d 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -585,12 +585,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
   PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
                                                 dex::StringIndex string_index);
-  PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
-                                                       uint32_t element_offset);
   Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
 
   void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, Register out, Register base);
@@ -645,10 +644,10 @@
 
   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
   Uint32ToLiteralMap uint32_literals_;
-  // PC-relative patch info for each HMipsDexCacheArraysBase.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
   // PC-relative type patch info for kBssEntry.
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index da43c4e..e4f1cbd 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -957,8 +957,8 @@
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       uint64_literals_(std::less<uint64_t>(),
                        graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -1440,14 +1440,12 @@
 void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_dex_cache_patches_.size() +
       pc_relative_method_patches_.size() +
+      method_bss_entry_patches_.size() +
       pc_relative_type_patches_.size() +
       type_bss_entry_patches_.size() +
       pc_relative_string_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_,
                                                                   linker_patches);
@@ -1461,6 +1459,8 @@
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
                                                                   linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   DCHECK_EQ(size, linker_patches->size());
@@ -1473,6 +1473,13 @@
                             &pc_relative_method_patches_);
 }
 
+CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewMethodBssEntryPatch(
+    MethodReference target_method) {
+  return NewPcRelativePatch(*target_method.dex_file,
+                            target_method.dex_method_index,
+                            &method_bss_entry_patches_);
+}
+
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeTypePatch(
     const DexFile& dex_file, dex::TypeIndex type_index) {
   return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
@@ -1488,11 +1495,6 @@
   return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
 }
 
-CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeDexCacheArrayPatch(
-    const DexFile& dex_file, uint32_t element_offset) {
-  return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
-}
-
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch(
     const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
   patches->emplace_back(dex_file, offset_or_index);
@@ -4949,10 +4951,9 @@
                      kLoadDoubleword,
                      DeduplicateUint64Literal(invoke->GetMethodAddress()));
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
-      uint32_t offset = invoke->GetDexCacheArrayOffset();
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
-          NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
+      PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
       EmitPcRelativeAddressPlaceholderHigh(info, AT);
       __ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
       break;
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 2e8af21..6260c73 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -551,12 +551,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
   PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
                                                 dex::StringIndex string_index);
-  PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
-                                                       uint32_t element_offset);
   PcRelativePatchInfo* NewPcRelativeCallPatch(const DexFile& dex_file,
                                               uint32_t method_index);
   Literal* DeduplicateBootImageAddressLiteral(uint64_t address);
@@ -609,10 +608,10 @@
   // Deduplication map for 64-bit literals, used for non-patchable method address or method code
   // address.
   Uint64ToLiteralMap uint64_literals_;
-  // PC-relative patch info.
-  ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
   // PC-relative type patch info for kBssEntry.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index ca921b8..83a261d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1032,8 +1032,8 @@
       move_resolver_(graph->GetArena(), this),
       assembler_(graph->GetArena()),
       isa_features_(isa_features),
-      pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+      method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
       string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
@@ -4553,16 +4553,14 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
       Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke,
                                                                 temp.AsRegister<Register>());
       __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
       // Bind a new fixup label at the end of the "movl" insn.
-      uint32_t offset = invoke->GetDexCacheArrayOffset();
-      __ Bind(NewPcRelativeDexCacheArrayPatch(
+      __ Bind(NewMethodBssEntryPatch(
           invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress(),
-          invoke->GetDexFileForPcRelativeDexCache(),
-          offset));
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())));
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -4629,6 +4627,16 @@
   __ Bind(&boot_image_method_patches_.back().label);
 }
 
+Label* CodeGeneratorX86::NewMethodBssEntryPatch(
+    HX86ComputeBaseMethodAddress* method_address,
+    MethodReference target_method) {
+  // Add the patch entry and bind its label at the end of the instruction.
+  method_bss_entry_patches_.emplace_back(method_address,
+                                         *target_method.dex_file,
+                                         target_method.dex_method_index);
+  return &method_bss_entry_patches_.back().label;
+}
+
 void CodeGeneratorX86::RecordBootTypePatch(HLoadClass* load_class) {
   HX86ComputeBaseMethodAddress* address = load_class->InputAt(0)->AsX86ComputeBaseMethodAddress();
   boot_image_type_patches_.emplace_back(address,
@@ -4663,15 +4671,6 @@
   return &string_patches_.back().label;
 }
 
-Label* CodeGeneratorX86::NewPcRelativeDexCacheArrayPatch(
-    HX86ComputeBaseMethodAddress* method_address,
-    const DexFile& dex_file,
-    uint32_t element_offset) {
-  // Add the patch entry and bind its label at the end of the instruction.
-  pc_relative_dex_cache_patches_.emplace_back(method_address, dex_file, element_offset);
-  return &pc_relative_dex_cache_patches_.back().label;
-}
-
 // The label points to the end of the "movl" or another instruction but the literal offset
 // for method patch needs to point to the embedded constant which occupies the last 4 bytes.
 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
@@ -4690,14 +4689,12 @@
 void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_dex_cache_patches_.size() +
       boot_image_method_patches_.size() +
+      method_bss_entry_patches_.size() +
       boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
       string_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_,
                                                                   linker_patches);
@@ -4709,6 +4706,8 @@
     DCHECK(boot_image_type_patches_.empty());
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   DCHECK_EQ(size, linker_patches->size());
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 689f93e..f48753b 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -415,13 +415,12 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
   void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
+  Label* NewMethodBssEntryPatch(HX86ComputeBaseMethodAddress* method_address,
+                                MethodReference target_method);
   void RecordBootTypePatch(HLoadClass* load_class);
   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
   void RecordBootStringPatch(HLoadString* load_string);
   Label* NewStringBssEntryPatch(HLoadString* load_string);
-  Label* NewPcRelativeDexCacheArrayPatch(HX86ComputeBaseMethodAddress* method_address,
-                                         const DexFile& dex_file,
-                                         uint32_t element_offset);
   Label* NewJitRootStringPatch(const DexFile& dex_file,
                                dex::StringIndex dex_index,
                                Handle<mirror::String> handle);
@@ -633,10 +632,10 @@
   X86Assembler assembler_;
   const X86InstructionSetFeatures& isa_features_;
 
-  // PC-relative DexCache access info.
-  ArenaDeque<X86PcRelativePatchInfo> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<X86PcRelativePatchInfo> boot_image_type_patches_;
   // Type patch locations for kBssEntry.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 148f551..7331a9e 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1002,12 +1002,12 @@
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress());
       break;
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
       __ movq(temp.AsRegister<CpuRegister>(),
               Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
       // Bind a new fixup label at the end of the "movl" insn.
-      uint32_t offset = invoke->GetDexCacheArrayOffset();
-      __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset));
+      __ Bind(NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())));
       break;
     }
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
@@ -1071,6 +1071,12 @@
   __ Bind(&boot_image_method_patches_.back().label);
 }
 
+Label* CodeGeneratorX86_64::NewMethodBssEntryPatch(MethodReference target_method) {
+  // Add a patch entry and return the label.
+  method_bss_entry_patches_.emplace_back(*target_method.dex_file, target_method.dex_method_index);
+  return &method_bss_entry_patches_.back().label;
+}
+
 void CodeGeneratorX86_64::RecordBootTypePatch(HLoadClass* load_class) {
   boot_image_type_patches_.emplace_back(load_class->GetDexFile(),
                                         load_class->GetTypeIndex().index_);
@@ -1094,13 +1100,6 @@
   return &string_patches_.back().label;
 }
 
-Label* CodeGeneratorX86_64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
-                                                            uint32_t element_offset) {
-  // Add a patch entry and return the label.
-  pc_relative_dex_cache_patches_.emplace_back(dex_file, element_offset);
-  return &pc_relative_dex_cache_patches_.back().label;
-}
-
 // The label points to the end of the "movl" or another instruction but the literal offset
 // for method patch needs to point to the embedded constant which occupies the last 4 bytes.
 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
@@ -1119,14 +1118,12 @@
 void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
-      pc_relative_dex_cache_patches_.size() +
       boot_image_method_patches_.size() +
+      method_bss_entry_patches_.size() +
       boot_image_type_patches_.size() +
       type_bss_entry_patches_.size() +
       string_patches_.size();
   linker_patches->reserve(size);
-  EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
-                                                               linker_patches);
   if (GetCompilerOptions().IsBootImage()) {
     EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_,
                                                                   linker_patches);
@@ -1138,6 +1135,8 @@
     DCHECK(boot_image_type_patches_.empty());
     EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches);
   }
+  EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_,
+                                                                linker_patches);
   EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
                                                               linker_patches);
   DCHECK_EQ(size, linker_patches->size());
@@ -1226,8 +1225,8 @@
         assembler_(graph->GetArena()),
         isa_features_(isa_features),
         constant_area_start_(0),
-        pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
         boot_image_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+        method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
         boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
         type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
         string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 31debde..33c6429 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -410,11 +410,11 @@
       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
 
   void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke);
+  Label* NewMethodBssEntryPatch(MethodReference target_method);
   void RecordBootTypePatch(HLoadClass* load_class);
   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
   void RecordBootStringPatch(HLoadString* load_string);
   Label* NewStringBssEntryPatch(HLoadString* load_string);
-  Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
   Label* NewJitRootStringPatch(const DexFile& dex_file,
                                dex::StringIndex dex_index,
                                Handle<mirror::String> handle);
@@ -603,10 +603,10 @@
   // Used for fixups to the constant area.
   int constant_area_start_;
 
-  // PC-relative DexCache access info.
-  ArenaDeque<PatchInfo<Label>> pc_relative_dex_cache_patches_;
   // PC-relative method patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PatchInfo<Label>> boot_image_method_patches_;
+  // PC-relative method patch info for kBssEntry.
+  ArenaDeque<PatchInfo<Label>> method_bss_entry_patches_;
   // PC-relative type patch info for kBootImageLinkTimePcRelative.
   ArenaDeque<PatchInfo<Label>> boot_image_type_patches_;
   // Type patch locations for kBssEntry.
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc
deleted file mode 100644
index 0c832a5..0000000
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_cache_array_fixups_arm.h"
-
-#include "base/arena_containers.h"
-#ifdef ART_USE_OLD_ARM_BACKEND
-#include "code_generator_arm.h"
-#include "intrinsics_arm.h"
-#else
-#include "code_generator_arm_vixl.h"
-#include "intrinsics_arm_vixl.h"
-#endif
-#include "utils/dex_cache_arrays_layout-inl.h"
-
-namespace art {
-namespace arm {
-#ifdef ART_USE_OLD_ARM_BACKEND
-typedef CodeGeneratorARM CodeGeneratorARMType;
-typedef IntrinsicLocationsBuilderARM IntrinsicLocationsBuilderARMType;
-#else
-typedef CodeGeneratorARMVIXL CodeGeneratorARMType;
-typedef IntrinsicLocationsBuilderARMVIXL IntrinsicLocationsBuilderARMType;
-#endif
-
-/**
- * Finds instructions that need the dex cache arrays base as an input.
- */
-class DexCacheArrayFixupsVisitor : public HGraphVisitor {
- public:
-  DexCacheArrayFixupsVisitor(HGraph* graph, CodeGenerator* codegen)
-      : HGraphVisitor(graph),
-        codegen_(down_cast<CodeGeneratorARMType*>(codegen)),
-        dex_cache_array_bases_(std::less<const DexFile*>(),
-                               // Attribute memory use to code generator.
-                               graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {}
-
-  void MoveBasesIfNeeded() {
-    for (const auto& entry : dex_cache_array_bases_) {
-      // Bring the base closer to the first use (previously, it was in the
-      // entry block) and relieve some pressure on the register allocator
-      // while avoiding recalculation of the base in a loop.
-      HArmDexCacheArraysBase* base = entry.second;
-      base->MoveBeforeFirstUserAndOutOfLoops();
-    }
-  }
-
- private:
-  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
-    // If this is an invoke with PC-relative access to the dex cache methods array,
-    // we need to add the dex cache arrays base as the special input.
-    if (invoke->HasPcRelativeDexCache() &&
-        !IsCallFreeIntrinsic<IntrinsicLocationsBuilderARMType>(invoke, codegen_)) {
-      HArmDexCacheArraysBase* base =
-          GetOrCreateDexCacheArrayBase(invoke, invoke->GetDexFileForPcRelativeDexCache());
-      // Update the element offset in base.
-      DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFileForPcRelativeDexCache());
-      base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
-      // Add the special argument base to the method.
-      DCHECK(!invoke->HasCurrentMethodInput());
-      invoke->AddSpecialInput(base);
-    }
-  }
-
-  HArmDexCacheArraysBase* GetOrCreateDexCacheArrayBase(HInstruction* cursor,
-                                                       const DexFile& dex_file) {
-    if (GetGraph()->HasIrreducibleLoops()) {
-      HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file);
-      cursor->GetBlock()->InsertInstructionBefore(base, cursor);
-      return base;
-    } else {
-      // Ensure we only initialize the pointer once for each dex file.
-      auto lb = dex_cache_array_bases_.lower_bound(&dex_file);
-      if (lb != dex_cache_array_bases_.end() &&
-          !dex_cache_array_bases_.key_comp()(&dex_file, lb->first)) {
-        return lb->second;
-      }
-
-      // Insert the base at the start of the entry block, move it to a better
-      // position later in MoveBaseIfNeeded().
-      HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file);
-      HBasicBlock* entry_block = GetGraph()->GetEntryBlock();
-      entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction());
-      dex_cache_array_bases_.PutBefore(lb, &dex_file, base);
-      return base;
-    }
-  }
-
-  CodeGeneratorARMType* codegen_;
-
-  using DexCacheArraysBaseMap =
-      ArenaSafeMap<const DexFile*, HArmDexCacheArraysBase*, std::less<const DexFile*>>;
-  DexCacheArraysBaseMap dex_cache_array_bases_;
-};
-
-void DexCacheArrayFixups::Run() {
-  DexCacheArrayFixupsVisitor visitor(graph_, codegen_);
-  visitor.VisitInsertionOrder();
-  visitor.MoveBasesIfNeeded();
-}
-
-}  // namespace arm
-}  // namespace art
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.h b/compiler/optimizing/dex_cache_array_fixups_arm.h
deleted file mode 100644
index 9d67a31..0000000
--- a/compiler/optimizing/dex_cache_array_fixups_arm.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_
-#define ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_
-
-#include "nodes.h"
-#include "optimization.h"
-
-namespace art {
-
-class CodeGenerator;
-
-namespace arm {
-
-class DexCacheArrayFixups : public HOptimization {
- public:
-  DexCacheArrayFixups(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats)
-      : HOptimization(graph, kDexCacheArrayFixupsArmPassName, stats),
-        codegen_(codegen) {}
-
-  static constexpr const char* kDexCacheArrayFixupsArmPassName = "dex_cache_array_fixups_arm";
-
-  void Run() OVERRIDE;
-
- private:
-  CodeGenerator* codegen_;
-};
-
-}  // namespace arm
-}  // namespace art
-
-#endif  // ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc
deleted file mode 100644
index 7734f91..0000000
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "code_generator_mips.h"
-#include "dex_cache_array_fixups_mips.h"
-
-#include "base/arena_containers.h"
-#include "intrinsics_mips.h"
-#include "utils/dex_cache_arrays_layout-inl.h"
-
-namespace art {
-namespace mips {
-
-/**
- * Finds instructions that need the dex cache arrays base as an input.
- */
-class DexCacheArrayFixupsVisitor : public HGraphVisitor {
- public:
-  explicit DexCacheArrayFixupsVisitor(HGraph* graph, CodeGenerator* codegen)
-      : HGraphVisitor(graph),
-        codegen_(down_cast<CodeGeneratorMIPS*>(codegen)),
-        dex_cache_array_bases_(std::less<const DexFile*>(),
-                               // Attribute memory use to code generator.
-                               graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {}
-
-  void MoveBasesIfNeeded() {
-    for (const auto& entry : dex_cache_array_bases_) {
-      // Bring the base closer to the first use (previously, it was in the
-      // entry block) and relieve some pressure on the register allocator
-      // while avoiding recalculation of the base in a loop.
-      HMipsDexCacheArraysBase* base = entry.second;
-      base->MoveBeforeFirstUserAndOutOfLoops();
-    }
-    // Computing the dex cache base for PC-relative accesses will clobber RA with
-    // the NAL instruction on R2. Take a note of this before generating the method
-    // entry.
-    if (!dex_cache_array_bases_.empty()) {
-      codegen_->ClobberRA();
-    }
-  }
-
- private:
-  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
-    // If this is an invoke with PC-relative access to the dex cache methods array,
-    // we need to add the dex cache arrays base as the special input.
-    if (invoke->HasPcRelativeDexCache() &&
-        !IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) {
-      // Initialize base for target method dex file if needed.
-      HMipsDexCacheArraysBase* base =
-          GetOrCreateDexCacheArrayBase(invoke->GetDexFileForPcRelativeDexCache());
-      // Update the element offset in base.
-      DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFileForPcRelativeDexCache());
-      base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
-      // Add the special argument base to the method.
-      DCHECK(!invoke->HasCurrentMethodInput());
-      invoke->AddSpecialInput(base);
-    }
-  }
-
-  HMipsDexCacheArraysBase* GetOrCreateDexCacheArrayBase(const DexFile& dex_file) {
-    return dex_cache_array_bases_.GetOrCreate(
-        &dex_file,
-        [this, &dex_file]() {
-          HMipsDexCacheArraysBase* base =
-              new (GetGraph()->GetArena()) HMipsDexCacheArraysBase(dex_file);
-          HBasicBlock* entry_block = GetGraph()->GetEntryBlock();
-          // Insert the base at the start of the entry block, move it to a better
-          // position later in MoveBaseIfNeeded().
-          entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction());
-          return base;
-        });
-  }
-
-  CodeGeneratorMIPS* codegen_;
-
-  using DexCacheArraysBaseMap =
-      ArenaSafeMap<const DexFile*, HMipsDexCacheArraysBase*, std::less<const DexFile*>>;
-  DexCacheArraysBaseMap dex_cache_array_bases_;
-};
-
-void DexCacheArrayFixups::Run() {
-  CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen_);
-  if (mips_codegen->GetInstructionSetFeatures().IsR6()) {
-    // Do nothing for R6 because it has PC-relative addressing.
-    return;
-  }
-  if (graph_->HasIrreducibleLoops()) {
-    // Do not run this optimization, as irreducible loops do not work with an instruction
-    // that can be live-in at the irreducible loop header.
-    return;
-  }
-  DexCacheArrayFixupsVisitor visitor(graph_, codegen_);
-  visitor.VisitInsertionOrder();
-  visitor.MoveBasesIfNeeded();
-}
-
-}  // namespace mips
-}  // namespace art
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.h b/compiler/optimizing/dex_cache_array_fixups_mips.h
deleted file mode 100644
index 861a199..0000000
--- a/compiler/optimizing/dex_cache_array_fixups_mips.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_
-#define ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_
-
-#include "nodes.h"
-#include "optimization.h"
-
-namespace art {
-
-class CodeGenerator;
-
-namespace mips {
-
-class DexCacheArrayFixups : public HOptimization {
- public:
-  DexCacheArrayFixups(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats)
-      : HOptimization(graph, kDexCacheArrayFixupsMipsPassName, stats),
-        codegen_(codegen) {}
-
-  static constexpr const char* kDexCacheArrayFixupsMipsPassName = "dex_cache_array_fixups_mips";
-
-  void Run() OVERRIDE;
-
- private:
-  CodeGenerator* codegen_;
-};
-
-}  // namespace mips
-}  // namespace art
-
-#endif  // ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index e53209f..d0047c5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2643,8 +2643,8 @@
       return os << "BootImageLinkTimePcRelative";
     case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
       return os << "DirectAddress";
-    case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
-      return os << "DexCachePcRelative";
+    case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry:
+      return os << "BssEntry";
     case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall:
       return os << "RuntimeCall";
     default:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 74bb2ab..2867797 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1410,12 +1410,7 @@
   M(IntermediateAddressIndex, Instruction)
 #endif
 
-#ifndef ART_ENABLE_CODEGEN_arm
 #define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M)
-#else
-#define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M)                            \
-  M(ArmDexCacheArraysBase, Instruction)
-#endif
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)
 
@@ -1424,7 +1419,6 @@
 #else
 #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M)                           \
   M(MipsComputeBaseMethodAddress, Instruction)                          \
-  M(MipsDexCacheArraysBase, Instruction)                                \
   M(MipsPackedSwitch, Instruction)
 #endif
 
@@ -4166,11 +4160,9 @@
     // Used for app->boot calls with non-relocatable image and for JIT-compiled calls.
     kDirectAddress,
 
-    // Load from resolved methods array in the dex cache using a PC-relative load.
-    // Used when we need to use the dex cache, for example for invoke-static that
-    // may cause class initialization (the entry may point to a resolution method),
-    // and we know that we can access the dex cache arrays using a PC-relative load.
-    kDexCachePcRelative,
+    // Load from an entry in the .bss section using a PC-relative load.
+    // Used for classes outside boot image when .bss is accessible with a PC-relative load.
+    kBssEntry,
 
     // Make a runtime call to resolve and call the method. This is the last-resort-kind
     // used when other kinds are unimplemented on a particular architecture.
@@ -4195,7 +4187,6 @@
     //   - thread entrypoint offset for kStringInit method if this is a string init invoke.
     //     Note that there are multiple string init methods, each having its own offset.
     //   - the method address for kDirectAddress
-    //   - the dex cache arrays offset for kDexCachePcRel.
     uint64_t method_load_data;
   };
 
@@ -4296,12 +4287,9 @@
   bool NeedsDexCacheOfDeclaringClass() const OVERRIDE;
   bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; }
   bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; }
-  bool HasPcRelativeDexCache() const {
-    return GetMethodLoadKind() == MethodLoadKind::kDexCachePcRelative;
-  }
   bool HasPcRelativeMethodLoadKind() const {
     return GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative ||
-           GetMethodLoadKind() == MethodLoadKind::kDexCachePcRelative;
+           GetMethodLoadKind() == MethodLoadKind::kBssEntry;
   }
   bool HasCurrentMethodInput() const {
     // This function can be called only after the invoke has been fully initialized by the builder.
@@ -4325,11 +4313,6 @@
     return dispatch_info_.method_load_data;
   }
 
-  uint32_t GetDexCacheArrayOffset() const {
-    DCHECK(HasPcRelativeDexCache());
-    return dispatch_info_.method_load_data;
-  }
-
   const DexFile& GetDexFileForPcRelativeDexCache() const;
 
   ClinitCheckRequirement GetClinitCheckRequirement() const {
@@ -6879,9 +6862,6 @@
 #if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64)
 #include "nodes_shared.h"
 #endif
-#ifdef ART_ENABLE_CODEGEN_arm
-#include "nodes_arm.h"
-#endif
 #ifdef ART_ENABLE_CODEGEN_mips
 #include "nodes_mips.h"
 #endif
diff --git a/compiler/optimizing/nodes_arm.h b/compiler/optimizing/nodes_arm.h
deleted file mode 100644
index d9f9740e..0000000
--- a/compiler/optimizing/nodes_arm.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_NODES_ARM_H_
-#define ART_COMPILER_OPTIMIZING_NODES_ARM_H_
-
-namespace art {
-
-class HArmDexCacheArraysBase FINAL : public HExpression<0> {
- public:
-  explicit HArmDexCacheArraysBase(const DexFile& dex_file)
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc),
-        dex_file_(&dex_file),
-        element_offset_(static_cast<size_t>(-1)) { }
-
-  bool CanBeMoved() const OVERRIDE { return true; }
-
-  void UpdateElementOffset(size_t element_offset) {
-    // Use the lowest offset from the requested elements so that all offsets from
-    // this base are non-negative because our assemblers emit negative-offset loads
-    // as a sequence of two or more instructions. (However, positive offsets beyond
-    // 4KiB also require two or more instructions, so this simple heuristic could
-    // be improved for cases where there is a dense cluster of elements far from
-    // the lowest offset. This is expected to be rare enough though, so we choose
-    // not to spend compile time on elaborate calculations.)
-    element_offset_ = std::min(element_offset_, element_offset);
-  }
-
-  const DexFile& GetDexFile() const {
-    return *dex_file_;
-  }
-
-  size_t GetElementOffset() const {
-    return element_offset_;
-  }
-
-  DECLARE_INSTRUCTION(ArmDexCacheArraysBase);
-
- private:
-  const DexFile* dex_file_;
-  size_t element_offset_;
-
-  DISALLOW_COPY_AND_ASSIGN(HArmDexCacheArraysBase);
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_OPTIMIZING_NODES_ARM_H_
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index 36431c1..8e439d9 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -34,38 +34,6 @@
   DISALLOW_COPY_AND_ASSIGN(HMipsComputeBaseMethodAddress);
 };
 
-class HMipsDexCacheArraysBase : public HExpression<0> {
- public:
-  explicit HMipsDexCacheArraysBase(const DexFile& dex_file)
-      : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc),
-        dex_file_(&dex_file),
-        element_offset_(static_cast<size_t>(-1)) { }
-
-  bool CanBeMoved() const OVERRIDE { return true; }
-
-  void UpdateElementOffset(size_t element_offset) {
-    // We'll maximize the range of a single load instruction for dex cache array accesses
-    // by aligning offset -32768 with the offset of the first used element.
-    element_offset_ = std::min(element_offset_, element_offset);
-  }
-
-  const DexFile& GetDexFile() const {
-    return *dex_file_;
-  }
-
-  size_t GetElementOffset() const {
-    return element_offset_;
-  }
-
-  DECLARE_INSTRUCTION(MipsDexCacheArraysBase);
-
- private:
-  const DexFile* dex_file_;
-  size_t element_offset_;
-
-  DISALLOW_COPY_AND_ASSIGN(HMipsDexCacheArraysBase);
-};
-
 // Mips version of HPackedSwitch that holds a pointer to the base method address.
 class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> {
  public:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index e5ab00b..890ba67 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -24,16 +24,11 @@
 
 #include "android-base/strings.h"
 
-#ifdef ART_ENABLE_CODEGEN_arm
-#include "dex_cache_array_fixups_arm.h"
-#endif
-
 #ifdef ART_ENABLE_CODEGEN_arm64
 #include "instruction_simplifier_arm64.h"
 #endif
 
 #ifdef ART_ENABLE_CODEGEN_mips
-#include "dex_cache_array_fixups_mips.h"
 #include "pc_relative_fixups_mips.h"
 #endif
 
@@ -522,8 +517,6 @@
   } else if (opt_name == CodeSinking::kCodeSinkingPassName) {
     return new (arena) CodeSinking(graph, stats);
 #ifdef ART_ENABLE_CODEGEN_arm
-  } else if (opt_name == arm::DexCacheArrayFixups::kDexCacheArrayFixupsArmPassName) {
-    return new (arena) arm::DexCacheArrayFixups(graph, codegen, stats);
   } else if (opt_name == arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName) {
     return new (arena) arm::InstructionSimplifierArm(graph, stats);
 #endif
@@ -532,8 +525,6 @@
     return new (arena) arm64::InstructionSimplifierArm64(graph, stats);
 #endif
 #ifdef ART_ENABLE_CODEGEN_mips
-  } else if (opt_name == mips::DexCacheArrayFixups::kDexCacheArrayFixupsMipsPassName) {
-    return new (arena) mips::DexCacheArrayFixups(graph, codegen, stats);
   } else if (opt_name == mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName) {
     return new (arena) mips::PcRelativeFixups(graph, codegen, stats);
 #endif
@@ -641,8 +632,6 @@
 #if defined(ART_ENABLE_CODEGEN_arm)
     case kThumb2:
     case kArm: {
-      arm::DexCacheArrayFixups* fixups =
-          new (arena) arm::DexCacheArrayFixups(graph, codegen, stats);
       arm::InstructionSimplifierArm* simplifier =
           new (arena) arm::InstructionSimplifierArm(graph, stats);
       SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
@@ -653,7 +642,6 @@
         simplifier,
         side_effects,
         gvn,
-        fixups,
         scheduling,
       };
       RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer);
@@ -682,11 +670,8 @@
     case kMips: {
       mips::PcRelativeFixups* pc_relative_fixups =
           new (arena) mips::PcRelativeFixups(graph, codegen, stats);
-      mips::DexCacheArrayFixups* dex_cache_array_fixups =
-          new (arena) mips::DexCacheArrayFixups(graph, codegen, stats);
       HOptimization* mips_optimizations[] = {
           pc_relative_fixups,
-          dex_cache_array_fixups
       };
       RunOptimizations(mips_optimizations, arraysize(mips_optimizations), pass_observer);
       break;
diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc
index bce54bf..21b6452 100644
--- a/compiler/optimizing/pc_relative_fixups_mips.cc
+++ b/compiler/optimizing/pc_relative_fixups_mips.cc
@@ -59,10 +59,9 @@
   }
 
   void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
-    // If this is an invoke with PC-relative pointer to a method,
+    // If this is an invoke with PC-relative load kind,
     // we need to add the base as the special input.
-    if (invoke->GetMethodLoadKind() ==
-            HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative &&
+    if (invoke->HasPcRelativeMethodLoadKind() &&
         !IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) {
       InitializePCRelativeBasePointer();
       // Add the special argument base to the method.
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index 832a7e1..e78cd78 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -818,10 +818,5 @@
   }
 }
 
-void SchedulingLatencyVisitorARM::VisitArmDexCacheArraysBase(art::HArmDexCacheArraysBase*) {
-  last_visited_internal_latency_ = kArmIntegerOpLatency;
-  last_visited_latency_ = kArmIntegerOpLatency;
-}
-
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 106b709..8bd568b 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -128,15 +128,8 @@
     method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative;
     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
   } else {
-    // Use PC-relative access to the dex cache arrays.
-    method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative;
-    // Note: we use the invoke's graph instead of the codegen graph, which are
-    // different when inlining (the codegen graph is the most outer graph). The
-    // invoke's dex method index is relative to the dex file where the invoke's graph
-    // was built from.
-    DexCacheArraysLayout layout(GetInstructionSetPointerSize(codegen->GetInstructionSet()),
-                                &invoke->GetBlock()->GetGraph()->GetDexFile());
-    method_load_data = layout.MethodOffset(invoke->GetDexMethodIndex());
+    // Use PC-relative access to the .bss methods arrays.
+    method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry;
     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
   }