blob: 961772c97e9318ae4d843abac932a69876a991f4 [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 Geoffrayfead4e42015-03-13 14:39:40 +000034// Size of Dex virtual registers.
35static size_t constexpr kVRegSize = 4;
36
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010037/**
38 * Classes in the following file are wrapper on stack map information backed
39 * by a MemoryRegion. As such they read and write to the region, they don't have
40 * their own fields.
41 */
42
43/**
44 * Inline information for a specific PC. The information is of the form:
45 * [inlining_depth, [method_dex reference]+]
46 */
47class InlineInfo {
48 public:
49 explicit InlineInfo(MemoryRegion region) : region_(region) {}
50
51 uint8_t GetDepth() const {
Roland Levillainede7bf82015-03-13 12:23:04 +000052 return region_.LoadUnaligned<uint8_t>(kDepthOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010053 }
54
55 void SetDepth(uint8_t depth) {
Roland Levillainede7bf82015-03-13 12:23:04 +000056 region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010057 }
58
59 uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
Roland Levillainede7bf82015-03-13 12:23:04 +000060 return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010061 }
62
63 void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
Roland Levillainede7bf82015-03-13 12:23:04 +000064 region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010065 }
66
67 static size_t SingleEntrySize() {
68 return sizeof(uint32_t);
69 }
70
71 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +000072 // TODO: Instead of plain types such as "uint8_t", introduce
73 // typedefs (and document the memory layout of InlineInfo).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010074 static constexpr int kDepthOffset = 0;
75 static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
76
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010077 MemoryRegion region_;
78
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 friend class CodeInfo;
80 friend class StackMap;
81 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +010082};
83
Roland Levillaina2d8ec62015-03-12 15:25:29 +000084// Dex register location container used by DexRegisterMap and StackMapStream.
85class DexRegisterLocation {
86 public:
87 /*
88 * The location kind used to populate the Dex register information in a
89 * StackMapStream can either be:
90 * - kNone: the register has no location yet, meaning it has not been set;
91 * - kConstant: value holds the constant;
92 * - kStack: value holds the stack offset;
93 * - kRegister: value holds the physical register number;
94 * - kFpuRegister: value holds the physical register number.
95 *
96 * In addition, DexRegisterMap also uses these values:
97 * - kInStackLargeOffset: value holds a "large" stack offset (greater than
98 * 128 bytes);
99 * - kConstantLargeValue: value holds a "large" constant (lower than or
100 * equal to -16, or greater than 16).
101 */
102 enum class Kind : uint8_t {
103 // Short location kinds, for entries fitting on one byte (3 bits
104 // for the kind, 5 bits for the value) in a DexRegisterMap.
105 kNone = 0, // 0b000
106 kInStack = 1, // 0b001
107 kInRegister = 2, // 0b010
108 kInFpuRegister = 3, // 0b011
109 kConstant = 4, // 0b100
110
111 // Large location kinds, requiring a 5-byte encoding (1 byte for the
112 // kind, 4 bytes for the value).
113
114 // Stack location at a large offset, meaning that the offset value
115 // divided by the stack frame slot size (4 bytes) cannot fit on a
116 // 5-bit unsigned integer (i.e., this offset value is greater than
117 // or equal to 2^5 * 4 = 128 bytes).
118 kInStackLargeOffset = 5, // 0b101
119
120 // Large constant, that cannot fit on a 5-bit signed integer (i.e.,
121 // lower than -2^(5-1) = -16, or greater than or equal to
122 // 2^(5-1) - 1 = 15).
123 kConstantLargeValue = 6, // 0b110
124
125 kLastLocationKind = kConstantLargeValue
126 };
127
128 static_assert(
129 sizeof(Kind) == 1u,
130 "art::DexRegisterLocation::Kind has a size different from one byte.");
131
132 static const char* PrettyDescriptor(Kind kind) {
133 switch (kind) {
134 case Kind::kNone:
135 return "none";
136 case Kind::kInStack:
137 return "in stack";
138 case Kind::kInRegister:
139 return "in register";
140 case Kind::kInFpuRegister:
141 return "in fpu register";
142 case Kind::kConstant:
143 return "as constant";
144 case Kind::kInStackLargeOffset:
145 return "in stack (large offset)";
146 case Kind::kConstantLargeValue:
147 return "as constant (large value)";
148 default:
149 UNREACHABLE();
150 }
151 }
152
153 static bool IsShortLocationKind(Kind kind) {
154 switch (kind) {
155 case Kind::kNone:
156 case Kind::kInStack:
157 case Kind::kInRegister:
158 case Kind::kInFpuRegister:
159 case Kind::kConstant:
160 return true;
161
162 case Kind::kInStackLargeOffset:
163 case Kind::kConstantLargeValue:
164 return false;
165
166 default:
167 UNREACHABLE();
168 }
169 }
170
171 // Convert `kind` to a "surface" kind, i.e. one that doesn't include
172 // any value with a "large" qualifier.
173 // TODO: Introduce another enum type for the surface kind?
174 static Kind ConvertToSurfaceKind(Kind kind) {
175 switch (kind) {
176 case Kind::kNone:
177 case Kind::kInStack:
178 case Kind::kInRegister:
179 case Kind::kInFpuRegister:
180 case Kind::kConstant:
181 return kind;
182
183 case Kind::kInStackLargeOffset:
184 return Kind::kInStack;
185
186 case Kind::kConstantLargeValue:
187 return Kind::kConstant;
188
189 default:
190 UNREACHABLE();
191 }
192 }
193
194 DexRegisterLocation(Kind kind, int32_t value)
195 : kind_(kind), value_(value) {}
196
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000197 static DexRegisterLocation None() {
198 return DexRegisterLocation(Kind::kNone, 0);
199 }
200
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000201 // Get the "surface" kind of the location, i.e., the one that doesn't
202 // include any value with a "large" qualifier.
203 Kind GetKind() const {
204 return ConvertToSurfaceKind(kind_);
205 }
206
207 // Get the value of the location.
208 int32_t GetValue() const { return value_; }
209
210 // Get the actual kind of the location.
211 Kind GetInternalKind() const { return kind_; }
212
213 private:
214 Kind kind_;
215 int32_t value_;
216};
217
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100218/**
219 * Information on dex register values for a specific PC. The information is
220 * of the form:
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000221 * [live_bit_mask, DexRegisterLocation+].
222 * DexRegisterLocations are either 1- or 5-byte wide (see art::DexRegisterLocation::Kind).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100223 */
224class DexRegisterMap {
225 public:
226 explicit DexRegisterMap(MemoryRegion region) : region_(region) {}
227
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000228 // Short (compressed) location, fitting on one byte.
229 typedef uint8_t ShortLocation;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100230
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000231 static size_t LiveBitMaskSize(uint16_t number_of_dex_registers) {
232 return RoundUp(number_of_dex_registers, kBitsPerByte) / kBitsPerByte;
233 }
234
235 void SetLiveBitMask(size_t offset,
236 uint16_t number_of_dex_registers,
237 const BitVector& live_dex_registers_mask) {
238 for (uint16_t i = 0; i < number_of_dex_registers; i++) {
239 region_.StoreBit(offset + i, live_dex_registers_mask.IsBitSet(i));
240 }
241 }
242
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000243 void SetRegisterInfo(size_t offset, const DexRegisterLocation& dex_register_location) {
244 DexRegisterLocation::Kind kind = ComputeCompressedKind(dex_register_location);
245 int32_t value = dex_register_location.GetValue();
246 if (DexRegisterLocation::IsShortLocationKind(kind)) {
247 // Short location. Compress the kind and the value as a single byte.
248 if (kind == DexRegisterLocation::Kind::kInStack) {
249 // Instead of storing stack offsets expressed in bytes for
250 // short stack locations, store slot offsets. A stack offset
251 // is a multiple of 4 (kFrameSlotSize). This means that by
252 // dividing it by 4, we can fit values from the [0, 128)
253 // interval in a short stack location, and not just values
254 // from the [0, 32) interval.
255 DCHECK_EQ(value % kFrameSlotSize, 0);
256 value /= kFrameSlotSize;
257 }
258 DCHECK(IsUint<kValueBits>(value)) << value;
259 region_.StoreUnaligned<ShortLocation>(offset, MakeShortLocation(kind, value));
260 } else {
261 // Large location. Write the location on one byte and the value
262 // on 4 bytes.
263 DCHECK(!IsUint<kValueBits>(value)) << value;
264 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
265 // Also divide large stack offsets by 4 for the sake of consistency.
266 DCHECK_EQ(value % kFrameSlotSize, 0);
267 value /= kFrameSlotSize;
268 }
269 // Data can be unaligned as the written Dex register locations can
270 // either be 1-byte or 5-byte wide. Use
271 // art::MemoryRegion::StoreUnaligned instead of
272 // art::MemoryRegion::Store to prevent unligned word accesses on ARM.
273 region_.StoreUnaligned<DexRegisterLocation::Kind>(offset, kind);
274 region_.StoreUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind), value);
Roland Levillain442b46a2015-02-18 16:54:21 +0000275 }
276 }
277
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000278 bool IsDexRegisterLive(uint16_t dex_register_index) const {
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000279 size_t offset = kFixedSize;
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000280 return region_.LoadBit(offset + dex_register_index);
281 }
282
283 static constexpr size_t kNoDexRegisterLocationOffset = -1;
284
285 static size_t GetDexRegisterMapLocationsOffset(uint16_t number_of_dex_registers) {
286 return kLiveBitMaskOffset + LiveBitMaskSize(number_of_dex_registers);
287 }
288
289 // Find the offset of the Dex register location number `dex_register_index`.
290 size_t FindLocationOffset(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
291 if (!IsDexRegisterLive(dex_register_index)) return kNoDexRegisterLocationOffset;
292 size_t offset = GetDexRegisterMapLocationsOffset(number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000293 // Skip the first `dex_register_index - 1` entries.
294 for (uint16_t i = 0; i < dex_register_index; ++i) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000295 if (IsDexRegisterLive(i)) {
296 // Read the first next byte and inspect its first 3 bits to decide
297 // whether it is a short or a large location.
298 DexRegisterLocation::Kind kind = ExtractKindAtOffset(offset);
299 if (DexRegisterLocation::IsShortLocationKind(kind)) {
300 // Short location. Skip the current byte.
301 offset += SingleShortEntrySize();
302 } else {
303 // Large location. Skip the 5 next bytes.
304 offset += SingleLargeEntrySize();
305 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000306 }
307 }
308 return offset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100309 }
310
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000311 // Get the surface kind.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000312 DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_index,
313 uint16_t number_of_dex_registers) const {
314 return IsDexRegisterLive(dex_register_index)
315 ? DexRegisterLocation::ConvertToSurfaceKind(
316 GetLocationInternalKind(dex_register_index, number_of_dex_registers))
317 : DexRegisterLocation::Kind::kNone;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100318 }
319
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000320 // Get the internal kind.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000321 DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_index,
322 uint16_t number_of_dex_registers) const {
323 return IsDexRegisterLive(dex_register_index)
324 ? ExtractKindAtOffset(FindLocationOffset(dex_register_index, number_of_dex_registers))
325 : DexRegisterLocation::Kind::kNone;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100326 }
327
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000328 // TODO: Rename as GetDexRegisterLocation?
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000329 DexRegisterLocation GetLocationKindAndValue(uint16_t dex_register_index,
330 uint16_t number_of_dex_registers) const {
331 if (!IsDexRegisterLive(dex_register_index)) {
332 return DexRegisterLocation::None();
333 }
334 size_t offset = FindLocationOffset(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000335 // Read the first byte and inspect its first 3 bits to get the location.
336 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
337 DexRegisterLocation::Kind kind = ExtractKindFromShortLocation(first_byte);
338 if (DexRegisterLocation::IsShortLocationKind(kind)) {
339 // Short location. Extract the value from the remaining 5 bits.
340 int32_t value = ExtractValueFromShortLocation(first_byte);
341 if (kind == DexRegisterLocation::Kind::kInStack) {
342 // Convert the stack slot (short) offset to a byte offset value.
343 value *= kFrameSlotSize;
344 }
345 return DexRegisterLocation(kind, value);
346 } else {
347 // Large location. Read the four next bytes to get the value.
348 int32_t value = region_.LoadUnaligned<int32_t>(offset + sizeof(DexRegisterLocation::Kind));
349 if (kind == DexRegisterLocation::Kind::kInStackLargeOffset) {
350 // Convert the stack slot (large) offset to a byte offset value.
351 value *= kFrameSlotSize;
352 }
353 return DexRegisterLocation(kind, value);
354 }
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100355 }
356
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000357 int32_t GetStackOffsetInBytes(uint16_t dex_register_index,
358 uint16_t number_of_dex_registers) const {
359 DexRegisterLocation location =
360 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000361 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
362 // GetLocationKindAndValue returns the offset in bytes.
363 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100364 }
365
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000366 int32_t GetConstant(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
367 DexRegisterLocation location =
368 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000369 DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
370 return location.GetValue();
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100371 }
372
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000373 int32_t GetMachineRegister(uint16_t dex_register_index, uint16_t number_of_dex_registers) const {
374 DexRegisterLocation location =
375 GetLocationKindAndValue(dex_register_index, number_of_dex_registers);
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000376 DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
377 || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
378 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
379 return location.GetValue();
380 }
381
382 // Compute the compressed kind of `location`.
383 static DexRegisterLocation::Kind ComputeCompressedKind(const DexRegisterLocation& location) {
384 switch (location.GetInternalKind()) {
385 case DexRegisterLocation::Kind::kNone:
386 DCHECK_EQ(location.GetValue(), 0);
387 return DexRegisterLocation::Kind::kNone;
388
389 case DexRegisterLocation::Kind::kInRegister:
390 DCHECK_GE(location.GetValue(), 0);
391 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
392 return DexRegisterLocation::Kind::kInRegister;
393
394 case DexRegisterLocation::Kind::kInFpuRegister:
395 DCHECK_GE(location.GetValue(), 0);
396 DCHECK_LT(location.GetValue(), 1 << DexRegisterMap::kValueBits);
397 return DexRegisterLocation::Kind::kInFpuRegister;
398
399 case DexRegisterLocation::Kind::kInStack:
400 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
401 return IsUint<DexRegisterMap::kValueBits>(location.GetValue() / kFrameSlotSize)
402 ? DexRegisterLocation::Kind::kInStack
403 : DexRegisterLocation::Kind::kInStackLargeOffset;
404
405 case DexRegisterLocation::Kind::kConstant:
406 return IsUint<DexRegisterMap::kValueBits>(location.GetValue())
407 ? DexRegisterLocation::Kind::kConstant
408 : DexRegisterLocation::Kind::kConstantLargeValue;
409
410 default:
411 LOG(FATAL) << "Unexpected location kind"
412 << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
413 UNREACHABLE();
414 }
415 }
416
417 // Can `location` be turned into a short location?
418 static bool CanBeEncodedAsShortLocation(const DexRegisterLocation& location) {
419 switch (location.GetInternalKind()) {
420 case DexRegisterLocation::Kind::kNone:
421 case DexRegisterLocation::Kind::kInRegister:
422 case DexRegisterLocation::Kind::kInFpuRegister:
423 return true;
424
425 case DexRegisterLocation::Kind::kInStack:
426 DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
427 return IsUint<kValueBits>(location.GetValue() / kFrameSlotSize);
428
429 case DexRegisterLocation::Kind::kConstant:
430 return IsUint<kValueBits>(location.GetValue());
431
432 default:
433 UNREACHABLE();
434 }
435 }
436
437 static size_t EntrySize(const DexRegisterLocation& location) {
438 return CanBeEncodedAsShortLocation(location)
439 ? DexRegisterMap::SingleShortEntrySize()
440 : DexRegisterMap::SingleLargeEntrySize();
441 }
442
443 static size_t SingleShortEntrySize() {
444 return sizeof(ShortLocation);
445 }
446
447 static size_t SingleLargeEntrySize() {
448 return sizeof(DexRegisterLocation::Kind) + sizeof(int32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100449 }
450
Roland Levillain12baf472015-03-05 12:41:42 +0000451 size_t Size() const {
452 return region_.size();
453 }
454
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000455 static constexpr int kLiveBitMaskOffset = 0;
456 static constexpr int kFixedSize = kLiveBitMaskOffset;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100457
Roland Levillain12baf472015-03-05 12:41:42 +0000458 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000459 // Width of the kind "field" in a short location, in bits.
460 static constexpr size_t kKindBits = 3;
461 // Width of the value "field" in a short location, in bits.
462 static constexpr size_t kValueBits = 5;
463
464 static constexpr uint8_t kKindMask = (1 << kKindBits) - 1;
465 static constexpr int32_t kValueMask = (1 << kValueBits) - 1;
466 static constexpr size_t kKindOffset = 0;
467 static constexpr size_t kValueOffset = kKindBits;
468
469 static ShortLocation MakeShortLocation(DexRegisterLocation::Kind kind, int32_t value) {
470 DCHECK(IsUint<kKindBits>(static_cast<uint8_t>(kind))) << static_cast<uint8_t>(kind);
471 DCHECK(IsUint<kValueBits>(value)) << value;
472 return (static_cast<uint8_t>(kind) & kKindMask) << kKindOffset
473 | (value & kValueMask) << kValueOffset;
474 }
475
476 static DexRegisterLocation::Kind ExtractKindFromShortLocation(ShortLocation location) {
477 uint8_t kind = (location >> kKindOffset) & kKindMask;
478 DCHECK_LE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kLastLocationKind));
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000479 // We do not encode kNone locations in the stack map.
480 DCHECK_NE(kind, static_cast<uint8_t>(DexRegisterLocation::Kind::kNone));
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000481 return static_cast<DexRegisterLocation::Kind>(kind);
482 }
483
484 static int32_t ExtractValueFromShortLocation(ShortLocation location) {
485 return (location >> kValueOffset) & kValueMask;
486 }
487
488 // Extract a location kind from the byte at position `offset`.
489 DexRegisterLocation::Kind ExtractKindAtOffset(size_t offset) const {
490 ShortLocation first_byte = region_.LoadUnaligned<ShortLocation>(offset);
491 return ExtractKindFromShortLocation(first_byte);
492 }
493
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100494 MemoryRegion region_;
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000495
496 friend class CodeInfo;
497 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100498};
499
500/**
501 * A Stack Map holds compilation information for a specific PC necessary for:
502 * - Mapping it to a dex PC,
503 * - Knowing which stack entries are objects,
504 * - Knowing which registers hold objects,
505 * - Knowing the inlining information,
506 * - Knowing the values of dex registers.
507 *
508 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100509 * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask, stack_mask].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100510 *
511 * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
512 * stack size of a method.
513 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100514class StackMap {
515 public:
516 explicit StackMap(MemoryRegion region) : region_(region) {}
517
518 uint32_t GetDexPc() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000519 return region_.LoadUnaligned<uint32_t>(kDexPcOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100520 }
521
522 void SetDexPc(uint32_t dex_pc) {
Roland Levillainede7bf82015-03-13 12:23:04 +0000523 region_.StoreUnaligned<uint32_t>(kDexPcOffset, dex_pc);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100524 }
525
Nicolas Geoffray39468442014-09-02 15:17:15 +0100526 uint32_t GetNativePcOffset() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000527 return region_.LoadUnaligned<uint32_t>(kNativePcOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100528 }
529
Nicolas Geoffray39468442014-09-02 15:17:15 +0100530 void SetNativePcOffset(uint32_t native_pc_offset) {
Roland Levillainede7bf82015-03-13 12:23:04 +0000531 region_.StoreUnaligned<uint32_t>(kNativePcOffsetOffset, native_pc_offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100532 }
533
534 uint32_t GetDexRegisterMapOffset() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000535 return region_.LoadUnaligned<uint32_t>(kDexRegisterMapOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100536 }
537
538 void SetDexRegisterMapOffset(uint32_t offset) {
Roland Levillainede7bf82015-03-13 12:23:04 +0000539 region_.StoreUnaligned<uint32_t>(kDexRegisterMapOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100540 }
541
542 uint32_t GetInlineDescriptorOffset() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000543 return region_.LoadUnaligned<uint32_t>(kInlineDescriptorOffsetOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100544 }
545
546 void SetInlineDescriptorOffset(uint32_t offset) {
Roland Levillainede7bf82015-03-13 12:23:04 +0000547 region_.StoreUnaligned<uint32_t>(kInlineDescriptorOffsetOffset, offset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100548 }
549
550 uint32_t GetRegisterMask() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000551 return region_.LoadUnaligned<uint32_t>(kRegisterMaskOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100552 }
553
554 void SetRegisterMask(uint32_t mask) {
Roland Levillainede7bf82015-03-13 12:23:04 +0000555 region_.StoreUnaligned<uint32_t>(kRegisterMaskOffset, mask);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100556 }
557
558 MemoryRegion GetStackMask() const {
559 return region_.Subregion(kStackMaskOffset, StackMaskSize());
560 }
561
562 void SetStackMask(const BitVector& sp_map) {
563 MemoryRegion region = GetStackMask();
564 for (size_t i = 0; i < region.size_in_bits(); i++) {
565 region.StoreBit(i, sp_map.IsBitSet(i));
566 }
567 }
568
Roland Levillain442b46a2015-02-18 16:54:21 +0000569 bool HasDexRegisterMap() const {
570 return GetDexRegisterMapOffset() != kNoDexRegisterMap;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100571 }
572
Roland Levillain442b46a2015-02-18 16:54:21 +0000573 bool HasInlineInfo() const {
574 return GetInlineDescriptorOffset() != kNoInlineInfo;
575 }
576
577 bool Equals(const StackMap& other) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100578 return region_.pointer() == other.region_.pointer()
579 && region_.size() == other.region_.size();
580 }
581
Roland Levillainede7bf82015-03-13 12:23:04 +0000582 static size_t ComputeStackMapSize(size_t stack_mask_size) {
583 return StackMap::kFixedSize + stack_mask_size;
Nicolas Geoffray376b2bb2014-12-09 14:26:32 +0000584 }
585
Roland Levillain442b46a2015-02-18 16:54:21 +0000586 // Special (invalid) offset for the DexRegisterMapOffset field meaning
587 // that there is no Dex register map for this stack map.
588 static constexpr uint32_t kNoDexRegisterMap = -1;
589
590 // Special (invalid) offset for the InlineDescriptorOffset field meaning
591 // that there is no inline info for this stack map.
592 static constexpr uint32_t kNoInlineInfo = -1;
593
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100594 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000595 // TODO: Instead of plain types such as "uint32_t", introduce
596 // typedefs (and document the memory layout of StackMap).
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100597 static constexpr int kDexPcOffset = 0;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100598 static constexpr int kNativePcOffsetOffset = kDexPcOffset + sizeof(uint32_t);
599 static constexpr int kDexRegisterMapOffsetOffset = kNativePcOffsetOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100600 static constexpr int kInlineDescriptorOffsetOffset =
601 kDexRegisterMapOffsetOffset + sizeof(uint32_t);
602 static constexpr int kRegisterMaskOffset = kInlineDescriptorOffsetOffset + sizeof(uint32_t);
603 static constexpr int kFixedSize = kRegisterMaskOffset + sizeof(uint32_t);
604 static constexpr int kStackMaskOffset = kFixedSize;
605
606 size_t StackMaskSize() const { return region_.size() - kFixedSize; }
607
608 MemoryRegion region_;
609
Nicolas Geoffray39468442014-09-02 15:17:15 +0100610 friend class CodeInfo;
611 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100612};
613
614
615/**
616 * Wrapper around all compiler information collected for a method.
617 * The information is of the form:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100618 * [overall_size, number_of_stack_maps, stack_mask_size, StackMap+, DexRegisterInfo+, InlineInfo*].
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100619 */
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100620class CodeInfo {
621 public:
622 explicit CodeInfo(MemoryRegion region) : region_(region) {}
623
Nicolas Geoffray39468442014-09-02 15:17:15 +0100624 explicit CodeInfo(const void* data) {
625 uint32_t size = reinterpret_cast<const uint32_t*>(data)[0];
626 region_ = MemoryRegion(const_cast<void*>(data), size);
627 }
628
629 StackMap GetStackMapAt(size_t i) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100630 size_t size = StackMapSize();
Nicolas Geoffray39468442014-09-02 15:17:15 +0100631 return StackMap(GetStackMaps().Subregion(i * size, size));
632 }
633
634 uint32_t GetOverallSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000635 return region_.LoadUnaligned<uint32_t>(kOverallSizeOffset);
Nicolas Geoffray39468442014-09-02 15:17:15 +0100636 }
637
638 void SetOverallSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000639 region_.StoreUnaligned<uint32_t>(kOverallSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100640 }
641
642 uint32_t GetStackMaskSize() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000643 return region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100644 }
645
646 void SetStackMaskSize(uint32_t size) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000647 region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, size);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100648 }
649
650 size_t GetNumberOfStackMaps() const {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000651 return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100652 }
653
654 void SetNumberOfStackMaps(uint32_t number_of_stack_maps) {
Nicolas Geoffrayaec8f932015-03-18 10:42:22 +0000655 region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100656 }
657
Roland Levillain29ba1b02015-03-13 11:45:07 +0000658 // Get the size of one stack map of this CodeInfo object, in bytes.
659 // All stack maps of a CodeInfo have the same size.
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100660 size_t StackMapSize() const {
Roland Levillainede7bf82015-03-13 12:23:04 +0000661 return StackMap::ComputeStackMapSize(GetStackMaskSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100662 }
663
Roland Levillain29ba1b02015-03-13 11:45:07 +0000664 // Get the size all the stack maps of this CodeInfo object, in bytes.
665 size_t StackMapsSize() const {
666 return StackMapSize() * GetNumberOfStackMaps();
667 }
668
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000669 uint32_t GetStackMapsOffset() const {
670 return kFixedSize;
671 }
672
Roland Levillain442b46a2015-02-18 16:54:21 +0000673 DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
674 DCHECK(stack_map.HasDexRegisterMap());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100675 uint32_t offset = stack_map.GetDexRegisterMapOffset();
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000676 size_t size = ComputeDexRegisterMapSize(offset, number_of_dex_registers);
677 return DexRegisterMap(region_.Subregion(offset, size));
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100678 }
679
Roland Levillain442b46a2015-02-18 16:54:21 +0000680 InlineInfo GetInlineInfoOf(StackMap stack_map) const {
681 DCHECK(stack_map.HasInlineInfo());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100682 uint32_t offset = stack_map.GetInlineDescriptorOffset();
683 uint8_t depth = region_.Load<uint8_t>(offset);
684 return InlineInfo(region_.Subregion(offset,
685 InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
686 }
687
Roland Levillain442b46a2015-02-18 16:54:21 +0000688 StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100689 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100690 StackMap stack_map = GetStackMapAt(i);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100691 if (stack_map.GetDexPc() == dex_pc) {
692 return stack_map;
693 }
694 }
695 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700696 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100697 }
698
Roland Levillain442b46a2015-02-18 16:54:21 +0000699 StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100700 // TODO: stack maps are sorted by native pc, we can do a binary search.
701 for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100702 StackMap stack_map = GetStackMapAt(i);
703 if (stack_map.GetNativePcOffset() == native_pc_offset) {
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100704 return stack_map;
705 }
706 }
707 LOG(FATAL) << "Unreachable";
Ian Rogers2c4257b2014-10-24 14:20:06 -0700708 UNREACHABLE();
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100709 }
710
711 private:
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000712 // TODO: Instead of plain types such as "uint32_t", introduce
713 // typedefs (and document the memory layout of CodeInfo).
Nicolas Geoffray39468442014-09-02 15:17:15 +0100714 static constexpr int kOverallSizeOffset = 0;
715 static constexpr int kNumberOfStackMapsOffset = kOverallSizeOffset + sizeof(uint32_t);
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100716 static constexpr int kStackMaskSizeOffset = kNumberOfStackMapsOffset + sizeof(uint32_t);
717 static constexpr int kFixedSize = kStackMaskSizeOffset + sizeof(uint32_t);
718
719 MemoryRegion GetStackMaps() const {
720 return region_.size() == 0
721 ? MemoryRegion()
Roland Levillain29ba1b02015-03-13 11:45:07 +0000722 : region_.Subregion(kFixedSize, StackMapsSize());
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100723 }
724
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000725 // Compute the size of a Dex register map starting at offset `origin` in
726 // `region_` and containing `number_of_dex_registers` locations.
727 size_t ComputeDexRegisterMapSize(uint32_t origin, uint32_t number_of_dex_registers) const {
728 // TODO: Ideally, we would like to use art::DexRegisterMap::Size or
729 // art::DexRegisterMap::FindLocationOffset, but the DexRegisterMap is not
730 // yet built. Try to factor common code.
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000731 size_t offset =
732 origin + DexRegisterMap::GetDexRegisterMapLocationsOffset(number_of_dex_registers);
733
734 // Create a temporary DexRegisterMap to be able to call DexRegisterMap.IsDexRegisterLive.
735 DexRegisterMap only_live_mask(MemoryRegion(region_.Subregion(origin, offset - origin)));
736
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000737 // Skip the first `number_of_dex_registers - 1` entries.
738 for (uint16_t i = 0; i < number_of_dex_registers; ++i) {
Nicolas Geoffrayfead4e42015-03-13 14:39:40 +0000739 if (only_live_mask.IsDexRegisterLive(i)) {
740 // Read the first next byte and inspect its first 3 bits to decide
741 // whether it is a short or a large location.
742 DexRegisterMap::ShortLocation first_byte =
743 region_.LoadUnaligned<DexRegisterMap::ShortLocation>(offset);
744 DexRegisterLocation::Kind kind =
745 DexRegisterMap::ExtractKindFromShortLocation(first_byte);
746 if (DexRegisterLocation::IsShortLocationKind(kind)) {
747 // Short location. Skip the current byte.
748 offset += DexRegisterMap::SingleShortEntrySize();
749 } else {
750 // Large location. Skip the 5 next bytes.
751 offset += DexRegisterMap::SingleLargeEntrySize();
752 }
Roland Levillaina2d8ec62015-03-12 15:25:29 +0000753 }
754 }
755 size_t size = offset - origin;
756 return size;
757 }
758
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100759 MemoryRegion region_;
Nicolas Geoffray39468442014-09-02 15:17:15 +0100760 friend class StackMapStream;
Nicolas Geoffray99ea58c2014-07-02 15:08:17 +0100761};
762
763} // namespace art
764
765#endif // ART_RUNTIME_STACK_MAP_H_