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 kBakerReadBarrier, // Baker read barrier. 48 }; 49 50 class ThunkKey { 51 public: 52 explicit ThunkKey(ThunkType type, uint32_t custom_value1 = 0u, uint32_t custom_value2 = 0u) type_(type)53 : type_(type), custom_value1_(custom_value1), custom_value2_(custom_value2) { } 54 GetType()55 ThunkType GetType() const { 56 return type_; 57 } 58 GetCustomValue1()59 uint32_t GetCustomValue1() const { 60 return custom_value1_; 61 } 62 GetCustomValue2()63 uint32_t GetCustomValue2() const { 64 return custom_value2_; 65 } 66 67 private: 68 ThunkType type_; 69 uint32_t custom_value1_; 70 uint32_t custom_value2_; 71 }; 72 73 class ThunkKeyCompare { 74 public: operator()75 bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const { 76 if (lhs.GetType() != rhs.GetType()) { 77 return lhs.GetType() < rhs.GetType(); 78 } 79 if (lhs.GetCustomValue1() != rhs.GetCustomValue1()) { 80 return lhs.GetCustomValue1() < rhs.GetCustomValue1(); 81 } 82 return lhs.GetCustomValue2() < rhs.GetCustomValue2(); 83 } 84 }; 85 86 static ThunkKey GetMethodCallKey(); 87 static ThunkKey GetBakerThunkKey(const LinkerPatch& patch); 88 89 uint32_t ReserveSpaceInternal(uint32_t offset, 90 const CompiledMethod* compiled_method, 91 MethodReference method_ref, 92 uint32_t max_extra_space); 93 uint32_t GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset); 94 95 uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset, 96 uint32_t target_offset); 97 98 virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0; 99 virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0; 100 101 private: 102 class ThunkData; 103 104 void ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset); 105 void AddUnreservedThunk(ThunkData* data); 106 107 void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref); 108 109 uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key); 110 ThunkData ThunkDataForPatch(const LinkerPatch& patch, uint32_t max_next_offset); 111 112 RelativePatcherThunkProvider* const thunk_provider_; 113 RelativePatcherTargetProvider* const target_provider_; 114 const InstructionSet instruction_set_; 115 116 // The data for all thunks. 117 // SafeMap<> nodes don't move after being inserted, so we can use direct pointers to the data. 118 using ThunkMap = SafeMap<ThunkKey, ThunkData, ThunkKeyCompare>; 119 ThunkMap thunks_; 120 121 // ReserveSpace() tracks unprocessed method call patches. These may be resolved later. 122 class UnprocessedMethodCallPatch { 123 public: UnprocessedMethodCallPatch(uint32_t patch_offset,MethodReference target_method)124 UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method) 125 : patch_offset_(patch_offset), target_method_(target_method) { } 126 GetPatchOffset()127 uint32_t GetPatchOffset() const { 128 return patch_offset_; 129 } 130 GetTargetMethod()131 MethodReference GetTargetMethod() const { 132 return target_method_; 133 } 134 135 private: 136 uint32_t patch_offset_; 137 MethodReference target_method_; 138 }; 139 std::deque<UnprocessedMethodCallPatch> unprocessed_method_call_patches_; 140 // Once we have compiled a method call thunk, cache pointer to the data. 141 ThunkData* method_call_thunk_; 142 143 // Thunks 144 std::deque<ThunkData*> unreserved_thunks_; 145 146 class PendingThunkComparator; 147 std::vector<ThunkData*> pending_thunks_; // Heap with the PendingThunkComparator. 148 149 friend class Arm64RelativePatcherTest; 150 friend class Thumb2RelativePatcherTest; 151 152 DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); 153 }; 154 155 } // namespace linker 156 } // namespace art 157 158 #endif // ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ 159