Implement method calls using relative BL on ARM.

Store the linker patches with each CompiledMethod instead of
keeping them in CompilerDriver. Reorganize oat file creation
to apply the patches as we're writing the method code. Add
framework for platform-specific relative call patches in the
OatWriter. Implement relative call patches for ARM.

Change-Id: Ie2effb3d92b61ac8f356140eba09dc37d62290f8
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 990c1c8..cdb816d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -342,6 +342,8 @@
       freezing_constructor_lock_("freezing constructor lock"),
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
+      compiled_methods_(),
+      non_relative_linker_patch_count_(0u),
       image_(image),
       image_classes_(image_classes),
       thread_count_(thread_count),
@@ -426,18 +428,6 @@
     MutexLock mu(self, compiled_methods_lock_);
     STLDeleteValues(&compiled_methods_);
   }
-  {
-    MutexLock mu(self, compiled_methods_lock_);
-    STLDeleteElements(&code_to_patch_);
-  }
-  {
-    MutexLock mu(self, compiled_methods_lock_);
-    STLDeleteElements(&methods_to_patch_);
-  }
-  {
-    MutexLock mu(self, compiled_methods_lock_);
-    STLDeleteElements(&classes_to_patch_);
-  }
   CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
   compiler_->UnInit();
 }
@@ -1320,77 +1310,6 @@
   return result;
 }
 
-void CompilerDriver::AddCodePatch(const DexFile* dex_file,
-                                  uint16_t referrer_class_def_idx,
-                                  uint32_t referrer_method_idx,
-                                  InvokeType referrer_invoke_type,
-                                  uint32_t target_method_idx,
-                                  const DexFile* target_dex_file,
-                                  InvokeType target_invoke_type,
-                                  size_t literal_offset) {
-  MutexLock mu(Thread::Current(), compiled_methods_lock_);
-  code_to_patch_.push_back(new CallPatchInformation(dex_file,
-                                                    referrer_class_def_idx,
-                                                    referrer_method_idx,
-                                                    referrer_invoke_type,
-                                                    target_method_idx,
-                                                    target_dex_file,
-                                                    target_invoke_type,
-                                                    literal_offset));
-}
-void CompilerDriver::AddRelativeCodePatch(const DexFile* dex_file,
-                                          uint16_t referrer_class_def_idx,
-                                          uint32_t referrer_method_idx,
-                                          InvokeType referrer_invoke_type,
-                                          uint32_t target_method_idx,
-                                          const DexFile* target_dex_file,
-                                          InvokeType target_invoke_type,
-                                          size_t literal_offset,
-                                          int32_t pc_relative_offset) {
-  MutexLock mu(Thread::Current(), compiled_methods_lock_);
-  code_to_patch_.push_back(new RelativeCallPatchInformation(dex_file,
-                                                            referrer_class_def_idx,
-                                                            referrer_method_idx,
-                                                            referrer_invoke_type,
-                                                            target_method_idx,
-                                                            target_dex_file,
-                                                            target_invoke_type,
-                                                            literal_offset,
-                                                            pc_relative_offset));
-}
-void CompilerDriver::AddMethodPatch(const DexFile* dex_file,
-                                    uint16_t referrer_class_def_idx,
-                                    uint32_t referrer_method_idx,
-                                    InvokeType referrer_invoke_type,
-                                    uint32_t target_method_idx,
-                                    const DexFile* target_dex_file,
-                                    InvokeType target_invoke_type,
-                                    size_t literal_offset) {
-  MutexLock mu(Thread::Current(), compiled_methods_lock_);
-  methods_to_patch_.push_back(new CallPatchInformation(dex_file,
-                                                       referrer_class_def_idx,
-                                                       referrer_method_idx,
-                                                       referrer_invoke_type,
-                                                       target_method_idx,
-                                                       target_dex_file,
-                                                       target_invoke_type,
-                                                       literal_offset));
-}
-void CompilerDriver::AddClassPatch(const DexFile* dex_file,
-                                    uint16_t referrer_class_def_idx,
-                                    uint32_t referrer_method_idx,
-                                    uint32_t target_type_idx,
-                                    const DexFile* target_type_dex_file,
-                                    size_t literal_offset) {
-  MutexLock mu(Thread::Current(), compiled_methods_lock_);
-  classes_to_patch_.push_back(new TypePatchInformation(dex_file,
-                                                       referrer_class_def_idx,
-                                                       referrer_method_idx,
-                                                       target_type_idx,
-                                                       target_type_dex_file,
-                                                       literal_offset));
-}
-
 class ParallelCompilationManager {
  public:
   typedef void Callback(const ParallelCompilationManager* manager, size_t index);
@@ -2076,11 +1995,19 @@
 
   Thread* self = Thread::Current();
   if (compiled_method != nullptr) {
+    // Count non-relative linker patches.
+    size_t non_relative_linker_patch_count = 0u;
+    for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+      if (patch.Type() != kLinkerPatchCallRelative) {
+        ++non_relative_linker_patch_count;
+      }
+    }
     MethodReference ref(&dex_file, method_idx);
     DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
     {
       MutexLock mu(self, compiled_methods_lock_);
       compiled_methods_.Put(ref, compiled_method);
+      non_relative_linker_patch_count_ += non_relative_linker_patch_count;
     }
     DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
   }
@@ -2138,6 +2065,11 @@
   return it->second;
 }
 
+size_t CompilerDriver::GetNonRelativeLinkerPatchCount() const {
+  MutexLock mu(Thread::Current(), compiled_methods_lock_);
+  return non_relative_linker_patch_count_;
+}
+
 void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
                                                    uint16_t class_def_index) {
   WriterMutexLock mu(self, freezing_constructor_lock_);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e7bd357..c445683 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -169,6 +169,8 @@
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
+  size_t GetNonRelativeLinkerPatchCount() const
+      LOCKS_EXCLUDED(compiled_methods_lock_);
 
   void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
                                      uint16_t class_def_index);
@@ -313,43 +315,6 @@
   const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
   bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
 
-  // Record patch information for later fix up.
-  void AddCodePatch(const DexFile* dex_file,
-                    uint16_t referrer_class_def_idx,
-                    uint32_t referrer_method_idx,
-                    InvokeType referrer_invoke_type,
-                    uint32_t target_method_idx,
-                    const DexFile* target_dex_file,
-                    InvokeType target_invoke_type,
-                    size_t literal_offset)
-      LOCKS_EXCLUDED(compiled_methods_lock_);
-  void AddRelativeCodePatch(const DexFile* dex_file,
-                            uint16_t referrer_class_def_idx,
-                            uint32_t referrer_method_idx,
-                            InvokeType referrer_invoke_type,
-                            uint32_t target_method_idx,
-                            const DexFile* target_dex_file,
-                            InvokeType target_invoke_type,
-                            size_t literal_offset,
-                            int32_t pc_relative_offset)
-      LOCKS_EXCLUDED(compiled_methods_lock_);
-  void AddMethodPatch(const DexFile* dex_file,
-                      uint16_t referrer_class_def_idx,
-                      uint32_t referrer_method_idx,
-                      InvokeType referrer_invoke_type,
-                      uint32_t target_method_idx,
-                      const DexFile* target_dex_file,
-                      InvokeType target_invoke_type,
-                      size_t literal_offset)
-      LOCKS_EXCLUDED(compiled_methods_lock_);
-  void AddClassPatch(const DexFile* dex_file,
-                     uint16_t referrer_class_def_idx,
-                     uint32_t referrer_method_idx,
-                     uint32_t target_method_idx,
-                     const DexFile* target_dex_file,
-                     size_t literal_offset)
-      LOCKS_EXCLUDED(compiled_methods_lock_);
-
   bool GetSupportBootImageFixup() const {
     return support_boot_image_fixup_;
   }
@@ -386,9 +351,6 @@
     return thread_count_;
   }
 
-  class CallPatchInformation;
-  class TypePatchInformation;
-
   bool GetDumpPasses() const {
     return dump_passes_;
   }
@@ -397,189 +359,6 @@
     return timings_logger_;
   }
 
