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 kBakerReadBarrierField, // Baker read barrier, load field or array element at known offset. 46 kBakerReadBarrierRoot, // Baker read barrier, GC root load. 47 }; 48 49 struct BakerReadBarrierOffsetParams { 50 uint32_t holder_reg; // Holder object for reading lock word. 51 uint32_t base_reg; // Base register, different from holder for large offset. 52 // If base differs from holder, it should be a pre-defined 53 // register to limit the number of thunks we need to emit. 54 // The offset is retrieved using introspection. 55 }; 56 57 struct BakerReadBarrierRootParams { 58 uint32_t root_reg; // The register holding the GC root. 59 uint32_t dummy; 60 }; 61 62 struct RawThunkParams { 63 uint32_t first; 64 uint32_t second; 65 }; 66 67 union ThunkParams { 68 RawThunkParams raw_params; 69 BakerReadBarrierOffsetParams offset_params; 70 BakerReadBarrierRootParams root_params; 71 }; 72 73 class ThunkKey { 74 public: ThunkKey(ThunkType type,ThunkParams params)75 ThunkKey(ThunkType type, ThunkParams params) : type_(type), params_(params) { } 76 GetType()77 ThunkType GetType() const { 78 return type_; 79 } 80 GetOffsetParams()81 BakerReadBarrierOffsetParams GetOffsetParams() const { 82 DCHECK(type_ == ThunkType::kBakerReadBarrierField); 83 return params_.offset_params; 84 } 85 GetRootParams()86 BakerReadBarrierRootParams GetRootParams() const { 87 DCHECK(type_ == ThunkType::kBakerReadBarrierRoot); 88 return params_.root_params; 89 } 90 GetRawParams()91 RawThunkParams GetRawParams() const { 92 return params_.raw_params; 93 } 94 95 private: 96 ThunkType type_; 97 ThunkParams params_; 98 }; 99 100 class ThunkKeyCompare { 101 public: operator()102 bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const { 103 if (lhs.GetType() != rhs.GetType()) { 104 return lhs.GetType() < rhs.GetType(); 105 } 106 if (lhs.GetRawParams().first != rhs.GetRawParams().first) { 107 return lhs.GetRawParams().first < rhs.GetRawParams().first; 108 } 109 return lhs.GetRawParams().second < rhs.GetRawParams().second; 110 } 111 }; 112 113 uint32_t ReserveSpaceInternal(uint32_t offset, 114 const CompiledMethod* compiled_method, 115 MethodReference method_ref, 116 uint32_t max_extra_space); 117 uint32_t GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset); 118 119 uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset, 120 uint32_t target_offset); 121 122 virtual ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) = 0; 123 virtual std::vector<uint8_t> CompileThunk(const ThunkKey& key) = 0; 124 virtual uint32_t MaxPositiveDisplacement(ThunkType type) = 0; 125 virtual uint32_t MaxNegativeDisplacement(ThunkType type) = 0; 126 127 private: 128 class ThunkData; 129 130 void ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset); 131 void AddUnreservedThunk(ThunkData* data); 132 133 void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref); 134 135 uint32_t CalculateMaxNextOffset(uint32_t patch_offset, ThunkType type); 136 137 RelativePatcherTargetProvider* const provider_; 138 const InstructionSet instruction_set_; 139 140 // The data for all thunks. 141 // SafeMap<> nodes don't move after being inserted, so we can use direct pointers to the data. 142 using ThunkMap = SafeMap<ThunkKey, ThunkData, ThunkKeyCompare>; 143 ThunkMap thunks_; 144 145 // ReserveSpace() tracks unprocessed method call patches. These may be resolved later. 146 class UnprocessedMethodCallPatch { 147 public: UnprocessedMethodCallPatch(uint32_t patch_offset,MethodReference target_method)148 UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method) 149 : patch_offset_(patch_offset), target_method_(target_method) { } 150 GetPatchOffset()151 uint32_t GetPatchOffset() const { 152 return patch_offset_; 153 } 154 GetTargetMethod()155 MethodReference GetTargetMethod() const { 156 return target_method_; 157 } 158 159 private: 160 uint32_t patch_offset_; 161 MethodReference target_method_; 162 }; 163 std::deque<UnprocessedMethodCallPatch> unprocessed_method_call_patches_; 164 // Once we have compiled a method call thunk, cache pointer to the data. 165 ThunkData* method_call_thunk_; 166 167 // Thunks 168 std::deque<ThunkData*> unreserved_thunks_; 169 170 class PendingThunkComparator; 171 std::vector<ThunkData*> pending_thunks_; // Heap with the PendingThunkComparator. 172 173 friend class Arm64RelativePatcherTest; 174 friend class Thumb2RelativePatcherTest; 175 176 DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher); 177 }; 178 179 } // namespace linker 180 } // namespace art 181 182 #endif // ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_ 183