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