blob: 3856da318964d03c13309cd2b3396e5dda587b6e [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
Roland Levillain9ac0e4d2015-03-12 18:33:05 +000031// Word alignment required on ARM, in bytes.
32static constexpr size_t kWordAlignment = 4;
33
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010034/**
35 * Classes in the following file are wrapper on stack map information backed
36 * by a MemoryRegion. As such they read and write to the region, they don't have
37 * their own fields.
38 */
39
40/**
41 * Inline information for a specific PC. The information is of the form:
42 * [inlining_depth, [method_dex reference]+]
43 */
44class InlineInfo {
45 public:
46 explicit InlineInfo(MemoryRegion region) : region_(region) {}
47
48 uint8_t GetDepth() const {
49 return region_.Load<uint8_t>(kDepthOffset);
50 }
51
52 void SetDepth(uint8_t depth) {
53 region_.Store<uint8_t>(kDepthOffset, depth);
54 }
55
56 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
57 return region_.Load<uint32_t>(kFixedSize + depth * SingleEntrySize());
58 }
59
60 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
61 region_.Store<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
62 }
63
64 static size_t SingleEntrySize() {
65 return sizeof(uint32_t);
66 }
67
68 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +000069 // TODO: Instead of plain types such as "uint8_t", introduce
70 // typedefs (and document the memory layout of InlineInfo).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010071 static constexpr int kDepthOffset = 0;
72 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
73
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010074 MemoryRegion region_;
75
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 friend class CodeInfo;
77 friend class StackMap;
78 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010079};
80
Roland Levillaina2d8ec62015-03-12 15:25:29 +000081// Dex register location container used by DexRegisterMap and StackMapStream.
82class DexRegisterLocation {
83 public:
84 /*
85 * The location kind used to populate the Dex register information in a
86 * StackMapStream can either be:
87 * - kNone: the register has no location yet, meaning it has not been set;
88 * - kConstant: value holds the constant;
89 * - kStack: value holds the stack offset;
90 * - kRegister: value holds the physical register number;
91 * - kFpuRegister: value holds the physical register number.
92 *
93 * In addition, DexRegisterMap also uses these values:
94 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
95 * 128 bytes);
96 * - kConstantLargeValue: value holds a "large" constant (lower than or
97 * equal to -16, or greater than 16).
98 */
99 enum class Kind : uint8_t {
100 // Short location kinds, for entries fitting on one byte (3 bits
101 // for the kind, 5 bits for the value) in a DexRegisterMap.
102 kNone = 0, // 0b000
103 kInStack = 1, // 0b001
104 kInRegister = 2, // 0b010
105 kInFpuRegister = 3, // 0b011
106 kConstant = 4, // 0b100
107
108 // Large location kinds, requiring a 5-byte encoding (1 byte for the
109 // kind, 4 bytes for the value).
110
111 // Stack location at a large offset, meaning that the offset value
112 // divided by the stack frame slot size (4 bytes) cannot fit on a
113 // 5-bit unsigned integer (i.e., this offset value is greater than
114 // or equal to 2^5 * 4 = 128 bytes).
115 kInStackLargeOffset = 5, // 0b101
116
117 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
118 // lower than -2^(5-1) = -16, or greater than or equal to
119 // 2^(5-1) - 1 = 15).
120 kConstantLargeValue = 6, // 0b110
121
122 kLastLocationKind = kConstantLargeValue
123 };
124
125 static_assert(
126 sizeof(Kind) == 1u,
127 "art::DexRegisterLocation::Kind has a size different from one byte.");
128
129 static const char* PrettyDescriptor(Kind kind) {
130 switch (kind) {
131 case Kind::kNone:
132 return "none";
133 case Kind::kInStack:
134 return "in stack";
135 case Kind::kInRegister:
136 return "in register";
137 case Kind::kInFpuRegister:
138 return "in fpu register";
139 case Kind::kConstant:
140 return "as constant";
141 case Kind::kInStackLargeOffset:
142 return "in stack (large offset)";
143 case Kind::kConstantLargeValue:
144 return "as constant (large value)";
145 default:
146 UNREACHABLE();
147 }
148 }
149
150 static bool IsShortLocationKind(Kind kind) {
151 switch (kind) {
152 case Kind::kNone:
153 case Kind::kInStack:
154 case Kind::kInRegister:
155 case Kind::kInFpuRegister:
156 case Kind::kConstant:
157 return true;
158
159 case Kind::kInStackLargeOffset:
160 case Kind::kConstantLargeValue:
161 return false;
162
163 default:
164 UNREACHABLE();
165 }
166 }
167
168 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
169 // any value with a "large" qualifier.
170 // TODO: Introduce another enum type for the surface kind?
171 static Kind ConvertToSurfaceKind(Kind kind) {
172 switch (kind) {
173 case Kind::kNone:
174 case Kind::kInStack:
175 case Kind::kInRegister:
176 case Kind::kInFpuRegister:
177 case Kind::kConstant:
178 return kind;
179
180 case Kind::kInStackLargeOffset:
181 return Kind::kInStack;
182
183 case Kind::kConstantLargeValue:
184 return Kind::kConstant;
185
186 default:
187 UNREACHABLE();
188 }
189 }
190
191 DexRegisterLocation(Kind kind, int32_t value)
192 : kind_(kind), value_(value) {}
193
194 // Get the "surface" kind of the location, i.e., the one that doesn't
195 // include any value with a "large" qualifier.
196 Kind GetKind() const {
197 return ConvertToSurfaceKind(kind_);
198 }
199
200 // Get the value of the location.
201 int32_t GetValue() const { return value_; }
202
203 // Get the actual kind of the location.
204 Kind GetInternalKind() const { return kind_; }
205
206 private:
207 Kind kind_;
208 int32_t value_;
209};
210
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100211/**
212 * Information on dex register values for a specific PC. The information is
213 * of the form:
214 * [location_kind, register_value]+.
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000215 * either on 1 or 5 bytes (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100216 */
217class DexRegisterMap {
218 public:
219 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
220
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000221 // Short (compressed) location, fitting on one byte.
222 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100223
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000224 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
225 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
226 int32_t value = dex_register_location.GetValue();
227 if (DexRegisterLocation::IsShortLocationKind(kind)) {
228 // Short location. Compress the kind and the value as a single byte.
229 if (kind == DexRegisterLocation::Kind::kInStack) {
230 // Instead of storing stack offsets expressed in bytes for
231 // short stack locations, store slot offsets. A stack offset
232 // is a multiple of 4 (kFrameSlotSize). This means that by
233 // dividing it by 4, we can fit values from the [0, 128)
234 // interval in a short stack location, and not just values
235 // from the [0, 32) interval.
236 DCHECK_EQ(value % kFrameSlotSize, 0);
237 value /= kFrameSlotSize;
238 }
239 DCHECK(IsUint<kValueBits>(value)) << value;
240 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
241 } else {
242 // Large location. Write the location on one byte and the value
243 // on 4 bytes.
244 DCHECK(!IsUint<kValueBits>(value)) << value;
245 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
246 // Also divide large stack offsets by 4 for the sake of consistency.
247 DCHECK_EQ(value % kFrameSlotSize, 0);
248 value /= kFrameSlotSize;
249 }
250 // Data can be unaligned as the written Dex register locations can
251 // either be 1-byte or 5-byte wide. Use
252 // art::MemoryRegion::StoreUnaligned instead of
253 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
254 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
255 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000256 }
257 }
258
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000259 // Find the offset of the Dex register location number `dex_register_index`.
260 size_t FindLocationOffset(uint16_t dex_register_index) const {
261 size_t offset = kFixedSize;
262 // Skip the first `dex_register_index - 1` entries.
263 for (uint16_t i = 0; i < dex_register_index; ++i) {
264 // Read the first next byte and inspect its first 3 bits to decide
265 // whether it is a short or a large location.
266 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
267 if (DexRegisterLocation::IsShortLocationKind(kind)) {
268 // Short location. Skip the current byte.
269 offset += SingleShortEntrySize();
270 } else {
271 // Large location. Skip the 5 next bytes.
272 offset += SingleLargeEntrySize();
273 }
274 }
275 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100276 }
277
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000278 // Get the surface kind.
279 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index) const {
280 return DexRegisterLocation::ConvertToSurfaceKind(GetLocationInternalKind(dex_register_index));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100281 }
282
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000283 // Get the internal kind.
284 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index) const {
285 size_t offset = FindLocationOffset(dex_register_index);
286 return ExtractKindAtOffset(offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100287 }
288
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000289 // TODO: Rename as GetDexRegisterLocation?
290 DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index) const {
291 size_t offset = FindLocationOffset(dex_register_index);
292 // Read the first byte and inspect its first 3 bits to get the location.
293 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
294 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
295 if (DexRegisterLocation::IsShortLocationKind(kind)) {
296 // Short location. Extract the value from the remaining 5 bits.
297 int32_t value = ExtractValueFromShortLocation(first_byte);
298 if (kind == DexRegisterLocation::Kind::kInStack) {
299 // Convert the stack slot (short) offset to a byte offset value.
300 value *= kFrameSlotSize;
301 }
302 return DexRegisterLocation(kind, value);
303 } else {
304 // Large location. Read the four next bytes to get the value.
305 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
306 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
307 // Convert the stack slot (large) offset to a byte offset value.
308 value *= kFrameSlotSize;
309 }
310 return DexRegisterLocation(kind, value);
311 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100312 }
313
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000314 int32_t GetStackOffsetInBytes(uint16_t dex_register_index) const {
315 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
316 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
317 // GetLocationKindAndValue returns the offset in bytes.
318 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100319 }
320
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000321 int32_t GetConstant(uint16_t dex_register_index) const {
322 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
323 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
324 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100325 }
326
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000327 int32_t GetMachineRegister(uint16_t dex_register_index) const {
328 DexRegisterLocation location = GetLocationKindAndValue(dex_register_index);
329 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
330 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
331 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
332 return location.GetValue();
333 }
334
335 // Compute the compressed kind of `location`.
336 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
337 switch (location.GetInternalKind()) {
338 case DexRegisterLocation::Kind::kNone:
339 DCHECK_EQ(location.GetValue(), 0);
340 return DexRegisterLocation::Kind::kNone;
341
342 case DexRegisterLocation::Kind::kInRegister:
343 DCHECK_GE(location.GetValue(), 0);
344 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
345 return DexRegisterLocation::Kind::kInRegister;
346
347 case DexRegisterLocation::Kind::kInFpuRegister:
348 DCHECK_GE(location.GetValue(), 0);
349 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
350 return DexRegisterLocation::Kind::kInFpuRegister;
351
352 case DexRegisterLocation::Kind::kInStack:
353 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
354 return IsUint<DexRegisterMap::kValueBits>(location.GetValue() / kFrameSlotSize)
355 ? DexRegisterLocation::Kind::kInStack
356 : DexRegisterLocation::Kind::kInStackLargeOffset;
357
358 case DexRegisterLocation::Kind::kConstant:
359 return IsUint<DexRegisterMap::kValueBits>(location.GetValue())
360 ? DexRegisterLocation::Kind::kConstant
361 : DexRegisterLocation::Kind::kConstantLargeValue;
362
363 default:
364 LOG(FATAL) << "Unexpected location kind"
365 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
366 UNREACHABLE();
367 }
368 }
369
370 // Can `location` be turned into a short location?
371 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
372 switch (location.GetInternalKind()) {
373 case DexRegisterLocation::Kind::kNone:
374 case DexRegisterLocation::Kind::kInRegister:
375 case DexRegisterLocation::Kind::kInFpuRegister:
376 return true;
377
378 case DexRegisterLocation::Kind::kInStack:
379 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
380 return IsUint<kValueBits>(location.GetValue() / kFrameSlotSize);
381
382 case DexRegisterLocation::Kind::kConstant:
383 return IsUint<kValueBits>(location.GetValue());
384
385 default:
386 UNREACHABLE();
387 }
388 }
389
390 static size_t EntrySize(const DexRegisterLocation& location) {
391 return CanBeEncodedAsShortLocation(location)
392 ? DexRegisterMap::SingleShortEntrySize()
393 : DexRegisterMap::SingleLargeEntrySize();
394 }
395
396 static size_t SingleShortEntrySize() {
397 return sizeof(ShortLocation);
398 }
399
400 static size_t SingleLargeEntrySize() {
401 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100402 }
403
Roland Levillain12baf472015-03-05 12:41:42 +0000404 size_t Size() const {
405 return region_.size();
406 }
407
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100408 static constexpr int kFixedSize = 0;
409
Roland Levillain12baf472015-03-05 12:41:42 +0000410 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000411 // Width of the kind "field" in a short location, in bits.
412 static constexpr size_t kKindBits = 3;
413 // Width of the value "field" in a short location, in bits.
414 static constexpr size_t kValueBits = 5;
415
416 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
417 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
418 static constexpr size_t kKindOffset = 0;
419 static constexpr size_t kValueOffset = kKindBits;
420
421 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
422 DCHECK(IsUint<kKindBits>(static_cast<uint8_t>(kind))) << static_cast<uint8_t>(kind);
423 DCHECK(IsUint<kValueBits>(value)) << value;
424 return (static_cast<uint8_t>(kind) & kKindMask) << kKindOffset
425 | (value & kValueMask) << kValueOffset;
426 }
427
428 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
429 uint8_t kind = (location >> kKindOffset) & kKindMask;
430 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
431 return static_cast<DexRegisterLocation::Kind>(kind);
432 }
433
434 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
435 return (location >> kValueOffset) & kValueMask;
436 }
437
438 // Extract a location kind from the byte at position `offset`.
439 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
440 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
441 return ExtractKindFromShortLocation(first_byte);
442 }
443
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100444 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000445
446 friend class CodeInfo;
447 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100448};
449
450/**
451 * A Stack Map holds compilation information for a specific PC necessary for:
452 * - Mapping it to a dex PC,
453 * - Knowing which stack entries are objects,
454 * - Knowing which registers hold objects,
455 * - Knowing the inlining information,
456 * - Knowing the values of dex registers.
457 *
458 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100459 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100460 *
461 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
462 * stack size of a method.
463 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100464class StackMap {
465 public:
466 explicit StackMap(MemoryRegion region) : region_(region) {}
467
468 uint32_t GetDexPc() const {
469 return region_.Load<uint32_t>(kDexPcOffset);
470 }
471
472 void SetDexPc(uint32_t dex_pc) {
473 region_.Store<uint32_t>(kDexPcOffset, dex_pc);
474 }
475
Nicolas Geoffray39468442014-09-02 15:17:15 +0100476 uint32_t GetNativePcOffset() const {
477 return region_.Load<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100478 }
479
Nicolas Geoffray39468442014-09-02 15:17:15 +0100480 void SetNativePcOffset(uint32_t native_pc_offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000481 region_.Store<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100482 }
483
484 uint32_t GetDexRegisterMapOffset() const {
485 return region_.Load<uint32_t>(kDexRegisterMapOffsetOffset);
486 }
487
488 void SetDexRegisterMapOffset(uint32_t offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000489 region_.Store<uint32_t>(kDexRegisterMapOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100490 }
491
492 uint32_t GetInlineDescriptorOffset() const {
493 return region_.Load<uint32_t>(kInlineDescriptorOffsetOffset);
494 }
495
496 void SetInlineDescriptorOffset(uint32_t offset) {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000497 region_.Store<uint32_t>(kInlineDescriptorOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100498 }
499
500 uint32_t GetRegisterMask() const {
501 return region_.Load<uint32_t>(kRegisterMaskOffset);
502 }
503
504 void SetRegisterMask(uint32_t mask) {
505 region_.Store<uint32_t>(kRegisterMaskOffset, mask);
506 }
507
508 MemoryRegion GetStackMask() const {
509 return region_.Subregion(kStackMaskOffset, StackMaskSize());
510 }
511
512 void SetStackMask(const BitVector& sp_map) {
513 MemoryRegion region = GetStackMask();
514 for (size_t i = 0; i < region.size_in_bits(); i++) {
515 region.StoreBit(i, sp_map.IsBitSet(i));
516 }
517 }
518
Roland Levillain442b46a2015-02-18 16:54:21 +0000519 bool HasDexRegisterMap() const {
520 return GetDexRegisterMapOffset() != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100521 }
522
Roland Levillain442b46a2015-02-18 16:54:21 +0000523 bool HasInlineInfo() const {
524 return GetInlineDescriptorOffset() != kNoInlineInfo;
525 }
526
527 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100528 return region_.pointer() == other.region_.pointer()
529 && region_.size() == other.region_.size();
530 }
531
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000532 static size_t ComputeAlignedStackMapSize(size_t stack_mask_size) {
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000533 // On ARM, the stack maps must be 4-byte aligned.
Roland Levillain9ac0e4d2015-03-12 18:33:05 +0000534 return RoundUp(StackMap::kFixedSize + stack_mask_size, kWordAlignment);
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000535 }
536
Roland Levillain442b46a2015-02-18 16:54:21 +0000537 // Special (invalid) offset for the DexRegisterMapOffset field meaning
538 // that there is no Dex register map for this stack map.
539 static constexpr uint32_t kNoDexRegisterMap = -1;
540
541 // Special (invalid) offset for the InlineDescriptorOffset field meaning
542 // that there is no inline info for this stack map.
543 static constexpr uint32_t kNoInlineInfo = -1;
544
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100545 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000546 // TODO: Instead of plain types such as "uint32_t", introduce
547 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100548 static constexpr int kDexPcOffset = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100549 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
550 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100551 static constexpr int kInlineDescriptorOffsetOffset =
552 kDexRegisterMapOffsetOffset + sizeof(uint32_t);
553 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
554 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
555 static constexpr int kStackMaskOffset = kFixedSize;
556
557 size_t StackMaskSize() const { return region_.size() - kFixedSize; }
558
559 MemoryRegion region_;
560
Nicolas Geoffray39468442014-09-02 15:17:15 +0100561 friend class CodeInfo;
562 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100563};
564
565
566/**
567 * Wrapper around all compiler information collected for a method.
568 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100569 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100570 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100571class CodeInfo {
572 public:
573 explicit CodeInfo(MemoryRegion region) : region_(region) {}
574
Nicolas Geoffray39468442014-09-02 15:17:15 +0100575 explicit CodeInfo(const void* data) {
576 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
577 region_ = MemoryRegion(const_cast<void*>(data), size);
578 }
579
580 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100581 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100582 return StackMap(GetStackMaps().Subregion(i * size, size));
583 }
584
585 uint32_t GetOverallSize() const {
586 return region_.Load<uint32_t>(kOverallSizeOffset);
587 }
588
589 void SetOverallSize(uint32_t size) {
590 region_.Store<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100591 }
592
593 uint32_t GetStackMaskSize() const {
594 return region_.Load<uint32_t>(kStackMaskSizeOffset);
595 }
596
597 void SetStackMaskSize(uint32_t size) {
598 region_.Store<uint32_t>(kStackMaskSizeOffset, size);
599 }
600
601 size_t GetNumberOfStackMaps() const {
602 return region_.Load<uint32_t>(kNumberOfStackMapsOffset);
603 }
604
605 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
606 region_.Store<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
607 }
608
Roland Levillain29ba1b02015-03-13 11:45:07 +0000609 // Get the size of one stack map of this CodeInfo object, in bytes.
610 // All stack maps of a CodeInfo have the same size.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100611 size_t StackMapSize() const {
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000612 return StackMap::ComputeAlignedStackMapSize(GetStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100613 }
614
Roland Levillain29ba1b02015-03-13 11:45:07 +0000615 // Get the size all the stack maps of this CodeInfo object, in bytes.
616 size_t StackMapsSize() const {
617 return StackMapSize() * GetNumberOfStackMaps();
618 }
619
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000620 uint32_t GetStackMapsOffset() const {
621 return kFixedSize;
622 }
623
Roland Levillain442b46a2015-02-18 16:54:21 +0000624 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
625 DCHECK(stack_map.HasDexRegisterMap());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100626 uint32_t offset = stack_map.GetDexRegisterMapOffset();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000627 size_t size = ComputeDexRegisterMapSize(offset, number_of_dex_registers);
628 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100629 }
630
Roland Levillain442b46a2015-02-18 16:54:21 +0000631 InlineInfo GetInlineInfoOf(StackMap stack_map) const {
632 DCHECK(stack_map.HasInlineInfo());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100633 uint32_t offset = stack_map.GetInlineDescriptorOffset();
634 uint8_t depth = region_.Load<uint8_t>(offset);
635 return InlineInfo(region_.Subregion(offset,
636 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
637 }
638
Roland Levillain442b46a2015-02-18 16:54:21 +0000639 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100640 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100641 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100642 if (stack_map.GetDexPc() == dex_pc) {
643 return stack_map;
644 }
645 }
646 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700647 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100648 }
649
Roland Levillain442b46a2015-02-18 16:54:21 +0000650 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100651 // TODO: stack maps are sorted by native pc, we can do a binary search.
652 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100653 StackMap stack_map = GetStackMapAt(i);
654 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100655 return stack_map;
656 }
657 }
658 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700659 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100660 }
661
662 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000663 // TODO: Instead of plain types such as "uint32_t", introduce
664 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +0100665 static constexpr int kOverallSizeOffset = 0;
666 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100667 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
668 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
669
670 MemoryRegion GetStackMaps() const {
671 return region_.size() == 0
672 ? MemoryRegion()
Roland Levillain29ba1b02015-03-13 11:45:07 +0000673 : region_.Subregion(kFixedSize, StackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100674 }
675
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000676 // Compute the size of a Dex register map starting at offset `origin` in
677 // `region_` and containing `number_of_dex_registers` locations.
678 size_t ComputeDexRegisterMapSize(uint32_t origin, uint32_t number_of_dex_registers) const {
679 // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
680 // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
681 // yet built. Try to factor common code.
682 size_t offset = origin + DexRegisterMap::kFixedSize;
683 // Skip the first `number_of_dex_registers - 1` entries.
684 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
685 // Read the first next byte and inspect its first 3 bits to decide
686 // whether it is a short or a large location.
687 DexRegisterMap::ShortLocation first_byte =
688 region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
689 DexRegisterLocation::Kind kind =
690 DexRegisterMap::ExtractKindFromShortLocation(first_byte);
691 if (DexRegisterLocation::IsShortLocationKind(kind)) {
692 // Short location. Skip the current byte.
693 offset += DexRegisterMap::SingleShortEntrySize();
694 } else {
695 // Large location. Skip the 5 next bytes.
696 offset += DexRegisterMap::SingleLargeEntrySize();
697 }
698 }
699 size_t size = offset - origin;
700 return size;
701 }
702
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100703 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100704 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100705};
706
707} // namespace art
708
709#endif // ART_RUNTIME_STACK_MAP_H_