1 /*
2  * Copyright (C) 2014 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_RUNTIME_STACK_MAP_H_
18 #define ART_RUNTIME_STACK_MAP_H_
19 
20 #include "base/bit_vector.h"
21 #include "memory_region.h"
22 
23 namespace art {
24 
25 /**
26  * Classes in the following file are wrapper on stack map information backed
27  * by a MemoryRegion. As such they read and write to the region, they don't have
28  * their own fields.
29  */
30 
31 /**
32  * Inline information for a specific PC. The information is of the form:
33  * [inlining_depth, [method_dex reference]+]
34  */
35 class InlineInfo {
36  public:
InlineInfo(MemoryRegion region)37   explicit InlineInfo(MemoryRegion region) : region_(region) {}
38 
GetDepth()39   uint8_t GetDepth() const {
40     return region_.Load<uint8_t>(kDepthOffset);
41   }
42 
SetDepth(uint8_t depth)43   void SetDepth(uint8_t depth) {
44     region_.Store<uint8_t>(kDepthOffset, depth);
45   }
46 
GetMethodReferenceIndexAtDepth(uint8_t depth)47   uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
48     return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
49   }
50 
SetMethodReferenceIndexAtDepth(uint8_t depth,uint32_t index)51   void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
52     region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
53   }
54 
SingleEntrySize()55   static size_t SingleEntrySize() {
56     return sizeof(uint32_t);
57   }
58 
59  private:
60   static constexpr int kDepthOffset = 0;
61   static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
62 
63   static constexpr uint32_t kNoInlineInfo = -1;
64 
65   MemoryRegion region_;
66 
67   template<typename T> friend class CodeInfo;
68   template<typename T> friend class StackMap;
69   template<typename T> friend class StackMapStream;
70 };
71 
72 /**
73  * Information on dex register values for a specific PC. The information is
74  * of the form:
75  * [location_kind, register_value]+.
76  *
77  * The location_kind for a Dex register can either be:
78  * - Constant: register_value holds the constant,
79  * - Stack: register_value holds the stack offset,
80  * - Register: register_value holds the register number.
81  */
82 class DexRegisterMap {
83  public:
DexRegisterMap(MemoryRegion region)84   explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
85 
86   enum LocationKind {
87     kInStack,
88     kInRegister,
89     kConstant
90   };
91 
GetLocationKind(uint16_t register_index)92   LocationKind GetLocationKind(uint16_t register_index) const {
93     return region_.Load<LocationKind>(
94         kFixedSize + register_index * SingleEntrySize());
95   }
96 
SetRegisterInfo(uint16_t register_index,LocationKind kind,int32_t value)97   void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
98     size_t entry = kFixedSize + register_index * SingleEntrySize();
99     region_.Store<LocationKind>(entry, kind);
100     region_.Store<int32_t>(entry + sizeof(LocationKind), value);
101   }
102 
GetValue(uint16_t register_index)103   int32_t GetValue(uint16_t register_index) const {
104     return region_.Load<int32_t>(
105         kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
106   }
107 
SingleEntrySize()108   static size_t SingleEntrySize() {
109     return sizeof(LocationKind) + sizeof(int32_t);
110   }
111 
112  private:
113   static constexpr int kFixedSize = 0;
114 
115   MemoryRegion region_;
116 
117   template <typename T> friend class CodeInfo;
118   template <typename T> friend class StackMapStream;
119 };
120 
121 /**
122  * A Stack Map holds compilation information for a specific PC necessary for:
123  * - Mapping it to a dex PC,
124  * - Knowing which stack entries are objects,
125  * - Knowing which registers hold objects,
126  * - Knowing the inlining information,
127  * - Knowing the values of dex registers.
128  *
129  * The information is of the form:
130  * [dex_pc, native_pc, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
131  *
132  * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
133  * stack size of a method.
134  */
135 template <typename T>
136 class StackMap {
137  public:
StackMap(MemoryRegion region)138   explicit StackMap(MemoryRegion region) : region_(region) {}
139 
GetDexPc()140   uint32_t GetDexPc() const {
141     return region_.Load<uint32_t>(kDexPcOffset);
142   }
143 
SetDexPc(uint32_t dex_pc)144   void SetDexPc(uint32_t dex_pc) {
145     region_.Store<uint32_t>(kDexPcOffset, dex_pc);
146   }
147 
GetNativePc()148   T GetNativePc() const {
149     return region_.Load<T>(kNativePcOffset);
150   }
151 
SetNativePc(T native_pc)152   void SetNativePc(T native_pc) {
153     return region_.Store<T>(kNativePcOffset, native_pc);
154   }
155 
GetDexRegisterMapOffset()156   uint32_t GetDexRegisterMapOffset() const {
157     return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
158   }
159 
SetDexRegisterMapOffset(uint32_t offset)160   void SetDexRegisterMapOffset(uint32_t offset) {
161     return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
162   }
163 
GetInlineDescriptorOffset()164   uint32_t GetInlineDescriptorOffset() const {
165     return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
166   }
167 
SetInlineDescriptorOffset(uint32_t offset)168   void SetInlineDescriptorOffset(uint32_t offset) {
169     return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
170   }
171 
GetRegisterMask()172   uint32_t GetRegisterMask() const {
173     return region_.Load<uint32_t>(kRegisterMaskOffset);
174   }
175 
SetRegisterMask(uint32_t mask)176   void SetRegisterMask(uint32_t mask) {
177     region_.Store<uint32_t>(kRegisterMaskOffset, mask);
178   }
179 
GetStackMask()180   MemoryRegion GetStackMask() const {
181     return region_.Subregion(kStackMaskOffset, StackMaskSize());
182   }
183 
SetStackMask(const BitVector & sp_map)184   void SetStackMask(const BitVector& sp_map) {
185     MemoryRegion region = GetStackMask();
186     for (size_t i = 0; i < region.size_in_bits(); i++) {
187       region.StoreBit(i, sp_map.IsBitSet(i));
188     }
189   }
190 
HasInlineInfo()191   bool HasInlineInfo() const {
192     return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
193   }
194 
Equals(const StackMap & other)195   bool Equals(const StackMap& other) {
196     return region_.pointer() == other.region_.pointer()
197        && region_.size() == other.region_.size();
198   }
199 
200  private:
201   static constexpr int kDexPcOffset = 0;
202   static constexpr int kNativePcOffset = kDexPcOffset + sizeof(uint32_t);
203   static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffset + sizeof(T);
204   static constexpr int kInlineDescriptorOffsetOffset =
205       kDexRegisterMapOffsetOffset + sizeof(uint32_t);
206   static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
207   static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
208   static constexpr int kStackMaskOffset = kFixedSize;
209 
StackMaskSize()210   size_t StackMaskSize() const { return region_.size() - kFixedSize; }
211 
212   MemoryRegion region_;
213 
214   template <typename U> friend class CodeInfo;
215   template <typename U> friend class StackMapStream;
216 };
217 
218 
219 /**
220  * Wrapper around all compiler information collected for a method.
221  * The information is of the form:
222  * [number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
223  */
224 template <typename T>
225 class CodeInfo {
226  public:
CodeInfo(MemoryRegion region)227   explicit CodeInfo(MemoryRegion region) : region_(region) {}
228 
GetStackMapAt(size_t i)229   StackMap<T> GetStackMapAt(size_t i) const {
230     size_t size = StackMapSize();
231     return StackMap<T>(GetStackMaps().Subregion(i * size, size));
232   }
233 
GetStackMaskSize()234   uint32_t GetStackMaskSize() const {
235     return region_.Load<uint32_t>(kStackMaskSizeOffset);
236   }
237 
SetStackMaskSize(uint32_t size)238   void SetStackMaskSize(uint32_t size) {
239     region_.Store<uint32_t>(kStackMaskSizeOffset, size);
240   }
241 
GetNumberOfStackMaps()242   size_t GetNumberOfStackMaps() const {
243     return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
244   }
245 
SetNumberOfStackMaps(uint32_t number_of_stack_maps)246   void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
247     region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
248   }
249 
StackMapSize()250   size_t StackMapSize() const {
251     return StackMap<T>::kFixedSize + GetStackMaskSize();
252   }
253 
GetDexRegisterMapOf(StackMap<T> stack_map,uint32_t number_of_dex_registers)254   DexRegisterMap GetDexRegisterMapOf(StackMap<T> stack_map, uint32_t number_of_dex_registers) {
255     uint32_t offset = stack_map.GetDexRegisterMapOffset();
256     return DexRegisterMap(region_.Subregion(offset,
257         DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
258   }
259 
GetInlineInfoOf(StackMap<T> stack_map)260   InlineInfo GetInlineInfoOf(StackMap<T> stack_map) {
261     uint32_t offset = stack_map.GetInlineDescriptorOffset();
262     uint8_t depth = region_.Load<uint8_t>(offset);
263     return InlineInfo(region_.Subregion(offset,
264         InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
265   }
266 
GetStackMapForDexPc(uint32_t dex_pc)267   StackMap<T> GetStackMapForDexPc(uint32_t dex_pc) {
268     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
269       StackMap<T> stack_map = GetStackMapAt(i);
270       if (stack_map.GetDexPc() == dex_pc) {
271         return stack_map;
272       }
273     }
274     LOG(FATAL) << "Unreachable";
275     return StackMap<T>(MemoryRegion());
276   }
277 
GetStackMapForNativePc(T native_pc)278   StackMap<T> GetStackMapForNativePc(T native_pc) {
279     // TODO: stack maps are sorted by native pc, we can do a binary search.
280     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
281       StackMap<T> stack_map = GetStackMapAt(i);
282       if (stack_map.GetNativePc() == native_pc) {
283         return stack_map;
284       }
285     }
286     LOG(FATAL) << "Unreachable";
287     return StackMap<T>(MemoryRegion());
288   }
289 
290  private:
291   static constexpr int kNumberOfStackMapsOffset = 0;
292   static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
293   static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
294 
GetStackMaps()295   MemoryRegion GetStackMaps() const {
296     return region_.size() == 0
297         ? MemoryRegion()
298         : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
299   }
300 
301   MemoryRegion region_;
302   template<typename U> friend class StackMapStream;
303 };
304 
305 }  // namespace art
306 
307 #endif  // ART_RUNTIME_STACK_MAP_H_
308