stack_map.h revision 102cbed1e52b7c5f09458b44903fe97bb3e14d5f
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  friend class CodeInfo;
68  friend class StackMap;
69  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 physical register number.
81 * - None: 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  LocationKind GetLocationKind(uint16_t register_index) const {
96    return region_.Load<LocationKind>(
97        kFixedSize + register_index * SingleEntrySize());
98  }
99
100  void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
101    size_t entry = kFixedSize + register_index * SingleEntrySize();
102    region_.Store<LocationKind>(entry, kind);
103    region_.Store<int32_t>(entry + sizeof(LocationKind), value);
104  }
105
106  int32_t GetValue(uint16_t register_index) const {
107    return region_.Load<int32_t>(
108        kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
109  }
110
111  static size_t SingleEntrySize() {
112    return sizeof(LocationKind) + sizeof(int32_t);
113  }
114
115 private:
116  static constexpr int kFixedSize = 0;
117
118  MemoryRegion region_;
119
120  friend class CodeInfo;
121  friend class StackMapStream;
122};
123
124/**
125 * A Stack Map holds compilation information for a specific PC necessary for:
126 * - Mapping it to a dex PC,
127 * - Knowing which stack entries are objects,
128 * - Knowing which registers hold objects,
129 * - Knowing the inlining information,
130 * - Knowing the values of dex registers.
131 *
132 * The information is of the form:
133 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
134 *
135 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
136 * stack size of a method.
137 */
138class StackMap {
139 public:
140  explicit StackMap(MemoryRegion region) : region_(region) {}
141
142  uint32_t GetDexPc() const {
143    return region_.Load<uint32_t>(kDexPcOffset);
144  }
145
146  void SetDexPc(uint32_t dex_pc) {
147    region_.Store<uint32_t>(kDexPcOffset, dex_pc);
148  }
149
150  uint32_t GetNativePcOffset() const {
151    return region_.Load<uint32_t>(kNativePcOffsetOffset);
152  }
153
154  void SetNativePcOffset(uint32_t native_pc_offset) {
155    return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
156  }
157
158  uint32_t GetDexRegisterMapOffset() const {
159    return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
160  }
161
162  void SetDexRegisterMapOffset(uint32_t offset) {
163    return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
164  }
165
166  uint32_t GetInlineDescriptorOffset() const {
167    return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
168  }
169
170  void SetInlineDescriptorOffset(uint32_t offset) {
171    return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
172  }
173
174  uint32_t GetRegisterMask() const {
175    return region_.Load<uint32_t>(kRegisterMaskOffset);
176  }
177
178  void SetRegisterMask(uint32_t mask) {
179    region_.Store<uint32_t>(kRegisterMaskOffset, mask);
180  }
181
182  MemoryRegion GetStackMask() const {
183    return region_.Subregion(kStackMaskOffset, StackMaskSize());
184  }
185
186  void SetStackMask(const BitVector& sp_map) {
187    MemoryRegion region = GetStackMask();
188    for (size_t i = 0; i < region.size_in_bits(); i++) {
189      region.StoreBit(i, sp_map.IsBitSet(i));
190    }
191  }
192
193  bool HasInlineInfo() const {
194    return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
195  }
196
197  bool Equals(const StackMap& other) {
198    return region_.pointer() == other.region_.pointer()
199       && region_.size() == other.region_.size();
200  }
201
202 private:
203  static constexpr int kDexPcOffset = 0;
204  static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
205  static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
206  static constexpr int kInlineDescriptorOffsetOffset =
207      kDexRegisterMapOffsetOffset + sizeof(uint32_t);
208  static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
209  static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
210  static constexpr int kStackMaskOffset = kFixedSize;
211
212  size_t StackMaskSize() const { return region_.size() - kFixedSize; }
213
214  MemoryRegion region_;
215
216  friend class CodeInfo;
217  friend class StackMapStream;
218};
219
220
221/**
222 * Wrapper around all compiler information collected for a method.
223 * The information is of the form:
224 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
225 */
226class CodeInfo {
227 public:
228  explicit CodeInfo(MemoryRegion region) : region_(region) {}
229
230  explicit CodeInfo(const void* data) {
231    uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
232    region_ = MemoryRegion(const_cast<void*>(data), size);
233  }
234
235  StackMap GetStackMapAt(size_t i) const {
236    size_t size = StackMapSize();
237    return StackMap(GetStackMaps().Subregion(i * size, size));
238  }
239
240  uint32_t GetOverallSize() const {
241    return region_.Load<uint32_t>(kOverallSizeOffset);
242  }
243
244  void SetOverallSize(uint32_t size) {
245    region_.Store<uint32_t>(kOverallSizeOffset, size);
246  }
247
248  uint32_t GetStackMaskSize() const {
249    return region_.Load<uint32_t>(kStackMaskSizeOffset);
250  }
251
252  void SetStackMaskSize(uint32_t size) {
253    region_.Store<uint32_t>(kStackMaskSizeOffset, size);
254  }
255
256  size_t GetNumberOfStackMaps() const {
257    return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
258  }
259
260  void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
261    region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
262  }
263
264  size_t StackMapSize() const {
265    return StackMap::kFixedSize + GetStackMaskSize();
266  }
267
268  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
269    uint32_t offset = stack_map.GetDexRegisterMapOffset();
270    return DexRegisterMap(region_.Subregion(offset,
271        DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
272  }
273
274  InlineInfo GetInlineInfoOf(StackMap stack_map) {
275    uint32_t offset = stack_map.GetInlineDescriptorOffset();
276    uint8_t depth = region_.Load<uint8_t>(offset);
277    return InlineInfo(region_.Subregion(offset,
278        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
279  }
280
281  StackMap GetStackMapForDexPc(uint32_t dex_pc) {
282    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
283      StackMap stack_map = GetStackMapAt(i);
284      if (stack_map.GetDexPc() == dex_pc) {
285        return stack_map;
286      }
287    }
288    LOG(FATAL) << "Unreachable";
289    return StackMap(MemoryRegion());
290  }
291
292  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
293    // TODO: stack maps are sorted by native pc, we can do a binary search.
294    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
295      StackMap stack_map = GetStackMapAt(i);
296      if (stack_map.GetNativePcOffset() == native_pc_offset) {
297        return stack_map;
298      }
299    }
300    LOG(FATAL) << "Unreachable";
301    return StackMap(MemoryRegion());
302  }
303
304 private:
305  static constexpr int kOverallSizeOffset = 0;
306  static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
307  static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
308  static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
309
310  MemoryRegion GetStackMaps() const {
311    return region_.size() == 0
312        ? MemoryRegion()
313        : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
314  }
315
316  MemoryRegion region_;
317  friend class StackMapStream;
318};
319
320}  // namespace art
321
322#endif  // ART_RUNTIME_STACK_MAP_H_
323