Split RelativePatcher::ReserveSpace() into two.

Instead of passing nullptr and MethodReference(nullptr, 0u)
to ReserveSpace() at the end, call a newly created function
ReserveSpaceEnd().

Change-Id: I38815fe9464b4e1a919878b6e8577614f1058d00
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc
index 2eae2a8..ceace82 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.cc
+++ b/compiler/linker/arm/relative_patcher_arm_base.cc
@@ -29,6 +29,21 @@
   return ReserveSpaceInternal(offset, compiled_method, method_ref, 0u);
 }
 
+uint32_t ArmBaseRelativePatcher::ReserveSpaceEnd(uint32_t offset) {
+  // NOTE: The final thunk can be reserved from InitCodeMethodVisitor::EndClass() while it
+  // may be written early by WriteCodeMethodVisitor::VisitMethod() for a deduplicated chunk
+  // of code. To avoid any alignment discrepancies for the final chunk, we always align the
+  // offset after reserving of writing any chunk.
+  uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
+  bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset, MethodReference(nullptr, 0u),
+                                                aligned_offset);
+  if (needs_thunk) {
+    thunk_locations_.push_back(aligned_offset);
+    offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_);
+  }
+  return offset;
+}
+
 uint32_t ArmBaseRelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) {
   if (current_thunk_to_write_ == thunk_locations_.size()) {
     return offset;
@@ -69,20 +84,6 @@
                                                       const CompiledMethod* compiled_method,
                                                       MethodReference method_ref,
                                                       uint32_t max_extra_space) {
-  // NOTE: The final thunk can be reserved from InitCodeMethodVisitor::EndClass() while it
-  // may be written early by WriteCodeMethodVisitor::VisitMethod() for a deduplicated chunk
-  // of code. To avoid any alignment discrepancies for the final chunk, we always align the
-  // offset after reserving of writing any chunk.
-  if (UNLIKELY(compiled_method == nullptr)) {
-    uint32_t aligned_offset = CompiledMethod::AlignCode(offset, instruction_set_);
-    DCHECK(method_ref.dex_file == nullptr && method_ref.dex_method_index == 0u);
-    bool needs_thunk = ReserveSpaceProcessPatches(aligned_offset, method_ref, aligned_offset);
-    if (needs_thunk) {
-      thunk_locations_.push_back(aligned_offset);
-      offset = CompiledMethod::AlignCode(aligned_offset + thunk_code_.size(), instruction_set_);
-    }
-    return offset;
-  }
   DCHECK(compiled_method->GetQuickCode() != nullptr);
   uint32_t quick_code_size = compiled_method->GetQuickCode()->size();
   uint32_t quick_code_offset = compiled_method->AlignCode(offset) + sizeof(OatQuickMethodHeader);
diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h
index 78bc941..f80dd96 100644
--- a/compiler/linker/arm/relative_patcher_arm_base.h
+++ b/compiler/linker/arm/relative_patcher_arm_base.h
@@ -29,6 +29,7 @@
  public:
   uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method,
                         MethodReference method_ref) OVERRIDE;
+  uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE;
   uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE;
 
  protected:
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index b61b3d8..1cbe481 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -58,12 +58,11 @@
   // Count the number of ADRP insns as the upper bound on the number of thunks needed
   // and use it to reserve space for other linker patches.
   size_t num_adrp = 0u;
-  if (LIKELY(compiled_method != nullptr)) {
-    for (const LinkerPatch& patch : compiled_method->GetPatches()) {
-      if (patch.Type() == kLinkerPatchDexCacheArray &&
-          patch.LiteralOffset() == patch.PcInsnOffset()) {  // ADRP patch
-        ++num_adrp;
-      }
+  DCHECK(compiled_method != nullptr);
+  for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+    if (patch.Type() == kLinkerPatchDexCacheArray &&
+        patch.LiteralOffset() == patch.PcInsnOffset()) {  // ADRP patch
+      ++num_adrp;
     }
   }
   offset = ReserveSpaceInternal(offset, compiled_method, method_ref, kAdrpThunkSize * num_adrp);
@@ -90,6 +89,20 @@
   return offset;
 }
 
+uint32_t Arm64RelativePatcher::ReserveSpaceEnd(uint32_t offset) {
+  if (!fix_cortex_a53_843419_) {
+    DCHECK(adrp_thunk_locations_.empty());
+  } else {
+    // Add thunks for the last method if any.
+    if (reserved_adrp_thunks_ != adrp_thunk_locations_.size()) {
+      size_t num_adrp_thunks = adrp_thunk_locations_.size() - reserved_adrp_thunks_;
+      offset = CompiledMethod::AlignCode(offset, kArm64) + kAdrpThunkSize * num_adrp_thunks;
+      reserved_adrp_thunks_ = adrp_thunk_locations_.size();
+    }
+  }
+  return ArmBaseRelativePatcher::ReserveSpaceEnd(offset);
+}
+
 uint32_t Arm64RelativePatcher::WriteThunks(OutputStream* out, uint32_t offset) {
   if (fix_cortex_a53_843419_) {
     if (!current_method_thunks_.empty()) {
diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h
index b2a1da5..2d07e75 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.h
+++ b/compiler/linker/arm64/relative_patcher_arm64.h
@@ -30,6 +30,7 @@
 
   uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method,
                         MethodReference method_ref) OVERRIDE;
+  uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE;
   uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE;
   void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset,
                  uint32_t patch_offset, uint32_t target_offset) OVERRIDE;
diff --git a/compiler/linker/relative_patcher.cc b/compiler/linker/relative_patcher.cc
index 71f38b4..8ee87aa 100644
--- a/compiler/linker/relative_patcher.cc
+++ b/compiler/linker/relative_patcher.cc
@@ -38,6 +38,10 @@
       return offset;  // No space reserved; no patches expected.
     }
 
+    uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE {
+      return offset;  // No space reserved; no patches expected.
+    }
+
     uint32_t WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) OVERRIDE {
       return offset;  // No thunks added; no patches expected.
     }
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
index 7a78254..8a9f3f8 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -82,11 +82,13 @@
     return size_misc_thunks_;
   }
 
