Home | History | Annotate | Download | only in arm
      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:
     75     ThunkKey(ThunkType type, ThunkParams params) : type_(type), params_(params) { }
     76 
     77     ThunkType GetType() const {
     78       return type_;
     79     }
     80 
     81     BakerReadBarrierOffsetParams GetOffsetParams() const {
     82       DCHECK(type_ == ThunkType::kBakerReadBarrierField);
     83       return params_.offset_params;
     84     }
     85 
     86     BakerReadBarrierRootParams GetRootParams() const {
     87       DCHECK(type_ == ThunkType::kBakerReadBarrierRoot);
     88       return params_.root_params;
     89     }
     90 
     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:
    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:
    148     UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method)
    149         : patch_offset_(patch_offset), target_method_(target_method) { }
    150 
    151     uint32_t GetPatchOffset() const {
    152       return patch_offset_;
    153     }
    154 
    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