blob: 9b49d31ed9246dcd1ffd02cba6944e650f6ad9e9 [file] [log] [blame]
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001/*
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
Nicolas Geoffray39468442014-09-02 15:17:15 +010067 friend class CodeInfo;
68 friend class StackMap;
69 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010070};
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,
Nicolas Geoffray39468442014-09-02 15:17:15 +010080 * - Register: register_value holds the physical register number.
81 * - None: the register has no location yet, meaning it has not been set.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010082 */
83class DexRegisterMap {
84 public:
85 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
86
87 enum LocationKind {
Nicolas Geoffray39468442014-09-02 15:17:15 +010088 kNone,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010089 kInStack,
90 kInRegister,
91 kConstant
92 };
93
94 LocationKind GetLocationKind(uint16_t register_index) const {
95 return region_.Load<LocationKind>(
96 kFixedSize + register_index * SingleEntrySize());
97 }
98
99 void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
100 size_t entry = kFixedSize + register_index * SingleEntrySize();
101 region_.Store<LocationKind>(entry, kind);
102 region_.Store<int32_t>(entry + sizeof(LocationKind), value);
103 }
104
105 int32_t GetValue(uint16_t register_index) const {
106 return region_.Load<int32_t>(
107 kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
108 }
109
110 static size_t SingleEntrySize() {
111 return sizeof(LocationKind) + sizeof(int32_t);
112 }
113
114 private:
115 static constexpr int kFixedSize = 0;
116
117 MemoryRegion region_;
118
Nicolas Geoffray39468442014-09-02 15:17:15 +0100119 friend class CodeInfo;
120 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100121};
122
123/**
124 * A Stack Map holds compilation information for a specific PC necessary for:
125 * - Mapping it to a dex PC,
126 * - Knowing which stack entries are objects,
127 * - Knowing which registers hold objects,
128 * - Knowing the inlining information,
129 * - Knowing the values of dex registers.
130 *
131 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100132 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100133 *
134 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
135 * stack size of a method.
136 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100137class StackMap {
138 public:
139 explicit StackMap(MemoryRegion region) : region_(region) {}
140
141 uint32_t GetDexPc() const {
142 return region_.Load<uint32_t>(kDexPcOffset);
143 }
144
145 void SetDexPc(uint32_t dex_pc) {
146 region_.Store<uint32_t>(kDexPcOffset, dex_pc);
147 }
148
Nicolas Geoffray39468442014-09-02 15:17:15 +0100149 uint32_t GetNativePcOffset() const {
150 return region_.Load<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100151 }
152
Nicolas Geoffray39468442014-09-02 15:17:15 +0100153 void SetNativePcOffset(uint32_t native_pc_offset) {
154 return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100155 }
156
157 uint32_t GetDexRegisterMapOffset() const {
158 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
159 }
160
161 void SetDexRegisterMapOffset(uint32_t offset) {
162 return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
163 }
164
165 uint32_t GetInlineDescriptorOffset() const {
166 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
167 }
168
169 void SetInlineDescriptorOffset(uint32_t offset) {
170 return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
171 }
172
173 uint32_t GetRegisterMask() const {
174 return region_.Load<uint32_t>(kRegisterMaskOffset);
175 }
176
177 void SetRegisterMask(uint32_t mask) {
178 region_.Store<uint32_t>(kRegisterMaskOffset, mask);
179 }
180
181 MemoryRegion GetStackMask() const {
182 return region_.Subregion(kStackMaskOffset, StackMaskSize());
183 }
184
185 void SetStackMask(const BitVector& sp_map) {
186 MemoryRegion region = GetStackMask();
187 for (size_t i = 0; i < region.size_in_bits(); i++) {
188 region.StoreBit(i, sp_map.IsBitSet(i));
189 }
190 }
191
192 bool HasInlineInfo() const {
193 return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
194 }
195
196 bool Equals(const StackMap& other) {
197 return region_.pointer() == other.region_.pointer()
198 && region_.size() == other.region_.size();
199 }
200
201 private:
202 static constexpr int kDexPcOffset = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100203 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
204 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100205 static constexpr int kInlineDescriptorOffsetOffset =
206 kDexRegisterMapOffsetOffset + sizeof(uint32_t);
207 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
208 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
209 static constexpr int kStackMaskOffset = kFixedSize;
210
211 size_t StackMaskSize() const { return region_.size() - kFixedSize; }
212
213 MemoryRegion region_;
214
Nicolas Geoffray39468442014-09-02 15:17:15 +0100215 friend class CodeInfo;
216 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100217};
218
219
220/**
221 * Wrapper around all compiler information collected for a method.
222 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100223 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100224 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100225class CodeInfo {
226 public:
227 explicit CodeInfo(MemoryRegion region) : region_(region) {}
228
Nicolas Geoffray39468442014-09-02 15:17:15 +0100229 explicit CodeInfo(const void* data) {
230 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
231 region_ = MemoryRegion(const_cast<void*>(data), size);
232 }
233
234 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100235 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100236 return StackMap(GetStackMaps().Subregion(i * size, size));
237 }
238
239 uint32_t GetOverallSize() const {
240 return region_.Load<uint32_t>(kOverallSizeOffset);
241 }
242
243 void SetOverallSize(uint32_t size) {
244 region_.Store<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100245 }
246
247 uint32_t GetStackMaskSize() const {
248 return region_.Load<uint32_t>(kStackMaskSizeOffset);
249 }
250
251 void SetStackMaskSize(uint32_t size) {
252 region_.Store<uint32_t>(kStackMaskSizeOffset, size);
253 }
254
255 size_t GetNumberOfStackMaps() const {
256 return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
257 }
258
259 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
260 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
261 }
262
263 size_t StackMapSize() const {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100264 return StackMap::kFixedSize + GetStackMaskSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100265 }
266
Nicolas Geoffray39468442014-09-02 15:17:15 +0100267 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100268 uint32_t offset = stack_map.GetDexRegisterMapOffset();
269 return DexRegisterMap(region_.Subregion(offset,
270 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
271 }
272
Nicolas Geoffray39468442014-09-02 15:17:15 +0100273 InlineInfo GetInlineInfoOf(StackMap stack_map) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100274 uint32_t offset = stack_map.GetInlineDescriptorOffset();
275 uint8_t depth = region_.Load<uint8_t>(offset);
276 return InlineInfo(region_.Subregion(offset,
277 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
278 }
279
Nicolas Geoffray39468442014-09-02 15:17:15 +0100280 StackMap GetStackMapForDexPc(uint32_t dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100281 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100282 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100283 if (stack_map.GetDexPc() == dex_pc) {
284 return stack_map;
285 }
286 }
287 LOG(FATAL) << "Unreachable";
Nicolas Geoffray39468442014-09-02 15:17:15 +0100288 return StackMap(MemoryRegion());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100289 }
290
Nicolas Geoffray39468442014-09-02 15:17:15 +0100291 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100292 // TODO: stack maps are sorted by native pc, we can do a binary search.
293 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100294 StackMap stack_map = GetStackMapAt(i);
295 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100296 return stack_map;
297 }
298 }
299 LOG(FATAL) << "Unreachable";
Nicolas Geoffray39468442014-09-02 15:17:15 +0100300 return StackMap(MemoryRegion());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100301 }
302
303 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100304 static constexpr int kOverallSizeOffset = 0;
305 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100306 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
307 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
308
309 MemoryRegion GetStackMaps() const {
310 return region_.size() == 0
311 ? MemoryRegion()
312 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
313 }
314
315 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100316 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100317};
318
319} // namespace art
320
321#endif // ART_RUNTIME_STACK_MAP_H_