-  // Reserve space for relative call thunks if needed, return adjusted offset. After all methods
-  // of a class have been processed it's called one last time with compiled_method == nullptr.
+  // Reserve space for thunks if needed before a method, return adjusted offset.
   virtual uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method,
                                 MethodReference method_ref) = 0;
 
+  // Reserve space for thunks if needed after the last method, return adjusted offset.
+  virtual uint32_t ReserveSpaceEnd(uint32_t offset) = 0;
+
   // Write relative call thunks if needed, return adjusted offset.
   virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0;
 
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index dede42e..08167b3 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -98,7 +98,7 @@
       method_offset_map_.map.Put(compiled_method_refs_[idx], quick_code_offset);
       ++idx;
     }
-    offset = patcher_->ReserveSpace(offset, nullptr, MethodReference(nullptr, 0u));
+    offset = patcher_->ReserveSpaceEnd(offset);
     uint32_t output_size = offset;
     output_.reserve(output_size);
 
diff --git a/compiler/linker/x86/relative_patcher_x86_base.cc b/compiler/linker/x86/relative_patcher_x86_base.cc
index ea3472d..bc285a7 100644
--- a/compiler/linker/x86/relative_patcher_x86_base.cc
+++ b/compiler/linker/x86/relative_patcher_x86_base.cc
@@ -26,6 +26,10 @@
   return offset;  // No space reserved; no limit on relative call distance.
 }
 
+uint32_t X86BaseRelativePatcher::ReserveSpaceEnd(uint32_t offset) {
+  return offset;  // No space reserved; no limit on relative call distance.
+}
+
 uint32_t X86BaseRelativePatcher::WriteThunks(OutputStream* out ATTRIBUTE_UNUSED, uint32_t offset) {
   return offset;  // No thunks added; no limit on relative call distance.
 }
diff --git a/compiler/linker/x86/relative_patcher_x86_base.h b/compiler/linker/x86/relative_patcher_x86_base.h
index 1f38cf2..9200709 100644
--- a/compiler/linker/x86/relative_patcher_x86_base.h
+++ b/compiler/linker/x86/relative_patcher_x86_base.h
@@ -27,6 +27,7 @@
   uint32_t ReserveSpace(uint32_t offset,
                         const CompiledMethod* compiled_method,
                         MethodReference method_ref) OVERRIDE;
+  uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE;
   uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE;
   void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset,
                  uint32_t patch_offset, uint32_t target_offset) OVERRIDE;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index e15890f..baa6210 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -357,8 +357,7 @@
   bool EndClass() {
     OatDexMethodVisitor::EndClass();
     if (oat_class_index_ == writer_->oat_classes_.size()) {
-      offset_ = writer_->relative_patcher_->ReserveSpace(offset_, nullptr,
-                                                         MethodReference(nullptr, 0u));
+      offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
     }
     return true;
   }