blob: 7cc3e57895aad28de7b4e2ee1470edcbd32ec1b1 [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"
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +000022#include "utils.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010023
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 static constexpr uint32_t kNoInlineInfo = -1;
65
66 MemoryRegion region_;
67
Nicolas Geoffray39468442014-09-02 15:17:15 +010068 friend class CodeInfo;
69 friend class StackMap;
70 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010071};
72
73/**
74 * Information on dex register values for a specific PC. The information is
75 * of the form:
76 * [location_kind, register_value]+.
77 *
78 * The location_kind for a Dex register can either be:
79 * - Constant: register_value holds the constant,
80 * - Stack: register_value holds the stack offset,
Nicolas Geoffray39468442014-09-02 15:17:15 +010081 * - Register: register_value holds the physical register number.
82 * - None: the register has no location yet, meaning it has not been set.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010083 */
84class DexRegisterMap {
85 public:
86 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
87
88 enum LocationKind {
Nicolas Geoffray39468442014-09-02 15:17:15 +010089 kNone,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010090 kInStack,
91 kInRegister,
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010092 kInFpuRegister,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010093 kConstant
94 };
95
96 LocationKind GetLocationKind(uint16_t register_index) const {
97 return region_.Load<LocationKind>(
98 kFixedSize + register_index * SingleEntrySize());
99 }
100
101 void SetRegisterInfo(uint16_t register_index, LocationKind kind, int32_t value) {
102 size_t entry = kFixedSize + register_index * SingleEntrySize();
103 region_.Store<LocationKind>(entry, kind);
104 region_.Store<int32_t>(entry + sizeof(LocationKind), value);
105 }
106
107 int32_t GetValue(uint16_t register_index) const {
108 return region_.Load<int32_t>(
109 kFixedSize + sizeof(LocationKind) + register_index * SingleEntrySize());
110 }
111
112 static size_t SingleEntrySize() {
113 return sizeof(LocationKind) + sizeof(int32_t);
114 }
115
116 private:
117 static constexpr int kFixedSize = 0;
118
119 MemoryRegion region_;
120
Nicolas Geoffray39468442014-09-02 15:17:15 +0100121 friend class CodeInfo;
122 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100123};
124
125/**
126 * A Stack Map holds compilation information for a specific PC necessary for:
127 * - Mapping it to a dex PC,
128 * - Knowing which stack entries are objects,
129 * - Knowing which registers hold objects,
130 * - Knowing the inlining information,
131 * - Knowing the values of dex registers.
132 *
133 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100134 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100135 *
136 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
137 * stack size of a method.
138 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100139class StackMap {
140 public:
141 explicit StackMap(MemoryRegion region) : region_(region) {}
142
143 uint32_t GetDexPc() const {
144 return region_.Load<uint32_t>(kDexPcOffset);
145 }
146
147 void SetDexPc(uint32_t dex_pc) {
148 region_.Store<uint32_t>(kDexPcOffset, dex_pc);
149 }
150
Nicolas Geoffray39468442014-09-02 15:17:15 +0100151 uint32_t GetNativePcOffset() const {
152 return region_.Load<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100153 }
154
Nicolas Geoffray39468442014-09-02 15:17:15 +0100155 void SetNativePcOffset(uint32_t native_pc_offset) {
156 return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100157 }
158
159 uint32_t GetDexRegisterMapOffset() const {
160 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
161 }
162
163 void SetDexRegisterMapOffset(uint32_t offset) {
164 return region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
165 }
166
167 uint32_t GetInlineDescriptorOffset() const {
168 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
169 }
170
171 void SetInlineDescriptorOffset(uint32_t offset) {
172 return region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
173 }
174
175 uint32_t GetRegisterMask() const {
176 return region_.Load<uint32_t>(kRegisterMaskOffset);
177 }
178
179 void SetRegisterMask(uint32_t mask) {
180 region_.Store<uint32_t>(kRegisterMaskOffset, mask);
181 }
182
183 MemoryRegion GetStackMask() const {
184 return region_.Subregion(kStackMaskOffset, StackMaskSize());
185 }
186
187 void SetStackMask(const BitVector& sp_map) {
188 MemoryRegion region = GetStackMask();
189 for (size_t i = 0; i < region.size_in_bits(); i++) {
190 region.StoreBit(i, sp_map.IsBitSet(i));
191 }
192 }
193
194 bool HasInlineInfo() const {
195 return GetInlineDescriptorOffset() != InlineInfo::kNoInlineInfo;
196 }
197
198 bool Equals(const StackMap& other) {
199 return region_.pointer() == other.region_.pointer()
200 && region_.size() == other.region_.size();
201 }
202
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000203 static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
204 // On ARM, the stack maps must be 4-byte aligned.
205 return RoundUp(StackMap::kFixedSize + stack_mask_size, 4);
206 }
207
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100208 private:
209 static constexpr int kDexPcOffset = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100210 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
211 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100212 static constexpr int kInlineDescriptorOffsetOffset =
213 kDexRegisterMapOffsetOffset + sizeof(uint32_t);
214 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
215 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
216 static constexpr int kStackMaskOffset = kFixedSize;
217
218 size_t StackMaskSize() const { return region_.size() - kFixedSize; }
219
220 MemoryRegion region_;
221
Nicolas Geoffray39468442014-09-02 15:17:15 +0100222 friend class CodeInfo;
223 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100224};
225
226
227/**
228 * Wrapper around all compiler information collected for a method.
229 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100230 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100231 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100232class CodeInfo {
233 public:
234 explicit CodeInfo(MemoryRegion region) : region_(region) {}
235
Nicolas Geoffray39468442014-09-02 15:17:15 +0100236 explicit CodeInfo(const void* data) {
237 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
238 region_ = MemoryRegion(const_cast<void*>(data), size);
239 }
240
241 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100242 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100243 return StackMap(GetStackMaps().Subregion(i * size, size));
244 }
245
246 uint32_t GetOverallSize() const {
247 return region_.Load<uint32_t>(kOverallSizeOffset);
248 }
249
250 void SetOverallSize(uint32_t size) {
251 region_.Store<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100252 }
253
254 uint32_t GetStackMaskSize() const {
255 return region_.Load<uint32_t>(kStackMaskSizeOffset);
256 }
257
258 void SetStackMaskSize(uint32_t size) {
259 region_.Store<uint32_t>(kStackMaskSizeOffset, size);
260 }
261
262 size_t GetNumberOfStackMaps() const {
263 return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
264 }
265
266 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
267 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
268 }
269
270 size_t StackMapSize() const {
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000271 return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100272 }
273
Nicolas Geoffray39468442014-09-02 15:17:15 +0100274 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100275 uint32_t offset = stack_map.GetDexRegisterMapOffset();
276 return DexRegisterMap(region_.Subregion(offset,
277 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
278 }
279
Nicolas Geoffray39468442014-09-02 15:17:15 +0100280 InlineInfo GetInlineInfoOf(StackMap stack_map) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100281 uint32_t offset = stack_map.GetInlineDescriptorOffset();
282 uint8_t depth = region_.Load<uint8_t>(offset);
283 return InlineInfo(region_.Subregion(offset,
284 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
285 }
286
Nicolas Geoffray39468442014-09-02 15:17:15 +0100287 StackMap GetStackMapForDexPc(uint32_t dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100288 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100289 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100290 if (stack_map.GetDexPc() == dex_pc) {
291 return stack_map;
292 }
293 }
294 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700295 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100296 }
297
Nicolas Geoffray39468442014-09-02 15:17:15 +0100298 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100299 // TODO: stack maps are sorted by native pc, we can do a binary search.
300 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100301 StackMap stack_map = GetStackMapAt(i);
302 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100303 return stack_map;
304 }
305 }
306 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700307 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100308 }
309
310 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100311 static constexpr int kOverallSizeOffset = 0;
312 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100313 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
314 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
315
316 MemoryRegion GetStackMaps() const {
317 return region_.size() == 0
318 ? MemoryRegion()
319 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
320 }
321
322 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100323 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100324};
325
326} // namespace art
327
328#endif // ART_RUNTIME_STACK_MAP_H_