blob: 1acc44291cf920faff3feb2d06b4c8dfcc28b9b9 [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"
Vladimir Marko80afd022015-05-19 18:08:00 +010021#include "base/bit_utils.h"
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010022#include "memory_region.h"
23
24namespace art {
25
Vladimir Marko8f1e08a2015-06-26 12:06:30 +010026class VariableIndentationOutputStream;
27
Roland Levillaina2d8ec62015-03-12 15:25:29 +000028// Size of a frame slot, in bytes. This constant is a signed value,
29// to please the compiler in arithmetic operations involving int32_t
30// (signed) values.
Roland Levillaina552e1c2015-03-26 15:01:03 +000031static constexpr ssize_t kFrameSlotSize = 4;
Roland Levillaina2d8ec62015-03-12 15:25:29 +000032
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000033// Size of Dex virtual registers.
Roland Levillaina552e1c2015-03-26 15:01:03 +000034static constexpr size_t kVRegSize = 4;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +000035
Roland Levillaind780c002015-07-15 14:30:26 +010036// We encode the number of bytes needed for writing a value on 3 bits
37// (i.e. up to 8 values), for values that we know are maximum 32-bit
38// long.
39static constexpr size_t kNumberOfBitForNumberOfBytesForEncoding = 3;
40
Nicolas Geoffray004c2302015-03-20 10:06:38 +000041class CodeInfo;
David Brazdilf677ebf2015-05-29 16:29:43 +010042class StackMapEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +000043
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010044/**
45 * Classes in the following file are wrapper on stack map information backed
46 * by a MemoryRegion. As such they read and write to the region, they don't have
47 * their own fields.
48 */
49
Roland Levillaina2d8ec62015-03-12 15:25:29 +000050// Dex register location container used by DexRegisterMap and StackMapStream.
51class DexRegisterLocation {
52 public:
53 /*
54 * The location kind used to populate the Dex register information in a
55 * StackMapStream can either be:
56 * - kNone: the register has no location yet, meaning it has not been set;
57 * - kConstant: value holds the constant;
58 * - kStack: value holds the stack offset;
59 * - kRegister: value holds the physical register number;
60 * - kFpuRegister: value holds the physical register number.
61 *
62 * In addition, DexRegisterMap also uses these values:
63 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
Roland Levillaina552e1c2015-03-26 15:01:03 +000064 * or equal to 128 bytes);
65 * - kConstantLargeValue: value holds a "large" constant (lower than 0, or
66 * or greater than or equal to 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000067 */
68 enum class Kind : uint8_t {
69 // Short location kinds, for entries fitting on one byte (3 bits
70 // for the kind, 5 bits for the value) in a DexRegisterMap.
71 kNone = 0, // 0b000
72 kInStack = 1, // 0b001
73 kInRegister = 2, // 0b010
74 kInFpuRegister = 3, // 0b011
75 kConstant = 4, // 0b100
76
77 // Large location kinds, requiring a 5-byte encoding (1 byte for the
78 // kind, 4 bytes for the value).
79
80 // Stack location at a large offset, meaning that the offset value
81 // divided by the stack frame slot size (4 bytes) cannot fit on a
82 // 5-bit unsigned integer (i.e., this offset value is greater than
83 // or equal to 2^5 * 4 = 128 bytes).
84 kInStackLargeOffset = 5, // 0b101
85
86 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
Roland Levillaina552e1c2015-03-26 15:01:03 +000087 // lower than 0, or greater than or equal to 2^5 = 32).
Roland Levillaina2d8ec62015-03-12 15:25:29 +000088 kConstantLargeValue = 6, // 0b110
89
90 kLastLocationKind = kConstantLargeValue
91 };
92
93 static_assert(
94 sizeof(Kind) == 1u,
95 "art::DexRegisterLocation::Kind has a size different from one byte.");
96
97 static const char* PrettyDescriptor(Kind kind) {
98 switch (kind) {
99 case Kind::kNone:
100 return "none";
101 case Kind::kInStack:
102 return "in stack";
103 case Kind::kInRegister:
104 return "in register";
105 case Kind::kInFpuRegister:
106 return "in fpu register";
107 case Kind::kConstant:
108 return "as constant";
109 case Kind::kInStackLargeOffset:
110 return "in stack (large offset)";
111 case Kind::kConstantLargeValue:
112 return "as constant (large value)";
113 default:
114 UNREACHABLE();
115 }
116 }
117
118 static bool IsShortLocationKind(Kind kind) {
119 switch (kind) {
120 case Kind::kNone:
121 case Kind::kInStack:
122 case Kind::kInRegister:
123 case Kind::kInFpuRegister:
124 case Kind::kConstant:
125 return true;
126
127 case Kind::kInStackLargeOffset:
128 case Kind::kConstantLargeValue:
129 return false;
130
131 default:
132 UNREACHABLE();
133 }
134 }
135
136 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
137 // any value with a "large" qualifier.
138 // TODO: Introduce another enum type for the surface kind?
139 static Kind ConvertToSurfaceKind(Kind kind) {
140 switch (kind) {
141 case Kind::kNone:
142 case Kind::kInStack:
143 case Kind::kInRegister:
144 case Kind::kInFpuRegister:
145 case Kind::kConstant:
146 return kind;
147
148 case Kind::kInStackLargeOffset:
149 return Kind::kInStack;
150
151 case Kind::kConstantLargeValue:
152 return Kind::kConstant;
153
154 default:
155 UNREACHABLE();
156 }
157 }
158
Roland Levillaina552e1c2015-03-26 15:01:03 +0000159 // Required by art::StackMapStream::LocationCatalogEntriesIndices.
160 DexRegisterLocation() : kind_(Kind::kNone), value_(0) {}
161
162 DexRegisterLocation(Kind kind, int32_t value) : kind_(kind), value_(value) {}
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000163
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000164 static DexRegisterLocation None() {
165 return DexRegisterLocation(Kind::kNone, 0);
166 }
167
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000168 // Get the "surface" kind of the location, i.e., the one that doesn't
169 // include any value with a "large" qualifier.
170 Kind GetKind() const {
171 return ConvertToSurfaceKind(kind_);
172 }
173
174 // Get the value of the location.
175 int32_t GetValue() const { return value_; }
176
177 // Get the actual kind of the location.
178 Kind GetInternalKind() const { return kind_; }
179
Calin Juravle6ae70962015-03-18 16:31:28 +0000180 bool operator==(DexRegisterLocation other) const {
181 return kind_ == other.kind_ && value_ == other.value_;
182 }
183
184 bool operator!=(DexRegisterLocation other) const {
185 return !(*this == other);
186 }
187
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000188 private:
189 Kind kind_;
190 int32_t value_;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000191
192 friend class DexRegisterLocationHashFn;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000193};
194
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100195/**
Roland Levillaina552e1c2015-03-26 15:01:03 +0000196 * Store information on unique Dex register locations used in a method.
197 * The information is of the form:
198 * [DexRegisterLocation+].
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000199 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100200 */
Roland Levillaina552e1c2015-03-26 15:01:03 +0000201class DexRegisterLocationCatalog {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100202 public:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000203 explicit DexRegisterLocationCatalog(MemoryRegion region) : region_(region) {}
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100204
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000205 // Short (compressed) location, fitting on one byte.
206 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100207
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000208 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
209 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
210 int32_t value = dex_register_location.GetValue();
211 if (DexRegisterLocation::IsShortLocationKind(kind)) {
212 // Short location. Compress the kind and the value as a single byte.
213 if (kind == DexRegisterLocation::Kind::kInStack) {
214 // Instead of storing stack offsets expressed in bytes for
215 // short stack locations, store slot offsets. A stack offset
216 // is a multiple of 4 (kFrameSlotSize). This means that by
217 // dividing it by 4, we can fit values from the [0, 128)
218 // interval in a short stack location, and not just values
219 // from the [0, 32) interval.
220 DCHECK_EQ(value % kFrameSlotSize, 0);
221 value /= kFrameSlotSize;
222 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000223 DCHECK(IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000224 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
225 } else {
226 // Large location. Write the location on one byte and the value
227 // on 4 bytes.
Roland Levillaina552e1c2015-03-26 15:01:03 +0000228 DCHECK(!IsShortValue(value)) << value;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000229 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
230 // Also divide large stack offsets by 4 for the sake of consistency.
231 DCHECK_EQ(value % kFrameSlotSize, 0);
232 value /= kFrameSlotSize;
233 }
234 // Data can be unaligned as the written Dex register locations can
235 // either be 1-byte or 5-byte wide. Use
236 // art::MemoryRegion::StoreUnaligned instead of
237 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
238 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
239 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000240 }
241 }
242
Roland Levillaina552e1c2015-03-26 15:01:03 +0000243 // Find the offset of the location catalog entry number `location_catalog_entry_index`.
244 size_t FindLocationOffset(size_t location_catalog_entry_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000245 size_t offset = kFixedSize;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000246 // Skip the first `location_catalog_entry_index - 1` entries.
247 for (uint16_t i = 0; i < location_catalog_entry_index; ++i) {
248 // Read the first next byte and inspect its first 3 bits to decide
249 // whether it is a short or a large location.
250 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
251 if (DexRegisterLocation::IsShortLocationKind(kind)) {
252 // Short location. Skip the current byte.
253 offset += SingleShortEntrySize();
254 } else {
255 // Large location. Skip the 5 next bytes.
256 offset += SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000257 }
258 }
259 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100260 }
261
Roland Levillaina552e1c2015-03-26 15:01:03 +0000262 // Get the internal kind of entry at `location_catalog_entry_index`.
263 DexRegisterLocation::Kind GetLocationInternalKind(size_t location_catalog_entry_index) const {
264 if (location_catalog_entry_index == kNoLocationEntryIndex) {
265 return DexRegisterLocation::Kind::kNone;
266 }
267 return ExtractKindAtOffset(FindLocationOffset(location_catalog_entry_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100268 }
269
Roland Levillaina552e1c2015-03-26 15:01:03 +0000270 // Get the (surface) kind and value of entry at `location_catalog_entry_index`.
271 DexRegisterLocation GetDexRegisterLocation(size_t location_catalog_entry_index) const {
272 if (location_catalog_entry_index == kNoLocationEntryIndex) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000273 return DexRegisterLocation::None();
274 }
Roland Levillaina552e1c2015-03-26 15:01:03 +0000275 size_t offset = FindLocationOffset(location_catalog_entry_index);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000276 // Read the first byte and inspect its first 3 bits to get the location.
277 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
278 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
279 if (DexRegisterLocation::IsShortLocationKind(kind)) {
280 // Short location. Extract the value from the remaining 5 bits.
281 int32_t value = ExtractValueFromShortLocation(first_byte);
282 if (kind == DexRegisterLocation::Kind::kInStack) {
283 // Convert the stack slot (short) offset to a byte offset value.
284 value *= kFrameSlotSize;
285 }
286 return DexRegisterLocation(kind, value);
287 } else {
288 // Large location. Read the four next bytes to get the value.
289 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
290 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
291 // Convert the stack slot (large) offset to a byte offset value.
292 value *= kFrameSlotSize;
293 }
294 return DexRegisterLocation(kind, value);
295 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100296 }
297
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000298 // Compute the compressed kind of `location`.
299 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
300 switch (location.GetInternalKind()) {
301 case DexRegisterLocation::Kind::kNone:
302 DCHECK_EQ(location.GetValue(), 0);
303 return DexRegisterLocation::Kind::kNone;
304
305 case DexRegisterLocation::Kind::kInRegister:
306 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000307 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000308 return DexRegisterLocation::Kind::kInRegister;
309
310 case DexRegisterLocation::Kind::kInFpuRegister:
311 DCHECK_GE(location.GetValue(), 0);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000312 DCHECK_LT(location.GetValue(), 1 << kValueBits);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000313 return DexRegisterLocation::Kind::kInFpuRegister;
314
315 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000316 return IsShortStackOffsetValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000317 ? DexRegisterLocation::Kind::kInStack
318 : DexRegisterLocation::Kind::kInStackLargeOffset;
319
320 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000321 return IsShortConstantValue(location.GetValue())
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000322 ? DexRegisterLocation::Kind::kConstant
323 : DexRegisterLocation::Kind::kConstantLargeValue;
324
325 default:
326 LOG(FATAL) << "Unexpected location kind"
327 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
328 UNREACHABLE();
329 }
330 }
331
332 // Can `location` be turned into a short location?
333 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
334 switch (location.GetInternalKind()) {
335 case DexRegisterLocation::Kind::kNone:
336 case DexRegisterLocation::Kind::kInRegister:
337 case DexRegisterLocation::Kind::kInFpuRegister:
338 return true;
339
340 case DexRegisterLocation::Kind::kInStack:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000341 return IsShortStackOffsetValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000342
343 case DexRegisterLocation::Kind::kConstant:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000344 return IsShortConstantValue(location.GetValue());
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000345
346 default:
347 UNREACHABLE();
348 }
349 }
350
351 static size_t EntrySize(const DexRegisterLocation& location) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000352 return CanBeEncodedAsShortLocation(location) ? SingleShortEntrySize() : SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000353 }
354
355 static size_t SingleShortEntrySize() {
356 return sizeof(ShortLocation);
357 }
358
359 static size_t SingleLargeEntrySize() {
360 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100361 }
362
Roland Levillain12baf472015-03-05 12:41:42 +0000363 size_t Size() const {
364 return region_.size();
365 }
366
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100367 void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
Roland Levillain0396ed72015-05-27 15:12:19 +0100368
Roland Levillaina552e1c2015-03-26 15:01:03 +0000369 // Special (invalid) Dex register location catalog entry index meaning
370 // that there is no location for a given Dex register (i.e., it is
371 // mapped to a DexRegisterLocation::Kind::kNone location).
372 static constexpr size_t kNoLocationEntryIndex = -1;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100373
Roland Levillain12baf472015-03-05 12:41:42 +0000374 private:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000375 static constexpr int kFixedSize = 0;
376
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000377 // Width of the kind "field" in a short location, in bits.
378 static constexpr size_t kKindBits = 3;
379 // Width of the value "field" in a short location, in bits.
380 static constexpr size_t kValueBits = 5;
381
382 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
383 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
384 static constexpr size_t kKindOffset = 0;
385 static constexpr size_t kValueOffset = kKindBits;
386
Roland Levillaina552e1c2015-03-26 15:01:03 +0000387 static bool IsShortStackOffsetValue(int32_t value) {
388 DCHECK_EQ(value % kFrameSlotSize, 0);
389 return IsShortValue(value / kFrameSlotSize);
390 }
391
392 static bool IsShortConstantValue(int32_t value) {
393 return IsShortValue(value);
394 }
395
396 static bool IsShortValue(int32_t value) {
397 return IsUint<kValueBits>(value);
398 }
399
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000400 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000401 uint8_t kind_integer_value = static_cast<uint8_t>(kind);
402 DCHECK(IsUint<kKindBits>(kind_integer_value)) << kind_integer_value;
403 DCHECK(IsShortValue(value)) << value;
404 return (kind_integer_value & kKindMask) << kKindOffset
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000405 | (value & kValueMask) << kValueOffset;
406 }
407
408 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
409 uint8_t kind = (location >> kKindOffset) & kKindMask;
410 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000411 // We do not encode kNone locations in the stack map.
412 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000413 return static_cast<DexRegisterLocation::Kind>(kind);
414 }
415
416 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
417 return (location >> kValueOffset) & kValueMask;
418 }
419
420 // Extract a location kind from the byte at position `offset`.
421 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
422 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
423 return ExtractKindFromShortLocation(first_byte);
424 }
425
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100426 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000427
428 friend class CodeInfo;
429 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100430};
431
Roland Levillaina552e1c2015-03-26 15:01:03 +0000432/* Information on Dex register locations for a specific PC, mapping a
433 * stack map's Dex register to a location entry in a DexRegisterLocationCatalog.
434 * The information is of the form:
435 * [live_bit_mask, entries*]
436 * where entries are concatenated unsigned integer values encoded on a number
437 * of bits (fixed per DexRegisterMap instances of a CodeInfo object) depending
438 * on the number of entries in the Dex register location catalog
439 * (see DexRegisterMap::SingleEntrySizeInBits). The map is 1-byte aligned.
440 */
441class DexRegisterMap {
442 public:
443 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
444
445 // Get the surface kind of Dex register `dex_register_number`.
446 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
447 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100448 const CodeInfo& code_info,
449 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000450 return DexRegisterLocation::ConvertToSurfaceKind(
David Brazdilf677ebf2015-05-29 16:29:43 +0100451 GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
Roland Levillaina552e1c2015-03-26 15:01:03 +0000452 }
453
454 // Get the internal kind of Dex register `dex_register_number`.
455 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
456 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100457 const CodeInfo& code_info,
458 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000459
460 // Get the Dex register location `dex_register_number`.
461 DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
462 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100463 const CodeInfo& code_info,
464 const StackMapEncoding& enc) const;
Roland Levillaina552e1c2015-03-26 15:01:03 +0000465
466 int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
467 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100468 const CodeInfo& code_info,
469 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000470 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100471 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000472 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
473 // GetDexRegisterLocation returns the offset in bytes.
474 return location.GetValue();
475 }
476
477 int32_t GetConstant(uint16_t dex_register_number,
478 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100479 const CodeInfo& code_info,
480 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000481 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100482 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100483 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
484 << DexRegisterLocation::PrettyDescriptor(location.GetKind());
Roland Levillaina552e1c2015-03-26 15:01:03 +0000485 return location.GetValue();
486 }
487
488 int32_t GetMachineRegister(uint16_t dex_register_number,
489 uint16_t number_of_dex_registers,
David Brazdilf677ebf2015-05-29 16:29:43 +0100490 const CodeInfo& code_info,
491 const StackMapEncoding& enc) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +0000492 DexRegisterLocation location =
David Brazdilf677ebf2015-05-29 16:29:43 +0100493 GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
Roland Levillaina552e1c2015-03-26 15:01:03 +0000494 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
495 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
496 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
497 return location.GetValue();
498 }
499
500 // Get the index of the entry in the Dex register location catalog
501 // corresponding to `dex_register_number`.
502 size_t GetLocationCatalogEntryIndex(uint16_t dex_register_number,
503 uint16_t number_of_dex_registers,
504 size_t number_of_location_catalog_entries) const {
505 if (!IsDexRegisterLive(dex_register_number)) {
506 return DexRegisterLocationCatalog::kNoLocationEntryIndex;
507 }
508
509 if (number_of_location_catalog_entries == 1) {
510 // We do not allocate space for location maps in the case of a
511 // single-entry location catalog, as it is useless. The only valid
512 // entry index is 0;
513 return 0;
514 }
515
516 // The bit offset of the beginning of the map locations.
517 size_t map_locations_offset_in_bits =
518 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
519 size_t index_in_dex_register_map = GetIndexInDexRegisterMap(dex_register_number);
520 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
521 // The bit size of an entry.
522 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
523 // The bit offset where `index_in_dex_register_map` is located.
524 size_t entry_offset_in_bits =
525 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
526 size_t location_catalog_entry_index =
527 region_.LoadBits(entry_offset_in_bits, map_entry_size_in_bits);
528 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
529 return location_catalog_entry_index;
530 }
531
532 // Map entry at `index_in_dex_register_map` to `location_catalog_entry_index`.
533 void SetLocationCatalogEntryIndex(size_t index_in_dex_register_map,
534 size_t location_catalog_entry_index,
535 uint16_t number_of_dex_registers,
536 size_t number_of_location_catalog_entries) {
537 DCHECK_LT(index_in_dex_register_map, GetNumberOfLiveDexRegisters(number_of_dex_registers));
538 DCHECK_LT(location_catalog_entry_index, number_of_location_catalog_entries);
539
540 if (number_of_location_catalog_entries == 1) {
541 // We do not allocate space for location maps in the case of a
542 // single-entry location catalog, as it is useless.
543 return;
544 }
545
546 // The bit offset of the beginning of the map locations.
547 size_t map_locations_offset_in_bits =
548 GetLocationMappingDataOffset(number_of_dex_registers) * kBitsPerByte;
549 // The bit size of an entry.
550 size_t map_entry_size_in_bits = SingleEntrySizeInBits(number_of_location_catalog_entries);
551 // The bit offset where `index_in_dex_register_map` is located.
552 size_t entry_offset_in_bits =
553 map_locations_offset_in_bits + index_in_dex_register_map * map_entry_size_in_bits;
554 region_.StoreBits(entry_offset_in_bits, location_catalog_entry_index, map_entry_size_in_bits);
555 }
556
557 void SetLiveBitMask(uint16_t number_of_dex_registers,
558 const BitVector& live_dex_registers_mask) {
559 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
560 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
561 region_.StoreBit(live_bit_mask_offset_in_bits + i, live_dex_registers_mask.IsBitSet(i));
562 }
563 }
564
565 bool IsDexRegisterLive(uint16_t dex_register_number) const {
566 size_t live_bit_mask_offset_in_bits = GetLiveBitMaskOffset() * kBitsPerByte;
567 return region_.LoadBit(live_bit_mask_offset_in_bits + dex_register_number);
568 }
569
570 size_t GetNumberOfLiveDexRegisters(uint16_t number_of_dex_registers) const {
571 size_t number_of_live_dex_registers = 0;
572 for (size_t i = 0; i < number_of_dex_registers; ++i) {
573 if (IsDexRegisterLive(i)) {
574 ++number_of_live_dex_registers;
575 }
576 }
577 return number_of_live_dex_registers;
578 }
579
580 static size_t GetLiveBitMaskOffset() {
581 return kFixedSize;
582 }
583
584 // Compute the size of the live register bit mask (in bytes), for a
585 // method having `number_of_dex_registers` Dex registers.
586 static size_t GetLiveBitMaskSize(uint16_t number_of_dex_registers) {
587 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
588 }
589
590 static size_t GetLocationMappingDataOffset(uint16_t number_of_dex_registers) {
591 return GetLiveBitMaskOffset() + GetLiveBitMaskSize(number_of_dex_registers);
592 }
593
594 size_t GetLocationMappingDataSize(uint16_t number_of_dex_registers,
595 size_t number_of_location_catalog_entries) const {
596 size_t location_mapping_data_size_in_bits =
597 GetNumberOfLiveDexRegisters(number_of_dex_registers)
598 * SingleEntrySizeInBits(number_of_location_catalog_entries);
599 return RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
600 }
601
602 // Return the size of a map entry in bits. Note that if
603 // `number_of_location_catalog_entries` equals 1, this function returns 0,
604 // which is fine, as there is no need to allocate a map for a
605 // single-entry location catalog; the only valid location catalog entry index
606 // for a live register in this case is 0 and there is no need to
607 // store it.
608 static size_t SingleEntrySizeInBits(size_t number_of_location_catalog_entries) {
609 // Handle the case of 0, as we cannot pass 0 to art::WhichPowerOf2.
610 return number_of_location_catalog_entries == 0
611 ? 0u
612 : WhichPowerOf2(RoundUpToPowerOfTwo(number_of_location_catalog_entries));
613 }
614
615 // Return the size of the DexRegisterMap object, in bytes.
616 size_t Size() const {
617 return region_.size();
618 }
619
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100620 void Dump(VariableIndentationOutputStream* vios,
621 const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100622
Roland Levillaina552e1c2015-03-26 15:01:03 +0000623 private:
624 // Return the index in the Dex register map corresponding to the Dex
625 // register number `dex_register_number`.
626 size_t GetIndexInDexRegisterMap(uint16_t dex_register_number) const {
627 if (!IsDexRegisterLive(dex_register_number)) {
628 return kInvalidIndexInDexRegisterMap;
629 }
630 return GetNumberOfLiveDexRegisters(dex_register_number);
631 }
632
633 // Special (invalid) Dex register map entry index meaning that there
634 // is no index in the map for a given Dex register (i.e., it must
635 // have been mapped to a DexRegisterLocation::Kind::kNone location).
636 static constexpr size_t kInvalidIndexInDexRegisterMap = -1;
637
638 static constexpr int kFixedSize = 0;
639
640 MemoryRegion region_;
641
642 friend class CodeInfo;
643 friend class StackMapStream;
644};
645
David Brazdilf677ebf2015-05-29 16:29:43 +0100646class StackMapEncoding {
647 public:
648 StackMapEncoding() {}
649
650 StackMapEncoding(size_t stack_mask_size,
651 size_t bytes_for_inline_info,
652 size_t bytes_for_dex_register_map,
653 size_t bytes_for_dex_pc,
654 size_t bytes_for_native_pc,
655 size_t bytes_for_register_mask)
656 : bytes_for_stack_mask_(stack_mask_size),
657 bytes_for_inline_info_(bytes_for_inline_info),
658 bytes_for_dex_register_map_(bytes_for_dex_register_map),
659 bytes_for_dex_pc_(bytes_for_dex_pc),
660 bytes_for_native_pc_(bytes_for_native_pc),
661 bytes_for_register_mask_(bytes_for_register_mask) {}
662
663 static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
664 size_t inline_info_size,
665 size_t dex_register_map_size,
666 size_t dex_pc_max,
667 size_t native_pc_max,
668 size_t register_mask_max) {
669 return StackMapEncoding(
670 stack_mask_size,
671 // + 1 to also encode kNoInlineInfo: if an inline info offset
672 // is at 0xFF, we want to overflow to a larger encoding, because it will
673 // conflict with kNoInlineInfo.
674 // The offset is relative to the dex register map. TODO: Change this.
675 inline_info_size == 0
676 ? 0
677 : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
678 // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
679 // is at 0xFF, we want to overflow to a larger encoding, because it will
680 // conflict with kNoDexRegisterMap.
681 EncodingSizeInBytes(dex_register_map_size + 1),
682 EncodingSizeInBytes(dex_pc_max),
683 EncodingSizeInBytes(native_pc_max),
684 EncodingSizeInBytes(register_mask_max));
685 }
686
687 // Get the size of one stack map of this CodeInfo object, in bytes.
688 // All stack maps of a CodeInfo have the same size.
689 size_t ComputeStackMapSize() const {
690 return bytes_for_register_mask_
691 + bytes_for_stack_mask_
692 + bytes_for_inline_info_
693 + bytes_for_dex_register_map_
694 + bytes_for_dex_pc_
695 + bytes_for_native_pc_;
696 }
697
698 bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
699
700 size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
701 size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
702 size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
703 size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
704 size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
705 size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
706
707 size_t ComputeStackMapRegisterMaskOffset() const {
708 return kRegisterMaskOffset;
709 }
710
711 size_t ComputeStackMapStackMaskOffset() const {
712 return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
713 }
714
715 size_t ComputeStackMapDexPcOffset() const {
716 return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
717 }
718
719 size_t ComputeStackMapNativePcOffset() const {
720 return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
721 }
722
723 size_t ComputeStackMapDexRegisterMapOffset() const {
724 return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
725 }
726
727 size_t ComputeStackMapInlineInfoOffset() const {
728 return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
729 }
730
731 private:
732 static size_t EncodingSizeInBytes(size_t max_element) {
733 DCHECK(IsUint<32>(max_element));
734 return (max_element == 0) ? 0
735 : IsUint<8>(max_element) ? 1
736 : IsUint<16>(max_element) ? 2
737 : IsUint<24>(max_element) ? 3
738 : 4;
739 }
740
741 static constexpr int kRegisterMaskOffset = 0;
742
743 size_t bytes_for_stack_mask_;
744 size_t bytes_for_inline_info_;
745 size_t bytes_for_dex_register_map_;
746 size_t bytes_for_dex_pc_;
747 size_t bytes_for_native_pc_;
748 size_t bytes_for_register_mask_;
749};
750
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100751/**
752 * A Stack Map holds compilation information for a specific PC necessary for:
753 * - Mapping it to a dex PC,
754 * - Knowing which stack entries are objects,
755 * - Knowing which registers hold objects,
756 * - Knowing the inlining information,
757 * - Knowing the values of dex registers.
758 *
759 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000760 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
761 * stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100762 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100763class StackMap {
764 public:
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100765 StackMap() {}
David Brazdilf677ebf2015-05-29 16:29:43 +0100766 explicit StackMap(MemoryRegion region) : region_(region) {}
Nicolas Geoffraye12997f2015-05-22 14:01:33 +0100767
768 bool IsValid() const { return region_.pointer() != nullptr; }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100769
David Brazdilf677ebf2015-05-29 16:29:43 +0100770 uint32_t GetDexPc(const StackMapEncoding& encoding) const {
771 return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
772 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100773
David Brazdilf677ebf2015-05-29 16:29:43 +0100774 void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
775 StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
776 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100777
David Brazdilf677ebf2015-05-29 16:29:43 +0100778 uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
779 return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
780 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100781
David Brazdilf677ebf2015-05-29 16:29:43 +0100782 void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
783 StoreAt(encoding.NumberOfBytesForNativePc(),
784 encoding.ComputeStackMapNativePcOffset(),
785 native_pc_offset);
786 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100787
David Brazdilf677ebf2015-05-29 16:29:43 +0100788 uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
789 return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
790 encoding.ComputeStackMapDexRegisterMapOffset(),
791 /* check_max */ true);
792 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100793
David Brazdilf677ebf2015-05-29 16:29:43 +0100794 void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
795 StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
796 encoding.ComputeStackMapDexRegisterMapOffset(),
797 offset);
798 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100799
David Brazdilf677ebf2015-05-29 16:29:43 +0100800 uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
801 if (!encoding.HasInlineInfo()) return kNoInlineInfo;
802 return LoadAt(encoding.NumberOfBytesForInlineInfo(),
803 encoding.ComputeStackMapInlineInfoOffset(),
804 /* check_max */ true);
805 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100806
David Brazdilf677ebf2015-05-29 16:29:43 +0100807 void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
808 DCHECK(encoding.HasInlineInfo());
809 StoreAt(encoding.NumberOfBytesForInlineInfo(),
810 encoding.ComputeStackMapInlineInfoOffset(),
811 offset);
812 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100813
David Brazdilf677ebf2015-05-29 16:29:43 +0100814 uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
815 return LoadAt(encoding.NumberOfBytesForRegisterMask(),
816 encoding.ComputeStackMapRegisterMaskOffset());
817 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100818
David Brazdilf677ebf2015-05-29 16:29:43 +0100819 void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
820 StoreAt(encoding.NumberOfBytesForRegisterMask(),
821 encoding.ComputeStackMapRegisterMaskOffset(),
822 mask);
823 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100824
David Brazdilf677ebf2015-05-29 16:29:43 +0100825 MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
826 return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
827 encoding.NumberOfBytesForStackMask());
828 }
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100829
David Brazdilf677ebf2015-05-29 16:29:43 +0100830 void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
831 MemoryRegion region = GetStackMask(encoding);
David Brazdilf10a25f2015-06-02 14:29:52 +0100832 sp_map.CopyTo(region.start(), region.size());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100833 }
834
David Brazdilf677ebf2015-05-29 16:29:43 +0100835 bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
836 return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100837 }
838
David Brazdilf677ebf2015-05-29 16:29:43 +0100839 bool HasInlineInfo(const StackMapEncoding& encoding) const {
840 return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
Roland Levillain442b46a2015-02-18 16:54:21 +0000841 }
842
843 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100844 return region_.pointer() == other.region_.pointer()
845 && region_.size() == other.region_.size();
846 }
847
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100848 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +0100849 const CodeInfo& code_info,
David Brazdilf677ebf2015-05-29 16:29:43 +0100850 const StackMapEncoding& encoding,
Roland Levillainf2650d12015-05-28 14:53:28 +0100851 uint32_t code_offset,
852 uint16_t number_of_dex_registers,
853 const std::string& header_suffix = "") const;
854
Roland Levillain442b46a2015-02-18 16:54:21 +0000855 // Special (invalid) offset for the DexRegisterMapOffset field meaning
856 // that there is no Dex register map for this stack map.
857 static constexpr uint32_t kNoDexRegisterMap = -1;
858
859 // Special (invalid) offset for the InlineDescriptorOffset field meaning
860 // that there is no inline info for this stack map.
861 static constexpr uint32_t kNoInlineInfo = -1;
862
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100863 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000864 // TODO: Instead of plain types such as "uint32_t", introduce
865 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100866 static constexpr int kFixedSize = 0;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100867
David Brazdilf677ebf2015-05-29 16:29:43 +0100868 // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
869 // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
870 uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
871 void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
872
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100873 MemoryRegion region_;
874
Nicolas Geoffray39468442014-09-02 15:17:15 +0100875 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100876};
877
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100878/**
879 * Inline information for a specific PC. The information is of the form:
880 * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
881 */
882class InlineInfo {
883 public:
884 explicit InlineInfo(MemoryRegion region) : region_(region) {}
885
886 uint8_t GetDepth() const {
887 return region_.LoadUnaligned<uint8_t>(kDepthOffset);
888 }
889
890 void SetDepth(uint8_t depth) {
891 region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
892 }
893
894 uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100895 return region_.LoadUnaligned<uint32_t>(
896 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100897 }
898
899 void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100900 region_.StoreUnaligned<uint32_t>(
901 kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100902 }
903
904 uint32_t GetDexPcAtDepth(uint8_t depth) const {
905 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100906 kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100907 }
908
909 void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
910 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100911 kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
912 }
913
914 uint8_t GetInvokeTypeAtDepth(uint8_t depth) const {
915 return region_.LoadUnaligned<uint8_t>(
916 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
917 }
918
919 void SetInvokeTypeAtDepth(uint8_t depth, uint8_t invoke_type) {
920 region_.StoreUnaligned<uint8_t>(
921 kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100922 }
923
924 uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
925 return region_.LoadUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100926 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100927 }
928
929 void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
930 region_.StoreUnaligned<uint32_t>(
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100931 kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100932 }
933
934 bool HasDexRegisterMapAtDepth(uint8_t depth) const {
935 return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
936 }
937
938 static size_t SingleEntrySize() {
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100939 return kFixedEntrySize;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100940 }
941
Vladimir Marko8f1e08a2015-06-26 12:06:30 +0100942 void Dump(VariableIndentationOutputStream* vios,
943 const CodeInfo& info, uint16_t* number_of_dex_registers) const;
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100944
945 private:
946 // TODO: Instead of plain types such as "uint8_t", introduce
947 // typedefs (and document the memory layout of InlineInfo).
948 static constexpr int kDepthOffset = 0;
949 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
950
Nicolas Geoffrayb176d7c2015-05-20 18:48:31 +0100951 static constexpr int kMethodIndexOffset = 0;
952 static constexpr int kDexPcOffset = kMethodIndexOffset + sizeof(uint32_t);
953 static constexpr int kInvokeTypeOffset = kDexPcOffset + sizeof(uint32_t);
954 static constexpr int kDexRegisterMapOffset = kInvokeTypeOffset + sizeof(uint8_t);
955 static constexpr int kFixedEntrySize = kDexRegisterMapOffset + sizeof(uint32_t);
956
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +0100957 MemoryRegion region_;
958
959 friend class CodeInfo;
960 friend class StackMap;
961 friend class StackMapStream;
962};
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100963
964/**
965 * Wrapper around all compiler information collected for a method.
966 * The information is of the form:
Roland Levillaina552e1c2015-03-26 15:01:03 +0000967 * [overall_size, number_of_location_catalog_entries, number_of_stack_maps, stack_mask_size,
968 * DexRegisterLocationCatalog+, StackMap+, DexRegisterMap+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100969 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100970class CodeInfo {
971 public:
972 explicit CodeInfo(MemoryRegion region) : region_(region) {}
973
Nicolas Geoffray39468442014-09-02 15:17:15 +0100974 explicit CodeInfo(const void* data) {
975 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
976 region_ = MemoryRegion(const_cast<void*>(data), size);
977 }
978
David Brazdilf677ebf2015-05-29 16:29:43 +0100979 StackMapEncoding ExtractEncoding() const {
980 return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
981 GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
982 GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
983 GetNumberOfBytesForEncoding(kDexPcBitOffset),
984 GetNumberOfBytesForEncoding(kNativePcBitOffset),
985 GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100986 }
987
David Brazdilf677ebf2015-05-29 16:29:43 +0100988 void SetEncoding(const StackMapEncoding& encoding) {
989 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
990 region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
991 SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
992 SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
993 SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
994 SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
995 SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
Nicolas Geoffray896f8f72015-03-30 15:44:25 +0100996 }
997
998 void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
Roland Levillaind780c002015-07-15 14:30:26 +0100999 region_.StoreBits(bit_offset, number_of_bytes, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001000 }
1001
1002 size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
Roland Levillaind780c002015-07-15 14:30:26 +01001003 return region_.LoadBits(bit_offset, kNumberOfBitForNumberOfBytesForEncoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001004 }
1005
1006 bool HasInlineInfo() const {
1007 return region_.LoadBit(kHasInlineInfoBitOffset);
1008 }
1009
David Brazdilf677ebf2015-05-29 16:29:43 +01001010 DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
Roland Levillaina552e1c2015-03-26 15:01:03 +00001011 return DexRegisterLocationCatalog(region_.Subregion(
David Brazdilf677ebf2015-05-29 16:29:43 +01001012 GetDexRegisterLocationCatalogOffset(encoding),
1013 GetDexRegisterLocationCatalogSize(encoding)));
Roland Levillaina552e1c2015-03-26 15:01:03 +00001014 }
1015
David Brazdilf677ebf2015-05-29 16:29:43 +01001016 StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
1017 size_t stack_map_size = encoding.ComputeStackMapSize();
1018 return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001019 }
1020
1021 uint32_t GetOverallSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001022 return region_.LoadUnaligned<uint32_t>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001023 }
1024
1025 void SetOverallSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001026 region_.StoreUnaligned<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001027 }
1028
Roland Levillaina552e1c2015-03-26 15:01:03 +00001029 uint32_t GetNumberOfDexRegisterLocationCatalogEntries() const {
1030 return region_.LoadUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset);
1031 }
1032
1033 void SetNumberOfDexRegisterLocationCatalogEntries(uint32_t num_entries) {
1034 region_.StoreUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset, num_entries);
1035 }
1036
David Brazdilf677ebf2015-05-29 16:29:43 +01001037 uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
1038 return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
Roland Levillaina552e1c2015-03-26 15:01:03 +00001039 GetNumberOfDexRegisterLocationCatalogEntries());
1040 }
1041
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001042 size_t GetNumberOfStackMaps() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001043 return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001044 }
1045
1046 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +00001047 region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001048 }
1049
Roland Levillain29ba1b02015-03-13 11:45:07 +00001050 // Get the size all the stack maps of this CodeInfo object, in bytes.
David Brazdilf677ebf2015-05-29 16:29:43 +01001051 size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
1052 return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
Roland Levillain29ba1b02015-03-13 11:45:07 +00001053 }
1054
David Brazdilf677ebf2015-05-29 16:29:43 +01001055 uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
1056 return GetStackMapsOffset() + GetStackMapsSize(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001057 }
1058
David Brazdilf677ebf2015-05-29 16:29:43 +01001059 size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
1060 return GetDexRegisterLocationCatalogOffset(encoding)
1061 + GetDexRegisterLocationCatalogSize(encoding);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001062 }
1063
Nicolas Geoffray6530baf2015-05-26 15:22:58 +01001064 uint32_t GetStackMapsOffset() const {
1065 return kFixedSize;
1066 }
1067
David Brazdilf677ebf2015-05-29 16:29:43 +01001068 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
1069 const StackMapEncoding& encoding,
1070 uint32_t number_of_dex_registers) const {
1071 DCHECK(stack_map.HasDexRegisterMap(encoding));
1072 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1073 + stack_map.GetDexRegisterMapOffset(encoding);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001074 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001075 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001076 }
1077
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001078 // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
1079 DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
1080 InlineInfo inline_info,
David Brazdilf677ebf2015-05-29 16:29:43 +01001081 const StackMapEncoding& encoding,
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001082 uint32_t number_of_dex_registers) const {
1083 DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
David Brazdilf677ebf2015-05-29 16:29:43 +01001084 uint32_t offset = GetDexRegisterMapsOffset(encoding)
1085 + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
Nicolas Geoffrayb1d0f3f2015-05-14 12:41:51 +01001086 size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
1087 return DexRegisterMap(region_.Subregion(offset, size));
1088 }
1089
David Brazdilf677ebf2015-05-29 16:29:43 +01001090 InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
1091 DCHECK(stack_map.HasInlineInfo(encoding));
1092 uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
1093 + GetDexRegisterMapsOffset(encoding);
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001094 uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001095 return InlineInfo(region_.Subregion(offset,
1096 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
1097 }
1098
David Brazdilf677ebf2015-05-29 16:29:43 +01001099 StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001100 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001101 StackMap stack_map = GetStackMapAt(i, encoding);
1102 if (stack_map.GetDexPc(encoding) == dex_pc) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001103 return stack_map;
1104 }
1105 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001106 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001107 }
1108
David Brazdilf677ebf2015-05-29 16:29:43 +01001109 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
1110 const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001111 // TODO: stack maps are sorted by native pc, we can do a binary search.
1112 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
David Brazdilf677ebf2015-05-29 16:29:43 +01001113 StackMap stack_map = GetStackMapAt(i, encoding);
1114 if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001115 return stack_map;
1116 }
1117 }
Nicolas Geoffraye12997f2015-05-22 14:01:33 +01001118 return StackMap();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001119 }
1120
Roland Levillainf2650d12015-05-28 14:53:28 +01001121 // Dump this CodeInfo object on `os`. `code_offset` is the (absolute)
1122 // native PC of the compiled method and `number_of_dex_registers` the
1123 // number of Dex virtual registers used in this method. If
1124 // `dump_stack_maps` is true, also dump the stack maps and the
1125 // associated Dex register maps.
Vladimir Marko8f1e08a2015-06-26 12:06:30 +01001126 void Dump(VariableIndentationOutputStream* vios,
Roland Levillainf2650d12015-05-28 14:53:28 +01001127 uint32_t code_offset,
1128 uint16_t number_of_dex_registers,
1129 bool dump_stack_maps) const;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001130
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001131 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001132 // TODO: Instead of plain types such as "uint32_t", introduce
1133 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +01001134 static constexpr int kOverallSizeOffset = 0;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001135 static constexpr int kEncodingInfoOffset = kOverallSizeOffset + sizeof(uint32_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001136 static constexpr int kNumberOfDexRegisterLocationCatalogEntriesOffset =
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001137 kEncodingInfoOffset + sizeof(uint16_t);
Roland Levillaina552e1c2015-03-26 15:01:03 +00001138 static constexpr int kNumberOfStackMapsOffset =
1139 kNumberOfDexRegisterLocationCatalogEntriesOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001140 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
1141 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
1142
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001143 static constexpr int kHasInlineInfoBitOffset = (kEncodingInfoOffset * kBitsPerByte);
Nicolas Geoffray896f8f72015-03-30 15:44:25 +01001144 static constexpr int kInlineInfoBitOffset = kHasInlineInfoBitOffset + 1;
Roland Levillaind780c002015-07-15 14:30:26 +01001145 static constexpr int kDexRegisterMapBitOffset =
1146 kInlineInfoBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
1147 static constexpr int kDexPcBitOffset =
1148 kDexRegisterMapBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
1149 static constexpr int kNativePcBitOffset =
1150 kDexPcBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
1151 static constexpr int kRegisterMaskBitOffset =
1152 kNativePcBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
Nicolas Geoffray004c2302015-03-20 10:06:38 +00001153
David Brazdilf677ebf2015-05-29 16:29:43 +01001154 MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001155 return region_.size() == 0
1156 ? MemoryRegion()
David Brazdilf677ebf2015-05-29 16:29:43 +01001157 : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001158 }
1159
Roland Levillaina552e1c2015-03-26 15:01:03 +00001160 // Compute the size of the Dex register map associated to the stack map at
1161 // `dex_register_map_offset_in_code_info`.
1162 size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset_in_code_info,
1163 uint16_t number_of_dex_registers) const {
1164 // Offset where the actual mapping data starts within art::DexRegisterMap.
1165 size_t location_mapping_data_offset_in_dex_register_map =
1166 DexRegisterMap::GetLocationMappingDataOffset(number_of_dex_registers);
1167 // Create a temporary art::DexRegisterMap to be able to call
1168 // art::DexRegisterMap::GetNumberOfLiveDexRegisters and
1169 DexRegisterMap dex_register_map_without_locations(
1170 MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info,
1171 location_mapping_data_offset_in_dex_register_map)));
1172 size_t number_of_live_dex_registers =
1173 dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers);
1174 size_t location_mapping_data_size_in_bits =
1175 DexRegisterMap::SingleEntrySizeInBits(GetNumberOfDexRegisterLocationCatalogEntries())
1176 * number_of_live_dex_registers;
1177 size_t location_mapping_data_size_in_bytes =
1178 RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte;
1179 size_t dex_register_map_size =
1180 location_mapping_data_offset_in_dex_register_map + location_mapping_data_size_in_bytes;
1181 return dex_register_map_size;
1182 }
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001183
Roland Levillaina552e1c2015-03-26 15:01:03 +00001184 // Compute the size of a Dex register location catalog starting at offset `origin`
1185 // in `region_` and containing `number_of_dex_locations` entries.
1186 size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin,
1187 uint32_t number_of_dex_locations) const {
1188 // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or
1189 // art::DexRegisterLocationCatalog::FindLocationOffset, but the
1190 // DexRegisterLocationCatalog is not yet built. Try to factor common code.
1191 size_t offset = origin + DexRegisterLocationCatalog::kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +00001192
Roland Levillaina552e1c2015-03-26 15:01:03 +00001193 // Skip the first `number_of_dex_locations - 1` entries.
1194 for (uint16_t i = 0; i < number_of_dex_locations; ++i) {
1195 // Read the first next byte and inspect its first 3 bits to decide
1196 // whether it is a short or a large location.
1197 DexRegisterLocationCatalog::ShortLocation first_byte =
1198 region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset);
1199 DexRegisterLocation::Kind kind =
1200 DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte);
1201 if (DexRegisterLocation::IsShortLocationKind(kind)) {
1202 // Short location. Skip the current byte.
1203 offset += DexRegisterLocationCatalog::SingleShortEntrySize();
1204 } else {
1205 // Large location. Skip the 5 next bytes.
1206 offset += DexRegisterLocationCatalog::SingleLargeEntrySize();
Roland Levillaina2d8ec62015-03-12 15:25:29 +00001207 }
1208 }
1209 size_t size = offset - origin;
1210 return size;
1211 }
1212
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001213 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +01001214 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +01001215};
1216
1217} // namespace art
1218
1219#endif // ART_RUNTIME_STACK_MAP_H_