Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 1 | /* |
| 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 Marko | 6d66fcf | 2018-04-12 13:15:27 +0100 | [diff] [blame] | 17 | #ifndef ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ |
| 18 | #define ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 19 | |
| 20 | #include <deque> |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 21 | #include <vector> |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 22 | |
David Sehr | 67bf42e | 2018-02-26 16:43:04 -0800 | [diff] [blame] | 23 | #include "base/safe_map.h" |
David Sehr | 312f3b2 | 2018-03-19 08:39:26 -0700 | [diff] [blame] | 24 | #include "dex/method_reference.h" |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 25 | #include "linker/relative_patcher.h" |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 26 | |
| 27 | namespace art { |
| 28 | namespace linker { |
| 29 | |
| 30 | class ArmBaseRelativePatcher : public RelativePatcher { |
| 31 | public: |
Vladimir Marko | 944da60 | 2016-02-19 12:27:55 +0000 | [diff] [blame] | 32 | uint32_t ReserveSpace(uint32_t offset, |
| 33 | const CompiledMethod* compiled_method, |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 34 | 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 Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 38 | |
| 39 | protected: |
Vladimir Marko | ca1e038 | 2018-04-11 09:58:41 +0000 | [diff] [blame] | 40 | ArmBaseRelativePatcher(RelativePatcherThunkProvider* thunk_provider, |
| 41 | RelativePatcherTargetProvider* target_provider, |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 42 | InstructionSet instruction_set); |
| 43 | ~ArmBaseRelativePatcher(); |
| 44 | |
| 45 | enum class ThunkType { |
| 46 | kMethodCall, // Method call thunk. |
Vladimir Marko | f667508 | 2019-05-17 12:05:28 +0100 | [diff] [blame] | 47 | kEntrypointCall, // Entrypoint call. |
Vladimir Marko | 0a51fc3 | 2017-05-02 13:12:02 +0100 | [diff] [blame] | 48 | kBakerReadBarrier, // Baker read barrier. |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 49 | }; |
| 50 | |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 51 | class ThunkKey { |
| 52 | public: |
Vladimir Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 53 | 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 Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 55 | |
| 56 | ThunkType GetType() const { |
| 57 | return type_; |
| 58 | } |
| 59 | |
Vladimir Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 60 | uint32_t GetCustomValue1() const { |
| 61 | return custom_value1_; |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 62 | } |
| 63 | |
Vladimir Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 64 | uint32_t GetCustomValue2() const { |
| 65 | return custom_value2_; |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | private: |
| 69 | ThunkType type_; |
Vladimir Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 70 | uint32_t custom_value1_; |
| 71 | uint32_t custom_value2_; |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 72 | }; |
| 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 Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 80 | if (lhs.GetCustomValue1() != rhs.GetCustomValue1()) { |
| 81 | return lhs.GetCustomValue1() < rhs.GetCustomValue1(); |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 82 | } |
Vladimir Marko | b59d5fb | 2017-05-09 14:19:21 +0100 | [diff] [blame] | 83 | return lhs.GetCustomValue2() < rhs.GetCustomValue2(); |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 84 | } |
| 85 | }; |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 86 | |
Vladimir Marko | 0a51fc3 | 2017-05-02 13:12:02 +0100 | [diff] [blame] | 87 | static ThunkKey GetMethodCallKey(); |
Vladimir Marko | f667508 | 2019-05-17 12:05:28 +0100 | [diff] [blame] | 88 | static ThunkKey GetEntrypointCallKey(const LinkerPatch& patch); |
Vladimir Marko | 0a51fc3 | 2017-05-02 13:12:02 +0100 | [diff] [blame] | 89 | static ThunkKey GetBakerThunkKey(const LinkerPatch& patch); |
| 90 | |
Vladimir Marko | 944da60 | 2016-02-19 12:27:55 +0000 | [diff] [blame] | 91 | uint32_t ReserveSpaceInternal(uint32_t offset, |
| 92 | const CompiledMethod* compiled_method, |
| 93 | MethodReference method_ref, |
| 94 | uint32_t max_extra_space); |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 95 | 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 Marko | 0a51fc3 | 2017-05-02 13:12:02 +0100 | [diff] [blame] | 100 | virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0; |
| 101 | virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0; |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 102 | |
| 103 | private: |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 104 | 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 Marko | 0a51fc3 | 2017-05-02 13:12:02 +0100 | [diff] [blame] | 111 | uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key); |
Vladimir Marko | ca1e038 | 2018-04-11 09:58:41 +0000 | [diff] [blame] | 112 | ThunkData ThunkDataForPatch(const LinkerPatch& patch, uint32_t max_next_offset); |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 113 | |
Vladimir Marko | ca1e038 | 2018-04-11 09:58:41 +0000 | [diff] [blame] | 114 | RelativePatcherThunkProvider* const thunk_provider_; |
| 115 | RelativePatcherTargetProvider* const target_provider_; |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 116 | const InstructionSet instruction_set_; |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 117 | |
Vladimir Marko | f4f2daa | 2017-03-20 18:26:59 +0000 | [diff] [blame] | 118 | // 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 Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 150 | |
Vladimir Marko | 3f311cf | 2015-04-02 15:28:45 +0100 | [diff] [blame] | 151 | friend class Arm64RelativePatcherTest; |
Vladimir Marko | 4d23c9d | 2015-04-01 23:03:09 +0100 | [diff] [blame] | 152 | friend class Thumb2RelativePatcherTest; |
| 153 | |
Vladimir Marko | b163bb7 | 2015-03-31 21:49:49 +0100 | [diff] [blame] | 154 | DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); |
| 155 | }; |
| 156 | |
| 157 | } // namespace linker |
| 158 | } // namespace art |
| 159 | |
Vladimir Marko | 6d66fcf | 2018-04-12 13:15:27 +0100 | [diff] [blame] | 160 | #endif // ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ |