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 17 #ifndef ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ 18 #define ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ 19 20 #include <deque> 21 #include <vector> 22 23 #include "base/safe_map.h" 24 #include "dex/method_reference.h" 25 #include "linker/relative_patcher.h" 26 27 namespace art { 28 namespace linker { 29 30 class ArmBaseRelativePatcher : public RelativePatcher { 31 public: 32 uint32_t ReserveSpace(uint32_t offset, 33 const CompiledMethod* compiled_method, 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; 38 39 protected: 40 ArmBaseRelativePatcher(RelativePatcherThunkProvider* thunk_provider, 41 RelativePatcherTargetProvider* target_provider, 42 InstructionSet instruction_set); 43 ~ArmBaseRelativePatcher(); 44 45 enum class ThunkType { 46 kMethodCall, // Method call thunk. 47 kEntrypointCall, // Entrypoint call. 48 kBakerReadBarrier, // Baker read barrier. 49 }; 50 51 class ThunkKey { 52 public: 53 explicit ThunkKey(ThunkType type, uint32_t custom_value1 = 0u, uint32_t custom_value2 = 0u) type_(type)54 : type_(type), custom_value1_(custom_value1), custom_value2_(custom_value2) { } 55 GetType()56 ThunkType GetType() const { 57 return type_; 58 } 59 GetCustomValue1()60 uint32_t GetCustomValue1() const { 61 return custom_value1_; 62 } 63 GetCustomValue2()64 uint32_t GetCustomValue2() const { 65 return custom_value2_; 66 } 67 68 private: 69 ThunkType type_; 70 uint32_t custom_value1_; 71 uint32_t custom_value2_; 72 }; 73 74 class ThunkKeyCompare { 75 public: operator()76 bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const { 77 if (lhs.GetType() != rhs.GetType()) { 78 return lhs.GetType() < rhs.GetType(); 79 } 80 if (lhs.GetCustomValue1() != rhs.GetCustomValue1()) { 81 return lhs.GetCustomValue1() < rhs.GetCustomValue1(); 82 } 83 return lhs.GetCustomValue2() < rhs.GetCustomValue2(); 84 } 85 }; 86 87 static ThunkKey GetMethodCallKey(); 88 static ThunkKey GetEntrypointCallKey(const LinkerPatch& patch); 89 static ThunkKey GetBakerThunkKey(const LinkerPatch& patch); 90 91 uint32_t ReserveSpaceInternal(uint32_t offset, 92 const CompiledMethod* compiled_method, 93 MethodReference method_ref, 94 uint32_t max_extra_space); 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 100 virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0; 101 virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0; 102 103 private: 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 111 uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key); 112 ThunkData ThunkDataForPatch(const LinkerPatch& patch, uint32_t max_next_offset); 113 114 RelativePatcherThunkProvider* const thunk_provider_; 115 RelativePatcherTargetProvider* const target_provider_; 116 const InstructionSet instruction_set_; 117 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: UnprocessedMethodCallPatch(uint32_t patch_offset,MethodReference target_method)126 UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method) 127 : patch_offset_(patch_offset), target_method_(target_method) { } 128 GetPatchOffset()129 uint32_t GetPatchOffset() const { 130 return patch_offset_; 131 } 132 GetTargetMethod()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. 150 151 friend class Arm64RelativePatcherTest; 152 friend class Thumb2RelativePatcherTest; 153 154 DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); 155 }; 156 157 } // namespace linker 158 } // namespace art 159 160 #endif // ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ 161