-  class PatchInformation {
-   public:
-    const DexFile& GetDexFile() const {
-      return *dex_file_;
-    }
-    uint16_t GetReferrerClassDefIdx() const {
-      return referrer_class_def_idx_;
-    }
-    uint32_t GetReferrerMethodIdx() const {
-      return referrer_method_idx_;
-    }
-    size_t GetLiteralOffset() const {
-      return literal_offset_;
-    }
-
-    virtual bool IsCall() const {
-      return false;
-    }
-    virtual bool IsType() const {
-      return false;
-    }
-    virtual const CallPatchInformation* AsCall() const {
-      LOG(FATAL) << "Unreachable";
-      return nullptr;
-    }
-    virtual const TypePatchInformation* AsType() const {
-      LOG(FATAL) << "Unreachable";
-      return nullptr;
-    }
-
-   protected:
-    PatchInformation(const DexFile* dex_file,
-                     uint16_t referrer_class_def_idx,
-                     uint32_t referrer_method_idx,
-                     size_t literal_offset)
-      : dex_file_(dex_file),
-        referrer_class_def_idx_(referrer_class_def_idx),
-        referrer_method_idx_(referrer_method_idx),
-        literal_offset_(literal_offset) {
-      CHECK(dex_file_ != nullptr);
-    }
-    virtual ~PatchInformation() {}
-
-    const DexFile* const dex_file_;
-    const uint16_t referrer_class_def_idx_;
-    const uint32_t referrer_method_idx_;
-    const size_t literal_offset_;
-
-    friend class CompilerDriver;
-  };
-
-  class CallPatchInformation : public PatchInformation {
-   public:
-    InvokeType GetReferrerInvokeType() const {
-      return referrer_invoke_type_;
-    }
-    uint32_t GetTargetMethodIdx() const {
-      return target_method_idx_;
-    }
-    const DexFile* GetTargetDexFile() const {
-      return target_dex_file_;
-    }
-    InvokeType GetTargetInvokeType() const {
-      return target_invoke_type_;
-    }
-
-    const CallPatchInformation* AsCall() const {
-      return this;
-    }
-    bool IsCall() const {
-      return true;
-    }
-    virtual bool IsRelative() const {
-      return false;
-    }
-    virtual int RelativeOffset() const {
-      return 0;
-    }
-
-   protected:
-    CallPatchInformation(const DexFile* dex_file,
-                         uint16_t referrer_class_def_idx,
-                         uint32_t referrer_method_idx,
-                         InvokeType referrer_invoke_type,
-                         uint32_t target_method_idx,
-                         const DexFile* target_dex_file,
-                         InvokeType target_invoke_type,
-                         size_t literal_offset)
-        : PatchInformation(dex_file, referrer_class_def_idx,
-                           referrer_method_idx, literal_offset),
-          referrer_invoke_type_(referrer_invoke_type),
-          target_method_idx_(target_method_idx),
-          target_dex_file_(target_dex_file),
-          target_invoke_type_(target_invoke_type) {
-    }
-
-   private:
-    const InvokeType referrer_invoke_type_;
-    const uint32_t target_method_idx_;
-    const DexFile* target_dex_file_;
-    const InvokeType target_invoke_type_;
-
-    friend class CompilerDriver;
-    DISALLOW_COPY_AND_ASSIGN(CallPatchInformation);
-  };
-
-  class RelativeCallPatchInformation : public CallPatchInformation {
-   public:
-    bool IsRelative() const {
-      return true;
-    }
-    int RelativeOffset() const {
-      return offset_;
-    }
-
-   private:
-    RelativeCallPatchInformation(const DexFile* dex_file,
-                                 uint16_t referrer_class_def_idx,
-                                 uint32_t referrer_method_idx,
-                                 InvokeType referrer_invoke_type,
-                                 uint32_t target_method_idx,
-                                 const DexFile* target_dex_file,
-                                 InvokeType target_invoke_type,
-                                 size_t literal_offset,
-                                 int32_t pc_relative_offset)
-        : CallPatchInformation(dex_file, referrer_class_def_idx,
-                           referrer_method_idx, referrer_invoke_type, target_method_idx,
-                           target_dex_file, target_invoke_type, literal_offset),
-          offset_(pc_relative_offset) {
-    }
-
-    const int offset_;
-
-    friend class CompilerDriver;
-    DISALLOW_COPY_AND_ASSIGN(RelativeCallPatchInformation);
-  };
-
-  class TypePatchInformation : public PatchInformation {
-   public:
-    const DexFile& GetTargetTypeDexFile() const {
-      return *target_type_dex_file_;
-    }
-
-    uint32_t GetTargetTypeIdx() const {
-      return target_type_idx_;
-    }
-
-    bool IsType() const {
-      return true;
-    }
-    const TypePatchInformation* AsType() const {
-      return this;
-    }
-
-   private:
-    TypePatchInformation(const DexFile* dex_file,
-                         uint16_t referrer_class_def_idx,
-                         uint32_t referrer_method_idx,
-                         uint32_t target_type_idx,
-                         const DexFile* target_type_dex_file,
-                         size_t literal_offset)
-        : PatchInformation(dex_file, referrer_class_def_idx,
-                           referrer_method_idx, literal_offset),
-          target_type_idx_(target_type_idx), target_type_dex_file_(target_type_dex_file) {
-    }
-
-    const uint32_t target_type_idx_;
-    const DexFile* target_type_dex_file_;
-
-    friend class CompilerDriver;
-    DISALLOW_COPY_AND_ASSIGN(TypePatchInformation);
-  };
-
-  const std::vector<const CallPatchInformation*>& GetCodeToPatch() const {
-    return code_to_patch_;
-  }
-  const std::vector<const CallPatchInformation*>& GetMethodsToPatch() const {
-    return methods_to_patch_;
-  }
-  const std::vector<const TypePatchInformation*>& GetClassesToPatch() const {
-    return classes_to_patch_;
-  }
-
   // Checks if class specified by type_idx is one of the image_classes_
   bool IsImageClass(const char* descriptor) const;
 
@@ -689,10 +468,6 @@
   static void CompileClass(const ParallelCompilationManager* context, size_t class_def_index)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  std::vector<const CallPatchInformation*> code_to_patch_;
-  std::vector<const CallPatchInformation*> methods_to_patch_;
-  std::vector<const TypePatchInformation*> classes_to_patch_;
-
   const CompilerOptions* const compiler_options_;
   VerificationResults* const verification_results_;
   DexFileToMethodInlinerMap* const method_inliner_map_;
@@ -715,6 +490,9 @@
   // All method references that this compiler has compiled.
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
+  // Number of non-relative patches in all compiled methods. These patches need space
+  // in the .oat_patches ELF section if requested in the compiler options.
+  size_t non_relative_linker_patch_count_ GUARDED_BY(compiled_methods_lock_);
 
   const bool image_;