stack_map.h revision 442b46a087c389a91a0b51547ac9205058432364
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#include "utils.h"
23
24namespace art {
25
26/**
27 * Classes in the following file are wrapper on stack map information backed
28 * by a MemoryRegion. As such they read and write to the region, they don't have
29 * their own fields.
30 */
31
32/**
33 * Inline information for a specific PC. The information is of the form:
34 * [inlining_depth, [method_dex reference]+]
35 */
36class InlineInfo {
37 public:
38  explicit InlineInfo(MemoryRegion region) : region_(region) {}
39
40  uint8_t GetDepth() const {
41    return region_.Load<uint8_t>(kDepthOffset);
42  }
43
44  void SetDepth(uint8_t depth) {
45    region_.Store<uint8_t>(kDepthOffset, depth);
46  }
47
48  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
49    return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
50  }
51
52  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
53    region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
54  }
55
56  static size_t SingleEntrySize() {
57    return sizeof(uint32_t);
58  }
59
60 private:
61  static constexpr int kDepthOffset = 0;
62  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
63
64  MemoryRegion region_;
65
66  friend class CodeInfo;
67  friend class StackMap;
68  friend class StackMapStream;
69};
70
71/**
72 * Information on dex register values for a specific PC. The information is
73 * of the form:
74 * [location_kind, register_value]+.
75 *
76 * The location_kind for a Dex register can either be:
77 * - kConstant: register_value holds the constant,
78 * - kStack: register_value holds the stack offset,
79 * - kRegister: register_value holds the physical register number.
80 * - kFpuRegister: register_value holds the physical register number.
81 * - kNone: the register has no location yet, meaning it has not been set.
82 */
83class DexRegisterMap {
84 public:
85  explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
86
87  enum LocationKind {
88    kNone,
89    kInStack,
90    kInRegister,
91    kInFpuRegister,
92    kConstant
93  };
94
95  static const char* PrettyDescriptor(LocationKind kind) {
96    switch (kind) {
97      case kNone:
98        return "none";
99      case kInStack:
100        return "in stack";
101      case kInRegister:
102        return "in register";
103      case kInFpuRegister:
104        return "in fpu register";
105      case kConstant:
106        return "as constant";
107      default:
108        LOG(FATAL) << "Invalid location kind " << static_cast<int>(kind);
109        return nullptr;
110    }
111  }
112
113  LocationKind GetLocationKind(uint16_t register_index) const {
114    return region_.Load<LocationKind>(
115        kFixedSize + register_index * SingleEntrySize());
116  }
117
118  void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
119    size_t entry = kFixedSize + register_index * SingleEntrySize();
120    region_.Store<LocationKind>(entry, kind);
121    region_.Store<int32_t>(entry + sizeof(LocationKind), value);
122  }
123
124  int32_t GetValue(uint16_t register_index) const {
125    return region_.Load<int32_t>(
126        kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
127  }
128
129  static size_t SingleEntrySize() {
130    return sizeof(LocationKind) + sizeof(int32_t);
131  }
132
133 private:
134  static constexpr int kFixedSize = 0;
135
136  MemoryRegion region_;
137
138  friend class CodeInfo;
139  friend class StackMapStream;
140};
141
142/**
143 * A Stack Map holds compilation information for a specific PC necessary for:
144 * - Mapping it to a dex PC,
145 * - Knowing which stack entries are objects,
146 * - Knowing which registers hold objects,
147 * - Knowing the inlining information,
148 * - Knowing the values of dex registers.
149 *
150 * The information is of the form:
151 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
152 *
153 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
154 * stack size of a method.
155 */
156class StackMap {
157 public:
158  explicit StackMap(MemoryRegion region) : region_(region) {}
159
160  uint32_t GetDexPc() const {
161    return region_.Load<uint32_t>(kDexPcOffset);
162  }
163
164  void SetDexPc(uint32_t dex_pc) {
165    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
166  }
167
168  uint32_t GetNativePcOffset() const {
169    return region_.Load<uint32_t>(kNativePcOffsetOffset);
170  }
171
172  void SetNativePcOffset(uint32_t native_pc_offset) {
173    return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
174  }
175
176  uint32_t GetDexRegisterMapOffset() const {
177    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
178  }
179
180  void SetDexRegisterMapOffset(uint32_t offset) {
181    return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
182  }
183
184  uint32_t GetInlineDescriptorOffset() const {
185    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
186  }
187
188  void SetInlineDescriptorOffset(uint32_t offset) {
189    return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
190  }
191
192  uint32_t GetRegisterMask() const {
193    return region_.Load<uint32_t>(kRegisterMaskOffset);
194  }
195
196  void SetRegisterMask(uint32_t mask) {
197    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
198  }
199
200  MemoryRegion GetStackMask() const {
201    return region_.Subregion(kStackMaskOffset, StackMaskSize());
202  }
203
204  void SetStackMask(const BitVector& sp_map) {
205    MemoryRegion region = GetStackMask();
206    for (size_t i = 0; i < region.size_in_bits(); i++) {
207      region.StoreBit(i, sp_map.IsBitSet(i));
208    }
209  }
210
211  bool HasDexRegisterMap() const {
212    return GetDexRegisterMapOffset() != kNoDexRegisterMap;
213  }
214
215  bool HasInlineInfo() const {
216    return GetInlineDescriptorOffset() != kNoInlineInfo;
217  }
218
219  bool Equals(const StackMap& other) const {
220    return region_.pointer() == other.region_.pointer()
221       && region_.size() == other.region_.size();
222  }
223
224  static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
225    // On ARM, the stack maps must be 4-byte aligned.
226    return RoundUp(StackMap::kFixedSize + stack_mask_size, 4);
227  }
228
229  // Special (invalid) offset for the DexRegisterMapOffset field meaning
230  // that there is no Dex register map for this stack map.
231  static constexpr uint32_t kNoDexRegisterMap = -1;
232
233  // Special (invalid) offset for the InlineDescriptorOffset field meaning
234  // that there is no inline info for this stack map.
235  static constexpr uint32_t kNoInlineInfo = -1;
236
237 private:
238  static constexpr int kDexPcOffset = 0;
239  static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
240  static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
241  static constexpr int kInlineDescriptorOffsetOffset =
242      kDexRegisterMapOffsetOffset + sizeof(uint32_t);
243  static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
244  static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
245  static constexpr int kStackMaskOffset = kFixedSize;
246
247  size_t StackMaskSize() const { return region_.size() - kFixedSize; }
248
249  MemoryRegion region_;
250
251  friend class CodeInfo;
252  friend class StackMapStream;
253};
254
255
256/**
257 * Wrapper around all compiler information collected for a method.
258 * The information is of the form:
259 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
260 */
261class CodeInfo {
262 public:
263  explicit CodeInfo(MemoryRegion region) : region_(region) {}
264
265  explicit CodeInfo(const void* data) {
266    uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
267    region_ = MemoryRegion(const_cast<void*>(data), size);
268  }
269
270  StackMap GetStackMapAt(size_t i) const {
271    size_t size = StackMapSize();
272    return StackMap(GetStackMaps().Subregion(i * size, size));
273  }
274
275  uint32_t GetOverallSize() const {
276    return region_.Load<uint32_t>(kOverallSizeOffset);
277  }
278
279  void SetOverallSize(uint32_t size) {
280    region_.Store<uint32_t>(kOverallSizeOffset, size);
281  }
282
283  uint32_t GetStackMaskSize() const {
284    return region_.Load<uint32_t>(kStackMaskSizeOffset);
285  }
286
287  void SetStackMaskSize(uint32_t size) {
288    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
289  }
290
291  size_t GetNumberOfStackMaps() const {
292    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
293  }
294
295  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
296    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
297  }
298
299  size_t StackMapSize() const {
300    return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
301  }
302
303  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
304    DCHECK(stack_map.HasDexRegisterMap());
305    uint32_t offset = stack_map.GetDexRegisterMapOffset();
306    return DexRegisterMap(region_.Subregion(offset,
307        DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
308  }
309
310  InlineInfo GetInlineInfoOf(StackMap stack_map) const {
311    DCHECK(stack_map.HasInlineInfo());
312    uint32_t offset = stack_map.GetInlineDescriptorOffset();
313    uint8_t depth = region_.Load<uint8_t>(offset);
314    return InlineInfo(region_.Subregion(offset,
315        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
316  }
317
318  StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
319    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
320      StackMap stack_map = GetStackMapAt(i);
321      if (stack_map.GetDexPc() == dex_pc) {
322        return stack_map;
323      }
324    }
325    LOG(FATAL) << "Unreachable";
326    UNREACHABLE();
327  }
328
329  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
330    // TODO: stack maps are sorted by native pc, we can do a binary search.
331    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
332      StackMap stack_map = GetStackMapAt(i);
333      if (stack_map.GetNativePcOffset() == native_pc_offset) {
334        return stack_map;
335      }
336    }
337    LOG(FATAL) << "Unreachable";
338    UNREACHABLE();
339  }
340
341 private:
342  static constexpr int kOverallSizeOffset = 0;
343  static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
344  static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
345  static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
346
347  MemoryRegion GetStackMaps() const {
348    return region_.size() == 0
349        ? MemoryRegion()
350        : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
351  }
352
353  MemoryRegion region_;
354  friend class StackMapStream;
355};
356
357}  // namespace art
358
359#endif  // ART_RUNTIME_STACK_MAP_H_
360