stack_map.h revision 12baf476389359d54ae04d7898190ef6f81ab0b2
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  size_t Size() const {
134    return region_.size();
135  }
136
137  static constexpr int kFixedSize = 0;
138
139 private:
140  MemoryRegion region_;
141};
142
143/**
144 * A Stack Map holds compilation information for a specific PC necessary for:
145 * - Mapping it to a dex PC,
146 * - Knowing which stack entries are objects,
147 * - Knowing which registers hold objects,
148 * - Knowing the inlining information,
149 * - Knowing the values of dex registers.
150 *
151 * The information is of the form:
152 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
153 *
154 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
155 * stack size of a method.
156 */
157class StackMap {
158 public:
159  explicit StackMap(MemoryRegion region) : region_(region) {}
160
161  uint32_t GetDexPc() const {
162    return region_.Load<uint32_t>(kDexPcOffset);
163  }
164
165  void SetDexPc(uint32_t dex_pc) {
166    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
167  }
168
169  uint32_t GetNativePcOffset() const {
170    return region_.Load<uint32_t>(kNativePcOffsetOffset);
171  }
172
173  void SetNativePcOffset(uint32_t native_pc_offset) {
174    return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
175  }
176
177  uint32_t GetDexRegisterMapOffset() const {
178    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
179  }
180
181  void SetDexRegisterMapOffset(uint32_t offset) {
182    return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
183  }
184
185  uint32_t GetInlineDescriptorOffset() const {
186    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
187  }
188
189  void SetInlineDescriptorOffset(uint32_t offset) {
190    return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
191  }
192
193  uint32_t GetRegisterMask() const {
194    return region_.Load<uint32_t>(kRegisterMaskOffset);
195  }
196
197  void SetRegisterMask(uint32_t mask) {
198    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
199  }
200
201  MemoryRegion GetStackMask() const {
202    return region_.Subregion(kStackMaskOffset, StackMaskSize());
203  }
204
205  void SetStackMask(const BitVector& sp_map) {
206    MemoryRegion region = GetStackMask();
207    for (size_t i = 0; i < region.size_in_bits(); i++) {
208      region.StoreBit(i, sp_map.IsBitSet(i));
209    }
210  }
211
212  bool HasDexRegisterMap() const {
213    return GetDexRegisterMapOffset() != kNoDexRegisterMap;
214  }
215
216  bool HasInlineInfo() const {
217    return GetInlineDescriptorOffset() != kNoInlineInfo;
218  }
219
220  bool Equals(const StackMap& other) const {
221    return region_.pointer() == other.region_.pointer()
222       && region_.size() == other.region_.size();
223  }
224
225  static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
226    // On ARM, the stack maps must be 4-byte aligned.
227    return RoundUp(StackMap::kFixedSize + stack_mask_size, 4);
228  }
229
230  // Special (invalid) offset for the DexRegisterMapOffset field meaning
231  // that there is no Dex register map for this stack map.
232  static constexpr uint32_t kNoDexRegisterMap = -1;
233
234  // Special (invalid) offset for the InlineDescriptorOffset field meaning
235  // that there is no inline info for this stack map.
236  static constexpr uint32_t kNoInlineInfo = -1;
237
238 private:
239  static constexpr int kDexPcOffset = 0;
240  static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
241  static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
242  static constexpr int kInlineDescriptorOffsetOffset =
243      kDexRegisterMapOffsetOffset + sizeof(uint32_t);
244  static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
245  static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
246  static constexpr int kStackMaskOffset = kFixedSize;
247
248  size_t StackMaskSize() const { return region_.size() - kFixedSize; }
249
250  MemoryRegion region_;
251
252  friend class CodeInfo;
253  friend class StackMapStream;
254};
255
256
257/**
258 * Wrapper around all compiler information collected for a method.
259 * The information is of the form:
260 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
261 */
262class CodeInfo {
263 public:
264  explicit CodeInfo(MemoryRegion region) : region_(region) {}
265
266  explicit CodeInfo(const void* data) {
267    uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
268    region_ = MemoryRegion(const_cast<void*>(data), size);
269  }
270
271  StackMap GetStackMapAt(size_t i) const {
272    size_t size = StackMapSize();
273    return StackMap(GetStackMaps().Subregion(i * size, size));
274  }
275
276  uint32_t GetOverallSize() const {
277    return region_.Load<uint32_t>(kOverallSizeOffset);
278  }
279
280  void SetOverallSize(uint32_t size) {
281    region_.Store<uint32_t>(kOverallSizeOffset, size);
282  }
283
284  uint32_t GetStackMaskSize() const {
285    return region_.Load<uint32_t>(kStackMaskSizeOffset);
286  }
287
288  void SetStackMaskSize(uint32_t size) {
289    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
290  }
291
292  size_t GetNumberOfStackMaps() const {
293    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
294  }
295
296  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
297    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
298  }
299
300  size_t StackMapSize() const {
301    return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
302  }
303
304  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
305    DCHECK(stack_map.HasDexRegisterMap());
306    uint32_t offset = stack_map.GetDexRegisterMapOffset();
307    return DexRegisterMap(region_.Subregion(offset,
308        DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
309  }
310
311  InlineInfo GetInlineInfoOf(StackMap stack_map) const {
312    DCHECK(stack_map.HasInlineInfo());
313    uint32_t offset = stack_map.GetInlineDescriptorOffset();
314    uint8_t depth = region_.Load<uint8_t>(offset);
315    return InlineInfo(region_.Subregion(offset,
316        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
317  }
318
319  StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
320    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
321      StackMap stack_map = GetStackMapAt(i);
322      if (stack_map.GetDexPc() == dex_pc) {
323        return stack_map;
324      }
325    }
326    LOG(FATAL) << "Unreachable";
327    UNREACHABLE();
328  }
329
330  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
331    // TODO: stack maps are sorted by native pc, we can do a binary search.
332    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
333      StackMap stack_map = GetStackMapAt(i);
334      if (stack_map.GetNativePcOffset() == native_pc_offset) {
335        return stack_map;
336      }
337    }
338    LOG(FATAL) << "Unreachable";
339    UNREACHABLE();
340  }
341
342 private:
343  static constexpr int kOverallSizeOffset = 0;
344  static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
345  static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
346  static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
347
348  MemoryRegion GetStackMaps() const {
349    return region_.size() == 0
350        ? MemoryRegion()
351        : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
352  }
353
354  MemoryRegion region_;
355  friend class StackMapStream;
356};
357
358}  // namespace art
359
360#endif  // ART_RUNTIME_STACK_MAP_H_
361