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_ARM64_RELATIVE_PATCHER_ARM64_H_
18 #define ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_
19 
20 #include "base/array_ref.h"
21 #include "base/bit_field.h"
22 #include "linker/arm/relative_patcher_arm_base.h"
23 
24 namespace art {
25 namespace linker {
26 
27 class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher {
28  public:
29   enum class BakerReadBarrierKind : uint8_t {
30     kField,   // Field get or array get with constant offset (i.e. constant index).
31     kGcRoot,  // GC root load.
32     kLast
33   };
34 
EncodeBakerReadBarrierFieldData(uint32_t base_reg,uint32_t holder_reg)35   static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg, uint32_t holder_reg) {
36     CheckValidReg(base_reg);
37     CheckValidReg(holder_reg);
38     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kField) |
39            BakerReadBarrierFirstRegField::Encode(base_reg) |
40            BakerReadBarrierSecondRegField::Encode(holder_reg);
41   }
42 
EncodeBakerReadBarrierGcRootData(uint32_t root_reg)43   static uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg) {
44     CheckValidReg(root_reg);
45     return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kGcRoot) |
46            BakerReadBarrierFirstRegField::Encode(root_reg) |
47            BakerReadBarrierSecondRegField::Encode(kInvalidEncodedReg);
48   }
49 
50   Arm64RelativePatcher(RelativePatcherTargetProvider* provider,
51                        const Arm64InstructionSetFeatures* features);
52 
53   uint32_t ReserveSpace(uint32_t offset,
54                         const CompiledMethod* compiled_method,
55                         MethodReference method_ref) OVERRIDE;
56   uint32_t ReserveSpaceEnd(uint32_t offset) OVERRIDE;
57   uint32_t WriteThunks(OutputStream* out, uint32_t offset) OVERRIDE;
58   void PatchCall(std::vector<uint8_t>* code,
59                  uint32_t literal_offset,
60                  uint32_t patch_offset,
61                  uint32_t target_offset) OVERRIDE;
62   void PatchPcRelativeReference(std::vector<uint8_t>* code,
63                                 const LinkerPatch& patch,
64                                 uint32_t patch_offset,
65                                 uint32_t target_offset) OVERRIDE;
66   void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
67                                    const LinkerPatch& patch,
68                                    uint32_t patch_offset) OVERRIDE;
69 
70  protected:
71   static constexpr uint32_t kInvalidEncodedReg = /* sp/zr is invalid */ 31u;
72 
73   ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) OVERRIDE;
74   std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
75   uint32_t MaxPositiveDisplacement(ThunkType type) OVERRIDE;
76   uint32_t MaxNegativeDisplacement(ThunkType type) OVERRIDE;
77 
78  private:
79   static constexpr size_t kBitsForBakerReadBarrierKind =
80       MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast));
81   static constexpr size_t kBitsForRegister = 5u;
82   using BakerReadBarrierKindField =
83       BitField<BakerReadBarrierKind, 0, kBitsForBakerReadBarrierKind>;
84   using BakerReadBarrierFirstRegField =
85       BitField<uint32_t, kBitsForBakerReadBarrierKind, kBitsForRegister>;
86   using BakerReadBarrierSecondRegField =
87       BitField<uint32_t, kBitsForBakerReadBarrierKind + kBitsForRegister, kBitsForRegister>;
88 
CheckValidReg(uint32_t reg)89   static void CheckValidReg(uint32_t reg) {
90     DCHECK(reg < 30u && reg != 16u && reg != 17u);
91   }
92 
93   static uint32_t PatchAdrp(uint32_t adrp, uint32_t disp);
94 
95   static bool NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, uint32_t literal_offset,
96                                       uint32_t patch_offset);
97   void SetInsn(std::vector<uint8_t>* code, uint32_t offset, uint32_t value);
98   static uint32_t GetInsn(ArrayRef<const uint8_t> code, uint32_t offset);
99 
100   template <typename Alloc>
101   static uint32_t GetInsn(std::vector<uint8_t, Alloc>* code, uint32_t offset);
102 
103   const bool fix_cortex_a53_843419_;
104   // Map original patch_offset to thunk offset.
105   std::vector<std::pair<uint32_t, uint32_t>> adrp_thunk_locations_;
106   size_t reserved_adrp_thunks_;
107   size_t processed_adrp_thunks_;
108   std::vector<uint8_t> current_method_thunks_;
109 
110   friend class Arm64RelativePatcherTest;
111 
112   DISALLOW_COPY_AND_ASSIGN(Arm64RelativePatcher);
113 };
114 
115 }  // namespace linker
116 }  // namespace art
117 
118 #endif  // ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_
119