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