Refactor RelativePatcher out of OatWriter.
Move the relative patcher classes to compiler/linker/ and
compiler/linker/<arch>/ . Refactor them to avoid OatWriter
dependency so that they can be unit tested. Add tests for
x86 and x86-64.
Change-Id: I1b42baa9fc431378e4cce1399bec590c5b5a409f
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
new file mode 100644
index 0000000..dbb18cc
--- /dev/null
+++ b/compiler/linker/relative_patcher.h
@@ -0,0 +1,123 @@
+/*
+ * 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_LINKER_RELATIVE_PATCHER_H_
+#define ART_COMPILER_LINKER_RELATIVE_PATCHER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "arch/instruction_set_features.h"
+#include "base/macros.h"
+#include "method_reference.h"
+#include "utils/array_ref.h"
+
+namespace art {
+
+class CompiledMethod;
+class LinkerPatch;
+class OutputStream;
+
+namespace linker {
+
+/**
+ * @class RelativePatcherTargetProvider
+ * @brief Interface for providing method offsets for relative call targets.
+ */
+class RelativePatcherTargetProvider {
+ public:
+ /**
+ * Find the offset of the target method of a relative call if known.
+ *
+ * The process of assigning target method offsets includes calls to the relative patcher's
+ * ReserveSpace() which in turn can use FindMethodOffset() to determine if a method already
+ * has an offset assigned and, if so, what's that offset. If the offset has not yet been
+ * assigned or if it's too far for the particular architecture's relative call,
+ * ReserveSpace() may need to allocate space for a special dispatch thunk.
+ *
+ * @param ref the target method of the relative call.
+ * @return true in the first element of the pair if the method was found, false otherwise;
+ * if found, the second element specifies the offset.
+ */
+ virtual std::pair<bool, uint32_t> FindMethodOffset(MethodReference ref) = 0;
+
+ protected:
+ virtual ~RelativePatcherTargetProvider() { }
+};
+
+/**
+ * @class RelativePatcher
+ * @brief Interface for architecture-specific link-time patching of PC-relative references.
+ */
+class RelativePatcher {
+ public:
+ static std::unique_ptr<RelativePatcher> Create(
+ InstructionSet instruction_set, const InstructionSetFeatures* features,
+ RelativePatcherTargetProvider* provider);
+
+ virtual ~RelativePatcher() { }
+
+ uint32_t CodeAlignmentSize() const {
+ return size_code_alignment_;
+ }
+
+ uint32_t RelativeCallThunksSize() const {
+ return size_relative_call_thunks_;
+ }
+
+ uint32_t MiscThunksSize() const {
+ 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.
+ virtual uint32_t ReserveSpace(uint32_t offset, const CompiledMethod* compiled_method) = 0;
+
+ // Write relative call thunks if needed, return adjusted offset.
+ virtual uint32_t WriteThunks(OutputStream* out, uint32_t offset) = 0;
+
+ // Patch method code. The input displacement is relative to the patched location,
+ // the patcher may need to adjust it if the correct base is different.
+ virtual void PatchCall(std::vector<uint8_t>* code, uint32_t literal_offset,
+ uint32_t patch_offset, uint32_t target_offset) = 0;
+
+ // Patch a reference to a dex cache location.
+ virtual void PatchDexCacheReference(std::vector<uint8_t>* code, const LinkerPatch& patch,
+ uint32_t patch_offset, uint32_t target_offset) = 0;
+
+ protected:
+ RelativePatcher()
+ : size_code_alignment_(0u),
+ size_relative_call_thunks_(0u),
+ size_misc_thunks_(0u) {
+ }
+
+ bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
+ bool WriteRelCallThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
+ bool WriteMiscThunk(OutputStream* out, const ArrayRef<const uint8_t>& thunk);
+
+ private:
+ uint32_t size_code_alignment_;
+ uint32_t size_relative_call_thunks_;
+ uint32_t size_misc_thunks_;
+
+ DISALLOW_COPY_AND_ASSIGN(RelativePatcher);
+};
+
+} // namespace linker
+} // namespace art
+
+#endif // ART_COMPILER_LINKER_RELATIVE_PATCHER_H_