blob: a58ecab17d2f281bcd59b9720dfd9dea9a0b014f [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,
Nicolas Geoffray102cbed2014-10-15 18:31:05 +010091 kInFpuRegister,
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010092 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
Nicolas Geoffray39468442014-09-02 15:17:15 +0100120 friend class CodeInfo;
121 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100122};
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:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100133 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100134 *
135 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
136 * stack size of a method.
137 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100138class 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
Nicolas Geoffray39468442014-09-02 15:17:15 +0100150 uint32_t GetNativePcOffset() const {
151 return region_.Load<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100152 }
153
Nicolas Geoffray39468442014-09-02 15:17:15 +0100154 void SetNativePcOffset(uint32_t native_pc_offset) {
155 return region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100156 }
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;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100204 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
205 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100206 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
Nicolas Geoffray39468442014-09-02 15:17:15 +0100216 friend class CodeInfo;
217 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100218};
219
220
221/**
222 * Wrapper around all compiler information collected for a method.
223 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100224 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100225 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100226class CodeInfo {
227 public:
228 explicit CodeInfo(MemoryRegion region) : region_(region) {}
229
Nicolas Geoffray39468442014-09-02 15:17:15 +0100230 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 {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100236 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100237 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);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100246 }
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 {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100265 return StackMap::kFixedSize + GetStackMaskSize();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100266 }
267
Nicolas Geoffray39468442014-09-02 15:17:15 +0100268 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100269 uint32_t offset = stack_map.GetDexRegisterMapOffset();
270 return DexRegisterMap(region_.Subregion(offset,
271 DexRegisterMap::kFixedSize + number_of_dex_registers * DexRegisterMap::SingleEntrySize()));
272 }
273
Nicolas Geoffray39468442014-09-02 15:17:15 +0100274 InlineInfo GetInlineInfoOf(StackMap stack_map) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100275 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
Nicolas Geoffray39468442014-09-02 15:17:15 +0100281 StackMap GetStackMapForDexPc(uint32_t dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100282 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100283 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100284 if (stack_map.GetDexPc() == dex_pc) {
285 return stack_map;
286 }
287 }
288 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700289 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100290 }
291
Nicolas Geoffray39468442014-09-02 15:17:15 +0100292 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100293 // 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) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100295 StackMap stack_map = GetStackMapAt(i);
296 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100297 return stack_map;
298 }
299 }
300 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700301 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100302 }
303
304 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100305 static constexpr int kOverallSizeOffset = 0;
306 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100307 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_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100317 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100318};
319
320} // namespace art
321
322#endif // ART_RUNTIME_STACK_MAP_H_