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_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
18 #define ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
19 
20 #include <deque>
21 #include <vector>
22 
23 #include "base/safe_map.h"
24 #include "dex/method_reference.h"
25 #include "linker/relative_patcher.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   std::vector<debug::MethodDebugInfo> GenerateThunkDebugInfo(uint32_t executable_offset) override;
38 
39  protected:
40   ArmBaseRelativePatcher(RelativePatcherThunkProvider* thunk_provider,
41                          RelativePatcherTargetProvider* target_provider,
42                          InstructionSet instruction_set);
43   ~ArmBaseRelativePatcher();
44 
45   enum class ThunkType {
46     kMethodCall,              // Method call thunk.
47     kBakerReadBarrier,        // Baker read barrier.
48   };
49 
50   class ThunkKey {
51    public:
52     explicit ThunkKey(ThunkType type, uint32_t custom_value1 = 0u, uint32_t custom_value2 = 0u)
type_(type)53         : type_(type), custom_value1_(custom_value1), custom_value2_(custom_value2) { }
54 
GetType()55     ThunkType GetType() const {
56       return type_;
57     }
58 
GetCustomValue1()59     uint32_t GetCustomValue1() const {
60       return custom_value1_;
61     }
62 
GetCustomValue2()63     uint32_t GetCustomValue2() const {
64       return custom_value2_;
65     }
66 
67    private:
68     ThunkType type_;
69     uint32_t custom_value1_;
70     uint32_t custom_value2_;
71   };
72 
73   class ThunkKeyCompare {
74    public:
operator()75     bool operator()(const ThunkKey& lhs, const ThunkKey& rhs) const {
76       if (lhs.GetType() != rhs.GetType()) {
77         return lhs.GetType() < rhs.GetType();
78       }
79       if (lhs.GetCustomValue1() != rhs.GetCustomValue1()) {
80         return lhs.GetCustomValue1() < rhs.GetCustomValue1();
81       }
82       return lhs.GetCustomValue2() < rhs.GetCustomValue2();
83     }
84   };
85 
86   static ThunkKey GetMethodCallKey();
87   static ThunkKey GetBakerThunkKey(const LinkerPatch& patch);
88 
89   uint32_t ReserveSpaceInternal(uint32_t offset,
90                                 const CompiledMethod* compiled_method,
91                                 MethodReference method_ref,
92                                 uint32_t max_extra_space);
93   uint32_t GetThunkTargetOffset(const ThunkKey& key, uint32_t patch_offset);
94 
95   uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset,
96                                            uint32_t target_offset);
97 
98   virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0;
99   virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0;
100 
101  private:
102   class ThunkData;
103 
104   void ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset);
105   void AddUnreservedThunk(ThunkData* data);
106 
107   void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref);
108 
109   uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key);
110   ThunkData ThunkDataForPatch(const LinkerPatch& patch, uint32_t max_next_offset);
111 
112   RelativePatcherThunkProvider* const thunk_provider_;
113   RelativePatcherTargetProvider* const target_provider_;
114   const InstructionSet instruction_set_;
115 
116   // The data for all thunks.
117   // SafeMap<> nodes don't move after being inserted, so we can use direct pointers to the data.
118   using ThunkMap = SafeMap<ThunkKey, ThunkData, ThunkKeyCompare>;
119   ThunkMap thunks_;
120 
121   // ReserveSpace() tracks unprocessed method call patches. These may be resolved later.
122   class UnprocessedMethodCallPatch {
123    public:
UnprocessedMethodCallPatch(uint32_t patch_offset,MethodReference target_method)124     UnprocessedMethodCallPatch(uint32_t patch_offset, MethodReference target_method)
125         : patch_offset_(patch_offset), target_method_(target_method) { }
126 
GetPatchOffset()127     uint32_t GetPatchOffset() const {
128       return patch_offset_;
129     }
130 
GetTargetMethod()131     MethodReference GetTargetMethod() const {
132       return target_method_;
133     }
134 
135    private:
136     uint32_t patch_offset_;
137     MethodReference target_method_;
138   };
139   std::deque<UnprocessedMethodCallPatch> unprocessed_method_call_patches_;
140   // Once we have compiled a method call thunk, cache pointer to the data.
141   ThunkData* method_call_thunk_;
142 
143   // Thunks
144   std::deque<ThunkData*> unreserved_thunks_;
145 
146   class PendingThunkComparator;
147   std::vector<ThunkData*> pending_thunks_;  // Heap with the PendingThunkComparator.
148 
149   friend class Arm64RelativePatcherTest;
150   friend class Thumb2RelativePatcherTest;
151 
152   DISALLOW_COPY_AND_ASSIGN(ArmBaseRelativePatcher);
153 };
154 
155 }  // namespace linker
156 }  // namespace art
157 
158 #endif  // ART_DEX2OAT_LINKER_ARM_RELATIVE_PATCHER_ARM_BASE_H_
159