blob: bf3e81f6b950637412e6378f7afde1730e88c3e9 [file] [log] [blame]
Vladimir Markob163bb72015-03-31 21:49:49 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Vladimir Marko6d66fcf2018-04-12 13:15:27 +010017#ifndef ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
18#define ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
Vladimir Markob163bb72015-03-31 21:49:49 +010019
20#include <deque>
Vladimir Markof4f2daa2017-03-20 18:26:59 +000021#include <vector>
Vladimir Markob163bb72015-03-31 21:49:49 +010022
David Sehr67bf42e2018-02-26 16:43:04 -080023#include "base/safe_map.h"
David Sehr312f3b22018-03-19 08:39:26 -070024#include "dex/method_reference.h"
Vladimir Markob163bb72015-03-31 21:49:49 +010025#include "linker/relative_patcher.h"
Vladimir Markob163bb72015-03-31 21:49:49 +010026
27namespace art {
28namespace linker {
29
30class ArmBaseRelativePatcher : public RelativePatcher {
31 public:
Vladimir Marko944da602016-02-19 12:27:55 +000032 uint32_t ReserveSpace(uint32_t offset,
33 const CompiledMethod* compiled_method,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010034 MethodReference method_ref) override;
35 uint32_t ReserveSpaceEnd(uint32_t offset) override;
36 uint32_t WriteThunks(OutputStream* out, uint32_t offset) override;
37 std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) override;
Vladimir Markob163bb72015-03-31 21:49:49 +010038
39 protected:
Vladimir Markoca1e0382018-04-11 09:58:41 +000040 ArmBaseRelativePatcher(RelativePatcherThunkProvider* thunk_provider,
41 RelativePatcherTargetProvider* target_provider,
Vladimir Markof4f2daa2017-03-20 18:26:59 +000042 InstructionSet instruction_set);
43 ~ArmBaseRelativePatcher();
44
45 enum class ThunkType {
46 kMethodCall, // Method call thunk.
Vladimir Markof6675082019-05-17 12:05:28 +010047 kEntrypointCall, // Entrypoint call.
Vladimir Marko0a51fc32017-05-02 13:12:02 +010048 kBakerReadBarrier, // Baker read barrier.
Vladimir Markof4f2daa2017-03-20 18:26:59 +000049 };
50
Vladimir Markof4f2daa2017-03-20 18:26:59 +000051 class ThunkKey {
52 public:
Vladimir Markob59d5fb2017-05-09 14:19:21 +010053 explicit ThunkKey(ThunkType type, uint32_t custom_value1 = 0u, uint32_t custom_value2 = 0u)
54 : type_(type), custom_value1_(custom_value1), custom_value2_(custom_value2) { }
Vladimir Markof4f2daa2017-03-20 18:26:59 +000055
56 ThunkType GetType() const {
57 return type_;
58 }
59
Vladimir Markob59d5fb2017-05-09 14:19:21 +010060 uint32_t GetCustomValue1() const {
61 return custom_value1_;
Vladimir Markof4f2daa2017-03-20 18:26:59 +000062 }
63
Vladimir Markob59d5fb2017-05-09 14:19:21 +010064 uint32_t GetCustomValue2() const {
65 return custom_value2_;
Vladimir Markof4f2daa2017-03-20 18:26:59 +000066 }
67
68 private:
69 ThunkType type_;
Vladimir Markob59d5fb2017-05-09 14:19:21 +010070 uint32_t custom_value1_;
71 uint32_t custom_value2_;
Vladimir Markof4f2daa2017-03-20 18:26:59 +000072 };
73
74 class ThunkKeyCompare {
75 public:
76 bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const {
77 if (lhs.GetType() != rhs.GetType()) {
78 return lhs.GetType() < rhs.GetType();
79 }
Vladimir Markob59d5fb2017-05-09 14:19:21 +010080 if (lhs.GetCustomValue1() != rhs.GetCustomValue1()) {
81 return lhs.GetCustomValue1() < rhs.GetCustomValue1();
Vladimir Markof4f2daa2017-03-20 18:26:59 +000082 }
Vladimir Markob59d5fb2017-05-09 14:19:21 +010083 return lhs.GetCustomValue2() < rhs.GetCustomValue2();
Vladimir Markof4f2daa2017-03-20 18:26:59 +000084 }
85 };
Vladimir Markob163bb72015-03-31 21:49:49 +010086
Vladimir Marko0a51fc32017-05-02 13:12:02 +010087 static ThunkKey GetMethodCallKey();
Vladimir Markof6675082019-05-17 12:05:28 +010088 static ThunkKey GetEntrypointCallKey(const LinkerPatch& patch);
Vladimir Marko0a51fc32017-05-02 13:12:02 +010089 static ThunkKey GetBakerThunkKey(const LinkerPatch& patch);
90
Vladimir Marko944da602016-02-19 12:27:55 +000091 uint32_t ReserveSpaceInternal(uint32_t offset,
92 const CompiledMethod* compiled_method,
93 MethodReference method_ref,
94 uint32_t max_extra_space);
Vladimir Markof4f2daa2017-03-20 18:26:59 +000095 uint32_t GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset);
96
97 uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset,
98 uint32_t target_offset);
99
Vladimir Marko0a51fc32017-05-02 13:12:02 +0100100 virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0;
101 virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0;
Vladimir Markob163bb72015-03-31 21:49:49 +0100102
103 private:
Vladimir Markof4f2daa2017-03-20 18:26:59 +0000104 class ThunkData;
105
106 void ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset);
107 void AddUnreservedThunk(ThunkData* data);
108
109 void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref);
110
Vladimir Marko0a51fc32017-05-02 13:12:02 +0100111 uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key);
Vladimir Markoca1e0382018-04-11 09:58:41 +0000112 ThunkData ThunkDataForPatch(const LinkerPatch& patch, uint32_t max_next_offset);
Vladimir Markob163bb72015-03-31 21:49:49 +0100113
Vladimir Markoca1e0382018-04-11 09:58:41 +0000114 RelativePatcherThunkProvider* const thunk_provider_;
115 RelativePatcherTargetProvider* const target_provider_;
Vladimir Markob163bb72015-03-31 21:49:49 +0100116 const InstructionSet instruction_set_;
Vladimir Markob163bb72015-03-31 21:49:49 +0100117
Vladimir Markof4f2daa2017-03-20 18:26:59 +0000118 // The data for all thunks.
119 // SafeMap<> nodes don't move after being inserted, so we can use direct pointers to the data.
120 using ThunkMap = SafeMap<ThunkKey, ThunkData, ThunkKeyCompare>;
121 ThunkMap thunks_;
122
123 // ReserveSpace() tracks unprocessed method call patches. These may be resolved later.
124 class UnprocessedMethodCallPatch {
125 public:
126 UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method)
127 : patch_offset_(patch_offset), target_method_(target_method) { }
128
129 uint32_t GetPatchOffset() const {
130 return patch_offset_;
131 }
132
133 MethodReference GetTargetMethod() const {
134 return target_method_;
135 }
136
137 private:
138 uint32_t patch_offset_;
139 MethodReference target_method_;
140 };
141 std::deque<UnprocessedMethodCallPatch> unprocessed_method_call_patches_;
142 // Once we have compiled a method call thunk, cache pointer to the data.
143 ThunkData* method_call_thunk_;
144
145 // Thunks
146 std::deque<ThunkData*> unreserved_thunks_;
147
148 class PendingThunkComparator;
149 std::vector<ThunkData*> pending_thunks_; // Heap with the PendingThunkComparator.
Vladimir Markob163bb72015-03-31 21:49:49 +0100150
Vladimir Marko3f311cf2015-04-02 15:28:45 +0100151 friend class Arm64RelativePatcherTest;
Vladimir Marko4d23c9d2015-04-01 23:03:09 +0100152 friend class Thumb2RelativePatcherTest;
153
Vladimir Markob163bb72015-03-31 21:49:49 +0100154 DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher);
155};
156
157} // namespace linker
158} // namespace art
159
Vladimir Marko6d66fcf2018-04-12 13:15:27 +0100160#endif // ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_