stack_map.h revision 99ea58cc68b51837c065f4a2a54efbf208dd76fa
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
23namespace 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 */
35class InlineInfo {
36 public:
37  explicit InlineInfo(MemoryRegion region) : region_(region) {}
38
39  uint8_t GetDepth() const {
40    return region_.Load<uint8_t>(kDepthOffset);
41  }
42
43  void SetDepth(uint8_t depth) {
44    region_.Store<uint8_t>(kDepthOffset, depth);
45  }
46
47  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
48    return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
49  }
50
51  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
52    region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
53  }
54
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 */
82class DexRegisterMap {
83 public:
84  explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
85
86  enum LocationKind {
87    kInStack,
88    kInRegister,
89    kConstant
90  };
91
92  LocationKind GetLocationKind(uint16_t register_index) const {
93    return region_.Load<LocationKind>(
94        kFixedSize + register_index * SingleEntrySize());
95  }
96
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
103  int32_t GetValue(uint16_t register_index) const {
104    return region_.Load<int32_t>(
105        kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
106  }
107
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 */
135template <typename T>
136class StackMap {
137 public:
138  explicit StackMap(MemoryRegion region) : region_(region) {}
139
140  uint32_t GetDexPc() const {
141    return region_.Load<uint32_t>(kDexPcOffset);
142  }
143
144  void SetDexPc(uint32_t dex_pc) {
145    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
146  }
147
148  T GetNativePc() const {
149    return region_.Load<T>(kNativePcOffset);
150  }
151
152  void SetNativePc(T native_pc) {
153    return region_.Store<T>(kNativePcOffset, native_pc);
154  }
155
156  uint32_t GetDexRegisterMapOffset() const {
157    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
158  }
159
160  void SetDexRegisterMapOffset(uint32_t offset) {
161    return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
162  }
163
164  uint32_t GetInlineDescriptorOffset() const {
165    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
166  }
167
168  void SetInlineDescriptorOffset(uint32_t offset) {
169    return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
170  }
171
172  uint32_t GetRegisterMask() const {
173    return region_.Load<uint32_t>(kRegisterMaskOffset);
174  }
175
176  void SetRegisterMask(uint32_t mask) {
177    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
178  }
179
180  MemoryRegion GetStackMask() const {
181    return region_.Subregion(kStackMaskOffset, StackMaskSize());
182  }
183
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
191  bool HasInlineInfo() const {
192    return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
193  }
194
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
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 */
224template <typename T>
225class CodeInfo {
226 public:
227  explicit CodeInfo(MemoryRegion region) : region_(region) {}
228
229  StackMap<T> GetStackMapAt(size_t i) const {
230    size_t size = StackMapSize();
231    return StackMap<T>(GetStackMaps().Subregion(i * size, size));
232  }
233
234  uint32_t GetStackMaskSize() const {
235    return region_.Load<uint32_t>(kStackMaskSizeOffset);
236  }
237
238  void SetStackMaskSize(uint32_t size) {
239    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
240  }
241
242  size_t GetNumberOfStackMaps() const {
243    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
244  }
245
246  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
247    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
248  }
249
250  size_t StackMapSize() const {
251    return StackMap<T>::kFixedSize + GetStackMaskSize();
252  }
253
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
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
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
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
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