1 /* 2 * Copyright (C) 2011 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_COMPILED_METHOD_H_ 18 #define ART_COMPILER_COMPILED_METHOD_H_ 19 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 #include "arch/instruction_set.h" 25 #include "base/bit_utils.h" 26 #include "method_reference.h" 27 #include "utils/array_ref.h" 28 #include "utils/swap_space.h" 29 30 namespace art { 31 32 class CompilerDriver; 33 34 class CompiledCode { 35 public: 36 // For Quick to supply an code blob 37 CompiledCode(CompilerDriver* compiler_driver, InstructionSet instruction_set, 38 const ArrayRef<const uint8_t>& quick_code, bool owns_code_array); 39 40 virtual ~CompiledCode(); 41 GetInstructionSet()42 InstructionSet GetInstructionSet() const { 43 return instruction_set_; 44 } 45 GetQuickCode()46 const SwapVector<uint8_t>* GetQuickCode() const { 47 return quick_code_; 48 } 49 50 void SetCode(const ArrayRef<const uint8_t>* quick_code); 51 52 bool operator==(const CompiledCode& rhs) const; 53 54 // To align an offset from a page-aligned value to make it suitable 55 // for code storage. For example on ARM, to ensure that PC relative 56 // valu computations work out as expected. 57 size_t AlignCode(size_t offset) const; 58 static size_t AlignCode(size_t offset, InstructionSet instruction_set); 59 60 // returns the difference between the code address and a usable PC. 61 // mainly to cope with kThumb2 where the lower bit must be set. 62 size_t CodeDelta() const; 63 static size_t CodeDelta(InstructionSet instruction_set); 64 65 // Returns a pointer suitable for invoking the code at the argument 66 // code_pointer address. Mainly to cope with kThumb2 where the 67 // lower bit must be set to indicate Thumb mode. 68 static const void* CodePointer(const void* code_pointer, 69 InstructionSet instruction_set); 70 71 const std::vector<uint32_t>& GetOatdataOffsetsToCompliledCodeOffset() const; 72 void AddOatdataOffsetToCompliledCodeOffset(uint32_t offset); 73 74 private: 75 CompilerDriver* const compiler_driver_; 76 77 const InstructionSet instruction_set_; 78 79 // If we own the code array (means that we free in destructor). 80 const bool owns_code_array_; 81 82 // Used to store the PIC code for Quick. 83 SwapVector<uint8_t>* quick_code_; 84 85 // There are offsets from the oatdata symbol to where the offset to 86 // the compiled method will be found. These are computed by the 87 // OatWriter and then used by the ElfWriter to add relocations so 88 // that MCLinker can update the values to the location in the linked .so. 89 std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_; 90 }; 91 92 class SrcMapElem { 93 public: 94 uint32_t from_; 95 int32_t to_; 96 97 // Lexicographical compare. 98 bool operator<(const SrcMapElem& other) const { 99 if (from_ != other.from_) { 100 return from_ < other.from_; 101 } 102 return to_ < other.to_; 103 } 104 }; 105 106 template <class Allocator> 107 class SrcMap FINAL : public std::vector<SrcMapElem, Allocator> { 108 public: 109 using std::vector<SrcMapElem, Allocator>::begin; 110 using typename std::vector<SrcMapElem, Allocator>::const_iterator; 111 using std::vector<SrcMapElem, Allocator>::empty; 112 using std::vector<SrcMapElem, Allocator>::end; 113 using std::vector<SrcMapElem, Allocator>::resize; 114 using std::vector<SrcMapElem, Allocator>::shrink_to_fit; 115 using std::vector<SrcMapElem, Allocator>::size; 116 SrcMap()117 explicit SrcMap() {} SrcMap(const Allocator & alloc)118 explicit SrcMap(const Allocator& alloc) : std::vector<SrcMapElem, Allocator>(alloc) {} 119 120 template <class InputIt> SrcMap(InputIt first,InputIt last,const Allocator & alloc)121 SrcMap(InputIt first, InputIt last, const Allocator& alloc) 122 : std::vector<SrcMapElem, Allocator>(first, last, alloc) {} 123 push_back(const SrcMapElem & elem)124 void push_back(const SrcMapElem& elem) { 125 if (!empty()) { 126 // Check that the addresses are inserted in sorted order. 127 DCHECK_GE(elem.from_, this->back().from_); 128 // If two consequitive entries map to the same value, ignore the later. 129 // E.g. for map {{0, 1}, {4, 1}, {8, 2}}, all values in [0,8) map to 1. 130 if (elem.to_ == this->back().to_) { 131 return; 132 } 133 } 134 std::vector<SrcMapElem, Allocator>::push_back(elem); 135 } 136 137 // Returns true and the corresponding "to" value if the mapping is found. 138 // Oterwise returns false and 0. Find(uint32_t from)139 std::pair<bool, int32_t> Find(uint32_t from) const { 140 // Finds first mapping such that lb.from_ >= from. 141 auto lb = std::lower_bound(begin(), end(), SrcMapElem {from, INT32_MIN}); 142 if (lb != end() && lb->from_ == from) { 143 // Found exact match. 144 return std::make_pair(true, lb->to_); 145 } else if (lb != begin()) { 146 // The previous mapping is still in effect. 147 return std::make_pair(true, (--lb)->to_); 148 } else { 149 // Not found because 'from' is smaller than first entry in the map. 150 return std::make_pair(false, 0); 151 } 152 } 153 }; 154 155 using DefaultSrcMap = SrcMap<std::allocator<SrcMapElem>>; 156 using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>; 157 158 159 enum LinkerPatchType { 160 kLinkerPatchMethod, 161 kLinkerPatchCall, 162 kLinkerPatchCallRelative, // NOTE: Actual patching is instruction_set-dependent. 163 kLinkerPatchType, 164 kLinkerPatchDexCacheArray, // NOTE: Actual patching is instruction_set-dependent. 165 }; 166 167 class LinkerPatch { 168 public: MethodPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_method_idx)169 static LinkerPatch MethodPatch(size_t literal_offset, 170 const DexFile* target_dex_file, 171 uint32_t target_method_idx) { 172 LinkerPatch patch(literal_offset, kLinkerPatchMethod, target_dex_file); 173 patch.method_idx_ = target_method_idx; 174 return patch; 175 } 176 CodePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_method_idx)177 static LinkerPatch CodePatch(size_t literal_offset, 178 const DexFile* target_dex_file, 179 uint32_t target_method_idx) { 180 LinkerPatch patch(literal_offset, kLinkerPatchCall, target_dex_file); 181 patch.method_idx_ = target_method_idx; 182 return patch; 183 } 184 RelativeCodePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_method_idx)185 static LinkerPatch RelativeCodePatch(size_t literal_offset, 186 const DexFile* target_dex_file, 187 uint32_t target_method_idx) { 188 LinkerPatch patch(literal_offset, kLinkerPatchCallRelative, target_dex_file); 189 patch.method_idx_ = target_method_idx; 190 return patch; 191 } 192 TypePatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t target_type_idx)193 static LinkerPatch TypePatch(size_t literal_offset, 194 const DexFile* target_dex_file, 195 uint32_t target_type_idx) { 196 LinkerPatch patch(literal_offset, kLinkerPatchType, target_dex_file); 197 patch.type_idx_ = target_type_idx; 198 return patch; 199 } 200 DexCacheArrayPatch(size_t literal_offset,const DexFile * target_dex_file,uint32_t pc_insn_offset,size_t element_offset)201 static LinkerPatch DexCacheArrayPatch(size_t literal_offset, 202 const DexFile* target_dex_file, 203 uint32_t pc_insn_offset, 204 size_t element_offset) { 205 DCHECK(IsUint<32>(element_offset)); 206 LinkerPatch patch(literal_offset, kLinkerPatchDexCacheArray, target_dex_file); 207 patch.pc_insn_offset_ = pc_insn_offset; 208 patch.element_offset_ = element_offset; 209 return patch; 210 } 211 212 LinkerPatch(const LinkerPatch& other) = default; 213 LinkerPatch& operator=(const LinkerPatch& other) = default; 214 LiteralOffset()215 size_t LiteralOffset() const { 216 return literal_offset_; 217 } 218 Type()219 LinkerPatchType Type() const { 220 return patch_type_; 221 } 222 IsPcRelative()223 bool IsPcRelative() const { 224 return Type() == kLinkerPatchCallRelative || Type() == kLinkerPatchDexCacheArray; 225 } 226 TargetMethod()227 MethodReference TargetMethod() const { 228 DCHECK(patch_type_ == kLinkerPatchMethod || 229 patch_type_ == kLinkerPatchCall || patch_type_ == kLinkerPatchCallRelative); 230 return MethodReference(target_dex_file_, method_idx_); 231 } 232 TargetTypeDexFile()233 const DexFile* TargetTypeDexFile() const { 234 DCHECK(patch_type_ == kLinkerPatchType); 235 return target_dex_file_; 236 } 237 TargetTypeIndex()238 uint32_t TargetTypeIndex() const { 239 DCHECK(patch_type_ == kLinkerPatchType); 240 return type_idx_; 241 } 242 TargetDexCacheDexFile()243 const DexFile* TargetDexCacheDexFile() const { 244 DCHECK(patch_type_ == kLinkerPatchDexCacheArray); 245 return target_dex_file_; 246 } 247 TargetDexCacheElementOffset()248 size_t TargetDexCacheElementOffset() const { 249 DCHECK(patch_type_ == kLinkerPatchDexCacheArray); 250 return element_offset_; 251 } 252 PcInsnOffset()253 uint32_t PcInsnOffset() const { 254 DCHECK(patch_type_ == kLinkerPatchDexCacheArray); 255 return pc_insn_offset_; 256 } 257 258 private: LinkerPatch(size_t literal_offset,LinkerPatchType patch_type,const DexFile * target_dex_file)259 LinkerPatch(size_t literal_offset, LinkerPatchType patch_type, const DexFile* target_dex_file) 260 : target_dex_file_(target_dex_file), 261 literal_offset_(literal_offset), 262 patch_type_(patch_type) { 263 cmp1_ = 0u; 264 cmp2_ = 0u; 265 // The compiler rejects methods that are too big, so the compiled code 266 // of a single method really shouln't be anywhere close to 16MiB. 267 DCHECK(IsUint<24>(literal_offset)); 268 } 269 270 const DexFile* target_dex_file_; 271 uint32_t literal_offset_ : 24; // Method code size up to 16MiB. 272 LinkerPatchType patch_type_ : 8; 273 union { 274 uint32_t cmp1_; // Used for relational operators. 275 uint32_t method_idx_; // Method index for Call/Method patches. 276 uint32_t type_idx_; // Type index for Type patches. 277 uint32_t element_offset_; // Element offset in the dex cache arrays. 278 }; 279 union { 280 uint32_t cmp2_; // Used for relational operators. 281 // Literal offset of the insn loading PC (same as literal_offset if it's the same insn, 282 // may be different if the PC-relative addressing needs multiple insns). 283 uint32_t pc_insn_offset_; 284 static_assert(sizeof(pc_insn_offset_) == sizeof(cmp2_), "needed by relational operators"); 285 }; 286 287 friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs); 288 friend bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs); 289 }; 290 291 inline bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs) { 292 return lhs.literal_offset_ == rhs.literal_offset_ && 293 lhs.patch_type_ == rhs.patch_type_ && 294 lhs.target_dex_file_ == rhs.target_dex_file_ && 295 lhs.cmp1_ == rhs.cmp1_ && 296 lhs.cmp2_ == rhs.cmp2_; 297 } 298 299 inline bool operator<(const LinkerPatch& lhs, const LinkerPatch& rhs) { 300 return (lhs.literal_offset_ != rhs.literal_offset_) ? lhs.literal_offset_ < rhs.literal_offset_ 301 : (lhs.patch_type_ != rhs.patch_type_) ? lhs.patch_type_ < rhs.patch_type_ 302 : (lhs.target_dex_file_ != rhs.target_dex_file_) ? lhs.target_dex_file_ < rhs.target_dex_file_ 303 : (lhs.cmp1_ != rhs.cmp1_) ? lhs.cmp1_ < rhs.cmp1_ 304 : lhs.cmp2_ < rhs.cmp2_; 305 } 306 307 class CompiledMethod FINAL : public CompiledCode { 308 public: 309 // Constructs a CompiledMethod. 310 // Note: Consider using the static allocation methods below that will allocate the CompiledMethod 311 // in the swap space. 312 CompiledMethod(CompilerDriver* driver, 313 InstructionSet instruction_set, 314 const ArrayRef<const uint8_t>& quick_code, 315 const size_t frame_size_in_bytes, 316 const uint32_t core_spill_mask, 317 const uint32_t fp_spill_mask, 318 DefaultSrcMap* src_mapping_table, 319 const ArrayRef<const uint8_t>& mapping_table, 320 const ArrayRef<const uint8_t>& vmap_table, 321 const ArrayRef<const uint8_t>& native_gc_map, 322 const ArrayRef<const uint8_t>& cfi_info, 323 const ArrayRef<const LinkerPatch>& patches); 324 325 virtual ~CompiledMethod(); 326 327 static CompiledMethod* SwapAllocCompiledMethod( 328 CompilerDriver* driver, 329 InstructionSet instruction_set, 330 const ArrayRef<const uint8_t>& quick_code, 331 const size_t frame_size_in_bytes, 332 const uint32_t core_spill_mask, 333 const uint32_t fp_spill_mask, 334 DefaultSrcMap* src_mapping_table, 335 const ArrayRef<const uint8_t>& mapping_table, 336 const ArrayRef<const uint8_t>& vmap_table, 337 const ArrayRef<const uint8_t>& native_gc_map, 338 const ArrayRef<const uint8_t>& cfi_info, 339 const ArrayRef<const LinkerPatch>& patches); 340 341 static void ReleaseSwapAllocatedCompiledMethod(CompilerDriver* driver, CompiledMethod* m); 342 GetFrameSizeInBytes()343 size_t GetFrameSizeInBytes() const { 344 return frame_size_in_bytes_; 345 } 346 GetCoreSpillMask()347 uint32_t GetCoreSpillMask() const { 348 return core_spill_mask_; 349 } 350 GetFpSpillMask()351 uint32_t GetFpSpillMask() const { 352 return fp_spill_mask_; 353 } 354 GetSrcMappingTable()355 const SwapSrcMap& GetSrcMappingTable() const { 356 DCHECK(src_mapping_table_ != nullptr); 357 return *src_mapping_table_; 358 } 359 GetMappingTable()360 SwapVector<uint8_t> const* GetMappingTable() const { 361 return mapping_table_; 362 } 363 GetVmapTable()364 const SwapVector<uint8_t>* GetVmapTable() const { 365 DCHECK(vmap_table_ != nullptr); 366 return vmap_table_; 367 } 368 GetGcMap()369 SwapVector<uint8_t> const* GetGcMap() const { 370 return gc_map_; 371 } 372 GetCFIInfo()373 const SwapVector<uint8_t>* GetCFIInfo() const { 374 return cfi_info_; 375 } 376 GetPatches()377 ArrayRef<const LinkerPatch> GetPatches() const { 378 return ArrayRef<const LinkerPatch>(patches_); 379 } 380 381 private: 382 // Whether or not the arrays are owned by the compiled method or dedupe sets. 383 const bool owns_arrays_; 384 // For quick code, the size of the activation used by the code. 385 const size_t frame_size_in_bytes_; 386 // For quick code, a bit mask describing spilled GPR callee-save registers. 387 const uint32_t core_spill_mask_; 388 // For quick code, a bit mask describing spilled FPR callee-save registers. 389 const uint32_t fp_spill_mask_; 390 // For quick code, a set of pairs (PC, DEX) mapping from native PC offset to DEX offset. 391 SwapSrcMap* src_mapping_table_; 392 // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to 393 // native PC offset. Size prefixed. 394 SwapVector<uint8_t>* mapping_table_; 395 // For quick code, a uleb128 encoded map from GPR/FPR register to dex register. Size prefixed. 396 SwapVector<uint8_t>* vmap_table_; 397 // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers 398 // are live. 399 SwapVector<uint8_t>* gc_map_; 400 // For quick code, a FDE entry for the debug_frame section. 401 SwapVector<uint8_t>* cfi_info_; 402 // For quick code, linker patches needed by the method. 403 const SwapVector<LinkerPatch> patches_; 404 }; 405 406 } // namespace art 407 408 #endif // ART_COMPILER_COMPILED_METHOD_H_ 409