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