blob: c98162306c5744ef670dd07ceb83552982b1d429 [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
Roland Levillaina2d8ec62015-03-12 15:25:29 +000026// Size of a frame slot, in bytes. This constant is a signed value,
27// to please the compiler in arithmetic operations involving int32_t
28// (signed) values.
29static ssize_t constexpr kFrameSlotSize = 4;
30
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010031/**
32 * Classes in the following file are wrapper on stack map information backed
33 * by a MemoryRegion. As such they read and write to the region, they don't have
34 * their own fields.
35 */
36
37/**
38 * Inline information for a specific PC. The information is of the form:
39 * [inlining_depth, [method_dex reference]+]
40 */
41class InlineInfo {
42 public:
43 explicit InlineInfo(MemoryRegion region) : region_(region) {}
44
45 uint8_t GetDepth() const {
46 return region_.Load<uint8_t>(kDepthOffset);
47 }
48
49 void SetDepth(uint8_t depth) {
50 region_.Store<uint8_t>(kDepthOffset, depth);
51 }
52
53 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
54 return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
55 }
56
57 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
58 region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
59 }
60
61 static size_t SingleEntrySize() {
62 return sizeof(uint32_t);
63 }
64
65 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +000066 // TODO: Instead of plain types such as "uint8_t", introduce
67 // typedefs (and document the memory layout of InlineInfo).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010068 static constexpr int kDepthOffset = 0;
69 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
70
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010071 MemoryRegion region_;
72
Nicolas Geoffray39468442014-09-02 15:17:15 +010073 friend class CodeInfo;
74 friend class StackMap;
75 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010076};
77
Roland Levillaina2d8ec62015-03-12 15:25:29 +000078// Dex register location container used by DexRegisterMap and StackMapStream.
79class DexRegisterLocation {
80 public:
81 /*
82 * The location kind used to populate the Dex register information in a
83 * StackMapStream can either be:
84 * - kNone: the register has no location yet, meaning it has not been set;
85 * - kConstant: value holds the constant;
86 * - kStack: value holds the stack offset;
87 * - kRegister: value holds the physical register number;
88 * - kFpuRegister: value holds the physical register number.
89 *
90 * In addition, DexRegisterMap also uses these values:
91 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
92 * 128 bytes);
93 * - kConstantLargeValue: value holds a "large" constant (lower than or
94 * equal to -16, or greater than 16).
95 */
96 enum class Kind : uint8_t {
97 // Short location kinds, for entries fitting on one byte (3 bits
98 // for the kind, 5 bits for the value) in a DexRegisterMap.
99 kNone = 0, // 0b000
100 kInStack = 1, // 0b001
101 kInRegister = 2, // 0b010
102 kInFpuRegister = 3, // 0b011
103 kConstant = 4, // 0b100
104
105 // Large location kinds, requiring a 5-byte encoding (1 byte for the
106 // kind, 4 bytes for the value).
107
108 // Stack location at a large offset, meaning that the offset value
109 // divided by the stack frame slot size (4 bytes) cannot fit on a
110 // 5-bit unsigned integer (i.e., this offset value is greater than
111 // or equal to 2^5 * 4 = 128 bytes).
112 kInStackLargeOffset = 5, // 0b101
113
114 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
115 // lower than -2^(5-1) = -16, or greater than or equal to
116 // 2^(5-1) - 1 = 15).
117 kConstantLargeValue = 6, // 0b110
118
119 kLastLocationKind = kConstantLargeValue
120 };
121
122 static_assert(
123 sizeof(Kind) == 1u,
124 "art::DexRegisterLocation::Kind has a size different from one byte.");
125
126 static const char* PrettyDescriptor(Kind kind) {
127 switch (kind) {
128 case Kind::kNone:
129 return "none";
130 case Kind::kInStack:
131 return "in stack";
132 case Kind::kInRegister:
133 return "in register";
134 case Kind::kInFpuRegister:
135 return "in fpu register";
136 case Kind::kConstant:
137 return "as constant";
138 case Kind::kInStackLargeOffset:
139 return "in stack (large offset)";
140 case Kind::kConstantLargeValue:
141 return "as constant (large value)";
142 default:
143 UNREACHABLE();
144 }
145 }
146
147 static bool IsShortLocationKind(Kind kind) {
148 switch (kind) {
149 case Kind::kNone:
150 case Kind::kInStack:
151 case Kind::kInRegister:
152 case Kind::kInFpuRegister:
153 case Kind::kConstant:
154 return true;
155
156 case Kind::kInStackLargeOffset:
157 case Kind::kConstantLargeValue:
158 return false;
159
160 default:
161 UNREACHABLE();
162 }
163 }
164
165 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
166 // any value with a "large" qualifier.
167 // TODO: Introduce another enum type for the surface kind?
168 static Kind ConvertToSurfaceKind(Kind kind) {
169 switch (kind) {
170 case Kind::kNone:
171 case Kind::kInStack:
172 case Kind::kInRegister:
173 case Kind::kInFpuRegister:
174 case Kind::kConstant:
175 return kind;
176
177 case Kind::kInStackLargeOffset:
178 return Kind::kInStack;
179
180 case Kind::kConstantLargeValue:
181 return Kind::kConstant;
182
183 default:
184 UNREACHABLE();
185 }
186 }
187
188 DexRegisterLocation(Kind kind, int32_t value)
189 : kind_(kind), value_(value) {}
190
191 // Get the "surface" kind of the location, i.e., the one that doesn't
192 // include any value with a "large" qualifier.
193 Kind GetKind() const {
194 return ConvertToSurfaceKind(kind_);
195 }
196
197 // Get the value of the location.
198 int32_t GetValue() const { return value_; }
199
200 // Get the actual kind of the location.
201 Kind GetInternalKind() const { return kind_; }
202
203 private:
204 Kind kind_;
205 int32_t value_;
206};
207
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100208/**
209 * Information on dex register values for a specific PC. The information is
210 * of the form:
211 * [location_kind, register_value]+.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000212 * either on 1 or 5 bytes (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100213 */
214class DexRegisterMap {
215 public:
216 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
217
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000218 // Short (compressed) location, fitting on one byte.
219 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100220
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000221 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
222 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
223 int32_t value = dex_register_location.GetValue();
224 if (DexRegisterLocation::IsShortLocationKind(kind)) {
225 // Short location. Compress the kind and the value as a single byte.
226 if (kind == DexRegisterLocation::Kind::kInStack) {
227 // Instead of storing stack offsets expressed in bytes for
228 // short stack locations, store slot offsets. A stack offset
229 // is a multiple of 4 (kFrameSlotSize). This means that by
230 // dividing it by 4, we can fit values from the [0, 128)
231 // interval in a short stack location, and not just values
232 // from the [0, 32) interval.
233 DCHECK_EQ(value % kFrameSlotSize, 0);
234 value /= kFrameSlotSize;
235 }
236 DCHECK(IsUint<kValueBits>(value)) << value;
237 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
238 } else {
239 // Large location. Write the location on one byte and the value
240 // on 4 bytes.
241 DCHECK(!IsUint<kValueBits>(value)) << value;
242 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
243 // Also divide large stack offsets by 4 for the sake of consistency.
244 DCHECK_EQ(value % kFrameSlotSize, 0);
245 value /= kFrameSlotSize;
246 }
247 // Data can be unaligned as the written Dex register locations can
248 // either be 1-byte or 5-byte wide. Use
249 // art::MemoryRegion::StoreUnaligned instead of
250 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
251 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
252 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000253 }
254 }
255
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000256 // Find the offset of the Dex register location number `dex_register_index`.
257 size_t FindLocationOffset(uint16_t dex_register_index) const {
258 size_t offset = kFixedSize;
259 // Skip the first `dex_register_index - 1` entries.
260 for (uint16_t i = 0; i < dex_register_index; ++i) {
261 // Read the first next byte and inspect its first 3 bits to decide
262 // whether it is a short or a large location.
263 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
264 if (DexRegisterLocation::IsShortLocationKind(kind)) {
265 // Short location. Skip the current byte.
266 offset += SingleShortEntrySize();
267 } else {
268 // Large location. Skip the 5 next bytes.
269 offset += SingleLargeEntrySize();
270 }
271 }
272 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100273 }
274
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000275 // Get the surface kind.
276 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index) const {
277 return DexRegisterLocation::ConvertToSurfaceKind(GetLocationInternalKind(dex_register_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100278 }
279
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000280 // Get the internal kind.
281 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index) const {
282 size_t offset = FindLocationOffset(dex_register_index);
283 return ExtractKindAtOffset(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100284 }
285
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000286 // TODO: Rename as GetDexRegisterLocation?
287 DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index) const {
288 size_t offset = FindLocationOffset(dex_register_index);
289 // Read the first byte and inspect its first 3 bits to get the location.
290 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
291 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
292 if (DexRegisterLocation::IsShortLocationKind(kind)) {
293 // Short location. Extract the value from the remaining 5 bits.
294 int32_t value = ExtractValueFromShortLocation(first_byte);
295 if (kind == DexRegisterLocation::Kind::kInStack) {
296 // Convert the stack slot (short) offset to a byte offset value.
297 value *= kFrameSlotSize;
298 }
299 return DexRegisterLocation(kind, value);
300 } else {
301 // Large location. Read the four next bytes to get the value.
302 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
303 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
304 // Convert the stack slot (large) offset to a byte offset value.
305 value *= kFrameSlotSize;
306 }
307 return DexRegisterLocation(kind, value);
308 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100309 }
310
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000311 int32_t GetStackOffsetInBytes(uint16_t dex_register_index) const {
312 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
313 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
314 // GetLocationKindAndValue returns the offset in bytes.
315 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100316 }
317
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000318 int32_t GetConstant(uint16_t dex_register_index) const {
319 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
320 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
321 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100322 }
323
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000324 int32_t GetMachineRegister(uint16_t dex_register_index) const {
325 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
326 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
327 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
328 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
329 return location.GetValue();
330 }
331
332 // Compute the compressed kind of `location`.
333 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
334 switch (location.GetInternalKind()) {
335 case DexRegisterLocation::Kind::kNone:
336 DCHECK_EQ(location.GetValue(), 0);
337 return DexRegisterLocation::Kind::kNone;
338
339 case DexRegisterLocation::Kind::kInRegister:
340 DCHECK_GE(location.GetValue(), 0);
341 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
342 return DexRegisterLocation::Kind::kInRegister;
343
344 case DexRegisterLocation::Kind::kInFpuRegister:
345 DCHECK_GE(location.GetValue(), 0);
346 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
347 return DexRegisterLocation::Kind::kInFpuRegister;
348
349 case DexRegisterLocation::Kind::kInStack:
350 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
351 return IsUint<DexRegisterMap::kValueBits>(location.GetValue() / kFrameSlotSize)
352 ? DexRegisterLocation::Kind::kInStack
353 : DexRegisterLocation::Kind::kInStackLargeOffset;
354
355 case DexRegisterLocation::Kind::kConstant:
356 return IsUint<DexRegisterMap::kValueBits>(location.GetValue())
357 ? DexRegisterLocation::Kind::kConstant
358 : DexRegisterLocation::Kind::kConstantLargeValue;
359
360 default:
361 LOG(FATAL) << "Unexpected location kind"
362 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
363 UNREACHABLE();
364 }
365 }
366
367 // Can `location` be turned into a short location?
368 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
369 switch (location.GetInternalKind()) {
370 case DexRegisterLocation::Kind::kNone:
371 case DexRegisterLocation::Kind::kInRegister:
372 case DexRegisterLocation::Kind::kInFpuRegister:
373 return true;
374
375 case DexRegisterLocation::Kind::kInStack:
376 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
377 return IsUint<kValueBits>(location.GetValue() / kFrameSlotSize);
378
379 case DexRegisterLocation::Kind::kConstant:
380 return IsUint<kValueBits>(location.GetValue());
381
382 default:
383 UNREACHABLE();
384 }
385 }
386
387 static size_t EntrySize(const DexRegisterLocation& location) {
388 return CanBeEncodedAsShortLocation(location)
389 ? DexRegisterMap::SingleShortEntrySize()
390 : DexRegisterMap::SingleLargeEntrySize();
391 }
392
393 static size_t SingleShortEntrySize() {
394 return sizeof(ShortLocation);
395 }
396
397 static size_t SingleLargeEntrySize() {
398 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100399 }
400
Roland Levillain12baf472015-03-05 12:41:42 +0000401 size_t Size() const {
402 return region_.size();
403 }
404
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100405 static constexpr int kFixedSize = 0;
406
Roland Levillain12baf472015-03-05 12:41:42 +0000407 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000408 // Width of the kind "field" in a short location, in bits.
409 static constexpr size_t kKindBits = 3;
410 // Width of the value "field" in a short location, in bits.
411 static constexpr size_t kValueBits = 5;
412
413 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
414 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
415 static constexpr size_t kKindOffset = 0;
416 static constexpr size_t kValueOffset = kKindBits;
417
418 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
419 DCHECK(IsUint<kKindBits>(static_cast<uint8_t>(kind))) << static_cast<uint8_t>(kind);
420 DCHECK(IsUint<kValueBits>(value)) << value;
421 return (static_cast<uint8_t>(kind) & kKindMask) << kKindOffset
422 | (value & kValueMask) << kValueOffset;
423 }
424
425 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
426 uint8_t kind = (location >> kKindOffset) & kKindMask;
427 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
428 return static_cast<DexRegisterLocation::Kind>(kind);
429 }
430
431 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
432 return (location >> kValueOffset) & kValueMask;
433 }
434
435 // Extract a location kind from the byte at position `offset`.
436 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
437 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
438 return ExtractKindFromShortLocation(first_byte);
439 }
440
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100441 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000442
443 friend class CodeInfo;
444 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100445};
446
447/**
448 * A Stack Map holds compilation information for a specific PC necessary for:
449 * - Mapping it to a dex PC,
450 * - Knowing which stack entries are objects,
451 * - Knowing which registers hold objects,
452 * - Knowing the inlining information,
453 * - Knowing the values of dex registers.
454 *
455 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100456 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100457 *
458 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
459 * stack size of a method.
460 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100461class StackMap {
462 public:
463 explicit StackMap(MemoryRegion region) : region_(region) {}
464
465 uint32_t GetDexPc() const {
466 return region_.Load<uint32_t>(kDexPcOffset);
467 }
468
469 void SetDexPc(uint32_t dex_pc) {
470 region_.Store<uint32_t>(kDexPcOffset, dex_pc);
471 }
472
Nicolas Geoffray39468442014-09-02 15:17:15 +0100473 uint32_t GetNativePcOffset() const {
474 return region_.Load<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100475 }
476
Nicolas Geoffray39468442014-09-02 15:17:15 +0100477 void SetNativePcOffset(uint32_t native_pc_offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000478 region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100479 }
480
481 uint32_t GetDexRegisterMapOffset() const {
482 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
483 }
484
485 void SetDexRegisterMapOffset(uint32_t offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000486 region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100487 }
488
489 uint32_t GetInlineDescriptorOffset() const {
490 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
491 }
492
493 void SetInlineDescriptorOffset(uint32_t offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000494 region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100495 }
496
497 uint32_t GetRegisterMask() const {
498 return region_.Load<uint32_t>(kRegisterMaskOffset);
499 }
500
501 void SetRegisterMask(uint32_t mask) {
502 region_.Store<uint32_t>(kRegisterMaskOffset, mask);
503 }
504
505 MemoryRegion GetStackMask() const {
506 return region_.Subregion(kStackMaskOffset, StackMaskSize());
507 }
508
509 void SetStackMask(const BitVector& sp_map) {
510 MemoryRegion region = GetStackMask();
511 for (size_t i = 0; i < region.size_in_bits(); i++) {
512 region.StoreBit(i, sp_map.IsBitSet(i));
513 }
514 }
515
Roland Levillain442b46a2015-02-18 16:54:21 +0000516 bool HasDexRegisterMap() const {
517 return GetDexRegisterMapOffset() != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100518 }
519
Roland Levillain442b46a2015-02-18 16:54:21 +0000520 bool HasInlineInfo() const {
521 return GetInlineDescriptorOffset() != kNoInlineInfo;
522 }
523
524 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100525 return region_.pointer() == other.region_.pointer()
526 && region_.size() == other.region_.size();
527 }
528
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000529 static size_t ComputeAlignedStackMapSize(size_t stack_map_size) {
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000530 // On ARM, the stack maps must be 4-byte aligned.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000531 return RoundUp(StackMap::kFixedSize + stack_map_size, 4);
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000532 }
533
Roland Levillain442b46a2015-02-18 16:54:21 +0000534 // Special (invalid) offset for the DexRegisterMapOffset field meaning
535 // that there is no Dex register map for this stack map.
536 static constexpr uint32_t kNoDexRegisterMap = -1;
537
538 // Special (invalid) offset for the InlineDescriptorOffset field meaning
539 // that there is no inline info for this stack map.
540 static constexpr uint32_t kNoInlineInfo = -1;
541
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100542 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000543 // TODO: Instead of plain types such as "uint32_t", introduce
544 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100545 static constexpr int kDexPcOffset = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100546 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
547 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100548 static constexpr int kInlineDescriptorOffsetOffset =
549 kDexRegisterMapOffsetOffset + sizeof(uint32_t);
550 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
551 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
552 static constexpr int kStackMaskOffset = kFixedSize;
553
554 size_t StackMaskSize() const { return region_.size() - kFixedSize; }
555
556 MemoryRegion region_;
557
Nicolas Geoffray39468442014-09-02 15:17:15 +0100558 friend class CodeInfo;
559 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100560};
561
562
563/**
564 * Wrapper around all compiler information collected for a method.
565 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100566 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100567 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100568class CodeInfo {
569 public:
570 explicit CodeInfo(MemoryRegion region) : region_(region) {}
571
Nicolas Geoffray39468442014-09-02 15:17:15 +0100572 explicit CodeInfo(const void* data) {
573 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
574 region_ = MemoryRegion(const_cast<void*>(data), size);
575 }
576
577 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100578 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100579 return StackMap(GetStackMaps().Subregion(i * size, size));
580 }
581
582 uint32_t GetOverallSize() const {
583 return region_.Load<uint32_t>(kOverallSizeOffset);
584 }
585
586 void SetOverallSize(uint32_t size) {
587 region_.Store<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100588 }
589
590 uint32_t GetStackMaskSize() const {
591 return region_.Load<uint32_t>(kStackMaskSizeOffset);
592 }
593
594 void SetStackMaskSize(uint32_t size) {
595 region_.Store<uint32_t>(kStackMaskSizeOffset, size);
596 }
597
598 size_t GetNumberOfStackMaps() const {
599 return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
600 }
601
602 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
603 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
604 }
605
606 size_t StackMapSize() const {
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000607 return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100608 }
609
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000610 uint32_t GetStackMapsOffset() const {
611 return kFixedSize;
612 }
613
Roland Levillain442b46a2015-02-18 16:54:21 +0000614 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
615 DCHECK(stack_map.HasDexRegisterMap());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100616 uint32_t offset = stack_map.GetDexRegisterMapOffset();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000617 size_t size = ComputeDexRegisterMapSize(offset, number_of_dex_registers);
618 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100619 }
620
Roland Levillain442b46a2015-02-18 16:54:21 +0000621 InlineInfo GetInlineInfoOf(StackMap stack_map) const {
622 DCHECK(stack_map.HasInlineInfo());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100623 uint32_t offset = stack_map.GetInlineDescriptorOffset();
624 uint8_t depth = region_.Load<uint8_t>(offset);
625 return InlineInfo(region_.Subregion(offset,
626 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
627 }
628
Roland Levillain442b46a2015-02-18 16:54:21 +0000629 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100630 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100631 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100632 if (stack_map.GetDexPc() == dex_pc) {
633 return stack_map;
634 }
635 }
636 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700637 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100638 }
639
Roland Levillain442b46a2015-02-18 16:54:21 +0000640 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100641 // TODO: stack maps are sorted by native pc, we can do a binary search.
642 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100643 StackMap stack_map = GetStackMapAt(i);
644 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100645 return stack_map;
646 }
647 }
648 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700649 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100650 }
651
652 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000653 // TODO: Instead of plain types such as "uint32_t", introduce
654 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +0100655 static constexpr int kOverallSizeOffset = 0;
656 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100657 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
658 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
659
660 MemoryRegion GetStackMaps() const {
661 return region_.size() == 0
662 ? MemoryRegion()
663 : region_.Subregion(kFixedSize, StackMapSize() * GetNumberOfStackMaps());
664 }
665
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000666 // Compute the size of a Dex register map starting at offset `origin` in
667 // `region_` and containing `number_of_dex_registers` locations.
668 size_t ComputeDexRegisterMapSize(uint32_t origin, uint32_t number_of_dex_registers) const {
669 // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
670 // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
671 // yet built. Try to factor common code.
672 size_t offset = origin + DexRegisterMap::kFixedSize;
673 // Skip the first `number_of_dex_registers - 1` entries.
674 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
675 // Read the first next byte and inspect its first 3 bits to decide
676 // whether it is a short or a large location.
677 DexRegisterMap::ShortLocation first_byte =
678 region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
679 DexRegisterLocation::Kind kind =
680 DexRegisterMap::ExtractKindFromShortLocation(first_byte);
681 if (DexRegisterLocation::IsShortLocationKind(kind)) {
682 // Short location. Skip the current byte.
683 offset += DexRegisterMap::SingleShortEntrySize();
684 } else {
685 // Large location. Skip the 5 next bytes.
686 offset += DexRegisterMap::SingleLargeEntrySize();
687 }
688 }
689 size_t size = offset - origin;
690 return size;
691 }
692
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100693 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100694 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100695};
696
697} // namespace art
698
699#endif // ART_RUNTIME_STACK_MAP_H_