Home | History | Annotate | Download | only in compiler
      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 
     42   InstructionSet GetInstructionSet() const {
     43     return instruction_set_;
     44   }
     45 
     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 
    117   explicit SrcMap() {}
    118   explicit SrcMap(const Allocator& alloc) : std::vector<SrcMapElem, Allocator>(alloc) {}
    119 
    120   template <class InputIt>
    121   SrcMap(InputIt first, InputIt last, const Allocator& alloc)
    122       : std::vector<SrcMapElem, Allocator>(first, last, alloc) {}
    123 
    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.
    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:
    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 
    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 
    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 
    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 
    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 
    215   size_t LiteralOffset() const {
    216     return literal_offset_;
    217   }
    218 
    219   LinkerPatchType Type() const {
    220     return patch_type_;
    221   }
    222 
    223   bool IsPcRelative() const {
    224     return Type() == kLinkerPatchCallRelative || Type() == kLinkerPatchDexCacheArray;
    225   }
    226 
    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 
    233   const DexFile* TargetTypeDexFile() const {
    234     DCHECK(patch_type_ == kLinkerPatchType);
    235     return target_dex_file_;
    236   }
    237 
    238   uint32_t TargetTypeIndex() const {
    239     DCHECK(patch_type_ == kLinkerPatchType);
    240     return type_idx_;
    241   }
    242 
    243   const DexFile* TargetDexCacheDexFile() const {
    244     DCHECK(patch_type_ == kLinkerPatchDexCacheArray);
    245     return target_dex_file_;
    246   }
    247 
    248   size_t TargetDexCacheElementOffset() const {
    249     DCHECK(patch_type_ == kLinkerPatchDexCacheArray);
    250     return element_offset_;
    251   }
    252 
    253   uint32_t PcInsnOffset() const {
    254     DCHECK(patch_type_ == kLinkerPatchDexCacheArray);
    255     return pc_insn_offset_;
    256   }
    257 
    258  private:
    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 
    343   size_t GetFrameSizeInBytes() const {
    344     return frame_size_in_bytes_;
    345   }
    346 
    347   uint32_t GetCoreSpillMask() const {
    348     return core_spill_mask_;
    349   }
    350 
    351   uint32_t GetFpSpillMask() const {
    352     return fp_spill_mask_;
    353   }
    354 
    355   const SwapSrcMap& GetSrcMappingTable() const {
    356     DCHECK(src_mapping_table_ != nullptr);
    357     return *src_mapping_table_;
    358   }
    359 
    360   SwapVector<uint8_t> const* GetMappingTable() const {
    361     return mapping_table_;
    362   }
    363 
    364   const SwapVector<uint8_t>* GetVmapTable() const {
    365     DCHECK(vmap_table_ != nullptr);
    366     return vmap_table_;
    367   }
    368 
    369   SwapVector<uint8_t> const* GetGcMap() const {
    370     return gc_map_;
    371   }
    372 
    373   const SwapVector<uint8_t>* GetCFIInfo() const {
    374     return cfi_info_;
    375   }
    376 
    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