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
27namespace art {
28namespace linker {
29
30class 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