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/compiled_method.h b/compiler/compiled_method.h
index cc46b92..cdae8d2 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -22,7 +22,9 @@
#include <vector>
#include "instruction_set.h"
+#include "method_reference.h"
#include "utils.h"
+#include "utils/array_ref.h"
namespace llvm {
class Function;
@@ -171,6 +173,101 @@
}
};
+enum LinkerPatchType {
+ kLinkerPatchMethod,
+ kLinkerPatchCall,
+ kLinkerPatchCallRelative, // NOTE: Actual patching is instruction_set-dependent.
+ kLinkerPatchType,
+};
+
+class LinkerPatch {
+ public:
+ static LinkerPatch MethodPatch(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t target_method_idx) {
+ return LinkerPatch(literal_offset, kLinkerPatchMethod,
+ target_method_idx, target_dex_file);
+ }
+
+ static LinkerPatch CodePatch(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t target_method_idx) {
+ return LinkerPatch(literal_offset, kLinkerPatchCall,
+ target_method_idx, target_dex_file);
+ }
+
+ static LinkerPatch RelativeCodePatch(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t target_method_idx) {
+ return LinkerPatch(literal_offset, kLinkerPatchCallRelative,
+ target_method_idx, target_dex_file);
+ }
+
+ static LinkerPatch TypePatch(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t target_type_idx) {
+ return LinkerPatch(literal_offset, kLinkerPatchType, target_type_idx, target_dex_file);
+ }
+
+ LinkerPatch(const LinkerPatch& other) = default;
+ LinkerPatch& operator=(const LinkerPatch& other) = default;
+
+ size_t LiteralOffset() const {
+ return literal_offset_;
+ }
+
+ LinkerPatchType Type() const {
+ return patch_type_;
+ }
+
+ MethodReference TargetMethod() const {
+ DCHECK(patch_type_ == kLinkerPatchMethod ||
+ patch_type_ == kLinkerPatchCall || patch_type_ == kLinkerPatchCallRelative);
+ return MethodReference(target_dex_file_, target_idx_);
+ }
+
+ const DexFile* TargetTypeDexFile() const {
+ DCHECK(patch_type_ == kLinkerPatchType);
+ return target_dex_file_;
+ }
+
+ uint32_t TargetTypeIndex() const {
+ DCHECK(patch_type_ == kLinkerPatchType);
+ return target_idx_;
+ }
+
+ private:
+ LinkerPatch(size_t literal_offset, LinkerPatchType patch_type,
+ uint32_t target_idx, const DexFile* target_dex_file)
+ : literal_offset_(literal_offset),
+ patch_type_(patch_type),
+ target_idx_(target_idx),
+ target_dex_file_(target_dex_file) {
+ }
+
+ size_t literal_offset_;
+ LinkerPatchType patch_type_;
+ uint32_t target_idx_; // Method index (Call/Method patches) or type index (Type patches).
+ const DexFile* target_dex_file_;
+
+ friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
+ friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs);
+};
+
+inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) {
+ return lhs.literal_offset_ == rhs.literal_offset_ &&
+ lhs.patch_type_ == rhs.patch_type_ &&
+ lhs.target_idx_ == rhs.target_idx_ &&
+ lhs.target_dex_file_ == rhs.target_dex_file_;
+}
+
+inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) {
+ return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_
+ : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_
+ : (lhs.target_idx_ != rhs.target_idx_) ? lhs.target_idx_ < rhs.target_idx_
+ : lhs.target_dex_file_ < rhs.target_dex_file_;
+}
+
class CompiledMethod FINAL : public CompiledCode {
public:
// Constructs a CompiledMethod for Quick.
@@ -184,7 +281,8 @@
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
const std::vector<uint8_t>& native_gc_map,
- const std::vector<uint8_t>* cfi_info);
+ const std::vector<uint8_t>* cfi_info,
+ const ArrayRef<LinkerPatch>& patches = ArrayRef<LinkerPatch>());
// Constructs a CompiledMethod for Optimizing.
CompiledMethod(CompilerDriver* driver,
@@ -250,6 +348,10 @@
return cfi_info_;
}
+ const std::vector<LinkerPatch>& GetPatches() const {
+ return patches_;
+ }
+
private:
// For quick code, the size of the activation used by the code.
const size_t frame_size_in_bytes_;
@@ -269,6 +371,8 @@
std::vector<uint8_t>* gc_map_;
// For quick code, a FDE entry for the debug_frame section.
std::vector<uint8_t>* cfi_info_;
+ // For quick code, linker patches needed by the method.
+ std::vector<LinkerPatch> patches_;
};
} // namespace art